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
--- 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: