Bug 591688 - Notify when decision task fails draft
authorBrian Stack <bstack@mozilla.com>
Wed, 12 Apr 2017 21:01:46 -0700
changeset 564506 aae35159b126f9f35a44baae65f4cd51e141b57e
parent 561690 aca6b2a5a2ab3338436c9e819dc2244a022b6425
child 624757 eaa608decb8198b9b37b1868ed20fcee6186c5d6
push id54619
push userbstack@mozilla.com
push dateTue, 18 Apr 2017 17:08:45 +0000
bugs591688
milestone55.0a1
Bug 591688 - Notify when decision task fails This uses the email provided by mozilla-taskcluster to find who to email about failed decision tasks. It also adds some validation of the try syntax that we've previously ignored. Any platforms or build types specified in try sytax that don't exist in the full task graph will throw an error. MozReview-Commit-ID: JOKkLle7hEe
.taskcluster.yml
taskcluster/taskgraph/try_option_syntax.py
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -60,16 +60,18 @@ tasks:
 
       tags:
         createdForUser: {{owner}}
 
       routes:
         - "index.gecko.v2.{{project}}.latest.firefox.decision"
         - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
         - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
+        - "notify.email.{{owner}}.on-failed"
+        - "notify.email.{{owner}}.on-exception"
 
       payload:
         env:
           # checkout-gecko uses these to check out the source; the inputs
           # to `mach taskgraph decision` are all on the command line.
           GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
           GECKO_HEAD_REPOSITORY: '{{{url}}}'
           GECKO_HEAD_REF: '{{revision}}'
--- a/taskcluster/taskgraph/try_option_syntax.py
+++ b/taskcluster/taskgraph/try_option_syntax.py
@@ -244,17 +244,17 @@ def parse_message(message):
                         dest='taskcluster_worker', action='store_true', default=False)
     # Similarly, an extra flag for enabling os x jobs in generic-worker
     parser.add_argument('-g', '--generic-worker',
                         dest='generic_worker', action='store_true', default=False)
 
     # In order to run test jobs multiple times
     parser.add_argument('--rebuild', dest='trigger_tests', type=int, default=1)
     parts = parts[try_idx:] if try_idx is not None else []
-    args, _ = parser.parse_known_args(parts[try_idx:])
+    args, _ = parser.parse_known_args(parts)
     return args
 
 
 class TryOptionSyntax(object):
 
     def __init__(self, message, full_task_graph):
         """
         Parse a "try syntax" formatted commit message.  This is the old "-b do -p
@@ -301,18 +301,18 @@ class TryOptionSyntax(object):
         try_idx, _ = find_try_idx(message)
         if try_idx is None:
             return None
 
         args = parse_message(message)
         assert args is not None
 
         self.jobs = self.parse_jobs(args.jobs)
-        self.build_types = self.parse_build_types(args.build_types)
-        self.platforms = self.parse_platforms(args.platforms)
+        self.build_types = self.parse_build_types(args.build_types, full_task_graph)
+        self.platforms = self.parse_platforms(args.platforms, full_task_graph)
         self.unittests = self.parse_test_option(
             "unittest_try_name", args.unittests, full_task_graph)
         self.talos = self.parse_test_option("talos_try_name", args.talos, full_task_graph)
         self.trigger_tests = args.trigger_tests
         self.interactive = args.interactive
         self.notifications = args.notifications
         self.talos_trigger_tests = args.talos_trigger_tests
         self.env = args.env
@@ -324,35 +324,55 @@ class TryOptionSyntax(object):
     def parse_jobs(self, jobs_arg):
         if not jobs_arg or jobs_arg == ['all']:
             return None
         expanded = []
         for job in jobs_arg:
             expanded.extend(j.strip() for j in job.split(','))
         return expanded
 
-    def parse_build_types(self, build_types_arg):
+    def parse_build_types(self, build_types_arg, full_task_graph):
         if build_types_arg is None:
             build_types_arg = []
+
         build_types = filter(None, [BUILD_TYPE_ALIASES.get(build_type) for
                              build_type in build_types_arg])
+
+        all_types = set(t.attributes['build_type']
+                        for t in full_task_graph.tasks.itervalues()
+                        if 'build_type' in t.attributes)
+        bad_types = set(build_types) - all_types
+        if bad_types:
+            raise Exception("Unknown build type(s) [%s] specified for try" % ','.join(bad_types))
+
         return build_types
 
-    def parse_platforms(self, platform_arg):
+    def parse_platforms(self, platform_arg, full_task_graph):
         if platform_arg == 'all':
             return None
 
         results = []
         for build in platform_arg.split(','):
             results.append(build)
             if build in RIDEALONG_BUILDS:
                 results.extend(RIDEALONG_BUILDS[build])
                 logger.info("platform %s triggers ridealong builds %s" %
                             (build, ', '.join(RIDEALONG_BUILDS[build])))
 
+        test_platforms = set(t.attributes['test_platform']
+                             for t in full_task_graph.tasks.itervalues()
+                             if 'test_platform' in t.attributes)
+        build_platforms = set(t.attributes['build_platform']
+                              for t in full_task_graph.tasks.itervalues()
+                              if 'build_platform' in t.attributes)
+        all_platforms = test_platforms | build_platforms
+        bad_platforms = set(results) - all_platforms
+        if bad_platforms:
+            raise Exception("Unknown platform(s) [%s] specified for try" % ','.join(bad_platforms))
+
         return results
 
     def parse_test_option(self, attr_name, test_arg, full_task_graph):
         '''
 
         Parse a unittest (-u) or talos (-t) option, in the context of a full
         task graph containing available `unittest_try_name` or `talos_try_name`
         attributes.  There are three cases: