Bug 1391075 - Add template to modify task env from |mach try fuzzy|, r?dustin draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Fri, 25 Aug 2017 15:24:22 -0400
changeset 655908 2f129792ae24b13a3d5b089a2e3b1721d8a22288
parent 655774 ab2d700fda2b4934d24227216972dce9fac19b74
child 728943 07b259d14ced55b9f5001c940497620e4ff94583
push id76991
push userahalberstadt@mozilla.com
push dateWed, 30 Aug 2017 13:56:10 +0000
reviewersdustin
bugs1391075
milestone57.0a1
Bug 1391075 - Add template to modify task env from |mach try fuzzy|, r?dustin This adds a new morph template for modifying a task's env and the corresponding glue to specify it from |mach try fuzzy|. It can be used like: ./mach try fuzzy --env FOO=1 --env BAR=baz This will simply set those environment variables in *all* tasks. We could add the ability to only specify it for a subset of tasks in the future, but that seems like a hard problem that probably isn't worth it. MozReview-Commit-ID: C4sokv886PU
taskcluster/taskgraph/templates/env.yml
taskcluster/taskgraph/test/test_morph.py
tools/tryselect/selectors/fuzzy.py
tools/tryselect/templates.py
tools/tryselect/test/test_fuzzy.t
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/templates/env.yml
@@ -0,0 +1,9 @@
+$merge:
+    - $eval: task
+    - payload:
+          $merge:
+              - $eval: task.payload
+              - env:
+                    $merge:
+                        - $eval: task.payload.env
+                        - $eval: input
--- a/taskcluster/taskgraph/test/test_morph.py
+++ b/taskcluster/taskgraph/test/test_morph.py
@@ -84,53 +84,63 @@ class TestIndexTask(MorphTestCase):
         # check the scope summary
         self.assertEqual(index_task.task['scopes'],
                          ['index:insert-task:gecko.v2.mozilla-central.*'])
 
 
 class TestApplyJSONeTemplates(MorphTestCase):
 
     tasks = [
-        Task(kind='build', label='a', attributes={}, task={
-            'extra': {
-                'treeherder': {
-                    'group': 'tc',
-                    'symbol': 'B'
+        {
+            'kind': 'build',
+            'label': 'a',
+            'attributes': {},
+            'task': {
+                'extra': {
+                    'treeherder': {
+                        'group': 'tc',
+                        'symbol': 'B'
+                    }
+                },
+                'payload': {
+                    'env': {
+                        'FOO': 'BAR'
+                    }
+                },
+                'tags': {
+                    'kind': 'build'
                 }
-            },
-            'payload': {
-                'env': {
-                    'FOO': 'BAR'
-                }
-            },
-            'tags': {
-                'kind': 'build'
             }
-        }),
-        Task(kind='test', label='b', attributes={}, task={
-            'extra': {
-                'treeherder': {
-                    'group': 'tc',
-                    'symbol': 't'
+        },
+        {
+            'kind': 'test',
+            'label': 'b',
+            'attributes': {},
+            'task': {
+                'extra': {
+                    'treeherder': {
+                        'group': 'tc',
+                        'symbol': 't'
+                    }
+                },
+                'payload': {
+                    'env': {
+                        'FOO': 'BAR'
+                    }
+                },
+                'tags': {
+                    'kind': 'test'
                 }
-            },
-            'payload': {
-                'env': {
-                    'FOO': 'BAR'
-                }
-            },
-            'tags': {
-                'kind': 'test'
             }
-        }),
+        },
     ]
 
     def test_template_artifact(self):
         tg, label_to_taskid = self.make_taskgraph({
-            t.label: t for t in self.tasks
+            t['label']: Task(**t) for t in self.tasks[:]
         })
 
         fn = morph.apply_jsone_templates({'artifact': {'enabled': 1}})
         morphed = fn(tg, label_to_taskid)[0]
 
         self.assertEqual(len(morphed.tasks), 2)
 
         for t in morphed.tasks.values():
@@ -138,11 +148,34 @@ class TestApplyJSONeTemplates(MorphTestC
                 self.assertEqual(t.task['extra']['treeherder']['group'], 'tc')
                 self.assertEqual(t.task['extra']['treeherder']['symbol'], 'Ba')
                 self.assertEqual(t.task['payload']['env']['USE_ARTIFACT'], 1)
             else:
                 self.assertEqual(t.task['extra']['treeherder']['group'], 'tc')
                 self.assertEqual(t.task['extra']['treeherder']['symbol'], 't')
                 self.assertNotIn('USE_ARTIFACT', t.task['payload']['env'])
 
+    def test_template_env(self):
+        tg, label_to_taskid = self.make_taskgraph({
+            t['label']: Task(**t) for t in self.tasks[:]
+        })
+
+        fn = morph.apply_jsone_templates({'env': {'ENABLED': 1, 'FOO': 'BAZ'}})
+        morphed = fn(tg, label_to_taskid)[0]
+
+        self.assertEqual(len(morphed.tasks), 2)
+        for t in morphed.tasks.values():
+            self.assertEqual(len(t.task['payload']['env']), 2)
+            self.assertEqual(t.task['payload']['env']['ENABLED'], 1)
+            self.assertEqual(t.task['payload']['env']['FOO'], 'BAZ')
+
+        fn = morph.apply_jsone_templates({'env': {'ENABLED': 0}})
+        morphed = fn(tg, label_to_taskid)[0]
+
+        self.assertEqual(len(morphed.tasks), 2)
+        for t in morphed.tasks.values():
+            self.assertEqual(len(t.task['payload']['env']), 2)
+            self.assertEqual(t.task['payload']['env']['ENABLED'], 0)
+            self.assertEqual(t.task['payload']['env']['FOO'], 'BAZ')
+
 
 if __name__ == '__main__':
     main()
--- a/tools/tryselect/selectors/fuzzy.py
+++ b/tools/tryselect/selectors/fuzzy.py
@@ -103,17 +103,17 @@ class FuzzyParser(BaseTryParser):
                   "target tasks).",
           }],
         [['-p', '--parameters'],
          {'default': None,
           'help': "Use the given parameters.yml to generate tasks, "
                   "defaults to latest parameters.yml from mozilla-central",
           }],
     ]
-    templates = ['artifact']
+    templates = ['artifact', 'env']
 
 
 def run(cmd, cwd=None):
     is_win = platform.system() == 'Windows'
     return subprocess.call(cmd, cwd=cwd, shell=True if is_win else False)
 
 
 def run_fzf_install_script(fzf_path, bin_only=False):
--- a/tools/tryselect/templates.py
+++ b/tools/tryselect/templates.py
@@ -49,11 +49,25 @@ class Artifact(Template):
         try:
             if build.substs.get("MOZ_ARTIFACT_BUILDS"):
                 print("Artifact builds enabled, pass --no-artifact to disable")
                 return {'enabled': '1'}
         except BuildEnvironmentNotFoundException:
             pass
 
 
+class Environment(Template):
+
+    def add_arguments(self, parser):
+        parser.add_argument('--env', action='append', default=None,
+                            help='Set an environment variable, of the form FOO=BAR. '
+                                 'Can be passed in multiple times.')
+
+    def context(self, env, **kwargs):
+        if not env:
+            return
+        return dict(e.split('=', 1) for e in env)
+
+
 all_templates = {
     'artifact': Artifact,
+    'env': Environment,
 }
--- a/tools/tryselect/test/test_fuzzy.t
+++ b/tools/tryselect/test/test_fuzzy.t
@@ -16,8 +16,38 @@ Test fuzzy selector
   $ ./mach try fuzzy $testargs --full -q "'bar"
   Calculated try selector:
   {
     "tasks":[
       "test/bar-debug",
       "test/bar-opt"
     ]
   }
+
+Test templates
+
+  $ ./mach try fuzzy --no-push --artifact -q "'foo"
+  Calculated try selector:
+  {
+    "templates":{
+      "artifact":{
+        "enabled":"1"
+      }
+    },
+    "tasks":[
+      "test/foo-debug",
+      "test/foo-opt"
+    ]
+  }
+  $ ./mach try fuzzy $testargs --env FOO=1 --env BAR=baz -q "'foo"
+  Calculated try selector:
+  {
+    "templates":{
+      "env":{
+        "FOO":"1",
+        "BAR":"baz"
+      }
+    },
+    "tasks":[
+      "test/foo-debug",
+      "test/foo-opt"
+    ]
+  }