Bug 1645838 [wpt PR 24151] - Switch WPT to use Taskcluster Checks integration, a=testonly
authorStephen McGruer <smcgruer@chromium.org>
Thu, 09 Jul 2020 14:15:51 +0000
changeset 539811 939665c53acbd87f85ddf8c994f7bc46107112cf
parent 539810 4edbc1e8e64676dedc7d3e94f5ef280a873e66a0
child 539812 71a9ba84db010f432706c649b7c6495760e1c5d7
push id37586
push userccoroiu@mozilla.com
push dateFri, 10 Jul 2020 16:06:24 +0000
treeherdermozilla-central@4e9d6619c9d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1645838, 24151, 14846
milestone80.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1645838 [wpt PR 24151] - Switch WPT to use Taskcluster Checks integration, a=testonly Automatic update from web-platform-tests Switch WPT to use Taskcluster Checks integration (#24151) See https://github.com/web-platform-tests/wpt/issues/14846; this should only be landed once wpt.fyi is ready to receive check_suite events. Co-authored-by: Robert Ma <robertma@chromium.org> -- wpt-commits: 972cc74af2d621fb45e5097350f4ee7d3b7c6ef4 wpt-pr: 24151
testing/web-platform/tests/.taskcluster.yml
testing/web-platform/tests/tools/ci/commands.json
testing/web-platform/tests/tools/ci/tc/decision.py
testing/web-platform/tests/tools/ci/tc/sink_task.py
testing/web-platform/tests/tools/ci/tc/tasks/test.yml
testing/web-platform/tests/tools/ci/tc/tests/test_valid.py
--- a/testing/web-platform/tests/.taskcluster.yml
+++ b/testing/web-platform/tests/.taskcluster.yml
@@ -1,9 +1,10 @@
 version: 1
+reporting: checks-v1
 policy:
   pullRequests: public
 tasks:
   $let:
     run_task:
       $if: 'tasks_for == "github-push"'
       then:
         $if: 'event.ref in ["refs/heads/master", "refs/heads/epochs/daily", "refs/heads/epochs/weekly", "refs/heads/triggers/chrome_stable", "refs/heads/triggers/chrome_beta", "refs/heads/triggers/chrome_dev", "refs/heads/triggers/firefox_stable", "refs/heads/triggers/firefox_beta", "refs/heads/triggers/firefox_nightly", "refs/heads/triggers/webkitgtk_minibrowser_stable", "refs/heads/triggers/webkitgtk_minibrowser_nightly", "refs/heads/triggers/servo_nightly"]'
--- a/testing/web-platform/tests/tools/ci/commands.json
+++ b/testing/web-platform/tests/tools/ci/commands.json
@@ -41,10 +41,20 @@
     "script": "run",
     "help": "Run the decision task",
     "virtualenv": true,
     "install": [
         "requests",
         "pyyaml",
         "taskcluster"
     ]
+  },
+  "tc-sink-task": {
+    "path": "tc/sink_task.py",
+    "parser": "get_parser",
+    "script": "run",
+    "help": "Run the sink task",
+    "virtualenv": true,
+    "install": [
+        "taskcluster"
+    ]
   }
 }
--- a/testing/web-platform/tests/tools/ci/tc/decision.py
+++ b/testing/web-platform/tests/tools/ci/tc/decision.py
@@ -234,23 +234,24 @@ def create_tc_task(event, task, taskgrou
             "artifacts": task.get("artifacts"),
             "command": command,
             "image": task.get("image"),
             "maxRunTime": task.get("maxRunTime"),
             "env": task.get("env", {}),
         },
         "extra": {
             "github_event": json.dumps(event)
-        }
+        },
+        "routes": ["checks"]
     }
     if env_extra:
         task_data["payload"]["env"].update(env_extra)
     if depends_on_ids:
         task_data["dependencies"] = depends_on_ids
-        task_data["requires"] = "all-completed"
+        task_data["requires"] = task.get("requires", "all-completed")
     return task_id, task_data
 
 
 def get_artifact_data(artifact, task_id_map):
     task_id, data = task_id_map[artifact["task"]]
     return {
         "task": task_id,
         "glob": artifact["glob"],
@@ -279,16 +280,26 @@ def build_task_graph(event, all_tasks, t
 
         task_id, task_data = create_tc_task(event, task, taskgroup_id, depends_on_ids,
                                             env_extra=env_extra)
         task_id_map[task_name] = (task_id, task_data)
 
     for task_name, task in iteritems(tasks):
         add_task(task_name, task)
 
+    # GitHub branch protection needs us to name explicit required tasks - which
+    # doesn't suffice when using a dynamic task graph. To work around this we
+    # declare a sink task that depends on all the other tasks completing, and
+    # checks if they have succeeded. We can then make the sink task the sole
+    # required task for GitHub.
+    depends_on_ids = [x[0] for x in task_id_map.values()]
+    sink_task = all_tasks['sink-task']
+    sink_task['command'] += ' {0}'.format(' '.join(depends_on_ids))
+    task_id_map['sink-task'] = create_tc_task(event, sink_task, taskgroup_id, depends_on_ids)
+
     return task_id_map
 
 
 def create_tasks(queue, task_id_map):
     for (task_id, task_data) in itervalues(task_id_map):
         queue.createTask(task_id, task_data)
 
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/tools/ci/tc/sink_task.py
@@ -0,0 +1,41 @@
+import argparse
+import logging
+import os
+
+import taskcluster
+
+
+logging.basicConfig()
+logger = logging.getLogger()
+
+
+def check_task_statuses(task_ids):
+    """Verifies whether a set of Taskcluster tasks completed successfully or not.
+
+    Returns 0 if all tasks passed completed successfully, 1 otherwise."""
+
+    queue = taskcluster.Queue({'rootUrl': os.environ['TASKCLUSTER_ROOT_URL']})
+    success = True
+    for task in task_ids:
+        status = queue.status(task)
+        state = status['status']['state']
+        if state == 'failed' or state == 'exception':
+            logger.error('Task {0} failed with state "{1}"'.format(task, state))
+            success = False
+        elif state != 'completed':
+            logger.error('Task {0} had unexpected state "{1}"'.format(task, state))
+            success = False
+    if success:
+        logger.info('All tasks completed successfully')
+    return 0 if success else 1
+
+
+def get_parser():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("tasks", nargs="+",
+            help="A set of Taskcluster task ids to verify the state of.")
+    return parser
+
+
+def run(venv, **kwargs):
+    return check_task_statuses(kwargs['tasks'])
--- a/testing/web-platform/tests/tools/ci/tc/tasks/test.yml
+++ b/testing/web-platform/tests/tools/ci/tc/tasks/test.yml
@@ -482,8 +482,16 @@ tasks:
         browser:
           - chrome
         channel: experimental
         xvfb: true
         hosts: false
       schedule-if:
         run-job:
           - wptrunner_infrastructure
+
+  - sink-task:
+      description: >-
+        Sink task for all other tasks; indicates success
+      use:
+        - wpt-base
+      command: "./wpt tc-sink-task"
+      requires: all-resolved
--- a/testing/web-platform/tests/tools/ci/tc/tests/test_valid.py
+++ b/testing/web-platform/tests/tools/ci/tc/tests/test_valid.py
@@ -126,40 +126,43 @@ def test_verify_payload():
       'wpt-firefox-nightly-wdspec-1',
       'wpt-firefox-nightly-wdspec-2',
       'wpt-chrome-dev-wdspec-1',
       'wpt-chrome-dev-wdspec-2',
       'wpt-firefox-nightly-crashtest-1',
       'wpt-chrome-dev-crashtest-1',
       'wpt-firefox-nightly-print-reftest-1',
       'wpt-chrome-dev-print-reftest-1',
-      'lint'}),
+      'lint',
+      'sink-task'}),
     ("pr_event.json", True, {".taskcluster.yml",".travis.yml","tools/ci/start.sh"},
      {'download-firefox-nightly',
       'lint',
       'tools/ unittests (Python 2)',
       'tools/ unittests (Python 3.6)',
       'tools/ unittests (Python 3.8)',
       'tools/ integration tests (Python 2)',
       'tools/ integration tests (Python 3.6)',
       'tools/ integration tests (Python 3.8)',
       'resources/ tests',
       'infrastructure/ tests',
-      'infrastructure/ tests (Python 3)'}),
+      'infrastructure/ tests (Python 3)',
+      'sink-task'}),
     # More tests are affected in the actual PR but it shouldn't affect the scheduled tasks
     ("pr_event_tests_affected.json", True, {"layout-instability/clip-negative-bottom-margin.html",
                                             "layout-instability/composited-element-movement.html"},
      {'download-firefox-nightly',
       'wpt-firefox-nightly-stability',
       'wpt-firefox-nightly-results',
       'wpt-firefox-nightly-results-without-changes',
       'wpt-chrome-dev-stability',
       'wpt-chrome-dev-results',
       'wpt-chrome-dev-results-without-changes',
-      'lint'}),
+      'lint',
+      'sink-task'}),
     ("epochs_daily_push_event.json", False, None,
      {'download-firefox-stable',
       'wpt-chrome-stable-reftest-1',
       'wpt-chrome-stable-reftest-2',
       'wpt-chrome-stable-reftest-3',
       'wpt-chrome-stable-reftest-4',
       'wpt-chrome-stable-reftest-5',
       'wpt-chrome-stable-print-reftest-1',
@@ -251,17 +254,18 @@ def test_verify_payload():
       'wpt-servo-nightly-testharness-4',
       'wpt-servo-nightly-testharness-5',
       'wpt-servo-nightly-testharness-6',
       'wpt-servo-nightly-testharness-7',
       'wpt-servo-nightly-testharness-8',
       'wpt-servo-nightly-testharness-9',
       'wpt-servo-nightly-wdspec-1',
       'wpt-servo-nightly-wdspec-2',
-      'wpt-servo-nightly-crashtest-1',})
+      'wpt-servo-nightly-crashtest-1',
+      'sink-task',})
 ])
 def test_schedule_tasks(event_path, is_pr, files_changed, expected):
     with mock.patch("tools.ci.tc.decision.get_fetch_rev", return_value=(None, None, None)):
         with mock.patch("tools.wpt.testfiles.repo_files_changed",
                         return_value=files_changed):
             with open(data_path(event_path), encoding="utf8") as event_file:
                 event = json.load(event_file)
                 scheduled = decision.decide(event)