diff options
-rw-r--r-- | .github/workflows/pull-request-wpt-export.yml | 6 | ||||
-rw-r--r-- | .github/workflows/test-export-wpt-changes.yml (renamed from .github/workflows/test-upstream-wpt-changes.yml) | 6 | ||||
-rwxr-xr-x | etc/ci/update-wpt-checkout | 2 | ||||
-rw-r--r-- | etc/ci/upstream-wpt-changes/README | 0 | ||||
-rw-r--r-- | python/README.md | 5 | ||||
-rw-r--r-- | python/servo/testing_commands.py | 74 | ||||
-rw-r--r-- | python/wpt/__init__.py | 61 | ||||
-rwxr-xr-x | python/wpt/export.py (renamed from etc/ci/upstream-wpt-changes/upstream-wpt-changes.py) | 2 | ||||
-rw-r--r-- | python/wpt/exporter/__init__.py (renamed from etc/ci/upstream-wpt-changes/wptupstreamer/__init__.py) | 0 | ||||
-rw-r--r-- | python/wpt/exporter/common.py (renamed from etc/ci/upstream-wpt-changes/wptupstreamer/common.py) | 0 | ||||
-rw-r--r-- | python/wpt/exporter/github.py (renamed from etc/ci/upstream-wpt-changes/wptupstreamer/github.py) | 0 | ||||
-rw-r--r-- | python/wpt/exporter/step.py (renamed from etc/ci/upstream-wpt-changes/wptupstreamer/step.py) | 0 | ||||
-rw-r--r-- | python/wpt/grouping_formatter.py (renamed from tests/wpt/grouping_formatter.py) | 0 | ||||
-rw-r--r-- | python/wpt/importer/__init__.py | 57 | ||||
-rw-r--r-- | python/wpt/importer/tree.py (renamed from tests/wpt/update/tree.py) | 20 | ||||
-rw-r--r-- | python/wpt/manifestupdate.py (renamed from tests/wpt/manifestupdate.py) | 72 | ||||
-rw-r--r-- | python/wpt/requirements-dev.txt (renamed from etc/ci/upstream-wpt-changes/requirements-dev.txt) | 0 | ||||
-rw-r--r-- | python/wpt/requirements.txt (renamed from etc/ci/upstream-wpt-changes/requirements.txt) | 0 | ||||
-rw-r--r-- | python/wpt/run.py (renamed from tests/wpt/servowpt.py) | 79 | ||||
-rw-r--r-- | python/wpt/test.py (renamed from etc/ci/upstream-wpt-changes/test.py) | 6 | ||||
-rw-r--r-- | python/wpt/tests/18746.diff (renamed from etc/ci/upstream-wpt-changes/tests/18746.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/add-non-utf8-file.diff (renamed from etc/ci/upstream-wpt-changes/tests/add-non-utf8-file.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/closed.json (renamed from etc/ci/upstream-wpt-changes/tests/closed.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/does-not-apply-cleanly.diff (renamed from etc/ci/upstream-wpt-changes/tests/does-not-apply-cleanly.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/edited.json (renamed from etc/ci/upstream-wpt-changes/tests/edited.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/merged.json (renamed from etc/ci/upstream-wpt-changes/tests/merged.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/move-into-wpt.diff (renamed from etc/ci/upstream-wpt-changes/tests/move-into-wpt.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/move-out-of-wpt.diff (renamed from etc/ci/upstream-wpt-changes/tests/move-out-of-wpt.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/non-wpt.diff (renamed from etc/ci/upstream-wpt-changes/tests/non-wpt.diff) | 0 | ||||
-rw-r--r-- | python/wpt/tests/opened-with-no-sync-signal.json (renamed from etc/ci/upstream-wpt-changes/tests/opened-with-no-sync-signal.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/opened.json (renamed from etc/ci/upstream-wpt-changes/tests/opened.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/README.md (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/README.md) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/something.py (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/something.py) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/test.html (renamed from etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/synchronize-multiple.json (renamed from etc/ci/upstream-wpt-changes/tests/synchronize-multiple.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/synchronize.json (renamed from etc/ci/upstream-wpt-changes/tests/synchronize.json) | 0 | ||||
-rw-r--r-- | python/wpt/tests/wpt-mock/css/css-test.html (renamed from etc/ci/upstream-wpt-changes/tests/wpt-mock/css/css-test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/wpt-mock/fetch/api/redirect/redirect-location.html (renamed from etc/ci/upstream-wpt-changes/tests/wpt-mock/fetch/api/redirect/redirect-location.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/wpt-mock/test.html (renamed from etc/ci/upstream-wpt-changes/tests/wpt-mock/test.html) | 0 | ||||
-rw-r--r-- | python/wpt/tests/wpt.diff (renamed from etc/ci/upstream-wpt-changes/tests/wpt.diff) | 0 | ||||
-rw-r--r-- | python/wpt/update.py | 29 | ||||
-rw-r--r-- | servo-tidy.toml | 2 | ||||
-rw-r--r-- | tests/wpt/README.md | 7 | ||||
-rw-r--r-- | tests/wpt/update/__init__.py | 41 | ||||
-rw-r--r-- | tests/wpt/update/github.py | 179 | ||||
-rw-r--r-- | tests/wpt/update/update.py | 42 | ||||
-rw-r--r-- | tests/wpt/update/updatecommandline.py | 44 | ||||
-rw-r--r-- | tests/wpt/update/upstream.py | 389 |
52 files changed, 236 insertions, 887 deletions
diff --git a/.github/workflows/pull-request-wpt-export.yml b/.github/workflows/pull-request-wpt-export.yml index 092a5d043b9..6f69ea6cd36 100644 --- a/.github/workflows/pull-request-wpt-export.yml +++ b/.github/workflows/pull-request-wpt-export.yml @@ -32,9 +32,9 @@ jobs: # See https://github.com/actions/checkout/issues/162. token: ${{ secrets.WPT_SYNC_TOKEN }} - name: Install requirements - run: pip install -r servo/etc/ci/upstream-wpt-changes/requirements.txt + run: pip install -r servo/python/wpt/requirements.txt - name: Process pull request - run: servo/etc/ci/upstream-wpt-changes/upstream-wpt-changes.py + run: servo/python/wpt/upstream.py env: GITHUB_CONTEXT: ${{ toJson(github) }} - WPT_SYNC_TOKEN: ${{ secrets.WPT_SYNC_TOKEN }}
\ No newline at end of file + WPT_SYNC_TOKEN: ${{ secrets.WPT_SYNC_TOKEN }} diff --git a/.github/workflows/test-upstream-wpt-changes.yml b/.github/workflows/test-export-wpt-changes.yml index 03b76f2c693..ec3b1c7f1c1 100644 --- a/.github/workflows/test-upstream-wpt-changes.yml +++ b/.github/workflows/test-export-wpt-changes.yml @@ -2,7 +2,7 @@ name: WPT exporter test on: pull_request: branches: ["**"] - paths: ["etc/ci/upstream-wpt-changes/**"] + paths: ["python/wpt/exporter/**"] jobs: test: @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v3 - name: Install dependencies run: | - python3 -m pip install --upgrade -r etc/ci/upstream-wpt-changes/requirements-dev.txt + python3 -m pip install --upgrade -r python/wpt/requirements-dev.txt - name: Running tests run: | - python3 etc/ci/upstream-wpt-changes/test.py + python3 python/wpt/test.py diff --git a/etc/ci/update-wpt-checkout b/etc/ci/update-wpt-checkout index 4ff7f7c125e..4a455ebd684 100755 --- a/etc/ci/update-wpt-checkout +++ b/etc/ci/update-wpt-checkout @@ -35,7 +35,7 @@ function unsafe_pull_from_upstream() { # Fetch all changes from upstream WPT and automatically transpose them # into a single servo commit. - ./mach update-wpt --sync --no-upstream --patch || return 2 + ./mach update-wpt --sync --patch || return 2 # If there was no new commit created, there are no changes that need syncing. # Skip the remaining steps. diff --git a/etc/ci/upstream-wpt-changes/README b/etc/ci/upstream-wpt-changes/README deleted file mode 100644 index e69de29bb2d..00000000000 --- a/etc/ci/upstream-wpt-changes/README +++ /dev/null diff --git a/python/README.md b/python/README.md index 4ee50a3edce..b79a4b2e8ea 100644 --- a/python/README.md +++ b/python/README.md @@ -10,3 +10,8 @@ is the canonical repository for this code. servo-tidy is used to check licenses, line lengths, whitespace, flake8 on Python files, lock file versions, and more. + +# `wpt` +servo-wpt is a module with support scripts for running, importing, +exporting, updating manifests, and updating expectations for WPT +tests.
\ No newline at end of file diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index 9818c5ab20e..9209e9240d8 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -22,6 +22,11 @@ import subprocess from xml.etree.ElementTree import XML from six import iteritems +import wpt +import wpt.manifestupdate +import wpt.run +import wpt.update + from mach.registrar import Registrar from mach.decorators import ( CommandArgument, @@ -29,25 +34,19 @@ from mach.decorators import ( Command, ) +from servo_tidy import tidy from servo.command_base import ( CommandBase, call, check_call, check_output, ) -from servo.util import host_triple - -from wptrunner import wptcommandline -from update import updatecommandline -from servo_tidy import tidy from servo_tidy_tests import test_tidy +from servo.util import host_triple SCRIPT_PATH = os.path.split(__file__)[0] PROJECT_TOPLEVEL_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, "..", "..")) WEB_PLATFORM_TESTS_PATH = os.path.join("tests", "wpt", "web-platform-tests") SERVO_TESTS_PATH = os.path.join("tests", "wpt", "mozilla", "tests") -sys.path.insert(0, os.path.join(PROJECT_TOPLEVEL_PATH, 'tests', 'wpt')) -import servowpt # noqa: E402 - CLANGFMT_CPP_DIRS = ["support/hololens/"] CLANGFMT_VERSION = "15" @@ -67,45 +66,6 @@ TEST_SUITES = OrderedDict([ TEST_SUITES_BY_PREFIX = {path: k for k, v in iteritems(TEST_SUITES) if "paths" in v for path in v["paths"]} -def create_parser_wpt(): - import mozlog.commandline - parser = wptcommandline.create_parser() - parser.add_argument('--release', default=False, action="store_true", - help="Run with a release build of servo") - parser.add_argument('--rr-chaos', default=False, action="store_true", - help="Run under chaos mode in rr until a failure is captured") - parser.add_argument('--pref', default=[], action="append", dest="prefs", - help="Pass preferences to servo") - parser.add_argument('--layout-2020', '--with-layout-2020', default=False, - action="store_true", help="Use expected results for the 2020 layout engine") - parser.add_argument('--log-servojson', action="append", type=mozlog.commandline.log_file, - help="Servo's JSON logger of unexpected results") - parser.add_argument('--always-succeed', default=False, action="store_true", - help="Always yield exit code of zero") - parser.add_argument('--no-default-test-types', default=False, action="store_true", - help="Run all of the test types provided by wptrunner or specified explicitly by --test-types") - parser.add_argument('--filter-intermittents', default=None, action="store", - help="Filter intermittents against known intermittents " - "and save the filtered output to the given file.") - parser.add_argument('--log-raw-unexpected', default=None, action="store", - help="Raw structured log messages for unexpected results." - " '--log-raw' Must also be passed in order to use this.") - return parser - - -def create_parser_manifest_update(): - import manifestupdate - return manifestupdate.create_parser() - - -def run_update(topdir, check_clean=False, rebuild=False, **kwargs): - import manifestupdate - from wptrunner import wptlogging - logger = wptlogging.setup(kwargs, {"mach": sys.stdout}) - wpt_dir = os.path.abspath(os.path.join(topdir, 'tests', 'wpt')) - return manifestupdate.update(logger, wpt_dir, check_clean, rebuild) - - @CommandProvider class MachCommands(CommandBase): DEFAULT_RENDER_MODE = "cpu" @@ -353,7 +313,7 @@ class MachCommands(CommandBase): if no_wpt: manifest_dirty = False else: - manifest_dirty = run_update(self.context.topdir, check_clean=True) + manifest_dirty = wpt.manifestupdate.update(check_clean=True) tidy_failed = tidy.scan(not all_files, not no_progress, stylo=stylo, no_wpt=no_wpt) self.install_rustfmt() rustfmt_failed = self.call_rustup_run(["cargo", "fmt", "--", "--check"]) @@ -399,7 +359,7 @@ class MachCommands(CommandBase): @Command('test-wpt-failure', description='Run the tests harness that verifies that the test failures are reported correctly', category='testing', - parser=create_parser_wpt) + parser=wpt.create_parser) def test_wpt_failure(self, **kwargs): kwargs["pause_after_test"] = False kwargs["include"] = ["infrastructure/failing-test.html"] @@ -408,7 +368,7 @@ class MachCommands(CommandBase): @Command('test-wpt', description='Run the regular web platform test suite', category='testing', - parser=create_parser_wpt) + parser=wpt.create_parser) def test_wpt(self, **kwargs): ret = self.run_test_list_or_dispatch(kwargs["test_list"], "wpt", self._test_wpt, **kwargs) if kwargs["always_succeed"]: @@ -419,7 +379,7 @@ class MachCommands(CommandBase): @Command('test-wpt-android', description='Run the web platform test suite in an Android emulator', category='testing', - parser=create_parser_wpt) + parser=wpt.create_parser) def test_wpt_android(self, release=False, dev=False, binary_args=None, **kwargs): kwargs.update( release=release, @@ -433,7 +393,7 @@ class MachCommands(CommandBase): def _test_wpt(self, android=False, **kwargs): self.set_run_env(android) - return servowpt.run_tests(**kwargs) + return wpt.run.run_tests(**kwargs) # Helper to ensure all specified paths are handled, otherwise dispatch to appropriate test suite. def run_test_list_or_dispatch(self, requested_paths, correct_suite, correct_function, **kwargs): @@ -454,9 +414,9 @@ class MachCommands(CommandBase): @Command('update-manifest', description='Run test-wpt --manifest-update SKIP_TESTS to regenerate MANIFEST.json', category='testing', - parser=create_parser_manifest_update) + parser=wpt.manifestupdate.create_parser) def update_manifest(self, **kwargs): - return run_update(self.context.topdir, **kwargs) + return wpt.manifestupdate.update(check_clean=False) @Command('fmt', description='Format the Rust and CPP source files with rustfmt and clang-format', @@ -474,13 +434,13 @@ class MachCommands(CommandBase): @Command('update-wpt', description='Update the web platform tests', category='testing', - parser=updatecommandline.create_parser()) + parser=wpt.update.create_parser) def update_wpt(self, **kwargs): patch = kwargs.get("patch", False) if not patch and kwargs["sync"]: print("Are you sure you don't want a patch?") return 1 - return servowpt.update_tests(**kwargs) + return wpt.update.update_tests(**kwargs) @Command('test-android-startup', description='Extremely minimal testing of Servo for Android', @@ -826,7 +786,7 @@ testing/web-platform/mozilla/tests for Servo-only tests""" % reference_path) proc = subprocess.Popen("%s %s" % (editor, test_path), shell=True) if not kwargs["no_run"]: - p = create_parser_wpt() + p = wpt.create_parser() args = [] if kwargs["release"]: args.append("--release") diff --git a/python/wpt/__init__.py b/python/wpt/__init__.py new file mode 100644 index 00000000000..4369e147822 --- /dev/null +++ b/python/wpt/__init__.py @@ -0,0 +1,61 @@ +# Copyright 2023 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. + +import os +import sys + +import mozlog.commandline + +SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) +SERVO_ROOT = os.path.abspath(os.path.join(SCRIPT_PATH, "..", "..")) +WPT_PATH = os.path.join(SERVO_ROOT, "tests", "wpt") +WPT_TOOLS_PATH = os.path.join(WPT_PATH, "web-platform-tests", "tools") +CERTS_PATH = os.path.join(WPT_TOOLS_PATH, "certs") + +sys.path.insert(0, WPT_TOOLS_PATH) +import localpaths # noqa: F401,E402 +import wptrunner.wptcommandline # noqa: E402 + + +def create_parser(): + parser = wptrunner.wptcommandline.create_parser() + parser.add_argument('--release', default=False, action="store_true", + help="Run with a release build of servo") + parser.add_argument('--rr-chaos', default=False, action="store_true", + help="Run under chaos mode in rr until a failure is captured") + parser.add_argument('--pref', default=[], action="append", dest="prefs", + help="Pass preferences to servo") + parser.add_argument('--layout-2020', '--with-layout-2020', default=False, + action="store_true", help="Use expected results for the 2020 layout engine") + parser.add_argument('--log-servojson', action="append", type=mozlog.commandline.log_file, + help="Servo's JSON logger of unexpected results") + parser.add_argument('--always-succeed', default=False, action="store_true", + help="Always yield exit code of zero") + parser.add_argument('--no-default-test-types', default=False, action="store_true", + help="Run all of the test types provided by wptrunner or specified explicitly by --test-types") + parser.add_argument('--filter-intermittents', default=None, action="store", + help="Filter intermittents against known intermittents " + "and save the filtered output to the given file.") + parser.add_argument('--log-raw-unexpected', default=None, action="store", + help="Raw structured log messages for unexpected results." + " '--log-raw' Must also be passed in order to use this.") + return parser + + +def update_args_for_layout_2020(kwargs: dict): + if kwargs.pop("layout_2020"): + kwargs["test_paths"]["/"]["metadata_path"] = os.path.join( + WPT_PATH, "metadata-layout-2020" + ) + kwargs["test_paths"]["/_mozilla/"]["metadata_path"] = os.path.join( + WPT_PATH, "mozilla", "meta-layout-2020" + ) + kwargs["include_manifest"] = os.path.join( + WPT_PATH, "include-layout-2020.ini" + ) diff --git a/etc/ci/upstream-wpt-changes/upstream-wpt-changes.py b/python/wpt/export.py index 202c4b3c479..a8753ceaee9 100755 --- a/etc/ci/upstream-wpt-changes/upstream-wpt-changes.py +++ b/python/wpt/export.py @@ -17,7 +17,7 @@ import logging import os import sys -from wptupstreamer import WPTSync +from exporter import WPTSync def main() -> int: diff --git a/etc/ci/upstream-wpt-changes/wptupstreamer/__init__.py b/python/wpt/exporter/__init__.py index 1ca65c56321..1ca65c56321 100644 --- a/etc/ci/upstream-wpt-changes/wptupstreamer/__init__.py +++ b/python/wpt/exporter/__init__.py diff --git a/etc/ci/upstream-wpt-changes/wptupstreamer/common.py b/python/wpt/exporter/common.py index 307edce0276..307edce0276 100644 --- a/etc/ci/upstream-wpt-changes/wptupstreamer/common.py +++ b/python/wpt/exporter/common.py diff --git a/etc/ci/upstream-wpt-changes/wptupstreamer/github.py b/python/wpt/exporter/github.py index 31fa5bb93c3..31fa5bb93c3 100644 --- a/etc/ci/upstream-wpt-changes/wptupstreamer/github.py +++ b/python/wpt/exporter/github.py diff --git a/etc/ci/upstream-wpt-changes/wptupstreamer/step.py b/python/wpt/exporter/step.py index 9781353ce15..9781353ce15 100644 --- a/etc/ci/upstream-wpt-changes/wptupstreamer/step.py +++ b/python/wpt/exporter/step.py diff --git a/tests/wpt/grouping_formatter.py b/python/wpt/grouping_formatter.py index 8ab69b6a59a..8ab69b6a59a 100644 --- a/tests/wpt/grouping_formatter.py +++ b/python/wpt/grouping_formatter.py diff --git a/python/wpt/importer/__init__.py b/python/wpt/importer/__init__.py new file mode 100644 index 00000000000..7022b2a791f --- /dev/null +++ b/python/wpt/importer/__init__.py @@ -0,0 +1,57 @@ +# 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 +import sys + +from .tree import GitTree, GeckoCommit + +from wptrunner.update import setup_logging, WPTUpdate # noqa: F401 +from wptrunner.update.base import Step, StepRunner, exit_unclean # noqa: F401 +from wptrunner.update.update import LoadConfig, SyncFromUpstream, UpdateMetadata # noqa: F401 +from wptrunner import wptcommandline # noqa: F401 + + +class LoadTrees(Step): + """Load gecko tree and sync tree containing web-platform-tests""" + + provides = ["local_tree", "sync_tree"] + + def create(self, state): + if os.path.exists(state.sync["path"]): + sync_tree = GitTree(root=state.sync["path"]) + else: + sync_tree = None + + assert GitTree.is_type() + state.update({"local_tree": GitTree(commit_cls=GeckoCommit), + "sync_tree": sync_tree}) + + +class UpdateRunner(StepRunner): + """Overall runner for updating web-platform-tests in Gecko.""" + steps = [LoadConfig, + LoadTrees, + SyncFromUpstream, + UpdateMetadata] + + +def run_update(**kwargs): + logger = setup_logging(kwargs, {"mach": sys.stdout}) + updater = WPTUpdate(logger, runner_cls=UpdateRunner, **kwargs) + return updater.run() != exit_unclean + + +def create_parser(): + parser = wptcommandline.create_parser_update() + parser.add_argument("--layout-2020", "--with-layout-2020", default=False, action="store_true", + help="Use expected results for the 2020 layout engine") + return parser + + +def check_args(kwargs): + wptcommandline.set_from_config(kwargs) + if hasattr(wptcommandline, 'check_paths'): + wptcommandline.check_paths(kwargs) + return kwargs diff --git a/tests/wpt/update/tree.py b/python/wpt/importer/tree.py index 7c00727c983..ec38e9b481e 100644 --- a/tests/wpt/update/tree.py +++ b/python/wpt/importer/tree.py @@ -9,16 +9,8 @@ import sys import tempfile from wptrunner import update as wptupdate - from wptrunner.update.tree import Commit, CommitMessage, get_unique_name -class HgTree(wptupdate.tree.HgTree): - def __init__(self, *args, **kwargs): - self.commit_cls = kwargs.pop("commit_cls", Commit) - wptupdate.tree.HgTree.__init__(self, *args, **kwargs) - - # TODO: The extra methods for upstreaming patches from a - # hg checkout class GitTree(wptupdate.tree.GitTree): def __init__(self, *args, **kwargs): @@ -117,6 +109,7 @@ class GitTree(wptupdate.tree.GitTree): if ref.startswith("refs/heads/")] return get_unique_name(branches, prefix) + class Patch(object): def __init__(self, author, email, message, merge_message, diff): self.author = author @@ -149,13 +142,13 @@ class GeckoCommitMessage(CommitMessage): # slightly different because we need to parse out specific parts of the message rather # than just enforce a general pattern. - _bug_re = re.compile("^Bug (\d+)[^\w]*(?:Part \d+[^\w]*)?(.*?)\s*(?:r=(\w*))?$", + _bug_re = re.compile(r"^Bug (\d+)[^\w]*(?:Part \d+[^\w]*)?(.*?)\s*(?:r=(\w*))?$", re.IGNORECASE) - _merge_re = re.compile("^Auto merge of #(\d+) - [^:]+:[^,]+, r=(.+)$", re.IGNORECASE) + _merge_re = re.compile(r"^Auto merge of #(\d+) - [^:]+:[^,]+, r=(.+)$", re.IGNORECASE) - _backout_re = re.compile("^(?:Back(?:ing|ed)\s+out)|Backout|(?:Revert|(?:ed|ing))", + _backout_re = re.compile(r"^(?:Back(?:ing|ed)\s+out)|Backout|(?:Revert|(?:ed|ing))", re.IGNORECASE) - _backout_sha1_re = re.compile("(?:\s|\:)(0-9a-f){12}") + _backout_sha1_re = re.compile(r"(?:\s|\:)(0-9a-f){12}") def _parse_message(self): CommitMessage._parse_message(self) @@ -188,7 +181,7 @@ class GeckoCommit(Commit): merge_rev = self.git("when-merged", *args).strip() except subprocess.CalledProcessError as exn: if not find_executable('git-when-merged'): - print('Please add the `when-merged` git command to your PATH ' + + print('Please add the `when-merged` git command to your PATH ' '(https://github.com/mhagger/git-when-merged/).') sys.exit(1) raise exn @@ -206,4 +199,3 @@ class GeckoCommit(Commit): merge_message = self.merge.message if self.merge else None return Patch(self.author, self.email, self.message, merge_message, diff) - diff --git a/tests/wpt/manifestupdate.py b/python/wpt/manifestupdate.py index 44fddda6027..05d380139db 100644 --- a/tests/wpt/manifestupdate.py +++ b/python/wpt/manifestupdate.py @@ -3,28 +3,21 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. import argparse -import imp import os import sys import tempfile from collections import defaultdict from six import iterkeys, iteritems +from . import SERVO_ROOT, WPT_PATH from mozlog.structured import commandline -from wptrunner.wptcommandline import get_test_paths, set_from_config - -manifest = None - -servo_root = os.path.join(os.path.dirname(__file__), - os.pardir, - os.pardir) +# This must happen after importing from "." since it adds WPT +# tools to the Python system path. +import manifest as wptmanifest - -def do_delayed_imports(wpt_dir): - global manifest - sys.path.insert(0, os.path.join(wpt_dir, "tools", "manifest")) - import manifest # noqa +from wptrunner.wptcommandline import get_test_paths, set_from_config +from wptrunner import wptlogging def create_parser(): @@ -38,11 +31,10 @@ def create_parser(): return p -def update(logger, wpt_dir, check_clean=True, rebuild=False): - localpaths = imp.load_source("localpaths", # noqa - os.path.join(wpt_dir, "web-platform-tests", "tools", "localpaths.py")) - kwargs = {"config": os.path.join(wpt_dir, "config.ini"), - "manifest_path": os.path.join(wpt_dir, "metadata"), +def update(check_clean=True, rebuild=False, **kwargs): + logger = wptlogging.setup(kwargs, {"mach": sys.stdout}) + kwargs = {"config": os.path.join(WPT_PATH, "config.ini"), + "manifest_path": os.path.join(WPT_PATH, "metadata"), "tests_root": None, "metadata_root": None} @@ -50,8 +42,6 @@ def update(logger, wpt_dir, check_clean=True, rebuild=False): config = kwargs["config"] test_paths = get_test_paths(config) - do_delayed_imports(wpt_dir) - if check_clean: return _check_clean(logger, test_paths) @@ -63,13 +53,13 @@ def _update(logger, test_paths, rebuild): manifest_path = os.path.join(paths["metadata_path"], "MANIFEST.json") cache_subdir = os.path.relpath(os.path.dirname(manifest_path), os.path.dirname(__file__)) - manifest.manifest.load_and_update(paths["tests_path"], - manifest_path, - url_base, - working_copy=True, - rebuild=rebuild, - cache_root=os.path.join(servo_root, ".wpt", - cache_subdir)) + wptmanifest.manifest.load_and_update(paths["tests_path"], + manifest_path, + url_base, + working_copy=True, + rebuild=rebuild, + cache_root=os.path.join(SERVO_ROOT, ".wpt", + cache_subdir)) return 0 @@ -80,26 +70,26 @@ def _check_clean(logger, test_paths): tests_path = paths["tests_path"] manifest_path = os.path.join(paths["metadata_path"], "MANIFEST.json") - old_manifest = manifest.manifest.load_and_update(tests_path, - manifest_path, - url_base, - working_copy=False, - update=False, - write_manifest=False,) + old_manifest = wptmanifest.manifest.load_and_update(tests_path, + manifest_path, + url_base, + working_copy=False, + update=False, + write_manifest=False) # Even if no cache is specified, one will be used automatically by the # VCS integration. Create a brand new cache every time to ensure that # the VCS integration always thinks that any file modifications in the # working directory are new and interesting. cache_root = tempfile.mkdtemp() - new_manifest = manifest.manifest.load_and_update(tests_path, - manifest_path, - url_base, - working_copy=True, - update=True, - cache_root=cache_root, - write_manifest=False, - allow_cached=False) + new_manifest = wptmanifest.manifest.load_and_update(tests_path, + manifest_path, + url_base, + working_copy=True, + update=True, + cache_root=cache_root, + write_manifest=False, + allow_cached=False) manifests_by_path[manifest_path] = (old_manifest, new_manifest) diff --git a/etc/ci/upstream-wpt-changes/requirements-dev.txt b/python/wpt/requirements-dev.txt index d60a3d3dad9..d60a3d3dad9 100644 --- a/etc/ci/upstream-wpt-changes/requirements-dev.txt +++ b/python/wpt/requirements-dev.txt diff --git a/etc/ci/upstream-wpt-changes/requirements.txt b/python/wpt/requirements.txt index 663bd1f6a2a..663bd1f6a2a 100644 --- a/etc/ci/upstream-wpt-changes/requirements.txt +++ b/python/wpt/requirements.txt diff --git a/tests/wpt/servowpt.py b/python/wpt/run.py index 7766d19ff88..5a75eee2c7a 100644 --- a/tests/wpt/servowpt.py +++ b/python/wpt/run.py @@ -1,10 +1,11 @@ # 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/. +# pylint: disable=missing-docstring import dataclasses -import grouping_formatter import json +import multiprocessing import os import re import sys @@ -12,22 +13,21 @@ import urllib.error import urllib.parse import urllib.request +from typing import List, NamedTuple, Optional, Union + import mozlog import mozlog.formatters -import multiprocessing -from typing import List, NamedTuple, Optional, Union -from grouping_formatter import UnexpectedResult, UnexpectedSubtestResult - -SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) -SERVO_ROOT = os.path.abspath(os.path.join(SCRIPT_PATH, "..", "..")) -WPT_TOOLS_PATH = os.path.join(SCRIPT_PATH, "web-platform-tests", "tools") -CERTS_PATH = os.path.join(WPT_TOOLS_PATH, "certs") +from . import SERVO_ROOT, WPT_PATH, WPT_TOOLS_PATH, update_args_for_layout_2020 +from .grouping_formatter import ( + ServoFormatter, ServoHandler, + UnexpectedResult, UnexpectedSubtestResult +) +from wptrunner import wptcommandline +from wptrunner import wptrunner -sys.path.insert(0, WPT_TOOLS_PATH) -import localpaths # noqa: F401,E402 -import update # noqa: F401,E402 +CERTS_PATH = os.path.join(WPT_TOOLS_PATH, "certs") TRACKER_API = "https://build.servo.org/intermittent-tracker" TRACKER_API_ENV_VAR = "INTERMITTENT_TRACKER_API" TRACKER_DASHBOARD_SECRET_ENV_VAR = "INTERMITTENT_TRACKER_DASHBOARD_SECRET" @@ -50,23 +50,7 @@ def set_if_none(args: dict, key: str, value): args[key] = value -def update_args_for_layout_2020(kwargs: dict): - if kwargs.pop("layout_2020"): - kwargs["test_paths"]["/"]["metadata_path"] = os.path.join( - SCRIPT_PATH, "metadata-layout-2020" - ) - kwargs["test_paths"]["/_mozilla/"]["metadata_path"] = os.path.join( - SCRIPT_PATH, "mozilla", "meta-layout-2020" - ) - kwargs["include_manifest"] = os.path.join( - SCRIPT_PATH, "include-layout-2020.ini" - ) - - def run_tests(**kwargs): - from wptrunner import wptrunner - from wptrunner import wptcommandline - # By default, Rayon selects the number of worker threads based on the # available CPU count. This doesn't work very well when running tests on CI, # since we run so many Servo processes in parallel. The result is a lot of @@ -77,8 +61,8 @@ def run_tests(**kwargs): os.environ["HOST_FILE"] = os.path.join(SERVO_ROOT, "tests", "wpt", "hosts") set_if_none(kwargs, "product", "servo") - set_if_none(kwargs, "config", os.path.join(SCRIPT_PATH, "config.ini")) - set_if_none(kwargs, "include_manifest", os.path.join(SCRIPT_PATH, "include.ini")) + set_if_none(kwargs, "config", os.path.join(WPT_PATH, "config.ini")) + set_if_none(kwargs, "include_manifest", os.path.join(WPT_PATH, "include.ini")) set_if_none(kwargs, "manifest_update", False) set_if_none(kwargs, "processes", multiprocessing.cpu_count()) @@ -131,7 +115,7 @@ def run_tests(**kwargs): update_args_for_layout_2020(kwargs) mozlog.commandline.log_formatters["servo"] = ( - grouping_formatter.ServoFormatter, + ServoFormatter, "Servo's grouping output formatter", ) @@ -146,7 +130,7 @@ def run_tests(**kwargs): else: logger = wptrunner.setup_logging(kwargs, {"servo": sys.stdout}) - handler = grouping_formatter.ServoHandler() + handler = ServoHandler() logger.add_handler(handler) wptrunner.run_tests(**kwargs) @@ -200,21 +184,6 @@ def run_tests(**kwargs): return return_value -def update_tests(**kwargs): - from update import updatecommandline - - set_if_none(kwargs, "product", "servo") - set_if_none(kwargs, "config", os.path.join(SCRIPT_PATH, "config.ini")) - kwargs["store_state"] = False - - updatecommandline.check_args(kwargs) - update_args_for_layout_2020(kwargs) - - logger = update.setup_logging(kwargs, {"mach": sys.stdout}) - return_value = update.run_update(logger, **kwargs) - return 1 if return_value is update.exit_unclean else 0 - - class GithubContextInformation(NamedTuple): build_url: Optional[str] pull_url: Optional[str] @@ -317,7 +286,7 @@ def filter_intermittents( dashboard = TrackerDashboardFilter() dashboard.report_failures(unexpected_results) - def add_result(output, text, results, filter_func) -> None: + def add_result(output, text, results: List[UnexpectedResult], filter_func) -> None: filtered = [str(result) for result in filter(filter_func, results)] if filtered: output += [f"{text} ({len(results)}): ", *filtered] @@ -325,7 +294,7 @@ def filter_intermittents( def is_stable_and_unexpected(result): return not result.flaky and not result.issues - output = [] + output: List[str] = [] add_result(output, "Flaky unexpected results", unexpected_results, lambda result: result.flaky) add_result(output, "Stable unexpected results that are known-intermittent", @@ -355,15 +324,3 @@ def write_unexpected_only_raw_log( if data["action"] in ["suite_start", "suite_end"] or \ ("test" in data and data["test"] in tests): output.write(line) - - -def main(): - from wptrunner import wptcommandline - - parser = wptcommandline.create_parser() - kwargs = vars(parser.parse_args()) - return run_tests(**kwargs) - - -if __name__ == "__main__": - sys.exit(0 if main() else 1) diff --git a/etc/ci/upstream-wpt-changes/test.py b/python/wpt/test.py index 3ecf3afbb3c..4b8f0663676 100644 --- a/etc/ci/upstream-wpt-changes/test.py +++ b/python/wpt/test.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # Copyright 2023 The Servo Project Developers. See the COPYRIGHT # file at the top-level directory of this distribution. # @@ -37,8 +39,8 @@ from wsgiref.simple_server import WSGIRequestHandler, make_server import flask import flask.cli import requests -from wptupstreamer import SyncRun, WPTSync -from wptupstreamer.step import CreateOrUpdateBranchForPRStep +from exporter import SyncRun, WPTSync +from exporter.step import CreateOrUpdateBranchForPRStep TESTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tests") SYNC: Optional[WPTSync] = None diff --git a/etc/ci/upstream-wpt-changes/tests/18746.diff b/python/wpt/tests/18746.diff index ad6150c1bdb..ad6150c1bdb 100644 --- a/etc/ci/upstream-wpt-changes/tests/18746.diff +++ b/python/wpt/tests/18746.diff diff --git a/etc/ci/upstream-wpt-changes/tests/add-non-utf8-file.diff b/python/wpt/tests/add-non-utf8-file.diff index bd3b755d87d..bd3b755d87d 100644 --- a/etc/ci/upstream-wpt-changes/tests/add-non-utf8-file.diff +++ b/python/wpt/tests/add-non-utf8-file.diff diff --git a/etc/ci/upstream-wpt-changes/tests/closed.json b/python/wpt/tests/closed.json index e81ff80eb2d..e81ff80eb2d 100644 --- a/etc/ci/upstream-wpt-changes/tests/closed.json +++ b/python/wpt/tests/closed.json diff --git a/etc/ci/upstream-wpt-changes/tests/does-not-apply-cleanly.diff b/python/wpt/tests/does-not-apply-cleanly.diff index aa49c3bafbe..aa49c3bafbe 100644 --- a/etc/ci/upstream-wpt-changes/tests/does-not-apply-cleanly.diff +++ b/python/wpt/tests/does-not-apply-cleanly.diff diff --git a/etc/ci/upstream-wpt-changes/tests/edited.json b/python/wpt/tests/edited.json index 4af10d6e5b9..4af10d6e5b9 100644 --- a/etc/ci/upstream-wpt-changes/tests/edited.json +++ b/python/wpt/tests/edited.json diff --git a/etc/ci/upstream-wpt-changes/tests/merged.json b/python/wpt/tests/merged.json index 4fe373ad7b3..4fe373ad7b3 100644 --- a/etc/ci/upstream-wpt-changes/tests/merged.json +++ b/python/wpt/tests/merged.json diff --git a/etc/ci/upstream-wpt-changes/tests/move-into-wpt.diff b/python/wpt/tests/move-into-wpt.diff index 02c437cdd7b..02c437cdd7b 100644 --- a/etc/ci/upstream-wpt-changes/tests/move-into-wpt.diff +++ b/python/wpt/tests/move-into-wpt.diff diff --git a/etc/ci/upstream-wpt-changes/tests/move-out-of-wpt.diff b/python/wpt/tests/move-out-of-wpt.diff index f81541363ec..f81541363ec 100644 --- a/etc/ci/upstream-wpt-changes/tests/move-out-of-wpt.diff +++ b/python/wpt/tests/move-out-of-wpt.diff diff --git a/etc/ci/upstream-wpt-changes/tests/non-wpt.diff b/python/wpt/tests/non-wpt.diff index 0e3862805e4..0e3862805e4 100644 --- a/etc/ci/upstream-wpt-changes/tests/non-wpt.diff +++ b/python/wpt/tests/non-wpt.diff diff --git a/etc/ci/upstream-wpt-changes/tests/opened-with-no-sync-signal.json b/python/wpt/tests/opened-with-no-sync-signal.json index 1a1671632a4..1a1671632a4 100644 --- a/etc/ci/upstream-wpt-changes/tests/opened-with-no-sync-signal.json +++ b/python/wpt/tests/opened-with-no-sync-signal.json diff --git a/etc/ci/upstream-wpt-changes/tests/opened.json b/python/wpt/tests/opened.json index 97a02be58b5..97a02be58b5 100644 --- a/etc/ci/upstream-wpt-changes/tests/opened.json +++ b/python/wpt/tests/opened.json diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/README.md b/python/wpt/tests/servo-mock/README.md index c2e23e99864..c2e23e99864 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/README.md +++ b/python/wpt/tests/servo-mock/README.md diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html b/python/wpt/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html index 542e2924b96..542e2924b96 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html +++ b/python/wpt/tests/servo-mock/tests/wpt/mozilla/tests/mozilla/mozilla-test.html diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/something.py b/python/wpt/tests/servo-mock/tests/wpt/something.py index 0f9ba39707a..0f9ba39707a 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/something.py +++ b/python/wpt/tests/servo-mock/tests/wpt/something.py diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html index cffb6eb6b5a..cffb6eb6b5a 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html +++ b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/css-test.html diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html index cffb6eb6b5a..cffb6eb6b5a 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html +++ b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/css/out-of-sync-test.html diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html index 48a68cd53ce..48a68cd53ce 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html +++ b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/fetch/api/redirect/redirect-location.html diff --git a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/test.html b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/test.html index 43b09d4e57d..43b09d4e57d 100644 --- a/etc/ci/upstream-wpt-changes/tests/servo-mock/tests/wpt/web-platform-tests/test.html +++ b/python/wpt/tests/servo-mock/tests/wpt/web-platform-tests/test.html diff --git a/etc/ci/upstream-wpt-changes/tests/synchronize-multiple.json b/python/wpt/tests/synchronize-multiple.json index 239d8d00e5a..239d8d00e5a 100644 --- a/etc/ci/upstream-wpt-changes/tests/synchronize-multiple.json +++ b/python/wpt/tests/synchronize-multiple.json diff --git a/etc/ci/upstream-wpt-changes/tests/synchronize.json b/python/wpt/tests/synchronize.json index cbb0d8966b8..cbb0d8966b8 100644 --- a/etc/ci/upstream-wpt-changes/tests/synchronize.json +++ b/python/wpt/tests/synchronize.json diff --git a/etc/ci/upstream-wpt-changes/tests/wpt-mock/css/css-test.html b/python/wpt/tests/wpt-mock/css/css-test.html index cffb6eb6b5a..cffb6eb6b5a 100644 --- a/etc/ci/upstream-wpt-changes/tests/wpt-mock/css/css-test.html +++ b/python/wpt/tests/wpt-mock/css/css-test.html diff --git a/etc/ci/upstream-wpt-changes/tests/wpt-mock/fetch/api/redirect/redirect-location.html b/python/wpt/tests/wpt-mock/fetch/api/redirect/redirect-location.html index 48a68cd53ce..48a68cd53ce 100644 --- a/etc/ci/upstream-wpt-changes/tests/wpt-mock/fetch/api/redirect/redirect-location.html +++ b/python/wpt/tests/wpt-mock/fetch/api/redirect/redirect-location.html diff --git a/etc/ci/upstream-wpt-changes/tests/wpt-mock/test.html b/python/wpt/tests/wpt-mock/test.html index 43b09d4e57d..43b09d4e57d 100644 --- a/etc/ci/upstream-wpt-changes/tests/wpt-mock/test.html +++ b/python/wpt/tests/wpt-mock/test.html diff --git a/etc/ci/upstream-wpt-changes/tests/wpt.diff b/python/wpt/tests/wpt.diff index 37781cf488e..37781cf488e 100644 --- a/etc/ci/upstream-wpt-changes/tests/wpt.diff +++ b/python/wpt/tests/wpt.diff diff --git a/python/wpt/update.py b/python/wpt/update.py new file mode 100644 index 00000000000..377ba06e3ce --- /dev/null +++ b/python/wpt/update.py @@ -0,0 +1,29 @@ +# 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/. +# pylint: disable=missing-docstring + +import os + +from . import WPT_PATH, update_args_for_layout_2020 +from . import importer + + +def set_if_none(args: dict, key: str, value): + if key not in args or args[key] is None: + args[key] = value + + +def update_tests(**kwargs): + set_if_none(kwargs, "product", "servo") + set_if_none(kwargs, "config", os.path.join(WPT_PATH, "config.ini")) + kwargs["store_state"] = False + + importer.check_args(kwargs) + update_args_for_layout_2020(kwargs) + + return 1 if not importer.run_update(**kwargs) else 0 + + +def create_parser(**kwargs): + return importer.create_parser() diff --git a/servo-tidy.toml b/servo-tidy.toml index 762eb169145..19dbd3e2c42 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -136,11 +136,9 @@ directories = [ "./support/magicleap/Servo2D/code/src.gen", "./support/magicleap/Servo2D/pipeline", "./tests/wpt/harness", - "./tests/wpt/update", "./tests/wpt/web-platform-tests", "./tests/wpt/mozilla/tests/mozilla/referrer-policy", "./tests/wpt/mozilla/tests/webgl", - "./tests/wpt/sync", "./python/tidy/servo_tidy_tests", "./components/script/dom/bindings/codegen/parser", "./components/script/dom/bindings/codegen/ply", diff --git a/tests/wpt/README.md b/tests/wpt/README.md index 7966faacb0e..102b9edb34e 100644 --- a/tests/wpt/README.md +++ b/tests/wpt/README.md @@ -9,7 +9,6 @@ In particular, this folder contains: * `config.ini`: some configuration for the web-platform-tests. * `include.ini`: the subset of web-platform-tests we currently run. -* `servowpt.py`: run the web-platform-tests in Servo. * `web-platform-tests`: copy of the web-platform-tests. * `metadata`: expected failures for the web-platform-tests we run. * `mozilla`: web-platform-tests that cannot be upstreamed. @@ -78,12 +77,6 @@ testharnessreport.js may have been installed incorrectly (see [**Running the tests manually**](#running-the-tests-manually) for more details). -Running the tests without mach ------------------------------- - -When avoiding `mach` for some reason, one can run `servowpt.py` -directly. However, this requires that all the dependencies for -`wptrunner` are available in the current python environment. Running the tests manually -------------------------- diff --git a/tests/wpt/update/__init__.py b/tests/wpt/update/__init__.py deleted file mode 100644 index 9390d237630..00000000000 --- a/tests/wpt/update/__init__.py +++ /dev/null @@ -1,41 +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/. - -#!/usr/bin/env python -import os -import subprocess -import sys - -from mozlog.structured import structuredlog - -here = os.path.split(__file__)[0] - -sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "web-platform-tests", "tools", "wptrunner"))) -sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "web-platform-tests", "tools", "wptserve"))) -sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "web-platform-tests", "tools"))) - -import localpaths - -from wptrunner.update import setup_logging, WPTUpdate -from wptrunner.update.base import exit_unclean - -from . import updatecommandline -from .update import UpdateRunner - -def run_update(logger, **kwargs): - updater = WPTUpdate(logger, runner_cls=UpdateRunner, **kwargs) - return updater.run() - - -if __name__ == "__main__": - args = updatecommandline.parse_args() - logger = setup_logging(args, {"mach": sys.stdout}) - assert structuredlog.get_default_logger() is not None - - - rv = run_update(logger, **args) - if rv is exit_unclean: - sys.exit(1) - else: - sys.exit(0) diff --git a/tests/wpt/update/github.py b/tests/wpt/update/github.py deleted file mode 100644 index 8df7e2fcee1..00000000000 --- a/tests/wpt/update/github.py +++ /dev/null @@ -1,179 +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/. - -from __future__ import print_function - -import json -import urllib - -requests = None - -class GitHubError(Exception): - def __init__(self, status, data): - self.status = status - self.data = data - - -class GitHub(object): - url_base = "https://api.github.com" - - def __init__(self, token): - # Defer the import of requests since it isn't installed by default - global requests - if requests is None: - import requests - - self.headers = {"Accept": "application/vnd.github.v3+json"} - self.auth = (token, "x-oauth-basic") - - def get(self, path): - return self._request("GET", path) - - def post(self, path, data): - return self._request("POST", path, data=data) - - def put(self, path, data): - return self._request("PUT", path, data=data) - - def _request(self, method, path, data=None): - url = urllib.parse.urljoin(self.url_base, path) - - kwargs = {"headers": self.headers, - "auth": self.auth} - if data is not None: - kwargs["data"] = json.dumps(data) - - resp = requests.request(method, url, **kwargs) - - if 200 <= resp.status_code < 300: - return resp.json() - else: - print(resp.status_code, resp.json()) - raise GitHubError(resp.status_code, resp.json()) - - def repo(self, owner, name): - """GitHubRepo for a particular repository. - - :param owner: String repository owner - :param name: String repository name - """ - return GitHubRepo.from_name(self, owner, name) - - -class GitHubRepo(object): - def __init__(self, github, data): - """Object respresenting a GitHub respoitory""" - self.gh = github - self.owner = data["owner"] - self.name = data["name"] - self.url = data["ssh_url"] - self._data = data - - @classmethod - def from_name(cls, github, owner, name): - data = github.get("/repos/%s/%s" % (owner, name)) - return cls(github, data) - - @property - def url_base(self): - return "/repos/%s/" % (self._data["full_name"]) - - def create_pr(self, title, head, base, body): - """Create a Pull Request in the repository - - :param title: Pull Request title - :param head: ref to the HEAD of the PR branch. - :param base: ref to the base branch for the Pull Request - :param body: Description of the PR - """ - return PullRequest.create(self, title, head, base, body) - - def load_pr(self, number): - """Load an existing Pull Request by number. - - :param number: Pull Request number - """ - return PullRequest.from_number(self, number) - - def path(self, suffix): - return urllib.parse.urljoin(self.url_base, suffix) - - -class PullRequest(object): - def __init__(self, repo, data): - """Object representing a Pull Request""" - - self.repo = repo - self._data = data - self.number = data["number"] - self.title = data["title"] - self.base = data["base"]["ref"] - self.base = data["head"]["ref"] - self._issue = None - - @classmethod - def from_number(cls, repo, number): - data = repo.gh.get(repo.path("pulls/%i" % number)) - return cls(repo, data) - - @classmethod - def create(cls, repo, title, head, base, body): - data = repo.gh.post(repo.path("pulls"), - {"title": title, - "head": head, - "base": base, - "body": body}) - return cls(repo, data) - - def path(self, suffix): - return urllib.parse.urljoin(self.repo.path("pulls/%i/" % self.number), suffix) - - @property - def issue(self): - """Issue related to the Pull Request""" - if self._issue is None: - self._issue = Issue.from_number(self.repo, self.number) - return self._issue - - def merge(self, commit_message=None): - """Merge the Pull Request into its base branch. - - :param commit_message: Message to use for the merge commit. If None a default - message is used instead - """ - if commit_message is None: - commit_message = "Merge pull request #%i from %s" % (self.number, self.base) - self.repo.gh.put(self.path("merge"), - {"commit_message": commit_message}) - - -class Issue(object): - def __init__(self, repo, data): - """Object representing a GitHub Issue""" - self.repo = repo - self._data = data - self.number = data["number"] - - @classmethod - def from_number(cls, repo, number): - data = repo.gh.get(repo.path("issues/%i" % number)) - return cls(repo, data) - - def path(self, suffix): - return urllib.parse.urljoin(self.repo.path("issues/%i/" % self.number), suffix) - - def add_label(self, label): - """Add a label to the issue. - - :param label: The name of the label - """ - self.repo.gh.post(self.path("labels"), [label]) - - def add_comment(self, message): - """Add a comment to the issue - - :param message: The text of the comment - """ - self.repo.gh.post(self.path("comments"), - {"body": message}) diff --git a/tests/wpt/update/update.py b/tests/wpt/update/update.py deleted file mode 100644 index ed16b0cf183..00000000000 --- a/tests/wpt/update/update.py +++ /dev/null @@ -1,42 +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 os - -from wptrunner.update.base import Step, StepRunner -from wptrunner.update.update import LoadConfig, SyncFromUpstream, UpdateMetadata -from wptrunner.update.tree import NoVCSTree - -from .tree import GitTree, HgTree, GeckoCommit -from .upstream import SyncToUpstream - -class LoadTrees(Step): - """Load gecko tree and sync tree containing web-platform-tests""" - - provides = ["local_tree", "sync_tree"] - - def create(self, state): - if os.path.exists(state.sync["path"]): - sync_tree = GitTree(root=state.sync["path"]) - else: - sync_tree = None - - if GitTree.is_type(): - local_tree = GitTree(commit_cls=GeckoCommit) - elif HgTree.is_type(): - local_tree = HgTree(commit_cls=GeckoCommit) - else: - local_tree = NoVCSTree() - - state.update({"local_tree": local_tree, - "sync_tree": sync_tree}) - - -class UpdateRunner(StepRunner): - """Overall runner for updating web-platform-tests in Gecko.""" - steps = [LoadConfig, - LoadTrees, - SyncToUpstream, - SyncFromUpstream, - UpdateMetadata] diff --git a/tests/wpt/update/updatecommandline.py b/tests/wpt/update/updatecommandline.py deleted file mode 100644 index deca822e2b9..00000000000 --- a/tests/wpt/update/updatecommandline.py +++ /dev/null @@ -1,44 +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/. - -def create_parser(): - from wptrunner import wptcommandline - - parser = wptcommandline.create_parser_update() - parser.add_argument("--upstream", dest="upstream", action="store_true", default=None, - help="Push local changes to upstream repository even when not syncing") - parser.add_argument("--no-upstream", dest="upstream", action="store_false", default=None, - help="Dont't push local changes to upstream repository when syncing") - parser.add_argument("--token-file", action="store", type=wptcommandline.abs_path, - help="Path to file containing github token") - parser.add_argument("--token", action="store", help="GitHub token to use") - parser.add_argument("--layout-2020", "--with-layout-2020", default=False, action="store_true", - help="Use expected results for the 2020 layout engine") - return parser - - -def check_args(kwargs): - from wptrunner import wptcommandline - - wptcommandline.set_from_config(kwargs) - if hasattr(wptcommandline, 'check_paths'): - wptcommandline.check_paths(kwargs) - kwargs["upstream"] = kwargs["upstream"] if kwargs["upstream"] is not None else kwargs["sync"] - - if kwargs["upstream"]: - if kwargs["rev"]: - raise ValueError("Setting --rev with --upstream isn't supported") - if kwargs["token"] is None: - if kwargs["token_file"] is None: - raise ValueError("Must supply either a token file or a token") - with open(kwargs["token_file"]) as f: - token = f.read().strip() - kwargs["token"] = token - del kwargs["token_file"] - return kwargs - -def parse_args(): - parser = create_parser() - kwargs = vars(parser.parse_args()) - return check_args(kwargs) diff --git a/tests/wpt/update/upstream.py b/tests/wpt/update/upstream.py deleted file mode 100644 index 440d3446c6c..00000000000 --- a/tests/wpt/update/upstream.py +++ /dev/null @@ -1,389 +0,0 @@ -from __future__ import print_function - -import os -import re -import subprocess -import sys -import urllib -from six.moves import input -from six import iteritems - -from wptrunner.update.sync import UpdateCheckout -from wptrunner.update.tree import get_unique_name -from wptrunner.update.base import Step, StepRunner, exit_clean, exit_unclean - -from .tree import Commit, GitTree, Patch -from .github import GitHub - - -def rewrite_patch(patch, strip_dir): - """Take a Patch and rewrite the message to remove the bug number and reviewer, but add - a bugzilla link in the summary. - - :param patch: the Patch to convert - """ - - return Patch(patch.author, patch.email, rewrite_message(patch), None, patch.diff) - -def rewrite_message(patch): - if patch.merge_message and patch.merge_message.bug: - bug = patch.merge_message.bug - else: - bug = patch.message.bug - if bug is not None: - return "\n".join([patch.message.summary, - patch.message.body, - "", - "Upstreamed from https://github.com/servo/servo/pull/%s [ci skip]" % - bug]) - - return "\n".join([patch.message.full_summary, "%s\n[ci skip]\n" % patch.message.body]) - - -class SyncToUpstream(Step): - """Sync local changes to upstream""" - - def create(self, state): - if not state.kwargs["upstream"]: - return - - if not isinstance(state.local_tree, GitTree): - self.logger.error("Cannot sync with upstream from a non-Git checkout.") - return exit_clean - - try: - import requests - except ImportError: - self.logger.error("Upstream sync requires the requests module to be installed") - return exit_clean - - if not state.sync_tree: - os.makedirs(state.sync["path"]) - state.sync_tree = GitTree(root=state.sync["path"]) - - kwargs = state.kwargs - with state.push(["local_tree", "sync_tree", "tests_path", "metadata_path", - "sync"]): - state.token = kwargs["token"] - runner = SyncToUpstreamRunner(self.logger, state) - runner.run() - -class GetLastSyncData(Step): - """Find the gecko commit at which we last performed a sync with upstream and the upstream - commit that was synced.""" - - provides = ["sync_data_path", "last_sync_commit", "old_upstream_rev"] - - def create(self, state): - self.logger.info("Looking for last sync commit") - state.sync_data_path = os.path.join(state.metadata_path, "mozilla-sync") - items = {} - with open(state.sync_data_path) as f: - for line in f.readlines(): - key, value = [item.strip() for item in line.split(":", 1)] - items[key] = value - - state.last_sync_commit = Commit(state.local_tree, items["local"]) - state.old_upstream_rev = items["upstream"] - - if not state.local_tree.contains_commit(state.last_sync_commit): - self.logger.error("Could not find last sync commit %s" % last_sync_sha1) - return exit_clean - - self.logger.info("Last sync to web-platform-tests happened in %s" % state.last_sync_commit.sha1) - - -class CheckoutBranch(Step): - """Create a branch in the sync tree pointing at the last upstream sync commit - and check it out""" - - provides = ["branch"] - - def create(self, state): - self.logger.info("Updating sync tree from %s" % state.sync["remote_url"]) - state.branch = state.sync_tree.unique_branch_name( - "outbound_update_%s" % state.old_upstream_rev) - state.sync_tree.update(state.sync["remote_url"], - state.sync["branch"], - state.branch) - state.sync_tree.checkout(state.old_upstream_rev, state.branch, force=True) - - -class GetBaseCommit(Step): - """Find the latest upstream commit on the branch that we are syncing with""" - - provides = ["base_commit"] - - def create(self, state): - state.base_commit = state.sync_tree.get_remote_sha1(state.sync["remote_url"], - state.sync["branch"]) - self.logger.debug("New base commit is %s" % state.base_commit.sha1) - - -class LoadCommits(Step): - """Get a list of commits in the gecko tree that need to be upstreamed""" - - provides = ["source_commits"] - - def create(self, state): - state.source_commits = state.local_tree.log(state.last_sync_commit, - state.tests_path) - - update_regexp = re.compile("Update web-platform-tests to revision [0-9a-f]{40}") - - for i, commit in enumerate(state.source_commits[:]): - if update_regexp.match(commit.message.text): - # This is a previous update commit so ignore it - state.source_commits.remove(commit) - continue - - if commit.message.backouts: - #TODO: Add support for collapsing backouts - raise NotImplementedError("Need to get the Git->Hg commits for backouts and remove the backed out patch") - - if not commit.message.bug and not (commit.merge and commit.merge.message.bug): - self.logger.error("Commit %i (%s) doesn't have an associated bug number." % - (i + 1, commit.sha1)) - return exit_unclean - - self.logger.debug("Source commits: %s" % state.source_commits) - -class SelectCommits(Step): - """Provide a UI to select which commits to upstream""" - - def create(self, state): - if not state.source_commits: - return - - while True: - commits = state.source_commits[:] - for i, commit in enumerate(commits): - print("%i:\t%s" % (i, commit.message.summary)) - - remove = input("Provide a space-separated list of any commits numbers to remove from the list to upstream:\n").strip() - remove_idx = set() - invalid = False - for item in remove.split(" "): - if not item: - continue - try: - item = int(item) - except: - invalid = True - break - if item < 0 or item >= len(commits): - invalid = True - break - remove_idx.add(item) - - if invalid: - continue - - keep_commits = [(i,cmt) for i,cmt in enumerate(commits) if i not in remove_idx] - #TODO: consider printed removed commits - print("Selected the following commits to keep:") - for i, commit in keep_commits: - print("%i:\t%s" % (i, commit.message.summary)) - confirm = input("Keep the above commits? y/n\n").strip().lower() - - if confirm == "y": - state.source_commits = [item[1] for item in keep_commits] - break - -class MovePatches(Step): - """Convert gecko commits into patches against upstream and commit these to the sync tree.""" - - provides = ["commits_loaded"] - - def create(self, state): - state.commits_loaded = 0 - - strip_path = os.path.relpath(state.tests_path, - state.local_tree.root) - self.logger.debug("Stripping patch %s" % strip_path) - - for commit in state.source_commits[state.commits_loaded:]: - i = state.commits_loaded + 1 - self.logger.info("Moving commit %i: %s" % (i, commit.message.full_summary)) - patch = commit.export_patch(state.tests_path) - stripped_patch = rewrite_patch(patch, strip_path) - strip_count = strip_path.count('/') - if strip_path[-1] != '/': - strip_count += 1 - try: - state.sync_tree.import_patch(stripped_patch, 1 + strip_count) - except: - print(patch.diff) - raise - state.commits_loaded = i - -class RebaseCommits(Step): - """Rebase commits from the current branch on top of the upstream destination branch. - - This step is particularly likely to fail if the rebase generates merge conflicts. - In that case the conflicts can be fixed up locally and the sync process restarted - with --continue. - """ - - provides = ["rebased_commits"] - - def create(self, state): - self.logger.info("Rebasing local commits") - continue_rebase = False - # Check if there's a rebase in progress - if (os.path.exists(os.path.join(state.sync_tree.root, - ".git", - "rebase-merge")) or - os.path.exists(os.path.join(state.sync_tree.root, - ".git", - "rebase-apply"))): - continue_rebase = True - - try: - state.sync_tree.rebase(state.base_commit, continue_rebase=continue_rebase) - except subprocess.CalledProcessError: - self.logger.info("Rebase failed, fix merge and run %s again with --continue" % sys.argv[0]) - raise - state.rebased_commits = state.sync_tree.log(state.base_commit) - self.logger.info("Rebase successful") - -class CheckRebase(Step): - """Check if there are any commits remaining after rebase""" - - def create(self, state): - if not state.rebased_commits: - self.logger.info("Nothing to upstream, exiting") - return exit_clean - -class MergeUpstream(Step): - """Run steps to push local commits as seperate PRs and merge upstream.""" - - provides = ["merge_index", "gh_repo"] - - def create(self, state): - gh = GitHub(state.token) - if "merge_index" not in state: - state.merge_index = 0 - - org, name = urllib.parse.urlsplit(state.sync["remote_url"]).path[1:].split("/") - if name.endswith(".git"): - name = name[:-4] - state.gh_repo = gh.repo(org, name) - for commit in state.rebased_commits[state.merge_index:]: - with state.push(["gh_repo", "sync_tree"]): - state.commit = commit - pr_merger = PRMergeRunner(self.logger, state) - rv = pr_merger.run() - if rv is not None: - return rv - state.merge_index += 1 - -class UpdateLastSyncData(Step): - """Update the gecko commit at which we last performed a sync with upstream.""" - - provides = [] - - def create(self, state): - self.logger.info("Updating last sync commit") - data = {"local": state.local_tree.rev, - "upstream": state.sync_tree.rev} - with open(state.sync_data_path, "w") as f: - for key, value in iteritems(data): - f.write("%s: %s\n" % (key, value)) - # This gets added to the patch later on - -class MergeLocalBranch(Step): - """Create a local branch pointing at the commit to upstream""" - - provides = ["local_branch"] - - def create(self, state): - branch_prefix = "sync_%s" % state.commit.sha1 - local_branch = state.sync_tree.unique_branch_name(branch_prefix) - - state.sync_tree.create_branch(local_branch, state.commit) - state.local_branch = local_branch - -class MergeRemoteBranch(Step): - """Get an unused remote branch name to use for the PR""" - provides = ["remote_branch"] - - def create(self, state): - remote_branch = "sync_%s" % state.commit.sha1 - branches = [ref[len("refs/heads/"):] for sha1, ref in - state.sync_tree.list_remote(state.gh_repo.url) - if ref.startswith("refs/heads")] - state.remote_branch = get_unique_name(branches, remote_branch) - - -class PushUpstream(Step): - """Push local branch to remote""" - def create(self, state): - self.logger.info("Pushing commit upstream") - state.sync_tree.push(state.gh_repo.url, - state.local_branch, - state.remote_branch) - -class CreatePR(Step): - """Create a PR for the remote branch""" - - provides = ["pr"] - - def create(self, state): - self.logger.info("Creating a PR") - commit = state.commit - state.pr = state.gh_repo.create_pr(commit.message.full_summary, - state.remote_branch, - "master", - commit.message.body if commit.message.body else "") - - -class PRAddComment(Step): - """Add an issue comment indicating that the code has been reviewed already""" - def create(self, state): - state.pr.issue.add_comment("Code reviewed upstream.") - state.pr.issue.add_label("servo-export") - - -class MergePR(Step): - """Merge the PR""" - - def create(self, state): - self.logger.info("Merging PR") - state.pr.merge() - - -class PRDeleteBranch(Step): - """Delete the remote branch""" - - def create(self, state): - self.logger.info("Deleting remote branch") - state.sync_tree.push(state.gh_repo.url, "", state.remote_branch) - - -class SyncToUpstreamRunner(StepRunner): - """Runner for syncing local changes to upstream""" - steps = [GetLastSyncData, - UpdateCheckout, - CheckoutBranch, - GetBaseCommit, - LoadCommits, - SelectCommits, - MovePatches, - RebaseCommits, - CheckRebase, - MergeUpstream, - UpdateLastSyncData] - - -class PRMergeRunner(StepRunner): - """(Sub)Runner for creating and merging a PR""" - steps = [ - MergeLocalBranch, - MergeRemoteBranch, - PushUpstream, - CreatePR, - PRAddComment, - MergePR, - PRDeleteBranch, - ] |