aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2023-04-10 13:56:47 +0200
committerMartin Robinson <mrobinson@igalia.com>2023-04-10 23:04:17 +0200
commitbc3abf995313ece462233c914f4aa61b76566e66 (patch)
tree48d83efc5f52ab9118dc09dd229ffee4ade9ceb3
parentd579bd91b8e82606907dd789f13f6ecaee6a9b18 (diff)
downloadservo-bc3abf995313ece462233c914f4aa61b76566e66.tar.gz
servo-bc3abf995313ece462233c914f4aa61b76566e66.zip
Remove more Taskcluster and Treeherder integration
Servo no longer uses Taskcluster and Treeherder, so this change removes script references to those services and support files.
-rw-r--r--.github/workflows/mac.yml6
-rw-r--r--.gitignore2
-rw-r--r--.taskcluster.yml120
-rw-r--r--README.md4
-rwxr-xr-xetc/ci/update-wpt-checkout5
-rw-r--r--etc/homebrew/Brewfile (renamed from etc/taskcluster/macos/Brewfile)0
-rw-r--r--etc/homebrew/Brewfile-build (renamed from etc/taskcluster/macos/Brewfile-build)0
-rw-r--r--etc/homebrew/Brewfile-wpt-update (renamed from etc/taskcluster/macos/Brewfile-wpt-update)0
-rw-r--r--etc/taskcluster/README.md277
-rw-r--r--etc/taskcluster/decision_task.py103
-rw-r--r--etc/taskcluster/decisionlib.py851
-rw-r--r--etc/taskcluster/docker/base.dockerfile33
-rw-r--r--etc/taskcluster/docker/build.dockerfile53
-rw-r--r--etc/taskcluster/docker/run-android-emulator.dockerfile11
-rw-r--r--etc/taskcluster/docker/run.dockerfile13
-rw-r--r--etc/taskcluster/docker/wpt-update.dockerfile5
-rwxr-xr-xetc/taskcluster/mock.py70
-rwxr-xr-xetc/taskcluster/simulate_github_events.py72
-rw-r--r--etc/taskcluster/treeherder.md103
-rw-r--r--python/servo/package_commands.py38
-rw-r--r--servo-tidy.toml3
-rwxr-xr-xtests/wpt/reftests-report/gen.py169
-rw-r--r--tests/wpt/reftests-report/prism.css141
-rw-r--r--tests/wpt/reftests-report/prism.js7
-rw-r--r--tests/wpt/update/fetchlogs.py99
25 files changed, 11 insertions, 2174 deletions
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index 57c4a7700d3..933683c713c 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -63,8 +63,8 @@ jobs:
- name: Bootstrap
run: |
python3 -m pip install --upgrade pip virtualenv
- brew bundle install --verbose --no-upgrade --file=etc/taskcluster/macos/Brewfile
- brew bundle install --verbose --no-upgrade --file=etc/taskcluster/macos/Brewfile-build
+ brew bundle install --verbose --no-upgrade --file=etc/homebrew/Brewfile
+ brew bundle install --verbose --no-upgrade --file=etc/homebrew/Brewfile-build
rm -rf /usr/local/etc/openssl
rm -rf /usr/local/etc/openssl@1.1
brew install openssl@1.1 gnu-tar
@@ -133,7 +133,7 @@ jobs:
# run: |
# gtar -xzf target.tar.gz
# python3 -m pip install --upgrade pip virtualenv
- # brew bundle install --verbose --no-upgrade --file=etc/taskcluster/macos/Brewfile
+ # brew bundle install --verbose --no-upgrade --file=etc/homebrew/Brewfile
# - name: Smoketest
# run: python3 ./mach smoketest
# - name: Run tests
diff --git a/.gitignore b/.gitignore
index 8b09f9790d0..221b769edf2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,4 +75,4 @@ support/hololens/.vs/
layout_trace*
# Package managers
-etc/taskcluster/macos/Brewfile.lock.json
+etc/homebrew/Brewfile.lock.json
diff --git a/.taskcluster.yml b/.taskcluster.yml
deleted file mode 100644
index b2c277f6f09..00000000000
--- a/.taskcluster.yml
+++ /dev/null
@@ -1,120 +0,0 @@
-version: 1
-
-# If and when switching to `reporting: checks-v1` here, also change the `statuses` route to `checks`
-# in `CONFIG.routes_for_all_subtasks` in `etc/taskcluster/decision_task.py`
-
-policy:
- # https://docs.taskcluster.net/docs/reference/integrations/taskcluster-github/docs/taskcluster-yml-v1#pull-requests
- pullRequests: public
-
- # NOTE: when updating this consider whether the daily hook needs similar changes:
-# https://tools.taskcluster.net/hooks/project-servo/daily
-tasks:
- $let:
- task_common:
- provisionerId:
- $if: "taskcluster_root_url == 'https://taskcluster.net'"
- then: aws-provisioner-v1
- else: proj-servo
- created: {$fromNow: ''}
- deadline: {$fromNow: '1 day'}
- priority: high
- extra:
- treeherder:
- machine: {platform: Linux}
- labels: [x64]
- symbol: Decision
- payload:
- maxRunTime: {$eval: '20 * 60'}
- # https://github.com/servo/taskcluster-bootstrap-docker-images#decision-task
- image: "servobrowser/taskcluster-bootstrap:decision-task@\
- sha256:7471a998e4462638c8d3e2cf0b4a99c9a5c8ca9f2ec0ae01cc069473b35cde10"
- features:
- taskclusterProxy: true
- artifacts:
- public/repo.bundle:
- type: file
- path: /repo.bundle
- expires: {$fromNow: '1 day'}
- env:
- GIT_URL: ${event.repository.clone_url}
- TASK_FOR: ${tasks_for}
- command:
- - /bin/bash
- - '--login'
- - '-e'
- - '-c'
- - >-
- git init repo &&
- cd repo &&
- git fetch --depth 1 "$GIT_URL" "$GIT_REF" &&
- git reset --hard "$GIT_SHA" &&
- python3 etc/taskcluster/decision_task.py
- in:
- - $if: "tasks_for == 'github-push'"
- then:
- $let:
- branch:
- $if: "event.ref[:11] == 'refs/heads/'"
- then: "${event.ref[11:]}"
- in:
- $if: "branch in ['auto', 'try', 'master'] || branch[:4] == 'try-'"
- then:
- $mergeDeep:
- - {$eval: "task_common"}
- - metadata:
- name: "Servo: GitHub push decision task"
- description: ""
- owner: ${event.pusher.name}@users.noreply.github.com
- source: ${event.compare}
- workerType:
- $if: "taskcluster_root_url == 'https://taskcluster.net'"
- then: servo-docker-worker
- else: docker
- scopes:
- - "assume:repo:github.com/servo/servo:branch:${branch}"
- routes:
- $let:
- treeherder_repo:
- $if: "branch[:4] == 'try-'"
- then: "servo-try"
- else: "servo-${branch}"
- in:
- - "tc-treeherder.v2._/${treeherder_repo}.${event.after}"
- - "tc-treeherder-staging.v2._/${treeherder_repo}.${event.after}"
- payload:
- env:
- GIT_REF: ${event.ref}
- GIT_SHA: ${event.after}
- TASK_OWNER: ${event.pusher.name}@users.noreply.github.com
- TASK_SOURCE: ${event.compare}
- - $if: >-
- tasks_for == 'github-pull-request' &&
- event['action'] in ['opened', 'reopened', 'synchronize']
- then:
- $mergeDeep:
- - {$eval: "task_common"}
- - metadata:
- name: "Servo: GitHub PR decision task"
- description: ""
- owner: ${event.sender.login}@users.noreply.github.com
- source: ${event.pull_request.url}
- workerType:
- $if: "taskcluster_root_url == 'https://taskcluster.net'"
- then: servo-docker-untrusted
- else: docker-untrusted
- scopes:
- - "assume:repo:github.com/servo/servo:pull-request"
- routes:
- - "tc-treeherder.v2._/servo-prs.${event.pull_request.head.sha}"
- - "tc-treeherder-staging.v2._/servo-prs.${event.pull_request.head.sha}"
- payload:
- env:
- # We use the merge commit made by GitHub, not the PR’s branch
- GIT_REF: refs/pull/${event.pull_request.number}/merge
- # `event.pull_request.merge_commit_sha` is tempting but not what we want:
- # https://github.com/servo/servo/pull/22597#issuecomment-451518810
- GIT_SHA: FETCH_HEAD
- TASK_OWNER: ${event.sender.login}@users.noreply.github.com
- TASK_SOURCE: ${event.pull_request.url}
-
diff --git a/README.md b/README.md
index 819fdf13263..771ae02f3fd 100644
--- a/README.md
+++ b/README.md
@@ -58,8 +58,8 @@ NOTE: run these steps after you've cloned the project locally.
``` sh
cd servo
-brew bundle install --file=etc/taskcluster/macos/Brewfile
-brew bundle install --file=etc/taskcluster/macos/Brewfile-build
+brew bundle install --file=etc/homebrew/Brewfile
+brew bundle install --file=etc/homebrew/Brewfile-build
pip install virtualenv
```
diff --git a/etc/ci/update-wpt-checkout b/etc/ci/update-wpt-checkout
index 58f5cc386a9..4ff7f7c125e 100755
--- a/etc/ci/update-wpt-checkout
+++ b/etc/ci/update-wpt-checkout
@@ -101,11 +101,6 @@ function unsafe_open_pull_request() {
# is unnecessary.
git checkout "${BRANCH_NAME}" || return 0
- if [[ -z "${WPT_SYNC_TOKEN+set}" && "${TASKCLUSTER_PROXY_URL+set}" == "set" ]]; then
- SECRET_RESPONSE=$(curl ${TASKCLUSTER_PROXY_URL}/api/secrets/v1/secret/project/servo/wpt-sync)
- WPT_SYNC_TOKEN=`echo "${SECRET_RESPONSE}" | jq --raw-output '.secret.token'`
- fi
-
if [[ -z "${WPT_SYNC_TOKEN+set}" ]]; then
echo "Github auth token missing from WPT_SYNC_TOKEN."
return 1
diff --git a/etc/taskcluster/macos/Brewfile b/etc/homebrew/Brewfile
index c11e49b6c30..c11e49b6c30 100644
--- a/etc/taskcluster/macos/Brewfile
+++ b/etc/homebrew/Brewfile
diff --git a/etc/taskcluster/macos/Brewfile-build b/etc/homebrew/Brewfile-build
index c78fe2cea3c..c78fe2cea3c 100644
--- a/etc/taskcluster/macos/Brewfile-build
+++ b/etc/homebrew/Brewfile-build
diff --git a/etc/taskcluster/macos/Brewfile-wpt-update b/etc/homebrew/Brewfile-wpt-update
index f563d5e7bf9..f563d5e7bf9 100644
--- a/etc/taskcluster/macos/Brewfile-wpt-update
+++ b/etc/homebrew/Brewfile-wpt-update
diff --git a/etc/taskcluster/README.md b/etc/taskcluster/README.md
deleted file mode 100644
index e91b526dfcc..00000000000
--- a/etc/taskcluster/README.md
+++ /dev/null
@@ -1,277 +0,0 @@
-# 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`](#docker-images)) 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 respectively.
-
-[mozilla/community-tc-config]: https://github.com/mozilla/community-tc-config/blob/master/config/projects.yml
-[servo/taskcluster-config]: https://github.com/servo/taskcluster-config/tree/master/config
-
-
-## Homu
-
-When a pull request is reviewed and the appropriate command is given,
-[Homu] creates a merge commit of `master` and the PR’s 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.
-
-[Homu]: https://github.com/servo/servo/wiki/Homu
-[GitHub Status API]: https://developer.github.com/v3/repos/statuses/
-[Webhook]: https://developer.github.com/webhooks/
-
-
-## 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].
-
-[GitHub integration service]: https://community-tc.services.mozilla.com/docs/manual/using/github
-[as a GitHub App]: https://github.com/apps/community-tc-integration/
-[`.taskcluster.yml`]: https://community-tc.services.mozilla.com/docs/reference/integrations/taskcluster-github/docs/taskcluster-yml-v1
-[task graph]: https://community-tc.services.mozilla.com/docs/manual/using/task-graph
-
-
-## Servo’s decision task
-
-This repository’s [`.taskcluster.yml`][tc.yml] schedules a single task
-that runs the Python 3 script [`etc/taskcluster/decision_task.py`](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`][hub].
-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.
-
-[tc.yml]: ../../../.taskcluster.yml
-[hub]: https://hub.docker.com/r/servobrowser/taskcluster-bootstrap/
-[Docker Hub automated builds]: https://docs.docker.com/docker-hub/builds/
-[`taskcluster-bootstrap-docker-images`]: https://github.com/servo/taskcluster-bootstrap-docker-images/
-
-
-## Docker images
-
-[Similar to Firefox][firefox], Servo’s decision task supports running other tasks
-in Docker images built on-demand, based on `Dockerfile`s 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 `Dockerfile`s 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`](docker/build.dockerfile) starts like so:
-
-```Dockerfile
-% include base.dockerfile
-
-RUN \
- apt-get install -qy --no-install-recommends \
-# […]
-```
-
-[firefox]: https://firefox-source-docs.mozilla.org/taskcluster/taskcluster/docker-images.html
-[context]: https://docs.docker.com/engine/reference/commandline/build/#extended-description
-[`COPY`]: https://docs.docker.com/engine/reference/builder/#copy
-
-
-## 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,
-Servo’s 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`](decision_task.py)
-and can be modified in any pull request.
-
-[web-platform-tests]: https://github.com/web-platform-tests/wpt
-[artifact]: https://community-tc.services.mozilla.com/docs/manual/using/artifacts
-
-
-## 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.
-
-Servo’s decision task additionally looks for `*.log` arguments to its tasks’s 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 one’s 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 those) 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:*`][branches] role matches.
-
-The [`project:servo:decision-task/base`][base]
-and [`project:servo:decision-task/trusted`][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.
-
-[Scopes]: https://community-tc.services.mozilla.com/docs/manual/design/apis/hawk/scopes
-[web UI]: https://community-tc.services.mozilla.com/
-[credentials]: https://community-tc.services.mozilla.com/profile
-[Roles]: https://community-tc.services.mozilla.com/docs/manual/design/apis/hawk/roles
-[expand]: https://community-tc.services.mozilla.com/docs/reference/platform/taskcluster-auth/docs/roles
-[branches]: https://community-tc.services.mozilla.com/auth/roles/repo%3Agithub.com%2Fservo%2Fservo%3Abranch%3A*
-[base]: https://community-tc.services.mozilla.com/auth/roles/project%3Aservo%3Adecision-task%2Fbase
-[trusted]: https://community-tc.services.mozilla.com/auth/roles/project%3Aservo%3Adecision-task%2Ftrusted
-[@servo/taskcluster-admins]: https://github.com/orgs/servo/teams/taskcluster-admins
-
-
-## Daily tasks
-
-The [`project-servo/daily`] hook in Taskcluster’s [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 differentiate 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.
-
-[`project.servo.daily`]: https://tools.taskcluster.net/index/project.servo.daily
-[`project-servo/daily`]: https://github.com/servo/taskcluster-config/blob/master/config/hooks.yml
-[Hooks service]: https://community-tc.services.mozilla.com/docs/manual/using/scheduled-tasks
-[`hook-id:project-servo/daily`]: https://github.com/servo/taskcluster-config/blob/master/config/roles.yml
-
-
-## Servo’s 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](#docker-images) of the task’s 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 don’t need to worry about evicting old entries from Cargo’s or rustup’s download cache,
- for example.
-
- [The Taskcluster team manages][mozilla/community-tc-config]
- the configuration and VM image for these two pools.
- The latter has fewer scopes. It runs automated testing of pull requests
- as soon as they’re 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][servo/taskcluster-config].
-
- 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`](decision_task.py) and [`decisionlib.py`](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][servo/taskcluster-config] through SaltStack.
- There is a task-owned (but preserved across tasks) install of Homebrew,
- with `Brewfile`s [in this repository](macos/).
-
- 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](https://github.com/taskcluster/taskcluster/issues/1972)
- with short-lived workers.)
-
-[Workers]: https://community-tc.services.mozilla.com/provisioners/proj-servo/worker-types/macos
-
-
-## Taskcluster − Treeherder integration
-
-See [`treeherder.md`](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 Mozilla’s Bugzilla, under `Taskcluster`][bug].
-
-[bug]: https://bugzilla.mozilla.org/enter_bug.cgi?product=Taskcluster
diff --git a/etc/taskcluster/decision_task.py b/etc/taskcluster/decision_task.py
deleted file mode 100644
index 89039137cb7..00000000000
--- a/etc/taskcluster/decision_task.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# coding: utf8
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-import os.path
-import decisionlib
-import functools
-from decisionlib import CONFIG, SHARED
-from urllib.request import urlopen
-
-
-def main(task_for):
- with decisionlib.make_repo_bundle():
- tasks(task_for)
-
-
-def tasks(task_for):
- if CONFIG.git_ref.startswith("refs/heads/"):
- branch = CONFIG.git_ref[len("refs/heads/"):]
- CONFIG.treeherder_repository_name = "servo-" + (
- branch if not branch.startswith("try-") else "try"
- )
-
- # Work around a tc-github bug/limitation:
- # https://bugzilla.mozilla.org/show_bug.cgi?id=1548781#c4
- if task_for.startswith("github"):
- # https://github.com/taskcluster/taskcluster/blob/21f257dc8/services/github/config.yml#L14
- CONFIG.routes_for_all_subtasks.append("statuses")
-
- if task_for == "github-push":
- all_tests = []
- by_branch_name = {
- "auto": all_tests,
- "try": all_tests,
- "try-taskcluster": [
- # Add functions here as needed, in your push to that branch
- ],
- "master": [],
-
- # The "try-*" keys match those in `servo_try_choosers` in Homu’s config:
- # https://github.com/servo/saltfs/blob/master/homu/map.jinja
-
- "try-mac": [],
- "try-linux": [],
- "try-windows": [],
- "try-arm": [],
- "try-wpt": [],
- "try-wpt-2020": [],
- "try-wpt-mac": [],
- "test-wpt": [],
- }
-
- elif task_for == "github-pull-request":
- CONFIG.treeherder_repository_name = "servo-prs"
- CONFIG.index_read_only = True
- CONFIG.docker_image_build_worker_type = None
-
- # We want the merge commit that GitHub creates for the PR.
- # The event does contain a `pull_request.merge_commit_sha` key, but it is wrong:
- # https://github.com/servo/servo/pull/22597#issuecomment-451518810
- CONFIG.git_sha_is_current_head()
-
- elif task_for == "try-windows-ami":
- CONFIG.git_sha_is_current_head()
- CONFIG.windows_worker_type = os.environ["NEW_AMI_WORKER_TYPE"]
-
- # https://tools.taskcluster.net/hooks/project-servo/daily
- elif task_for == "daily":
- daily_tasks_setup()
-
-
-ping_on_daily_task_failure = "SimonSapin, nox, emilio"
-build_artifacts_expire_in = "1 week"
-build_dependencies_artifacts_expire_in = "1 month"
-log_artifacts_expire_in = "1 year"
-
-
-def daily_tasks_setup():
- # Unlike when reacting to a GitHub push event,
- # the commit hash is not known until we clone the repository.
- CONFIG.git_sha_is_current_head()
-
- # On failure, notify a few people on IRC
- # https://docs.taskcluster.net/docs/reference/core/taskcluster-notify/docs/usage
- notify_route = "notify.irc-channel.#servo.on-failed"
- CONFIG.routes_for_all_subtasks.append(notify_route)
- CONFIG.scopes_for_all_subtasks.append("queue:route:" + notify_route)
- CONFIG.task_name_template = "Servo daily: %s. On failure, ping: " + ping_on_daily_task_failure
-
-
-CONFIG.task_name_template = "Servo: %s"
-CONFIG.docker_images_expire_in = build_dependencies_artifacts_expire_in
-CONFIG.repacked_msi_files_expire_in = build_dependencies_artifacts_expire_in
-CONFIG.index_prefix = "project.servo"
-CONFIG.default_provisioner_id = "proj-servo"
-CONFIG.docker_image_build_worker_type = "docker"
-
-CONFIG.windows_worker_type = "win2016"
-
-if __name__ == "__main__": # pragma: no cover
- main(task_for=os.environ["TASK_FOR"])
diff --git a/etc/taskcluster/decisionlib.py b/etc/taskcluster/decisionlib.py
deleted file mode 100644
index 22d9a2f22a0..00000000000
--- a/etc/taskcluster/decisionlib.py
+++ /dev/null
@@ -1,851 +0,0 @@
-# coding: utf8
-
-# Copyright 2018 The Servo Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-"""
-Project-independent library for Taskcluster decision tasks
-"""
-
-import base64
-import contextlib
-import datetime
-import hashlib
-import json
-import os
-import re
-import subprocess
-import sys
-import taskcluster
-
-
-# Public API
-__all__ = [
- "CONFIG", "SHARED", "Task", "DockerWorkerTask",
- "GenericWorkerTask", "WindowsGenericWorkerTask",
- "make_repo_bundle",
-]
-
-
-class Config:
- """
- Global configuration, for users of the library to modify.
- """
- def __init__(self):
- self.task_name_template = "%s"
- self.index_prefix = "garbage.servo-decisionlib"
- self.index_read_only = False
- self.scopes_for_all_subtasks = []
- self.routes_for_all_subtasks = []
- self.docker_image_build_worker_type = None
- self.docker_images_expire_in = "1 month"
- self.repacked_msi_files_expire_in = "1 month"
- self.treeherder_repository_name = None
-
- # Set by docker-worker:
- # https://docs.taskcluster.net/docs/reference/workers/docker-worker/docs/environment
- self.decision_task_id = os.environ.get("TASK_ID")
-
- # Set in the decision task’s payload, such as defined in .taskcluster.yml
- self.task_owner = os.environ.get("TASK_OWNER")
- self.task_source = os.environ.get("TASK_SOURCE")
- self.git_url = os.environ.get("GIT_URL")
- self.git_ref = os.environ.get("GIT_REF")
- self.git_sha = os.environ.get("GIT_SHA")
- self.git_bundle_shallow_ref = "refs/heads/shallow"
-
- self.tc_root_url = os.environ.get("TASKCLUSTER_ROOT_URL")
- self.default_provisioner_id = "proj-example"
-
-
- def tree_hash(self):
- if not hasattr(self, "_tree_hash"):
- # Use the SHA-1 hash of the git "tree" object rather than the commit.
- # A `@bors-servo retry` command creates a new merge commit with a different commit hash
- # but with the same tree hash.
- output = subprocess.check_output(["git", "show", "-s", "--format=%T", "HEAD"])
- self._tree_hash = output.decode("utf-8").strip()
- return self._tree_hash
-
- def git_sha_is_current_head(self):
- output = subprocess.check_output(["git", "rev-parse", "HEAD"])
- self.git_sha = output.decode("utf8").strip()
-
-
-class Shared:
- """
- Global shared state.
- """
- def __init__(self):
- self.now = datetime.datetime.utcnow()
- self.found_or_created_indexed_tasks = {}
-
- options = {"rootUrl": os.environ["TASKCLUSTER_PROXY_URL"]}
- self.queue_service = taskcluster.Queue(options)
- self.index_service = taskcluster.Index(options)
-
- def from_now_json(self, offset):
- """
- Same as `taskcluster.fromNowJSON`, but uses the creation time of `self` for “now”.
- """
- return taskcluster.stringDate(taskcluster.fromNow(offset, dateObj=self.now))
-
-
-CONFIG = Config()
-SHARED = Shared()
-
-
-def chaining(op, attr):
- def method(self, *args, **kwargs):
- op(self, attr, *args, **kwargs)
- return self
- return method
-
-
-def append_to_attr(self, attr, *args): getattr(self, attr).extend(args)
-def prepend_to_attr(self, attr, *args): getattr(self, attr)[0:0] = list(args)
-def update_attr(self, attr, **kwargs): getattr(self, attr).update(kwargs)
-
-
-class Task:
- """
- A task definition, waiting to be created.
-
- Typical is to use chain the `with_*` methods to set or extend this object’s attributes,
- then call the `crate` or `find_or_create` method to schedule a task.
-
- This is an abstract class that needs to be specialized for different worker implementations.
- """
- def __init__(self, name):
- self.name = name
- self.description = ""
- self.scheduler_id = "taskcluster-github"
- self.provisioner_id = CONFIG.default_provisioner_id
- self.worker_type = "github-worker"
- self.deadline_in = "1 day"
- self.expires_in = "1 year"
- self.index_and_artifacts_expire_in = self.expires_in
- self.dependencies = []
- self.scopes = []
- self.routes = []
- self.extra = {}
- self.treeherder_required = False
- self.priority = None # Defaults to 'lowest'
- self.git_fetch_url = CONFIG.git_url
- self.git_fetch_ref = CONFIG.git_ref
- self.git_checkout_sha = CONFIG.git_sha
-
- # All `with_*` methods return `self`, so multiple method calls can be chained.
- with_description = chaining(setattr, "description")
- with_scheduler_id = chaining(setattr, "scheduler_id")
- with_provisioner_id = chaining(setattr, "provisioner_id")
- with_worker_type = chaining(setattr, "worker_type")
- with_deadline_in = chaining(setattr, "deadline_in")
- with_expires_in = chaining(setattr, "expires_in")
- with_index_and_artifacts_expire_in = chaining(setattr, "index_and_artifacts_expire_in")
- with_priority = chaining(setattr, "priority")
-
- with_dependencies = chaining(append_to_attr, "dependencies")
- with_scopes = chaining(append_to_attr, "scopes")
- with_routes = chaining(append_to_attr, "routes")
-
- with_extra = chaining(update_attr, "extra")
-
- def with_index_at(self, index_path):
- self.routes.append("index.%s.%s" % (CONFIG.index_prefix, index_path))
- return self
-
- def with_treeherder_required(self):
- self.treeherder_required = True
- return self
-
- def with_treeherder(self, category, symbol, group_name=None, group_symbol=None):
- assert len(symbol) <= 25, symbol
- self.name = "%s: %s" % (category, self.name)
-
- # The message schema does not allow spaces in the platfrom or in labels,
- # but the UI shows them in that order separated by spaces.
- # So massage the metadata to get the UI to show the string we want.
- # `labels` defaults to ["opt"] if not provided or empty,
- # so use a more neutral underscore instead.
- parts = category.split(" ")
- platform = parts[0]
- labels = parts[1:] or ["_"]
-
- # https://github.com/mozilla/treeherder/blob/master/schemas/task-treeherder-config.yml
- self.with_extra(treeherder=dict_update_if_truthy(
- {
- "machine": {"platform": platform},
- "labels": labels,
- "symbol": symbol,
- },
- groupName=group_name,
- groupSymbol=group_symbol,
- ))
-
- if CONFIG.treeherder_repository_name:
- assert CONFIG.git_sha
- suffix = ".v2._/%s.%s" % (CONFIG.treeherder_repository_name, CONFIG.git_sha)
- self.with_routes(
- "tc-treeherder" + suffix,
- "tc-treeherder-staging" + suffix,
- )
-
- self.treeherder_required = False # Taken care of
- return self
-
- def build_worker_payload(self): # pragma: no cover
- """
- Overridden by sub-classes to return a dictionary in a worker-specific format,
- which is used as the `payload` property in a task definition request
- passed to the Queue’s `createTask` API.
-
- <https://docs.taskcluster.net/docs/reference/platform/taskcluster-queue/references/api#createTask>
- """
- raise NotImplementedError
-
- def create(self):
- """
- Call the Queue’s `createTask` API to schedule a new task, and return its ID.
-
- <https://docs.taskcluster.net/docs/reference/platform/taskcluster-queue/references/api#createTask>
- """
- worker_payload = self.build_worker_payload()
- assert not self.treeherder_required, \
- "make sure to call with_treeherder() for this task: %s" % self.name
-
- assert CONFIG.decision_task_id
- assert CONFIG.task_owner
- assert CONFIG.task_source
-
- def dedup(xs):
- seen = set()
- return [x for x in xs if not (x in seen or seen.add(x))]
-
- queue_payload = {
- "taskGroupId": CONFIG.decision_task_id,
- "dependencies": dedup([CONFIG.decision_task_id] + self.dependencies),
- "schedulerId": self.scheduler_id,
- "provisionerId": self.provisioner_id,
- "workerType": self.worker_type,
-
- "created": SHARED.from_now_json(""),
- "deadline": SHARED.from_now_json(self.deadline_in),
- "expires": SHARED.from_now_json(self.expires_in),
- "metadata": {
- "name": CONFIG.task_name_template % self.name,
- "description": self.description,
- "owner": CONFIG.task_owner,
- "source": CONFIG.task_source,
- },
-
- "payload": worker_payload,
- }
- scopes = self.scopes + CONFIG.scopes_for_all_subtasks
- routes = self.routes + CONFIG.routes_for_all_subtasks
- if any(r.startswith("index.") for r in routes):
- self.extra.setdefault("index", {})["expires"] = \
- SHARED.from_now_json(self.index_and_artifacts_expire_in)
- dict_update_if_truthy(
- queue_payload,
- scopes=scopes,
- routes=routes,
- extra=self.extra,
- priority=self.priority,
- )
-
- task_id = taskcluster.slugId()
- SHARED.queue_service.createTask(task_id, queue_payload)
- print("Scheduled %s: %s" % (task_id, self.name))
- return task_id
-
- @staticmethod
- def find(index_path):
- full_index_path = "%s.%s" % (CONFIG.index_prefix, index_path)
- task_id = SHARED.index_service.findTask(full_index_path)["taskId"]
- print("Found task %s indexed at %s" % (task_id, full_index_path))
- return task_id
-
- def find_or_create(self, index_path):
- """
- Try to find a task in the Index and return its ID.
-
- The index path used is `{CONFIG.index_prefix}.{index_path}`.
- `index_path` defaults to `by-task-definition.{sha256}`
- with a hash of the worker payload and worker type.
-
- If no task is found in the index,
- it is created with a route to add it to the index at that same path if it succeeds.
-
- <https://docs.taskcluster.net/docs/reference/core/taskcluster-index/references/api#findTask>
- """
- task_id = SHARED.found_or_created_indexed_tasks.get(index_path)
- if task_id is not None:
- return task_id
-
- try:
- task_id = Task.find(index_path)
- except taskcluster.TaskclusterRestFailure as e:
- if e.status_code != 404: # pragma: no cover
- raise
- if not CONFIG.index_read_only:
- self.with_index_at(index_path)
- task_id = self.create()
-
- SHARED.found_or_created_indexed_tasks[index_path] = task_id
- return task_id
-
- def with_curl_script(self, url, file_path):
- return self \
- .with_script("""
- curl --compressed --retry 5 --connect-timeout 10 -Lf "%s" -o "%s"
- """ % (url, file_path))
-
- def with_curl_artifact_script(self, task_id, artifact_name, out_directory=""):
- queue_service = CONFIG.tc_root_url + "/api/queue"
- return self \
- .with_dependencies(task_id) \
- .with_curl_script(
- queue_service + "/v1/task/%s/artifacts/public/%s" % (task_id, artifact_name),
- os.path.join(out_directory, url_basename(artifact_name)),
- )
-
- def with_repo_bundle(self, **kwargs):
- self.git_fetch_url = "../repo.bundle"
- self.git_fetch_ref = CONFIG.git_bundle_shallow_ref
- self.git_checkout_sha = "FETCH_HEAD"
- return self \
- .with_curl_artifact_script(CONFIG.decision_task_id, "repo.bundle") \
- .with_repo(**kwargs)
-
-
-class GenericWorkerTask(Task):
- """
- Task definition for a worker type that runs the `generic-worker` implementation.
-
- This is an abstract class that needs to be specialized for different operating systems.
-
- <https://github.com/taskcluster/generic-worker>
- """
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.max_run_time_minutes = 30
- self.env = {}
- self.features = {}
- self.mounts = []
- self.artifacts = []
-
- with_max_run_time_minutes = chaining(setattr, "max_run_time_minutes")
- with_mounts = chaining(append_to_attr, "mounts")
- with_env = chaining(update_attr, "env")
-
- def build_command(self): # pragma: no cover
- """
- Overridden by sub-classes to return the `command` property of the worker payload,
- in the format appropriate for the operating system.
- """
- raise NotImplementedError
-
- def build_worker_payload(self):
- """
- Return a `generic-worker` worker payload.
-
- <https://docs.taskcluster.net/docs/reference/workers/generic-worker/docs/payload>
- """
- worker_payload = {
- "command": self.build_command(),
- "maxRunTime": self.max_run_time_minutes * 60
- }
- return dict_update_if_truthy(
- worker_payload,
- env=self.env,
- mounts=self.mounts,
- features=self.features,
- artifacts=[
- {
- "type": type_,
- "path": path,
- "name": "public/" + url_basename(path),
- "expires": SHARED.from_now_json(self.index_and_artifacts_expire_in),
- }
- for type_, path in self.artifacts
- ],
- )
-
- def with_artifacts(self, *paths, type="file"):
- """
- Add each path in `paths` as a task artifact
- that expires in `self.index_and_artifacts_expire_in`.
-
- `type` can be `"file"` or `"directory"`.
-
- Paths are relative to the task’s home directory.
- """
- for path in paths:
- if (type, path) in self.artifacts:
- raise ValueError("Duplicate artifact: " + path) # pragma: no cover
- self.artifacts.append(tuple((type, path)))
- return self
-
- def with_features(self, *names):
- """
- Enable the given `generic-worker` features.
-
- <https://github.com/taskcluster/generic-worker/blob/master/native_windows.yml>
- """
- self.features.update({name: True for name in names})
- return self
-
- def _mount_content(self, url_or_artifact_name, task_id, sha256):
- if task_id:
- content = {"taskId": task_id, "artifact": url_or_artifact_name}
- else:
- content = {"url": url_or_artifact_name}
- if sha256:
- content["sha256"] = sha256
- return content
-
- def with_file_mount(self, url_or_artifact_name, task_id=None, sha256=None, path=None):
- """
- Make `generic-worker` download a file before the task starts
- and make it available at `path` (which is relative to the task’s home directory).
-
- If `sha256` is provided, `generic-worker` will hash the downloaded file
- and check it against the provided signature.
-
- If `task_id` is provided, this task will depend on that task
- and `url_or_artifact_name` is the name of an artifact of that task.
- """
- return self.with_mounts({
- "file": path or url_basename(url_or_artifact_name),
- "content": self._mount_content(url_or_artifact_name, task_id, sha256),
- })
-
- def with_directory_mount(self, url_or_artifact_name, task_id=None, sha256=None, path=None):
- """
- Make `generic-worker` download an archive before the task starts,
- and uncompress it at `path` (which is relative to the task’s home directory).
-
- `url_or_artifact_name` must end in one of `.rar`, `.tar.bz2`, `.tar.gz`, or `.zip`.
- The archive must be in the corresponding format.
-
- If `sha256` is provided, `generic-worker` will hash the downloaded archive
- and check it against the provided signature.
-
- If `task_id` is provided, this task will depend on that task
- and `url_or_artifact_name` is the name of an artifact of that task.
- """
- supported_formats = ["rar", "tar.bz2", "tar.gz", "zip"]
- for fmt in supported_formats:
- suffix = "." + fmt
- if url_or_artifact_name.endswith(suffix):
- return self.with_mounts({
- "directory": path or url_basename(url_or_artifact_name[:-len(suffix)]),
- "content": self._mount_content(url_or_artifact_name, task_id, sha256),
- "format": fmt,
- })
- raise ValueError(
- "%r does not appear to be in one of the supported formats: %r"
- % (url_or_artifact_name, ", ".join(supported_formats))
- ) # pragma: no cover
-
-
-class WindowsGenericWorkerTask(GenericWorkerTask):
- """
- Task definition for a `generic-worker` task running on Windows.
-
- Scripts are written as `.bat` files executed with `cmd.exe`.
- """
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.scripts = []
- self.rdp_info_artifact_name = None
-
- with_script = chaining(append_to_attr, "scripts")
- with_early_script = chaining(prepend_to_attr, "scripts")
-
- def build_worker_payload(self):
- if self.rdp_info_artifact_name:
- rdp_scope = "generic-worker:allow-rdp:%s/%s" % (self.provisioner_id, self.worker_type)
- self.scopes.append(rdp_scope)
- self.scopes.append("generic-worker:os-group:proj-servo/win2016/Administrators")
- self.scopes.append("generic-worker:run-as-administrator:proj-servo/win2016")
- self.with_features("runAsAdministrator")
- return dict_update_if_truthy(
- super().build_worker_payload(),
- rdpInfo=self.rdp_info_artifact_name,
- osGroups=["Administrators"]
- )
-
- def with_rdp_info(self, *, artifact_name):
- """
- Enable RDP access to this task’s environment.
-
- See `rdpInfo` in
- <https://community-tc.services.mozilla.com/docs/reference/workers/generic-worker/multiuser-windows-payload>
- """
- assert not artifact_name.startswith("public/")
- self.rdp_info_artifact_name = artifact_name
-
- def build_command(self):
- return [deindent(s) for s in self.scripts]
-
- def with_path_from_homedir(self, *paths):
- """
- Interpret each path in `paths` as relative to the task’s home directory,
- and add it to the `PATH` environment variable.
- """
- for p in paths:
- self.with_early_script("set PATH=%HOMEDRIVE%%HOMEPATH%\\{};%PATH%".format(p))
- return self
-
- def with_repo(self, sparse_checkout=None):
- """
- Make a clone the git repository at the start of the task.
- This uses `CONFIG.git_url`, `CONFIG.git_ref`, and `CONFIG.git_sha`,
- and creates the clone in a `repo` directory in the task’s home directory.
-
- If `sparse_checkout` is given, it must be a list of path patterns
- to be used in `.git/info/sparse-checkout`.
- See <https://git-scm.com/docs/git-read-tree#_sparse_checkout>.
- """
- git = """
- git init repo
- cd repo
- """
- if sparse_checkout:
- self.with_mounts({
- "file": "sparse-checkout",
- "content": {"raw": "\n".join(sparse_checkout)},
- })
- git += """
- git config core.sparsecheckout true
- copy ..\\sparse-checkout .git\\info\\sparse-checkout
- type .git\\info\\sparse-checkout
- """
- git += """
- git fetch --no-tags {} {}
- git reset --hard {}
- """.format(
- assert_truthy(self.git_fetch_url),
- assert_truthy(self.git_fetch_ref),
- assert_truthy(self.git_checkout_sha),
- )
- return self \
- .with_git() \
- .with_script(git)
-
- def with_git(self):
- """
- Make the task download `git-for-windows` and make it available for `git` commands.
-
- This is implied by `with_repo`.
- """
- return self \
- .with_path_from_homedir("git\\cmd") \
- .with_directory_mount(
- "https://github.com/git-for-windows/git/releases/download/" +
- "v2.24.0.windows.2/MinGit-2.24.0.2-64-bit.zip",
- sha256="c33aec6ae68989103653ca9fb64f12cabccf6c61d0dde30c50da47fc15cf66e2",
- path="git",
- )
-
- def with_curl_script(self, url, file_path):
- self.with_curl()
- return super().with_curl_script(url, file_path)
-
- def with_curl(self):
- return self \
- .with_path_from_homedir("curl\\curl-7.73.0-win64-mingw\\bin") \
- .with_directory_mount(
- "https://curl.haxx.se/windows/dl-7.73.0/curl-7.73.0-win64-mingw.zip",
- sha256="2e1ffdb6c25c8648a1243bb3a268120be442399b1c93d7da309bba235ecdab9a",
- path="curl",
- )
-
- def with_rustup(self):
- """
- Download rustup.rs and make it available to task commands,
- but does not download any default toolchain.
- """
- return self \
- .with_path_from_homedir(".cargo\\bin") \
- .with_early_script(
- "%HOMEDRIVE%%HOMEPATH%\\rustup-init.exe --default-toolchain none --profile=minimal -y"
- ) \
- .with_file_mount("https://win.rustup.rs/x86_64", path="rustup-init.exe")
-
- def with_repacked_msi(self, url, sha256, path):
- """
- Download an MSI file from `url`, extract the files in it with `lessmsi`,
- and make them available in the directory at `path` (relative to the task’s home directory).
-
- `sha256` is required and the MSI file must have that hash.
-
- The file extraction (and recompression in a ZIP file) is done in a separate task,
- wich is indexed based on `sha256` and cached for `CONFIG.repacked_msi_files_expire_in`.
-
- <https://github.com/activescott/lessmsi>
- """
- repack_task = (
- WindowsGenericWorkerTask("MSI repack: " + url)
- .with_worker_type(self.worker_type)
- .with_max_run_time_minutes(20)
- .with_file_mount(url, sha256=sha256, path="input.msi")
- .with_directory_mount(
- "https://github.com/activescott/lessmsi/releases/download/" +
- "v1.6.1/lessmsi-v1.6.1.zip",
- sha256="540b8801e08ec39ba26a100c855898f455410cecbae4991afae7bb2b4df026c7",
- path="lessmsi"
- )
- .with_directory_mount(
- "https://www.7-zip.org/a/7za920.zip",
- sha256="2a3afe19c180f8373fa02ff00254d5394fec0349f5804e0ad2f6067854ff28ac",
- path="7zip",
- )
- .with_path_from_homedir("lessmsi", "7zip")
- .with_script("""
- lessmsi x input.msi extracted\\
- cd extracted\\SourceDir
- 7za a repacked.zip *
- """)
- .with_artifacts("extracted/SourceDir/repacked.zip")
- .with_index_and_artifacts_expire_in(CONFIG.repacked_msi_files_expire_in)
- .find_or_create("repacked-msi." + sha256)
- )
- return self \
- .with_dependencies(repack_task) \
- .with_directory_mount("public/repacked.zip", task_id=repack_task, path=path)
-
- def with_python3(self):
- """
- For Python 3, use `with_directory_mount` and the "embeddable zip file" distribution
- from python.org.
- You may need to remove `python37._pth` from the ZIP in order to work around
- <https://bugs.python.org/issue34841>.
- """
- return (
- self
- .with_curl_script(
- "https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe",
- "do-the-python.exe"
- )
- .with_script("do-the-python.exe /quiet TargetDir=%HOMEDRIVE%%HOMEPATH%\\python3")
- .with_path_from_homedir("python3", "python3\\Scripts")
- .with_script("pip install virtualenv==20.2.1")
- )
-
-
-class UnixTaskMixin(Task):
- def with_repo(self, alternate_object_dir=""):
- """
- Make a clone the git repository at the start of the task.
- This uses `CONFIG.git_url`, `CONFIG.git_ref`, and `CONFIG.git_sha`
-
- * generic-worker: creates the clone in a `repo` directory
- in the task’s directory.
-
- * docker-worker: creates the clone in a `/repo` directory
- at the root of the Docker container’s filesystem.
- `git` and `ca-certificate` need to be installed in the Docker image.
-
- """
- # Not using $GIT_ALTERNATE_OBJECT_DIRECTORIES since it causes
- # "object not found - no match for id" errors when Cargo fetches git dependencies
- return self \
- .with_script("""
- git init repo
- cd repo
- echo "{alternate}" > .git/objects/info/alternates
- time git fetch --no-tags {} {}
- time git reset --hard {}
- """.format(
- assert_truthy(self.git_fetch_url),
- assert_truthy(self.git_fetch_ref),
- assert_truthy(self.git_checkout_sha),
- alternate=alternate_object_dir,
- ))
-
-
-class DockerWorkerTask(UnixTaskMixin, Task):
- """
- Task definition for a worker type that runs the `generic-worker` implementation.
-
- Scripts are interpreted with `bash`.
-
- <https://github.com/taskcluster/docker-worker>
- """
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.docker_image = "ubuntu:bionic-20180821"
- self.max_run_time_minutes = 30
- self.scripts = []
- self.env = {}
- self.caches = {}
- self.features = {}
- self.capabilities = {}
- self.artifacts = []
-
- with_docker_image = chaining(setattr, "docker_image")
- with_max_run_time_minutes = chaining(setattr, "max_run_time_minutes")
- with_script = chaining(append_to_attr, "scripts")
- with_early_script = chaining(prepend_to_attr, "scripts")
- with_caches = chaining(update_attr, "caches")
- with_env = chaining(update_attr, "env")
- with_capabilities = chaining(update_attr, "capabilities")
-
- def with_artifacts(self, *paths):
- for path in paths:
- if path in self.artifacts:
- raise ValueError("Duplicate artifact: " + path) # pragma: no cover
- self.artifacts.append(path)
- return self
-
- def build_worker_payload(self):
- """
- Return a `docker-worker` worker payload.
-
- <https://docs.taskcluster.net/docs/reference/workers/docker-worker/docs/payload>
- """
- worker_payload = {
- "image": self.docker_image,
- "maxRunTime": self.max_run_time_minutes * 60,
- "command": [
- "/bin/bash", "--login", "-x", "-e", "-o", "pipefail", "-c",
- deindent("\n".join(self.scripts))
- ],
- }
- return dict_update_if_truthy(
- worker_payload,
- env=self.env,
- cache=self.caches,
- features=self.features,
- capabilities=self.capabilities,
- artifacts={
- "public/" + url_basename(path): {
- "type": "file",
- "path": path,
- "expires": SHARED.from_now_json(self.index_and_artifacts_expire_in),
- }
- for path in self.artifacts
- },
- )
-
- def with_features(self, *names):
- """
- Enable the given `docker-worker` features.
-
- <https://github.com/taskcluster/docker-worker/blob/master/docs/features.md>
- """
- self.features.update({name: True for name in names})
- return self
-
- def with_dockerfile(self, dockerfile):
- """
- Build a Docker image based on the given `Dockerfile`, and use it for this task.
-
- `dockerfile` is a path in the filesystem where this code is running.
- Some non-standard syntax is supported, see `expand_dockerfile`.
-
- The image is indexed based on a hash of the expanded `Dockerfile`,
- and cached for `CONFIG.docker_images_expire_in`.
-
- Images are built without any *context*.
- <https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#understand-build-context>
- """
- basename = os.path.basename(dockerfile)
- suffix = ".dockerfile"
- assert basename.endswith(suffix)
- image_name = basename[:-len(suffix)]
-
- dockerfile_contents = expand_dockerfile(dockerfile)
- digest = hashlib.sha256(dockerfile_contents).hexdigest()
-
- image_build_task = (
- DockerWorkerTask("Docker image: " + image_name)
- .with_worker_type(CONFIG.docker_image_build_worker_type or self.worker_type)
- .with_max_run_time_minutes(30)
- .with_index_and_artifacts_expire_in(CONFIG.docker_images_expire_in)
- .with_features("dind")
- .with_env(DOCKERFILE=dockerfile_contents)
- .with_artifacts("/image.tar.lz4")
- .with_script("""
- echo "$DOCKERFILE" | docker build -t taskcluster-built -
- docker save taskcluster-built | lz4 > /image.tar.lz4
- """)
- .with_docker_image(
- # https://github.com/servo/taskcluster-bootstrap-docker-images#image-builder
- "servobrowser/taskcluster-bootstrap:image-builder@sha256:" \
- "0a7d012ce444d62ffb9e7f06f0c52fedc24b68c2060711b313263367f7272d9d"
- )
- .find_or_create("docker-image." + digest)
- )
-
- return self \
- .with_dependencies(image_build_task) \
- .with_docker_image({
- "type": "task-image",
- "path": "public/image.tar.lz4",
- "taskId": image_build_task,
- })
-
-
-def expand_dockerfile(dockerfile):
- """
- Read the file at path `dockerfile`,
- and transitively expand the non-standard `% include` header if it is present.
- """
- with open(dockerfile, "rb") as f:
- dockerfile_contents = f.read()
-
- include_marker = b"% include"
- if not dockerfile_contents.startswith(include_marker):
- return dockerfile_contents
-
- include_line, _, rest = dockerfile_contents.partition(b"\n")
- included = include_line[len(include_marker):].strip().decode("utf8")
- path = os.path.join(os.path.dirname(dockerfile), included)
- return b"\n".join([expand_dockerfile(path), rest])
-
-
-def assert_truthy(x):
- assert x
- return x
-
-
-def dict_update_if_truthy(d, **kwargs):
- for key, value in kwargs.items():
- if value:
- d[key] = value
- return d
-
-
-def deindent(string):
- return re.sub("\n +", "\n ", string).strip()
-
-
-def url_basename(url):
- return url.rpartition("/")[-1]
-
-
-@contextlib.contextmanager
-def make_repo_bundle():
- subprocess.check_call(["git", "config", "user.name", "Decision task"])
- subprocess.check_call(["git", "config", "user.email", "nobody@mozilla.com"])
- tree = subprocess.check_output(["git", "show", CONFIG.git_sha, "--pretty=%T", "--no-patch"])
- message = "Shallow version of commit " + CONFIG.git_sha
- commit = subprocess.check_output(["git", "commit-tree", tree.strip(), "-m", message])
- subprocess.check_call(["git", "update-ref", CONFIG.git_bundle_shallow_ref, commit.strip()])
- subprocess.check_call(["git", "show-ref"])
- create = ["git", "bundle", "create", "../repo.bundle", CONFIG.git_bundle_shallow_ref]
- with subprocess.Popen(create) as p:
- yield
- exit_code = p.wait()
- if exit_code:
- sys.exit(exit_code)
diff --git a/etc/taskcluster/docker/base.dockerfile b/etc/taskcluster/docker/base.dockerfile
deleted file mode 100644
index 18a2dbac6a0..00000000000
--- a/etc/taskcluster/docker/base.dockerfile
+++ /dev/null
@@ -1,33 +0,0 @@
-FROM ubuntu:20.04
-
-ENV \
- #
- # Some APT packages like 'tzdata' wait for user input on install by default.
- # https://stackoverflow.com/questions/44331836/apt-get-install-tzdata-noninteractive
- DEBIAN_FRONTEND=noninteractive \
- LANG=C.UTF-8 \
- LANGUAGE=C.UTF-8 \
- LC_ALL=C.UTF-8
-
-RUN \
- apt-get update -q && \
- apt-get install -qy --no-install-recommends \
- #
- # Cloning the repository
- git \
- ca-certificates \
- #
- # Running mach with Python 3
- python3 \
- python3-pip \
- python3-dev \
- virtualenv \
- #
- # Compiling C modules when installing Python packages in a virtualenv
- gcc \
- #
- # Installing rustup and sccache (build dockerfile) or fetching build artifacts (run tasks)
- curl \
- # Setting the default locale
- locales \
- locales-all
diff --git a/etc/taskcluster/docker/build.dockerfile b/etc/taskcluster/docker/build.dockerfile
deleted file mode 100644
index 60ae5606cdb..00000000000
--- a/etc/taskcluster/docker/build.dockerfile
+++ /dev/null
@@ -1,53 +0,0 @@
-% include base.dockerfile
-
-RUN \
- apt-get install -qy --no-install-recommends \
- #
- # Testing decisionlib (see etc/taskcluster/mock.py)
- python3-coverage \
- #
- # Multiple C/C++ dependencies built from source
- g++ \
- make \
- cmake \
- #
- # Fontconfig
- gperf \
- #
- # ANGLE
- xorg-dev \
- #
- # mozjs (SpiderMonkey)
- autoconf2.13 \
- #
- # Bindgen (for SpiderMonkey bindings)
- clang \
- llvm \
- llvm-dev \
- #
- # GStreamer
- libpcre3-dev \
- #
- # OpenSSL
- libssl-dev \
- #
- # blurz
- libdbus-1-dev \
- #
- # sampling profiler
- libunwind-dev \
- #
- # x11 integration
- libxcb-render-util0-dev \
- libxcb-shape0-dev \
- libxcb-xfixes0-dev \
- #
- && \
- #
- # Install the version of rustup that is current when this Docker image is being built:
- # We want at least 1.21 (increment in this comment to force an image rebuild).
- curl https://sh.rustup.rs -sSf | sh -s -- --profile=minimal -y && \
- #
- # There are no sccache binary releases that include this commit, so we install a particular
- # git commit instead.
- ~/.cargo/bin/cargo install sccache --git https://github.com/mozilla/sccache/ --rev e66c9c15142a7e583d6ab80bd614bdffb2ebcc47
diff --git a/etc/taskcluster/docker/run-android-emulator.dockerfile b/etc/taskcluster/docker/run-android-emulator.dockerfile
deleted file mode 100644
index 92eb116ef6b..00000000000
--- a/etc/taskcluster/docker/run-android-emulator.dockerfile
+++ /dev/null
@@ -1,11 +0,0 @@
-% include base.dockerfile
-
-RUN \
- apt-get install -qy --no-install-recommends \
- #
- # Multiple Android-related tools are in Java
- openjdk-8-jdk-headless \
- #
- # Emulator dependencies
- libgl1 \
- libpulse0
diff --git a/etc/taskcluster/docker/run.dockerfile b/etc/taskcluster/docker/run.dockerfile
deleted file mode 100644
index f02b4fdff97..00000000000
--- a/etc/taskcluster/docker/run.dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-% include base.dockerfile
-
-# Servo’s runtime dependencies:
-RUN apt-get install -qy --no-install-recommends \
- libgl1 \
- libssl1.1 \
- libdbus-1-3 \
- libxcb-shape0-dev \
- gstreamer1.0-plugins-good \
- gstreamer1.0-plugins-bad \
- gstreamer1.0-libav \
- gstreamer1.0-gl \
- libunwind8
diff --git a/etc/taskcluster/docker/wpt-update.dockerfile b/etc/taskcluster/docker/wpt-update.dockerfile
deleted file mode 100644
index 0a8edde7bc9..00000000000
--- a/etc/taskcluster/docker/wpt-update.dockerfile
+++ /dev/null
@@ -1,5 +0,0 @@
-% include run.dockerfile
-
-RUN apt-get install -qy --no-install-recommends \
- python3 \
- jq
diff --git a/etc/taskcluster/mock.py b/etc/taskcluster/mock.py
deleted file mode 100755
index 0bce7891876..00000000000
--- a/etc/taskcluster/mock.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2018 The Servo Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-''''set -e
-python3 -m coverage run $0
-python3 -m coverage report -m --fail-under 100
-exit
-
-Run the decision task with fake Taskcluster APIs, to catch Python errors before pushing.
-'''
-
-import os
-import sys
-from unittest.mock import MagicMock
-
-
-class TaskclusterRestFailure(Exception):
- status_code = 404
-
-
-class Index:
- __init__ = insertTask = lambda *_, **__: None
-
- def findTask(self, path):
- if decision_task.CONFIG.git_ref == "refs/heads/master":
- return {"taskId": "<from index>"}
- raise TaskclusterRestFailure
-
-
-stringDate = str
-slugId = b"<new id>".lower
-sys.exit = Queue = fromNow = MagicMock()
-sys.modules["taskcluster"] = sys.modules[__name__]
-sys.dont_write_bytecode = True
-os.environ.update(**{k: k for k in "TASK_ID TASK_OWNER TASK_SOURCE GIT_URL GIT_SHA".split()})
-os.environ["GIT_REF"] = "refs/heads/auto"
-os.environ["TASKCLUSTER_ROOT_URL"] = "https://community-tc.services.mozilla.com"
-os.environ["TASKCLUSTER_PROXY_URL"] = "http://taskcluster"
-os.environ["NEW_AMI_WORKER_TYPE"] = "-"
-import decision_task # noqa: E402
-decision_task.decisionlib.subprocess = MagicMock()
-
-print("\n# Push:")
-decision_task.main("github-push")
-
-print("\n# Push with hot caches:")
-decision_task.main("github-push")
-
-print("\n# Push to master:")
-decision_task.CONFIG.git_ref = "refs/heads/master"
-decision_task.main("github-push")
-
-print("\n# Daily:")
-decision_task.main("daily")
-
-print("\n# Try AMI:")
-decision_task.main("try-windows-ami")
-
-print("\n# PR:")
-decision_task.main("github-pull-request")
-
-print()
diff --git a/etc/taskcluster/simulate_github_events.py b/etc/taskcluster/simulate_github_events.py
deleted file mode 100755
index c99436b9106..00000000000
--- a/etc/taskcluster/simulate_github_events.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env bash
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-''''set -e
-cd "$(dirname $0)"
-exec ../../python/_virtualenv/bin/python "$(basename $0)"
-'''
-
-try:
- import jsone
-except ImportError:
- import sys
- sys.exit("pip install git+https://github.com/taskcluster/json-e")
-
-import yaml
-import json
-
-template = yaml.load(open("../../.taskcluster.yml").read().decode("utf8"))
-repo = dict(
- repository=dict(
- clone_url="https://github.com/servo/servo.git",
- ),
-)
-contexts = [
- dict(
- tasks_for="github-release",
- event=repo,
- ),
- dict(
- tasks_for="github-pull-request",
- event=dict(
- action="comment",
- **repo
- ),
- ),
- dict(
- tasks_for="github-push",
- event=dict(
- ref="refs/heads/master",
- compare="https://github.com/servo/servo/compare/1753cda...de09c8f",
- after="de09c8fb6ef87dec5932d5fab4adcb421d291a54",
- pusher=dict(
- name="bors-servo",
- ),
- **repo
- ),
- ),
- dict(
- tasks_for="github-pull-request",
- event=dict(
- action="synchronize",
- pull_request=dict(
- number=22583,
- url="https://github.com/servo/servo/pull/22583",
- head=dict(
- sha="51a422c9ef47420eb69c802643b7686bdb498652",
- ),
- merge_commit_sha="876fcf7a5fe971a9ac0a4ce117906c552c08c095",
- ),
- sender=dict(
- login="jdm",
- ),
- **repo
- ),
- ),
-]
-for context in contexts:
- print(context["tasks_for"])
- print(json.dumps(jsone.render(template, context), indent=2))
diff --git a/etc/taskcluster/treeherder.md b/etc/taskcluster/treeherder.md
deleted file mode 100644
index 63223dddfc6..00000000000
--- a/etc/taskcluster/treeherder.md
+++ /dev/null
@@ -1,103 +0,0 @@
-# Treeherder for Servo
-
-Treeherder is tool for visualizing the status of “trees”,
-meaning branches in various source repositories.
-It shows each push to the repository with the corresponding commits
-as well as the CI jobs that were started for that push.
-While it is possible to write other tools that submit job data,
-CI integration is easiest with Taskcluster.
-
-* [Production instance](https://treeherder.mozilla.org/)
-* [Staging instance](https://treeherder.allizom.org/)
-* [Source code](https://github.com/mozilla/treeherder/)
-
-
-## Trees / repositories / branches
-
-Treeherders knows a about a number of *repostories*.
-Mercurial on Mozilla’s servers and git on GitHub are supported.
-Despite the name, in the GitHub case
-each Treeherder repository maps to one branch in a git repository.
-They are configured in the [`repository.json`] file.
-As of this writing there are four for `github.com/servo/servo`,
-named after the corresponding branch:
-
-[`repository.json`]: https://github.com/mozilla/treeherder/blob/master/treeherder/model/fixtures/repository.json
-
-* [`servo-master`](https://treeherder.mozilla.org/#/jobs?repo=servo-master)
-* [`servo-auto`](https://treeherder.mozilla.org/#/jobs?repo=servo-auto)
-* [`servo-try`](https://treeherder.mozilla.org/#/jobs?repo=servo-try)
-* [`servo-try-taskcluster`](https://treeherder.mozilla.org/#/jobs?repo=servo-try-taskcluster)
-
-In the UI, the “Repos” button near the top right corner allows switching.
-
-`servo-auto` is the relevant one when a pull request is approved with Homu for landing,
-since the `auto` branch is where it pushes a merge commit for testing.
-
-
-## Data flow / how it all works
-
-(This section is mostly useful for future changes or troubleshooting.)
-
-Changes to the Treeherder repository are deployed to Staging
-soon (minutes) after they are merged on GitHub,
-and to Production manually at some point later.
-See [current deployment status](https://whatsdeployed.io/s-dqv).
-
-Once a configuration change with a new repository/branch is deployed,
-Treeherder will show it in its UI and start recording push and job data in its database.
-This data comes from [Pulse], Mozilla’s shared message queue that coordinates separate services.
-The [Pulse Inspector] shows messages as they come (though not in the past),
-which can be useful for debugging.
-Note that you need to add at least one “Binding”,
-or the “Start Listening” button won’t do anything.
-
-[Pulse]: https://wiki.mozilla.org/Auto-tools/Projects/Pulse
-[Pulse Inspector]: https://community-tc.services.mozilla.com/pulse-messages
-
-
-### Push data
-
-When [taskcluster-github] is [enabled] on a repository,
-it recieves [webhooks] from GitHub for various events
-such as a push to a branch of the repository.
-
-In addition to starting Taskcluster tasks based on `.taskcluster.yml` in the repository,
-in [`api.js`] it creates [Pulse messages] corresponding to those events.
-Treeherder consumes messages from the `exchange/taskcluster-github/v1/push` exchange
-(among others) in [`push_loader.py`].
-In Pulse Inspector, these messages for the Servo repository can be seen
-by specifying the [`primary.servo.servo`] routing key pattern.
-
-[taskcluster-github]: https://github.com/taskcluster/taskcluster/tree/master/services/github
-[enabled]: https://github.com/apps/community-tc-integration/
-[webhooks]: https://developer.github.com/webhooks/
-[Pulse messages]: https://community-tc.services.mozilla.com/docs/reference/integrations/github/exchanges
-[`api.js`]: https://github.com/taskcluster/taskcluster/blob/master/services/github/src/api.js
-[`push_loader.py`]: https://github.com/mozilla/treeherder/blob/master/treeherder/etl/push_loader.py
-[`primary.servo.servo`]: https://community-tc.services.mozilla.com/pulse-messages?bindings%5B0%5D%5Bexchange%5D=exchange%2Ftaskcluster-github%2Fv1%2Fpush&bindings%5B0%5D%5BroutingKeyPattern%5D=primary.servo.servo
-
-
-### (Taskcluster) job data
-
-The Taskcluster Queue generates a number of [Pulse messages about tasks].
-Each value of the `routes` array in the task definition, with a `route.` prefix prepended,
-is additional routing key for those messages.
-
-Treeherder reads those messages
-if they have an appropriate route ([see in Pulse inspector][inspector1]),
-However, it will drop an incoming message
-if the `extra.treeherder` object in the task definition doesn’t conform to the [schema].
-Such schema validation errors are logged, but those logs are not easy to access.
-Ask on IRC on `#taskcluster`.
-
-Finally, Treeherder reads that latter kind of message in [`job_loader.py`].
-
-
-
-[Pulse messages about tasks]: https://community-tc.services.mozilla.com/docs/reference/platform/taskcluster-queue/references/events
-[taskcluster-treeherder]: https://github.com/taskcluster/taskcluster-treeherder/
-[other messages]: https://community-tc.services.mozilla.com/docs/reference/integrations/taskcluster-treeherder#job-pulse-messages
-[schema]: https://schemas.taskcluster.net/treeherder/v1/task-treeherder-config.json
-[`job_loader.py`]: https://github.com/mozilla/treeherder/blob/master/treeherder/etl/job_loader.py
-[inspector1]: https://tools.taskcluster.net/pulse-inspector?bindings%5B0%5D%5Bexchange%5D=exchange%2Ftaskcluster-queue%2Fv1%2Ftask-defined&bindings%5B0%5D%5BroutingKeyPattern%5D=route.tc-treeherder.%23
diff --git a/python/servo/package_commands.py b/python/servo/package_commands.py
index f6010c0d3a0..53910dcd644 100644
--- a/python/servo/package_commands.py
+++ b/python/servo/package_commands.py
@@ -21,7 +21,6 @@ import shutil
import subprocess
import sys
import tempfile
-import urllib
import xml
from mach.decorators import (
@@ -98,15 +97,6 @@ else:
raise e
-def get_taskcluster_secret(name):
- url = (
- os.environ.get("TASKCLUSTER_PROXY_URL", "http://taskcluster")
- + "/api/secrets/v1/secret/project/servo/"
- + name
- )
- return json.load(urllib.request.urlopen(url))["secret"]
-
-
def otool(s):
o = subprocess.Popen(['/usr/bin/otool', '-L', s], stdout=subprocess.PIPE)
for line in map(lambda s: s.decode('ascii'), o.stdout):
@@ -601,23 +591,16 @@ class PackageCommands(CommandBase):
@CommandArgument('platform',
choices=PACKAGES.keys(),
help='Package platform type to upload')
- @CommandArgument('--secret-from-taskcluster',
- action='store_true',
- help='Retrieve the appropriate secrets from taskcluster.')
@CommandArgument('--secret-from-environment',
action='store_true',
help='Retrieve the appropriate secrets from the environment.')
- def upload_nightly(self, platform, secret_from_taskcluster, secret_from_environment):
+ def upload_nightly(self, platform, secret_from_environment):
import boto3
def get_s3_secret():
aws_access_key = None
aws_secret_access_key = None
- if secret_from_taskcluster:
- secret = get_taskcluster_secret("s3-upload-credentials")
- aws_access_key = secret["aws_access_key_id"]
- aws_secret_access_key = secret["aws_secret_access_key"]
- elif secret_from_environment:
+ if secret_from_environment:
secret = json.loads(os.environ['S3_UPLOAD_CREDENTIALS'])
aws_access_key = secret["aws_access_key_id"]
aws_secret_access_key = secret["aws_secret_access_key"]
@@ -758,10 +741,7 @@ class PackageCommands(CommandBase):
'--message=Version Bump: {}'.format(brew_version),
])
- if secret_from_taskcluster:
- token = get_taskcluster_secret('github-homebrew-token')["token"]
- else:
- token = os.environ['GITHUB_HOMEBREW_TOKEN']
+ token = os.environ['GITHUB_HOMEBREW_TOKEN']
push_url = 'https://{}@github.com/servo/homebrew-servo.git'
# TODO(aneeshusa): Use subprocess.DEVNULL with Python 3.3+
@@ -804,8 +784,6 @@ def setup_uwp_signing(ms_app_store, publisher):
if ms_app_store:
return ["/p:AppxPackageSigningEnabled=false"]
- is_tc = "TASKCLUSTER_PROXY_URL" in os.environ
-
def run_powershell_cmd(cmd):
try:
return (
@@ -818,10 +796,7 @@ def setup_uwp_signing(ms_app_store, publisher):
exit(1)
pfx = None
- if is_tc:
- print("Packaging on TC. Using secret certificate")
- pfx = get_taskcluster_secret("windows-codesign-cert/latest")["pfx"]["base64"]
- elif 'CODESIGN_CERT' in os.environ:
+ if 'CODESIGN_CERT' in os.environ:
pfx = os.environ['CODESIGN_CERT']
if pfx:
@@ -832,10 +807,7 @@ def setup_uwp_signing(ms_app_store, publisher):
# Powershell command that lists all certificates for publisher
cmd = '(dir cert: -Recurse | Where-Object {$_.Issuer -eq "' + publisher + '"}).Thumbprint'
certs = list(set(run_powershell_cmd(cmd).splitlines()))
- if not certs and is_tc:
- print("Error: No certificate installed for publisher " + publisher)
- exit(1)
- if not certs and not is_tc:
+ if not certs:
print("No certificate installed for publisher " + publisher)
print("Creating and installing a temporary certificate")
# PowerShell command that creates and install signing certificate for publisher
diff --git a/servo-tidy.toml b/servo-tidy.toml
index af3eee3aacb..762eb169145 100644
--- a/servo-tidy.toml
+++ b/servo-tidy.toml
@@ -123,9 +123,6 @@ files = [
"./tests/wpt/mozilla/tests/css/pre_with_tab.html",
"./tests/wpt/mozilla/tests/mozilla/textarea_placeholder.html",
# Python 3 syntax causes "E901 SyntaxError" when flake8 runs in Python 2
- "./etc/taskcluster/decision_task.py",
- "./etc/taskcluster/decisionlib.py",
- "./tests/wpt/reftests-report/gen.py",
"./components/style/properties/build.py",
]
# Directories that are ignored for the non-WPT tidy check.
diff --git a/tests/wpt/reftests-report/gen.py b/tests/wpt/reftests-report/gen.py
deleted file mode 100755
index ba07ca26469..00000000000
--- a/tests/wpt/reftests-report/gen.py
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/usr/bin/env python3
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-import gzip
-import json
-import os
-import re
-import sys
-import urllib.request
-from html import escape as html_escape
-
-
-TASKCLUSTER_ROOT_URL = "https://community-tc.services.mozilla.com"
-
-
-def fetch(url):
- url = TASKCLUSTER_ROOT_URL + "/api/" + url
- print("Fetching " + url)
- response = urllib.request.urlopen(url)
- assert response.getcode() == 200
- encoding = response.info().get("Content-Encoding")
- if not encoding:
- return response
- elif encoding == "gzip":
- return gzip.GzipFile(fileobj=response)
- else:
- raise ValueError("Unsupported Content-Encoding: %s" % encoding)
-
-
-def fetch_json(url):
- with fetch(url) as response:
- return json.load(response)
-
-
-def task(platform, chunk, key):
- return "index/v1/task/project.servo.%s_wpt_%s.%s" % (platform, chunk, key)
-
-
-def failing_reftests(platform, key):
- chunk_1_task_id = fetch_json(task(platform, 1, key))["taskId"]
- name = fetch_json("queue/v1/task/" + chunk_1_task_id)["metadata"]["name"]
- match = re.search("WPT chunk (\d+) / (\d+)", name)
- assert match.group(1) == "1"
- total_chunks = int(match.group(2))
-
- for chunk in range(1, total_chunks + 1):
- with fetch(task(platform, chunk, key) + "/artifacts/public/test-wpt.log") as response:
- yield from parse(response)
-
-
-def parse(file_like):
- seen = set()
- for line in file_like:
- message = json.loads(line)
- status = message.get("status")
- if status not in {None, "OK", "PASS"}:
- screenshots = message.get("extra", {}).get("reftest_screenshots")
- if screenshots:
- url = message["test"]
- assert url.startswith("/")
- yield url[1:], message.get("expected") == "PASS", screenshots
-
-
-def main(source, commit_sha=None):
- failures = Directory()
-
- if commit_sha:
- title = "<h1>Layout 2020 regressions in commit <code>%s</code></h1>" % commit_sha
- failures_2013 = {url for url, _, _ in failing_reftests("linux_x64", source)}
- for url, _expected_pass, screenshots in failing_reftests("linux_x64_2020", source):
- if url not in failures_2013:
- failures.add(url, screenshots)
- else:
- title = "Unexpected failures"
- with open(source, "rb") as file_obj:
- for url, expected_pass, screenshots in parse(file_obj):
- if expected_pass:
- failures.add(url, screenshots)
-
- here = os.path.dirname(__file__)
- with open(os.path.join(here, "prism.js")) as f:
- prism_js = f.read()
- with open(os.path.join(here, "prism.css")) as f:
- prism_css = f.read()
- with open(os.path.join(here, "report.html"), "w", encoding="utf-8") as html:
- os.chdir(os.path.join(here, ".."))
- html.write("""
- <!doctype html>
- <meta charset=utf-8>
- <title>WPT reftests failures report</title>
- <link rel=stylesheet href=prism.css>
- <style>
- ul { padding-left: 1em }
- li { list-style: "⯈ " }
- li.expanded { list-style: "⯆ " }
- li:not(.expanded) > ul, li:not(.expanded) > div { display: none }
- li > div { display: grid; grid-gap: 1em; grid-template-columns: 1fr 1fr }
- li > div > p { grid-column: span 2 }
- li > div > img { grid-row: 2; width: 300px; box-shadow: 0 0 10px }
- li > div > img:hover { transform: scale(3); transform-origin: 0 0 }
- li > div > pre { grid-row: 3; font-size: 12px !important }
- pre code { white-space: pre-wrap !important }
- <h1>%s</h1>
- </style>
- %s
- """ % (prism_css, title))
- failures.write(html)
- html.write("""
- <script>
- for (let li of document.getElementsByTagName("li")) {
- li.addEventListener('click', event => {
- li.classList.toggle("expanded")
- event.stopPropagation()
- })
- }
- %s
- </script>
- """ % prism_js)
-
-
-class Directory:
- def __init__(self):
- self.count = 0
- self.contents = {}
-
- def add(self, path, screenshots):
- self.count += 1
- first, _, rest = path.partition("/")
- if rest:
- self.contents.setdefault(first, Directory()).add(rest, screenshots)
- else:
- assert path not in self.contents
- self.contents[path] = screenshots
-
- def write(self, html):
- html.write("<ul>\n")
- for k, v in self.contents.items():
- html.write("<li><code>%s</code>\n" % k)
- if isinstance(v, Directory):
- html.write("<strong>%s</strong>\n" % v.count)
- v.write(html)
- else:
- a, rel, b = v
- html.write("<div>\n<p><code>%s</code> %s <code>%s</code></p>\n"
- % (a["url"], rel, b["url"]))
- for side in [a, b]:
- html.write("<img src='data:image/png;base64,%s'>\n" % side["screenshot"])
- url = side["url"]
- prefix = "/_mozilla/"
- if url.startswith(prefix):
- filename = "mozilla/tests/" + url[len(prefix):]
- elif url == "about:blank":
- src = ""
- filename = None
- else:
- filename = "web-platform-tests" + url
- if filename:
- with open(filename, encoding="utf-8") as f:
- src = html_escape(f.read())
- html.write("<pre><code class=language-html>%s</code></pre>\n" % src)
- html.write("</li>\n")
- html.write("</ul>\n")
-
-
-if __name__ == "__main__":
- sys.exit(main(*sys.argv[1:]))
diff --git a/tests/wpt/reftests-report/prism.css b/tests/wpt/reftests-report/prism.css
deleted file mode 100644
index 6fa6fcc5be6..00000000000
--- a/tests/wpt/reftests-report/prism.css
+++ /dev/null
@@ -1,141 +0,0 @@
-/* PrismJS 1.19.0
-https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
-/**
- * prism.js default theme for JavaScript, CSS and HTML
- * Based on dabblet (http://dabblet.com)
- * @author Lea Verou
- */
-
-code[class*="language-"],
-pre[class*="language-"] {
- color: black;
- background: none;
- text-shadow: 0 1px white;
- font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
- font-size: 1em;
- text-align: left;
- white-space: pre;
- word-spacing: normal;
- word-break: normal;
- word-wrap: normal;
- line-height: 1.5;
-
- -moz-tab-size: 4;
- -o-tab-size: 4;
- tab-size: 4;
-
- -webkit-hyphens: none;
- -moz-hyphens: none;
- -ms-hyphens: none;
- hyphens: none;
-}
-
-pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
-code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
- text-shadow: none;
- background: #b3d4fc;
-}
-
-pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
-code[class*="language-"]::selection, code[class*="language-"] ::selection {
- text-shadow: none;
- background: #b3d4fc;
-}
-
-@media print {
- code[class*="language-"],
- pre[class*="language-"] {
- text-shadow: none;
- }
-}
-
-/* Code blocks */
-pre[class*="language-"] {
- padding: 1em;
- margin: .5em 0;
- overflow: auto;
-}
-
-:not(pre) > code[class*="language-"],
-pre[class*="language-"] {
- background: #f5f2f0;
-}
-
-/* Inline code */
-:not(pre) > code[class*="language-"] {
- padding: .1em;
- border-radius: .3em;
- white-space: normal;
-}
-
-.token.comment,
-.token.prolog,
-.token.doctype,
-.token.cdata {
- color: slategray;
-}
-
-.token.punctuation {
- color: #999;
-}
-
-.token.namespace {
- opacity: .7;
-}
-
-.token.property,
-.token.tag,
-.token.boolean,
-.token.number,
-.token.constant,
-.token.symbol,
-.token.deleted {
- color: #905;
-}
-
-.token.selector,
-.token.attr-name,
-.token.string,
-.token.char,
-.token.builtin,
-.token.inserted {
- color: #690;
-}
-
-.token.operator,
-.token.entity,
-.token.url,
-.language-css .token.string,
-.style .token.string {
- color: #9a6e3a;
- background: hsla(0, 0%, 100%, .5);
-}
-
-.token.atrule,
-.token.attr-value,
-.token.keyword {
- color: #07a;
-}
-
-.token.function,
-.token.class-name {
- color: #DD4A68;
-}
-
-.token.regex,
-.token.important,
-.token.variable {
- color: #e90;
-}
-
-.token.important,
-.token.bold {
- font-weight: bold;
-}
-.token.italic {
- font-style: italic;
-}
-
-.token.entity {
- cursor: help;
-}
diff --git a/tests/wpt/reftests-report/prism.js b/tests/wpt/reftests-report/prism.js
deleted file mode 100644
index a43970450d6..00000000000
--- a/tests/wpt/reftests-report/prism.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/* PrismJS 1.19.0
-https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
-var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,r=0,C={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(r){return r instanceof _?new _(r.type,e(r.content),r.alias):Array.isArray(r)?r.map(e):r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++r}),e.__id},clone:function n(e,t){var a,r,i=C.util.type(e);switch(t=t||{},i){case"Object":if(r=C.util.objId(e),t[r])return t[r];for(var o in a={},t[r]=a,e)e.hasOwnProperty(o)&&(a[o]=n(e[o],t));return a;case"Array":return r=C.util.objId(e),t[r]?t[r]:(a=[],t[r]=a,e.forEach(function(e,r){a[r]=n(e,t)}),a);default:return e}},getLanguage:function(e){for(;e&&!c.test(e.className);)e=e.parentElement;return e?(e.className.match(c)||[,"none"])[1].toLowerCase():"none"},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(e){var r=(/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(e.stack)||[])[1];if(r){var n=document.getElementsByTagName("script");for(var t in n)if(n[t].src==r)return n[t]}return null}}},languages:{extend:function(e,r){var n=C.util.clone(C.languages[e]);for(var t in r)n[t]=r[t];return n},insertBefore:function(n,e,r,t){var a=(t=t||C.languages)[n],i={};for(var o in a)if(a.hasOwnProperty(o)){if(o==e)for(var l in r)r.hasOwnProperty(l)&&(i[l]=r[l]);r.hasOwnProperty(o)||(i[o]=a[o])}var s=t[n];return t[n]=i,C.languages.DFS(C.languages,function(e,r){r===s&&e!=n&&(this[e]=i)}),i},DFS:function e(r,n,t,a){a=a||{};var i=C.util.objId;for(var o in r)if(r.hasOwnProperty(o)){n.call(r,o,r[o],t||o);var l=r[o],s=C.util.type(l);"Object"!==s||a[i(l)]?"Array"!==s||a[i(l)]||(a[i(l)]=!0,e(l,n,o,a)):(a[i(l)]=!0,e(l,n,null,a))}}},plugins:{},highlightAll:function(e,r){C.highlightAllUnder(document,e,r)},highlightAllUnder:function(e,r,n){var t={callback:n,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};C.hooks.run("before-highlightall",t),t.elements=Array.prototype.slice.apply(t.container.querySelectorAll(t.selector)),C.hooks.run("before-all-elements-highlight",t);for(var a,i=0;a=t.elements[i++];)C.highlightElement(a,!0===r,t.callback)},highlightElement:function(e,r,n){var t=C.util.getLanguage(e),a=C.languages[t];e.className=e.className.replace(c,"").replace(/\s+/g," ")+" language-"+t;var i=e.parentNode;i&&"pre"===i.nodeName.toLowerCase()&&(i.className=i.className.replace(c,"").replace(/\s+/g," ")+" language-"+t);var o={element:e,language:t,grammar:a,code:e.textContent};function l(e){o.highlightedCode=e,C.hooks.run("before-insert",o),o.element.innerHTML=o.highlightedCode,C.hooks.run("after-highlight",o),C.hooks.run("complete",o),n&&n.call(o.element)}if(C.hooks.run("before-sanity-check",o),!o.code)return C.hooks.run("complete",o),void(n&&n.call(o.element));if(C.hooks.run("before-highlight",o),o.grammar)if(r&&u.Worker){var s=new Worker(C.filename);s.onmessage=function(e){l(e.data)},s.postMessage(JSON.stringify({language:o.language,code:o.code,immediateClose:!0}))}else l(C.highlight(o.code,o.grammar,o.language));else l(C.util.encode(o.code))},highlight:function(e,r,n){var t={code:e,grammar:r,language:n};return C.hooks.run("before-tokenize",t),t.tokens=C.tokenize(t.code,t.grammar),C.hooks.run("after-tokenize",t),_.stringify(C.util.encode(t.tokens),t.language)},matchGrammar:function(e,r,n,t,a,i,o){for(var l in n)if(n.hasOwnProperty(l)&&n[l]){var s=n[l];s=Array.isArray(s)?s:[s];for(var u=0;u<s.length;++u){if(o&&o==l+","+u)return;var c=s[u],g=c.inside,f=!!c.lookbehind,h=!!c.greedy,d=0,m=c.alias;if(h&&!c.pattern.global){var p=c.pattern.toString().match(/[imsuy]*$/)[0];c.pattern=RegExp(c.pattern.source,p+"g")}c=c.pattern||c;for(var y=t,v=a;y<r.length;v+=r[y].length,++y){var k=r[y];if(r.length>e.length)return;if(!(k instanceof _)){if(h&&y!=r.length-1){if(c.lastIndex=v,!(S=c.exec(e)))break;for(var b=S.index+(f&&S[1]?S[1].length:0),w=S.index+S[0].length,A=y,P=v,x=r.length;A<x&&(P<w||!r[A].type&&!r[A-1].greedy);++A)(P+=r[A].length)<=b&&(++y,v=P);if(r[y]instanceof _)continue;O=A-y,k=e.slice(v,P),S.index-=v}else{c.lastIndex=0;var S=c.exec(k),O=1}if(S){f&&(d=S[1]?S[1].length:0);w=(b=S.index+d)+(S=S[0].slice(d)).length;var E=k.slice(0,b),N=k.slice(w),j=[y,O];E&&(++y,v+=E.length,j.push(E));var L=new _(l,g?C.tokenize(S,g):S,m,S,h);if(j.push(L),N&&j.push(N),Array.prototype.splice.apply(r,j),1!=O&&C.matchGrammar(e,r,n,y,v,!0,l+","+u),i)break}else if(i)break}}}}},tokenize:function(e,r){var n=[e],t=r.rest;if(t){for(var a in t)r[a]=t[a];delete r.rest}return C.matchGrammar(e,n,r,0,0,!1),n},hooks:{all:{},add:function(e,r){var n=C.hooks.all;n[e]=n[e]||[],n[e].push(r)},run:function(e,r){var n=C.hooks.all[e];if(n&&n.length)for(var t,a=0;t=n[a++];)t(r)}},Token:_};function _(e,r,n,t,a){this.type=e,this.content=r,this.alias=n,this.length=0|(t||"").length,this.greedy=!!a}if(u.Prism=C,_.stringify=function r(e,n){if("string"==typeof e)return e;if(Array.isArray(e)){var t="";return e.forEach(function(e){t+=r(e,n)}),t}var a={type:e.type,content:r(e.content,n),tag:"span",classes:["token",e.type],attributes:{},language:n},i=e.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),C.hooks.run("wrap",a);var o="";for(var l in a.attributes)o+=" "+l+'="'+(a.attributes[l]||"").replace(/"/g,"&quot;")+'"';return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+o+">"+a.content+"</"+a.tag+">"},!u.document)return u.addEventListener&&(C.disableWorkerMessageHandler||u.addEventListener("message",function(e){var r=JSON.parse(e.data),n=r.language,t=r.code,a=r.immediateClose;u.postMessage(C.highlight(t,C.languages[n],n)),a&&u.close()},!1)),C;var e=C.util.currentScript();function n(){C.manual||C.highlightAll()}if(e&&(C.filename=e.src,e.hasAttribute("data-manual")&&(C.manual=!0)),!C.manual){var t=document.readyState;"loading"===t||"interactive"===t&&e&&e.defer?document.addEventListener("DOMContentLoaded",n):window.requestAnimationFrame?window.requestAnimationFrame(n):window.setTimeout(n,16)}return C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
-Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:(?!<!--)[^"'\]]|"[^"]*"|'[^']*'|<!--[\s\S]*?-->)*\]\s*)?>/i,greedy:!0},cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\[CDATA\[|\]\]>$/i;var n={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[\\s\\S]*?>)(?:<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\s*|[\\s\\S])*?(?=<\\/__>)".replace(/__/g,a),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
-!function(s){var e=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"}}},url:{pattern:RegExp("url\\((?:"+e.source+"|[^\n\r()]*)\\)","i"),inside:{function:/^url/i,punctuation:/^\(|\)$/}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+e.source+")*?(?=\\s*\\{)"),string:{pattern:e,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),s.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:t.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:s.languages.css}},alias:"language-css"}},t.tag))}(Prism);
-Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
-Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&|\|\||[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?[.?]?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*[\s\S]*?\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
diff --git a/tests/wpt/update/fetchlogs.py b/tests/wpt/update/fetchlogs.py
deleted file mode 100644
index 385f2c54174..00000000000
--- a/tests/wpt/update/fetchlogs.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at https://mozilla.org/MPL/2.0/.
-
-import argparse
-import cStringIO
-import gzip
-import json
-import os
-import requests
-import six.moves.urllib as urllib
-
-treeherder_base = "https://treeherder.mozilla.org/"
-
-"""Simple script for downloading structured logs from treeherder.
-
-For the moment this is specialised to work with web-platform-tests
-logs; in due course it should move somewhere generic and get hooked
-up to mach or similar"""
-
-# Interpretation of the "job" list from
-# https://github.com/mozilla/treeherder-service/blob/master/treeherder/webapp/api/utils.py#L18
-
-def create_parser():
- parser = argparse.ArgumentParser()
- parser.add_argument("branch", action="store",
- help="Branch on which jobs ran")
- parser.add_argument("commit",
- action="store",
- help="Commit hash for push")
-
- return parser
-
-def download(url, prefix, dest, force_suffix=True):
- if dest is None:
- dest = "."
-
- if prefix and not force_suffix:
- name = os.path.join(dest, prefix + ".log")
- else:
- name = None
- counter = 0
-
- while not name or os.path.exists(name):
- counter += 1
- sep = "" if not prefix else "-"
- name = os.path.join(dest, prefix + sep + str(counter) + ".log")
-
- with open(name, "wb") as f:
- resp = requests.get(url, stream=True)
- for chunk in resp.iter_content(1024):
- f.write(chunk)
-
-def get_blobber_url(branch, job):
- job_id = job["id"]
- resp = requests.get(urllib.parse.urljoin(treeherder_base,
- "/api/project/%s/artifact/?job_id=%i&name=Job%%20Info" % (branch,
- job_id)))
- job_data = resp.json()
-
- if job_data:
- assert len(job_data) == 1
- job_data = job_data[0]
- try:
- details = job_data["blob"]["job_details"]
- for item in details:
- if item["value"] == "wpt_raw.log":
- return item["url"]
- except:
- return None
-
-
-def get_structured_logs(branch, commit, dest=None):
- resp = requests.get(urllib.parse.urljoin(treeherder_base, "/api/project/%s/resultset/?revision=%s" % (branch, commit)))
-
- revision_data = resp.json()
-
- result_set = revision_data["results"][0]["id"]
-
- resp = requests.get(urllib.parse.urljoin(treeherder_base, "/api/project/%s/jobs/?result_set_id=%s&count=2000&exclusion_profile=false" % (branch, result_set)))
-
- job_data = resp.json()
-
- for result in job_data["results"]:
- job_type_name = result["job_type_name"]
- if job_type_name.startswith("W3C Web Platform"):
- url = get_blobber_url(branch, result)
- if url:
- prefix = result["platform"] # platform
- download(url, prefix, None)
-
-def main():
- parser = create_parser()
- args = parser.parse_args()
-
- get_structured_logs(args.branch, args.commit)
-
-if __name__ == "__main__":
- main()