servo/etc/taskcluster
bors-servo ef192c6b36
Auto merge of #24811 - servo:fail-fast, r=jdm
Fix updating the GitHub Status as soon as any TC task fails

… rather than only when the entire task group is resolved. This allows Homu to more quickly be notified of a failure, and move on to the next PR in the queue sooner.

(Plus drive-by Brewfile fix.)
2019-11-22 14:58:40 -05:00
..
docker Fix run.dockerfile to actually be able to run current Servo 2019-11-19 17:38:47 +01:00
macos Fix Brewfile’s for running Servo without bulding it 2019-11-22 16:09:02 +01:00
decision_task.py Auto merge of #24811 - servo:fail-fast, r=jdm 2019-11-22 14:58:40 -05:00
decisionlib.py Remove support for shallow clones. The bundle is already shallow. 2019-11-22 18:14:26 +01:00
mock.py Decision taks: add artifacts of the repository’s contents 2019-11-22 16:09:03 +01:00
README.md Add link to worker list view 2019-11-14 16:09:30 +01:00
simulate_github_events.py Add a script to run .taskcluster.yml expansion offline 2019-01-07 15:00:06 +01:00
treeherder.md Update etc/taskcluster/README.md for Community-TC migration 2019-11-13 20:24:42 +01:00

Testing Servo on Taskcluster

In-tree and out-of-tree configuration

Where possible, we prefer keeping Taskcluster-related configuration and code in this directory, set up CI so that testing of a given git branch uses the version in that branch. That way, anyone can make changes (such installing a new system dependency in a Dockerfile) in the same PR that relies on those changes.

For some things however that is not practical, or some deployment step that mutates global state is required. That configuration is split between the mozilla/community-tc-config and servo/taskcluster-config repositories, managed by the Taskcluster team and the Servo team repsectively.

Homu

When a pull request is reviewed and the appropriate command is given, Homu creates a merge commit of master and the PRs branch, and pushes it to the auto branch. One or more CI system (through their own means) get notified of this push by GitHub, start testing the merge commit, and use the GitHub Status API to report results.

Through a Webhook, Homu gets notified of changes to these statues. If all of the required statuses are reported successful, Homu pushes its merge commit to the master branch and goes on to testing the next pull request in its queue.

Taskcluster GitHub integration

Taskcluster is very flexible and not necessarily tied to GitHub, but it does have an optional GitHub integration service that you can enable on a repository as a GitHub App. When enabled, this service gets notified for every push, pull request, or GitHub release. It then schedules some tasks based on reading .taskcluster.yml in the corresponding commit.

This file contains templates for creating one or more tasks, but the logic it can support is fairly limited. So a common pattern is to have it only run a single initial task called a decision task that can have complex logic based on code and data in the repository to build an arbitrary task graph.

Servos decision task

This repositorys .taskcluster.yml schedules a single task that runs the Python 3 script etc/taskcluster/decision_task.py. It is called a decision task as it is responsible for deciding what other tasks to schedule.

The Docker image that runs the decision task is hosted on Docker Hub at servobrowser/taskcluster-bootstrap. It is built by Docker Hub automated builds based on a Dockerfile in the taskcluster-bootstrap-docker-images GitHub repository. Hopefully, this image does not need to be modified often as it only needs to clone the repository and run Python.

Docker images

Similar to Firefox, Servos decision task supports running other tasks in Docker images built on-demand, based on Dockerfiles in the main repository. Modifying a Dockerfile and relying on those new changes can be done in the same pull request or commit.

To avoid rebuilding images on every pull request, they are cached based on a hash of the source Dockerfile. For now, to support this hashing, we make Dockerfiles be self-contained (with one exception). Images are built without a context, so instructions like COPY cannot be used because there is nothing to copy from. The exception is that the decision task adds support for a non-standard include directive: when a Dockerfile first line is % include followed by a filename, that line is replaced with the content of that file.

For example, etc/taskcluster/docker/build.dockerfile starts like so:

% include base.dockerfile

RUN \
    apt-get install -qy --no-install-recommends \
# […]

Build artifacts

web-platform-tests (WPT) is large enough that running all of a it takes a long time. So it supports chunking, such as multiple chunks of the test suite can be run in parallel on different machines. As of this writing, Servos current Buildbot setup for this has each machine start by compiling its own copy of Servo. On Taskcluster with a decision task, we can have a single build task save its resulting binary executable as an artifact, together with multiple testing tasks that each depend on the build task (wait until it successfully finishes before they can start) and start by downloading the artifact that was saved earlier.

The logic for all this is in decision_task.py and can be modified in any pull request.

Log artifacts

Taskcluster automatically save the stdio output of a task as an artifact, and has special support for showing and streaming that output while the task is still running.

Servos decision task additionally looks for *.log arguments to its taskss commands, assumes they instruct a program to create a log file with that name, and saves those log files as individual artifacts.

For example, WPT tasks have a filtered-wpt-errorsummary.log artifact that is typically the most relevant output when such a task fails.

Scopes and roles

Scopes are what Taskcluster calls permissions. They control access to everything.

Anyone logged in in the web UI has (access to) a set of scopes, which is visible on the credentials page (reachable from clicking on ones own name on the top-right of any page).

A running task has a set of scopes allowing it access to various functionality and APIs. It can grant those scopes (and at most only thoses) to sub-tasks that it schedules (if it has the scope allowing it to schedule new tasks in the first place).

Roles represent each a set of scopes. They can be granted to… things, and then configured separately to modify what scopes they expand to.

For example, when Taskcluster-GitHub schedules tasks based on the .taskcluster.yml file in a push to the auto branch of this repository, those tasks are granted the scope assume:repo:github.com/servo/servo:branch:auto. Scopes that start with assume: are special, they expand to the scopes defined in the matching roles. In this case, the repo:github.com/servo/servo:branch:* role matches.

The project:servo:decision-task/base and project:servo:decision-task/trusted roles centralize the set of scopes granted to the decision task. This avoids maintaining them seprately in the repo:… roles, in the hook-id:… role, and in the taskcluster.yml file. Only the base role is granted to tasks executed when a pull request is opened. These tasks are less trusted because they run before the code has been reviewed, and anyone can open a PR.

Members of the @servo/taskcluster-admins GitHub team are granted the scope assume:project-admin:servo, which is necessary to deploy changes to those roles from the servo/taskcluster-config repository.

Daily tasks

The project-servo/daily hook in Taskclusters Hooks service is used to run some tasks automatically ever 24 hours. In this case as well we use a decision task. The decision_task.py script can differenciate this from a GitHub push based on the $TASK_FOR environment variable. Daily tasks can also be triggered manually.

Scopes available to the daily decision task need to be both requested in the hook definition and granted through the hook-id:project-servo/daily role.

Because they do not have something similar to GitHub statuses that link to them, daily tasks are indexed under the project.servo.daily namespace.

Servos worker pools

Each task is assigned to a “worker pool”. Servo has several, for the different environments a task can run in:

  • docker and docker-untrusted provide a Linux environment with full root privileges, in a Docker container running a Docker image of the tasks choice, in a short-lived virtual machine, on Google Cloud Platform.

    Instances are started automatically as needed when the existing capacity is insufficient to execute queued tasks. They terminate themselves after being idle without work for a while, or unconditionally after a few days. Because these workers are short-lived, we dont need to worry about evicting old entries from Cargos or rustups download cache, for example.

    The Taskcluster team manages the configuration and VM image for these two pools. The latter has fewer scopes. It runs automated testing of pull requests as soon as theyre opened or updated, before any review.

  • win2016 runs Windows Server 2016 on AWS EC2. Like with Docker tasks, workers are short-lived and started automatically. The configuration and VM image for this pool is managed by the Servo team.

    Tasks run as an unprivileged user. Because creating an new the VM image is slow and deploying it mutates global state, when a tool does not require system-wide installation we prefer having each task obtain it as needed by extracting an archive in a directory. See calls of with_directory_mount and with_repacked_msi in decision_task.py and decisionlib.py.

  • macos runs, you guessed it, macOS. Tasks run on dedicated hardware provided long-term by Macstadium. The system-wide configuration of those machines is managed by the Servo team through SaltStack. There is a task-owned (but preserved across tasks) install of Homebrew, with Brewfiles in this repository.

    This Workers page lists the current state of each macOS worker. (A similar page exists for other each worker pools, but as of this writing it has usability issues with short-lived workers.)

Taskcluster Treeherder integration

See treeherder.md.

Self-service, IRC, and Bugzilla

Taskcluster is designed to be “self-service” as much as possible. Between this repository servo/taskcluster-config and mozilla/community-tc-config, anyone should be able to submit PRs for any part of the configuration.

Feel free to ask for help on the #servo or #taskcluster channels on Mozilla IRC.

For issue reports or feature requests on various bits of Taskcluster software, file bugs in Mozillas Bugzilla, under Taskcluster.