Bug 1410513: Move ridealong build configuration to ci/config.yml; r?dustin draft
authorTom Prince <mozilla@hocat.ca>
Thu, 02 Nov 2017 14:34:47 -0600
changeset 693754 b93297ca203c8f911abd76fd6963694a639d528d
parent 693753 feafd4cd37b484f6679ae1d038b909d16f89334f
child 739123 c5ec128481e10750868cc96f2da3e1cc882cc773
push id87900
push userbmo:mozilla@hocat.ca
push dateMon, 06 Nov 2017 19:45:00 +0000
reviewersdustin
bugs1410513
milestone58.0a1
Bug 1410513: Move ridealong build configuration to ci/config.yml; r?dustin MozReview-Commit-ID: 761zWtiZFtz
taskcluster/ci/config.yml
taskcluster/taskgraph/config.py
taskcluster/taskgraph/filter_tasks.py
taskcluster/taskgraph/generator.py
taskcluster/taskgraph/target_tasks.py
taskcluster/taskgraph/test/test_generator.py
taskcluster/taskgraph/test/test_target_tasks.py
taskcluster/taskgraph/test/test_try_option_syntax.py
taskcluster/taskgraph/try_option_syntax.py
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -47,8 +47,34 @@ treeherder:
         'TMW': 'Toolchain builds for Windows MinGW'
         'TW32': 'Toolchain builds for Windows 32-bits'
         'TW64': 'Toolchain builds for Windows 64-bits'
         'SM-tc': 'Spidermonkey builds'
         'pub': 'APK publishing'
         'p': 'Partial generation'
         'ps': 'Partials signing'
         'Rel': 'Release promotion'
+
+try:
+    # We have a few platforms for which we want to do some "extra" builds, or at
+    # least build-ish things.  Sort of.  Anyway, these other things are implemented
+    # as different "platforms".  These do *not* automatically ride along with "-p
+    # all"
+    ridealong-builds:
+        'android-api-16':
+            - 'android-api-16-l10n'
+        'linux':
+            - 'linux-l10n'
+        'linux64':
+            - 'linux64-l10n'
+            - 'sm-plain'
+            - 'sm-nonunified'
+            - 'sm-arm-sim'
+            - 'sm-arm64-sim'
+            - 'sm-compacting'
+            - 'sm-rootanalysis'
+            - 'sm-package'
+            - 'sm-tsan'
+            - 'sm-asan'
+            - 'sm-mozjs-sys'
+            - 'sm-msan'
+            - 'sm-fuzzing'
+            - 'sm-rust-bindings'
--- a/taskcluster/taskgraph/config.py
+++ b/taskcluster/taskgraph/config.py
@@ -6,14 +6,21 @@ from __future__ import absolute_import, 
 
 from .util.schema import validate_schema, Schema
 from voluptuous import Required
 
 graph_config_schema = Schema({
     Required('treeherder'): {
         # Mapping of treeherder group symbols to descriptive names
         Required('group-names'): {basestring: basestring}
-    }
+    },
+    Required('try'): {
+        # We have a few platforms for which we want to do some "extra" builds, or at
+        # least build-ish things.  Sort of.  Anyway, these other things are implemented
+        # as different "platforms".  These do *not* automatically ride along with "-p
+        # all"
+        Required('ridealong-builds', default={}): {basestring: [basestring]},
+    },
 })
 
 
 def validate_graph_config(config):
     return validate_schema(graph_config_schema, config, "Invalid graph configuration:")
--- a/taskcluster/taskgraph/filter_tasks.py
+++ b/taskcluster/taskgraph/filter_tasks.py
@@ -19,29 +19,29 @@ def filter_task(name):
     """Generator to declare a task filter function."""
     def wrap(func):
         filter_task_functions[name] = func
         return func
     return wrap
 
 
 @filter_task('target_tasks_method')
-def filter_target_tasks(graph, parameters):
+def filter_target_tasks(graph, parameters, graph_config):
     """Proxy filter to use legacy target tasks code.
 
     This should go away once target_tasks are converted to filters.
     """
 
     attr = parameters.get('target_tasks_method', 'all_tasks')
     fn = target_tasks.get_method(attr)
-    return fn(graph, parameters)
+    return fn(graph, parameters, graph_config)
 
 
 @filter_task('check_servo')
-def filter_servo(graph, parameters):
+def filter_servo(graph, parameters, graph_config):
     """Filter out tasks for Servo vendoring changesets.
 
     If the change triggering is related to Servo vendoring, impact is minimal
     because not all platforms use Servo code.
 
     We filter out tests on platforms that don't run Servo tests because running
     tests will accomplish little for these changes.
     """
--- a/taskcluster/taskgraph/generator.py
+++ b/taskcluster/taskgraph/generator.py
@@ -253,17 +253,17 @@ class TaskGraphGenerator(object):
             len(full_task_set.graph.nodes), len(edges)))
         yield verifications('full_task_graph', full_task_graph)
 
         logger.info("Generating target task set")
         target_task_set = TaskGraph(dict(all_tasks),
                                     Graph(set(all_tasks.keys()), set()))
         for fltr in self.filters:
             old_len = len(target_task_set.graph.nodes)
-            target_tasks = set(fltr(target_task_set, self.parameters))
+            target_tasks = set(fltr(target_task_set, self.parameters, graph_config))
             target_task_set = TaskGraph(
                 {l: all_tasks[l] for l in target_tasks},
                 Graph(target_tasks, set()))
             logger.info('Filter %s pruned %d tasks (%d remain)' % (
                 fltr.__name__,
                 old_len - len(target_tasks),
                 len(target_tasks)))
 
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -88,25 +88,25 @@ def filter_beta_release_tasks(task, para
 
 def standard_filter(task, parameters):
     return all(
         filter_func(task, parameters) for filter_func in
         (filter_on_nightly, filter_for_project, filter_upload_symbols)
     )
 
 
-def _try_task_config(full_task_graph, parameters):
+def _try_task_config(full_task_graph, parameters, graph_config):
     requested_tasks = parameters['try_task_config']['tasks']
     return list(set(requested_tasks) & full_task_graph.graph.nodes)
 
 
-def _try_option_syntax(full_task_graph, parameters):
+def _try_option_syntax(full_task_graph, parameters, graph_config):
     """Generate a list of target tasks based on try syntax in
     parameters['message'] and, for context, the full task graph."""
-    options = try_option_syntax.TryOptionSyntax(parameters, full_task_graph)
+    options = try_option_syntax.TryOptionSyntax(parameters, full_task_graph, graph_config)
     target_tasks_labels = [t.label for t in full_task_graph.tasks.itervalues()
                            if options.task_matches(t)]
 
     attributes = {
         k: getattr(options, k) for k in [
             'env',
             'no_retry',
             'tag',
@@ -142,38 +142,38 @@ def _try_option_syntax(full_task_graph, 
             elif options.notifications == 'failure':
                 routes.append("notify.email.{}.on-failed".format(owner))
                 routes.append("notify.email.{}.on-exception".format(owner))
 
     return target_tasks_labels
 
 
 @_target_task('try_tasks')
-def target_tasks_try(full_task_graph, parameters):
+def target_tasks_try(full_task_graph, parameters, graph_config):
     try_mode = parameters['try_mode']
     if try_mode == 'try_task_config':
-        return _try_task_config(full_task_graph, parameters)
+        return _try_task_config(full_task_graph, parameters, graph_config)
     elif try_mode == 'try_option_syntax':
-        return _try_option_syntax(full_task_graph, parameters)
+        return _try_option_syntax(full_task_graph, parameters, graph_config)
     else:
         # With no try mode, we schedule nothing, allowing the user to add tasks
         # later via treeherder.
         return []
 
 
 @_target_task('default')
-def target_tasks_default(full_task_graph, parameters):
+def target_tasks_default(full_task_graph, parameters, graph_config):
     """Target the tasks which have indicated they should be run on this project
     via the `run_on_projects` attributes."""
     return [l for l, t in full_task_graph.tasks.iteritems()
             if standard_filter(t, parameters)]
 
 
 @_target_task('ash_tasks')
-def target_tasks_ash(full_task_graph, parameters):
+def target_tasks_ash(full_task_graph, parameters, graph_config):
     """Target tasks that only run on the ash branch."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         # Early return if platform is None
         if not platform:
             return False
         # Only on Linux platforms
         if 'linux' not in platform:
@@ -199,64 +199,64 @@ def target_tasks_ash(full_task_graph, pa
         # don't upload symbols
         if task.attributes['kind'] == 'upload-symbols':
             return False
         return True
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('cedar_tasks')
-def target_tasks_cedar(full_task_graph, parameters):
+def target_tasks_cedar(full_task_graph, parameters, graph_config):
     """Target tasks that only run on the cedar branch."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         # only select platforms
         if platform not in ('linux64', 'macosx64'):
             return False
         if task.attributes.get('unittest_suite'):
             if not (task.attributes['unittest_suite'].startswith('mochitest') or
                     'xpcshell' in task.attributes['unittest_suite']):
                 return False
         return True
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('graphics_tasks')
-def target_tasks_graphics(full_task_graph, parameters):
+def target_tasks_graphics(full_task_graph, parameters, graph_config):
     """In addition to doing the filtering by project that the 'default'
        filter does, also remove artifact builds because we have csets on
        the graphics branch that aren't on the candidate branches of artifact
        builds"""
     filtered_for_project = target_tasks_default(full_task_graph, parameters)
 
     def filter(task):
         if task.attributes['kind'] == 'artifact-build':
             return False
         return True
     return [l for l in filtered_for_project if filter(full_task_graph[l])]
 
 
 @_target_task('mochitest_valgrind')
-def target_tasks_valgrind(full_task_graph, parameters):
+def target_tasks_valgrind(full_task_graph, parameters, graph_config):
     """Target tasks that only run on the cedar branch."""
     def filter(task):
         platform = task.attributes.get('test_platform', '').split('/')[0]
         if platform not in ['linux64']:
             return False
 
         if task.attributes.get('unittest_suite', '').startswith('mochitest') and \
            task.attributes.get('unittest_flavor', '').startswith('valgrind-plain'):
             return True
         return False
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_fennec')
-def target_tasks_nightly_fennec(full_task_graph, parameters):
+def target_tasks_nightly_fennec(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of fennec. The
     nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         if platform in ('android-aarch64-nightly',
                         'android-api-16-nightly',
                         'android-api-16-old-id-nightly',
@@ -265,51 +265,51 @@ def target_tasks_nightly_fennec(full_tas
                         'android-x86-old-id-nightly'):
             if not task.attributes.get('nightly', False):
                 return False
             return filter_for_project(task, parameters)
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_linux')
-def target_tasks_nightly_linux(full_task_graph, parameters):
+def target_tasks_nightly_linux(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of linux. The
     nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         if platform in ('linux64-nightly', 'linux-nightly'):
             return task.attributes.get('nightly', False)
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('mozilla_beta_tasks')
-def target_tasks_mozilla_beta(full_task_graph, parameters):
+def target_tasks_mozilla_beta(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a promotable beta or release build
     of desktop, plus android CI. The candidates build process involves a pipeline
     of builds and signing, but does not include beetmover or balrog jobs."""
 
     return [l for l, t in full_task_graph.tasks.iteritems() if
             filter_beta_release_tasks(t, parameters)]
 
 
 @_target_task('mozilla_release_tasks')
-def target_tasks_mozilla_release(full_task_graph, parameters):
+def target_tasks_mozilla_release(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a promotable beta or release build
     of desktop, plus android CI. The candidates build process involves a pipeline
     of builds and signing, but does not include beetmover or balrog jobs."""
 
     return [l for l, t in full_task_graph.tasks.iteritems() if
             filter_beta_release_tasks(t, parameters)]
 
 
 @_target_task('maple_desktop_promotion')
 @_target_task('mozilla-beta_desktop_promotion')
 @_target_task('mozilla-release_desktop_promotion')
-def target_tasks_mozilla_beta_desktop_promotion(full_task_graph, parameters):
+def target_tasks_mozilla_beta_desktop_promotion(full_task_graph, parameters, graph_config):
     """Select the superset of tasks required to promote a beta or release build
     of desktop. This should include all non-android mozilla_beta tasks, plus
     l10n, beetmover, balrog, etc."""
 
     beta_tasks = [l for l, t in full_task_graph.tasks.iteritems() if
                   filter_beta_release_tasks(t, parameters,
                                             ignore_kinds=[],
                                             allow_l10n=True)]
@@ -344,17 +344,17 @@ def target_tasks_mozilla_beta_desktop_pr
         # TODO: bouncer sub
         # TODO: snap
         # TODO: recompression tasks
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('publish_firefox')
-def target_tasks_publish_firefox(full_task_graph, parameters):
+def target_tasks_publish_firefox(full_task_graph, parameters, graph_config):
     """Select the set of tasks required to publish a candidates build of firefox.
     Previous build deps will be optimized out via action task."""
     filtered_for_candidates = target_tasks_mozilla_beta_desktop_promotion(
         full_task_graph, parameters
     )
 
     def filter(task):
         # Include promotion tasks; these will be optimized out
@@ -370,17 +370,17 @@ def target_tasks_publish_firefox(full_ta
         # TODO: bouncer aliases
         # TODO: checksums
         # TODO: shipit mark as shipped
 
     return [l for l, t in full_task_graph.iteritems() if filter(t)]
 
 
 @_target_task('candidates_fennec')
-def target_tasks_candidates_fennec(full_task_graph, parameters):
+def target_tasks_candidates_fennec(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a candidates build of fennec. The
     nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     filtered_for_project = target_tasks_nightly_fennec(full_task_graph, parameters)
 
     def filter(task):
         attr = task.attributes.get
         # Don't ship single locale fennec anymore - Bug 1408083
@@ -398,17 +398,17 @@ def target_tasks_candidates_fennec(full_
             if task.kind in ('release-notify-promote',
                              ):
                 return True
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(full_task_graph[l])]
 
 
 @_target_task('publish_fennec')
-def target_tasks_publish_fennec(full_task_graph, parameters):
+def target_tasks_publish_fennec(full_task_graph, parameters, graph_config):
     """Select the set of tasks required to publish a candidates build of fennec.
     Previous build deps will be optimized out via action task."""
     filtered_for_candidates = target_tasks_candidates_fennec(full_task_graph, parameters)
 
     def filter(task):
         # Include candidates build tasks; these will be optimized out
         if task.label in filtered_for_candidates:
             return True
@@ -430,95 +430,95 @@ def target_tasks_publish_fennec(full_tas
 
         if task.kind in ('push-apk', 'push-apk-breakpoint'):
             return True
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(full_task_graph[l])]
 
 
 @_target_task('pine_tasks')
-def target_tasks_pine(full_task_graph, parameters):
+def target_tasks_pine(full_task_graph, parameters, graph_config):
     """Bug 1339179 - no mobile automation needed on pine"""
     def filter(task):
         platform = task.attributes.get('build_platform')
         # disable mobile jobs
         if str(platform).startswith('android'):
             return False
         # disable asan
         if platform == 'linux64-asan':
             return False
         # disable non-pine and nightly tasks
         if standard_filter(task, parameters):
             return True
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_macosx')
-def target_tasks_nightly_macosx(full_task_graph, parameters):
+def target_tasks_nightly_macosx(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of macosx. The
     nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         if platform in ('macosx64-nightly', ):
             return task.attributes.get('nightly', False)
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_win32')
-def target_tasks_nightly_win32(full_task_graph, parameters):
+def target_tasks_nightly_win32(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of win32 and win64.
     The nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         if not filter_for_project(task, parameters):
             return False
         if platform in ('win32-nightly', ):
             return task.attributes.get('nightly', False)
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_win64')
-def target_tasks_nightly_win64(full_task_graph, parameters):
+def target_tasks_nightly_win64(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of win32 and win64.
     The nightly build process involves a pipeline of builds, signing,
     and, eventually, uploading the tasks to balrog."""
     def filter(task):
         platform = task.attributes.get('build_platform')
         if not filter_for_project(task, parameters):
             return False
         if platform in ('win64-nightly', ):
             return task.attributes.get('nightly', False)
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('nightly_desktop')
-def target_tasks_nightly_desktop(full_task_graph, parameters):
+def target_tasks_nightly_desktop(full_task_graph, parameters, graph_config):
     """Select the set of tasks required for a nightly build of linux, mac,
     windows."""
     # Avoid duplicate tasks.
     return list(
         set(target_tasks_nightly_win32(full_task_graph, parameters))
         | set(target_tasks_nightly_win64(full_task_graph, parameters))
         | set(target_tasks_nightly_macosx(full_task_graph, parameters))
         | set(target_tasks_nightly_linux(full_task_graph, parameters))
     )
 
 
 # Opt DMD builds should only run nightly
 @_target_task('nightly_dmd')
-def target_tasks_dmd(full_task_graph, parameters):
+def target_tasks_dmd(full_task_graph, parameters, graph_config):
     """Target DMD that run nightly on the m-c branch."""
     def filter(task):
         platform = task.attributes.get('build_platform', '')
         return platform.endswith('-dmd')
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
 
 
 @_target_task('file_update')
-def target_tasks_file_update(full_task_graph, parameters):
+def target_tasks_file_update(full_task_graph, parameters, graph_config):
     """Select the set of tasks required to perform nightly in-tree file updates
     """
     def filter(task):
         # For now any task in the repo-update kind is ok
         return task.kind in ['repo-update']
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
--- a/taskcluster/taskgraph/test/test_generator.py
+++ b/taskcluster/taskgraph/test/test_generator.py
@@ -43,24 +43,24 @@ class FakeKind(Kind):
 
     def load_tasks(self, parameters, loaded_tasks):
         FakeKind.loaded_kinds.append(self.name)
         return super(FakeKind, self).load_tasks(parameters, loaded_tasks)
 
 
 class WithFakeKind(TaskGraphGenerator):
 
-    def _load_kinds(self):
+    def _load_kinds(self, graph_config):
         for kind_name, cfg in self.parameters['_kinds']:
             config = {
                 'transforms': [],
             }
             if cfg:
                 config.update(cfg)
-            yield FakeKind(kind_name, '/fake', config)
+            yield FakeKind(kind_name, '/fake', config, graph_config)
 
     def _load_graph_config(self):
         return {}
 
 
 class FakeParameters(dict):
     strict = True
 
@@ -86,17 +86,17 @@ class TestGenerator(unittest.TestCase):
     def patch(self, monkeypatch):
         self.patch = monkeypatch
 
     def maketgg(self, target_tasks=None, kinds=[('_fake', [])], params=None):
         params = params or {}
         FakeKind.loaded_kinds = []
         self.target_tasks = target_tasks or []
 
-        def target_tasks_method(full_task_graph, parameters):
+        def target_tasks_method(full_task_graph, parameters, graph_config):
             return self.target_tasks
 
         def make_fake_strategies():
             return {mode: FakeOptimization(mode)
                     for mode in ('always', 'never', 'even', 'odd')}
 
         target_tasks_mod._target_task_methods['test_method'] = target_tasks_method
         self.patch.setattr(optimize_mod, '_make_default_strategies', make_fake_strategies)
--- a/taskcluster/taskgraph/test/test_target_tasks.py
+++ b/taskcluster/taskgraph/test/test_target_tasks.py
@@ -12,17 +12,17 @@ from taskgraph import try_option_syntax
 from taskgraph.graph import Graph
 from taskgraph.taskgraph import TaskGraph
 from taskgraph.task import Task
 from mozunit import main
 
 
 class FakeTryOptionSyntax(object):
 
-    def __init__(self, message, task_graph):
+    def __init__(self, message, task_graph, graph_config):
         self.trigger_tests = 0
         self.talos_trigger_tests = 0
         self.notifications = None
         self.env = []
         self.profile = False
         self.tag = None
         self.no_retry = False
 
@@ -35,17 +35,17 @@ class TestTargetTasks(unittest.TestCase)
     def default_matches(self, run_on_projects, project):
         method = target_tasks.get_method('default')
         graph = TaskGraph(tasks={
             'a': Task(kind='build', label='a',
                       attributes={'run_on_projects': run_on_projects},
                       task={}),
         }, graph=Graph(nodes={'a'}, edges=set()))
         parameters = {'project': project}
-        return 'a' in method(graph, parameters)
+        return 'a' in method(graph, parameters, {})
 
     def test_default_all(self):
         """run_on_projects=[all] includes release, integration, and other projects"""
         self.assertTrue(self.default_matches(['all'], 'mozilla-central'))
         self.assertTrue(self.default_matches(['all'], 'mozilla-inbound'))
         self.assertTrue(self.default_matches(['all'], 'baobab'))
 
     def test_default_integration(self):
@@ -89,34 +89,34 @@ class TestTargetTasks(unittest.TestCase)
         tg = self.make_task_graph()
         method = target_tasks.get_method('try_tasks')
         params = {
             'try_mode': None,
             'project': 'try',
             'message': '',
         }
         # only runs the task with run_on_projects: try
-        self.assertEqual(method(tg, params), [])
+        self.assertEqual(method(tg, params, {}), [])
 
     def test_try_option_syntax(self):
         "try_mode = try_option_syntax uses TryOptionSyntax"
         tg = self.make_task_graph()
         method = target_tasks.get_method('try_tasks')
         with self.fake_TryOptionSyntax():
             params = {
                 'try_mode': 'try_option_syntax',
                 'message': 'try: -p all',
             }
-            self.assertEqual(method(tg, params), ['b'])
+            self.assertEqual(method(tg, params, {}), ['b'])
 
     def test_try_task_config(self):
         "try_mode = try_task_config uses the try config"
         tg = self.make_task_graph()
         method = target_tasks.get_method('try_tasks')
         params = {
             'try_mode': 'try_task_config',
             'try_task_config': {'tasks': ['a']},
         }
-        self.assertEqual(method(tg, params), ['a'])
+        self.assertEqual(method(tg, params, {}), ['a'])
 
 
 if __name__ == '__main__':
     main()
--- a/taskcluster/taskgraph/test/test_try_option_syntax.py
+++ b/taskcluster/taskgraph/test/test_try_option_syntax.py
@@ -2,17 +2,16 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import unittest
 
 from taskgraph.try_option_syntax import TryOptionSyntax, parse_message
-from taskgraph.try_option_syntax import RIDEALONG_BUILDS
 from taskgraph.graph import Graph
 from taskgraph.taskgraph import TaskGraph
 from taskgraph.task import Task
 from mozunit import main
 
 
 def unittest_task(n, tp, bt='opt'):
     return (n, Task('test', n, {
@@ -44,16 +43,25 @@ tasks = {k: v for k, v in [
     unittest_task('extra4', 'linux64/debug', 'debug'),
     unittest_task('extra5', 'linux/this'),
     unittest_task('extra6', 'linux/that'),
     unittest_task('extra7', 'linux/other'),
     unittest_task('extra8', 'linux64/asan'),
     talos_task('extra9', 'linux64/psan'),
 ]}
 
+RIDEALONG_BUILDS = {
+    'linux': ['linux-ridealong'],
+    'linux64': ['linux64-ridealong'],
+}
+
+GRAPH_CONFIG = {
+    'try': {'ridealong-builds': RIDEALONG_BUILDS},
+}
+
 for r in RIDEALONG_BUILDS.values():
     tasks.update({k: v for k, v in [
         unittest_task(n + '-test', n) for n in r
     ]})
 
 unittest_tasks = {k: v for k, v in tasks.iteritems()
                   if 'unittest_try_name' in v.attributes}
 talos_tasks = {k: v for k, v in tasks.iteritems()
@@ -61,283 +69,283 @@ talos_tasks = {k: v for k, v in tasks.it
 graph_with_jobs = TaskGraph(tasks, Graph(set(tasks), set()))
 
 
 class TestTryOptionSyntax(unittest.TestCase):
 
     def test_unknown_args(self):
         "unknown arguments are ignored"
         parameters = {'try_options': parse_message('try: --doubledash -z extra')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         # equilvant to "try:"..
         self.assertEqual(tos.build_types, [])
         self.assertEqual(tos.jobs, [])
 
     def test_apostrophe_in_message(self):
         "apostrophe does not break parsing"
         parameters = {'try_options': parse_message('Increase spammy log\'s log level. try: -b do')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['debug', 'opt'])
 
     def test_b_do(self):
         "-b do should produce both build_types"
         parameters = {'try_options': parse_message('try: -b do')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['debug', 'opt'])
 
     def test_b_d(self):
         "-b d should produce build_types=['debug']"
         parameters = {'try_options': parse_message('try: -b d')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['debug'])
 
     def test_b_o(self):
         "-b o should produce build_types=['opt']"
         parameters = {'try_options': parse_message('try: -b o')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['opt'])
 
     def test_build_o(self):
         "--build o should produce build_types=['opt']"
         parameters = {'try_options': parse_message('try: --build o')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['opt'])
 
     def test_b_dx(self):
         "-b dx should produce build_types=['debug'], silently ignoring the x"
         parameters = {'try_options': parse_message('try: -b dx')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.build_types), ['debug'])
 
     def test_j_job(self):
         "-j somejob sets jobs=['somejob']"
         parameters = {'try_options': parse_message('try: -j somejob')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.jobs), ['somejob'])
 
     def test_j_jobs(self):
         "-j job1,job2 sets jobs=['job1', 'job2']"
         parameters = {'try_options': parse_message('try: -j job1,job2')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.jobs), ['job1', 'job2'])
 
     def test_j_all(self):
         "-j all sets jobs=None"
         parameters = {'try_options': parse_message('try: -j all')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.jobs, None)
 
     def test_j_twice(self):
         "-j job1 -j job2 sets jobs=job1, job2"
         parameters = {'try_options': parse_message('try: -j job1 -j job2')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.jobs), sorted(['job1', 'job2']))
 
     def test_p_all(self):
         "-p all sets platforms=None"
         parameters = {'try_options': parse_message('try: -p all')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.platforms, None)
 
     def test_p_linux(self):
-        "-p linux sets platforms=['linux', 'linux-l10n']"
+        "-p linux sets platforms=['linux', 'linux-ridealong']"
         parameters = {'try_options': parse_message('try: -p linux')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
-        self.assertEqual(tos.platforms, ['linux', 'linux-l10n'])
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
+        self.assertEqual(tos.platforms, ['linux', 'linux-ridealong'])
 
     def test_p_linux_win32(self):
-        "-p linux,win32 sets platforms=['linux', 'linux-l10n', 'win32']"
+        "-p linux,win32 sets platforms=['linux', 'linux-ridealong', 'win32']"
         parameters = {'try_options': parse_message('try: -p linux,win32')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
-        self.assertEqual(sorted(tos.platforms), ['linux', 'linux-l10n', 'win32'])
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
+        self.assertEqual(sorted(tos.platforms), ['linux', 'linux-ridealong', 'win32'])
 
     def test_p_expands_ridealongs(self):
         "-p linux,linux64 includes the RIDEALONG_BUILDS"
         parameters = {'try_options': parse_message('try: -p linux,linux64')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         platforms = set(['linux'] + RIDEALONG_BUILDS['linux'])
         platforms |= set(['linux64'] + RIDEALONG_BUILDS['linux64'])
         self.assertEqual(sorted(tos.platforms), sorted(platforms))
 
     def test_u_none(self):
         "-u none sets unittests=[]"
         parameters = {'try_options': parse_message('try: -u none')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), [])
 
     def test_u_all(self):
         "-u all sets unittests=[..whole list..]"
         parameters = {'try_options': parse_message('try: -u all')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([{'test': t} for t in unittest_tasks]))
 
     def test_u_single(self):
         "-u mochitest-webgl sets unittests=[mochitest-webgl]"
         parameters = {'try_options': parse_message('try: -u mochitest-webgl')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([{'test': 'mochitest-webgl'}]))
 
     def test_u_alias(self):
         "-u mochitest-gl sets unittests=[mochitest-webgl]"
         parameters = {'try_options': parse_message('try: -u mochitest-gl')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([{'test': 'mochitest-webgl'}]))
 
     def test_u_multi_alias(self):
         "-u e10s sets unittests=[all e10s unittests]"
         parameters = {'try_options': parse_message('try: -u e10s')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': t} for t in unittest_tasks if 'e10s' in t
         ]))
 
     def test_u_commas(self):
         "-u mochitest-webgl,gtest sets unittests=both"
         parameters = {'try_options': parse_message('try: -u mochitest-webgl,gtest')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'mochitest-webgl'},
             {'test': 'gtest'},
         ]))
 
     def test_u_chunks(self):
         "-u gtest-3,gtest-4 selects the third and fourth chunk of gtest"
         parameters = {'try_options': parse_message('try: -u gtest-3,gtest-4')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'only_chunks': set('34')},
         ]))
 
     def test_u_platform(self):
         "-u gtest[linux] selects the linux platform for gtest"
         parameters = {'try_options': parse_message('try: -u gtest[linux]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'platforms': ['linux']},
         ]))
 
     def test_u_platforms(self):
         "-u gtest[linux,win32] selects the linux and win32 platforms for gtest"
         parameters = {'try_options': parse_message('try: -u gtest[linux,win32]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'platforms': ['linux', 'win32']},
         ]))
 
     def test_u_platforms_pretty(self):
         """-u gtest[Ubuntu] selects the linux, linux64, linux64-asan, linux64-stylo-disabled,
         and linux64-stylo-sequential platforms for gtest"""
         parameters = {'try_options': parse_message('try: -u gtest[Ubuntu]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'platforms': ['linux32', 'linux64', 'linux64-asan',
                                             'linux64-stylo-disabled', 'linux64-stylo-sequential']},
         ]))
 
     def test_u_platforms_negated(self):
         "-u gtest[-linux] selects all platforms but linux for gtest"
         parameters = {'try_options': parse_message('try: -u gtest[-linux]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         all_platforms = set([x.attributes['test_platform'] for x in unittest_tasks.values()])
         self.assertEqual(sorted(tos.unittests[0]['platforms']), sorted(
             [x for x in all_platforms if x != 'linux']
         ))
 
     def test_u_platforms_negated_pretty(self):
         "-u gtest[Ubuntu,-x64] selects just linux for gtest"
         parameters = {'try_options': parse_message('try: -u gtest[Ubuntu,-x64]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'platforms': ['linux32']},
         ]))
 
     def test_u_chunks_platforms(self):
         "-u gtest-1[linux,win32] selects the linux and win32 platforms for chunk 1 of gtest"
         parameters = {'try_options': parse_message('try: -u gtest-1[linux,win32]')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.unittests), sorted([
             {'test': 'gtest', 'platforms': ['linux', 'win32'], 'only_chunks': set('1')},
         ]))
 
     def test_t_none(self):
         "-t none sets talos=[]"
         parameters = {'try_options': parse_message('try: -t none')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.talos), [])
 
     def test_t_all(self):
         "-t all sets talos=[..whole list..]"
         parameters = {'try_options': parse_message('try: -t all')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.talos), sorted([{'test': t} for t in talos_tasks]))
 
     def test_t_single(self):
         "-t mochitest-webgl sets talos=[mochitest-webgl]"
         parameters = {'try_options': parse_message('try: -t mochitest-webgl')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(sorted(tos.talos), sorted([{'test': 'mochitest-webgl'}]))
 
     # -t shares an implementation with -u, so it's not tested heavily
 
     def test_trigger_tests(self):
         "--rebuild 10 sets trigger_tests"
         parameters = {'try_options': parse_message('try: --rebuild 10')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.trigger_tests, 10)
 
     def test_talos_trigger_tests(self):
         "--rebuild-talos 10 sets talos_trigger_tests"
         parameters = {'try_options': parse_message('try: --rebuild-talos 10')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.talos_trigger_tests, 10)
 
     def test_interactive(self):
         "--interactive sets interactive"
         parameters = {'try_options': parse_message('try: --interactive')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.interactive, True)
 
     def test_all_email(self):
         "--all-emails sets notifications"
         parameters = {'try_options': parse_message('try: --all-emails')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.notifications, 'all')
 
     def test_fail_email(self):
         "--failure-emails sets notifications"
         parameters = {'try_options': parse_message('try: --failure-emails')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.notifications, 'failure')
 
     def test_no_email(self):
         "no email settings don't set notifications"
         parameters = {'try_options': parse_message('try:')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.notifications, None)
 
     def test_setenv(self):
         "--setenv VAR=value adds a environment variables setting to env"
         parameters = {'try_options': parse_message(
             'try: --setenv VAR1=value1 --setenv VAR2=value2')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.env, ['VAR1=value1', 'VAR2=value2'])
 
     def test_profile(self):
         "--geckoProfile sets profile to true"
         parameters = {'try_options': parse_message('try: --geckoProfile')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertTrue(tos.profile)
 
     def test_tag(self):
         "--tag TAG sets tag to TAG value"
         parameters = {'try_options': parse_message('try: --tag tagName')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertEqual(tos.tag, 'tagName')
 
     def test_no_retry(self):
         "--no-retry sets no_retry to true"
         parameters = {'try_options': parse_message('try: --no-retry')}
-        tos = TryOptionSyntax(parameters, graph_with_jobs)
+        tos = TryOptionSyntax(parameters, graph_with_jobs, GRAPH_CONFIG)
         self.assertTrue(tos.no_retry)
 
 
 if __name__ == '__main__':
     main()
--- a/taskcluster/taskgraph/try_option_syntax.py
+++ b/taskcluster/taskgraph/try_option_syntax.py
@@ -147,45 +147,16 @@ UNITTEST_PLATFORM_PRETTY_NAMES = {
     'Windows 7 VM':  ['windows7-32-vm'],
     'Windows 8':  ['windows8-64'],
     'Windows 10':  ['windows10-64'],
     # 'Windows XP': [..TODO..],
     # 'win32': [..TODO..],
     # 'win64': [..TODO..],
 }
 
-# We have a few platforms for which we want to do some "extra" builds, or at
-# least build-ish things.  Sort of.  Anyway, these other things are implemented
-# as different "platforms".  These do *not* automatically ride along with "-p
-# all"
-RIDEALONG_BUILDS = {
-    'android-api-16': [
-        'android-api-16-l10n',
-    ],
-    'linux': [
-        'linux-l10n',
-    ],
-    'linux64': [
-        'linux64-l10n',
-        'sm-plain',
-        'sm-nonunified',
-        'sm-arm-sim',
-        'sm-arm64-sim',
-        'sm-compacting',
-        'sm-rootanalysis',
-        'sm-package',
-        'sm-tsan',
-        'sm-asan',
-        'sm-mozjs-sys',
-        'sm-msan',
-        'sm-fuzzing',
-        'sm-rust-bindings',
-    ],
-}
-
 TEST_CHUNK_SUFFIX = re.compile('(.*)-([0-9]+)$')
 
 
 def escape_whitespace_in_brackets(input_str):
     '''
     In tests you may restrict them by platform [] inside of the brackets
     whitespace may occur this is typically invalid shell syntax so we escape it
     with backslash sequences    .
@@ -257,17 +228,17 @@ def parse_message(message):
     # In order to run test jobs multiple times
     parser.add_argument('--rebuild', dest='trigger_tests', type=int, default=1)
     args, _ = parser.parse_known_args(parts)
     return vars(args)
 
 
 class TryOptionSyntax(object):
 
-    def __init__(self, parameters, full_task_graph):
+    def __init__(self, parameters, full_task_graph, graph_config):
         """
         Apply the try options in parameters.
 
         The resulting object has attributes:
 
         - build_types: a list containing zero or more of 'opt' and 'debug'
         - platforms: a list of selected platform names, or None for all
         - unittests: a list of tests, of the form given below, or None for all
@@ -284,16 +255,17 @@ class TryOptionSyntax(object):
         The unittests and talos lists contain dictionaries of the form:
 
         {
             'test': '<suite name>',
             'platforms': [..platform names..], # to limit to only certain platforms
             'only_chunks': set([..chunk numbers..]), # to limit only to certain chunks
         }
         """
+        self.graph_config = graph_config
         self.jobs = []
         self.build_types = []
         self.platforms = []
         self.unittests = []
         self.talos = []
         self.trigger_tests = 0
         self.interactive = False
         self.notifications = None
@@ -347,16 +319,17 @@ class TryOptionSyntax(object):
             raise Exception("Unknown build type(s) [%s] specified for try" % ','.join(bad_types))
 
         return build_types
 
     def parse_platforms(self, platform_arg, full_task_graph):
         if platform_arg == 'all':
             return None
 
+        RIDEALONG_BUILDS = self.graph_config['try']['ridealong-builds']
         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])))