From 1fdddacae3930ff69fbd27e97e8353724a14b016 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Tue, 7 Nov 2017 10:22:35 -0500 Subject: [PATCH] Bug 1414919 - [taskgraph] Create a 'rebuild' morph template, r=dustin This template takes a single integer as input, and sets the 'task_duplicates' attribute on any tasks that were explicitly specified by try_task_config.json. This means dependent tasks or 'always_target' tasks will not be rebuilt. To support this template, the apply_jsone_templates morph now requires the entire try_task_config object instead of just the templates. MozReview-Commit-ID: DwxUtlC5VD5 --HG-- extra : rebase_source : c57a80ada2fc4591a5ce4c94965b8c9f02bb53b1 --- taskcluster/docs/try.rst | 2 + taskcluster/taskgraph/morph.py | 9 +++-- taskcluster/taskgraph/templates/rebuild.yml | 8 ++++ taskcluster/taskgraph/test/test_morph.py | 44 +++++++++++++++++++-- 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 taskcluster/taskgraph/templates/rebuild.yml diff --git a/taskcluster/docs/try.rst b/taskcluster/docs/try.rst index 1790cb065117..adeeaa2f1fd4 100644 --- a/taskcluster/docs/try.rst +++ b/taskcluster/docs/try.rst @@ -114,6 +114,8 @@ The context available to the JSON-e render contains attributes from the { "attributes": task.attributes, "kind": task.kind, + "label": task.label, + "target_tasks": [], "task": task.task, "taskId": task.task_id, "input": ... diff --git a/taskcluster/taskgraph/morph.py b/taskcluster/taskgraph/morph.py index d5fe55e1a421..5cf6a7d12446 100644 --- a/taskcluster/taskgraph/morph.py +++ b/taskcluster/taskgraph/morph.py @@ -253,8 +253,9 @@ class apply_jsone_templates(object): """ template_dir = os.path.join(here, 'templates') - def __init__(self, templates): - self.templates = templates + def __init__(self, try_task_config): + self.templates = try_task_config.get('templates') + self.target_tasks = try_task_config.get('tasks') def __call__(self, taskgraph, label_to_taskid): if not self.templates: @@ -270,6 +271,8 @@ class apply_jsone_templates(object): 'input': self.templates[template], # The following context differs from action tasks 'attributes': task.attributes, + 'label': task.label, + 'target_tasks': self.target_tasks, } template_path = os.path.join(self.template_dir, template + '.yml') @@ -290,7 +293,7 @@ def morph(taskgraph, label_to_taskid, parameters): add_s3_uploader_task, ] if parameters['try_mode'] == 'try_task_config': - morphs.append(apply_jsone_templates(parameters['try_task_config'].get('templates'))) + morphs.append(apply_jsone_templates(parameters['try_task_config'])) for m in morphs: taskgraph, label_to_taskid = m(taskgraph, label_to_taskid) diff --git a/taskcluster/taskgraph/templates/rebuild.yml b/taskcluster/taskgraph/templates/rebuild.yml new file mode 100644 index 000000000000..7b032bfe217e --- /dev/null +++ b/taskcluster/taskgraph/templates/rebuild.yml @@ -0,0 +1,8 @@ +--- +$if: label in target_tasks +then: + attributes: + $merge: + - $eval: attributes + - task_duplicates: + $eval: input diff --git a/taskcluster/taskgraph/test/test_morph.py b/taskcluster/taskgraph/test/test_morph.py index b4d43f979b81..b9080191bea9 100644 --- a/taskcluster/taskgraph/test/test_morph.py +++ b/taskcluster/taskgraph/test/test_morph.py @@ -138,7 +138,12 @@ class TestApplyJSONeTemplates(MorphTestCase): t['label']: Task(**t) for t in self.tasks[:] }) - fn = morph.apply_jsone_templates({'artifact': {'enabled': 1}}) + try_task_config = { + 'templates': { + 'artifact': {'enabled': 1} + }, + } + fn = morph.apply_jsone_templates(try_task_config) morphed = fn(tg, label_to_taskid)[0] self.assertEqual(len(morphed.tasks), 2) @@ -158,7 +163,15 @@ class TestApplyJSONeTemplates(MorphTestCase): t['label']: Task(**t) for t in self.tasks[:] }) - fn = morph.apply_jsone_templates({'env': {'ENABLED': 1, 'FOO': 'BAZ'}}) + try_task_config = { + 'templates': { + 'env': { + 'ENABLED': 1, + 'FOO': 'BAZ', + } + }, + } + fn = morph.apply_jsone_templates(try_task_config) morphed = fn(tg, label_to_taskid)[0] self.assertEqual(len(morphed.tasks), 2) @@ -167,7 +180,10 @@ class TestApplyJSONeTemplates(MorphTestCase): self.assertEqual(t.task['payload']['env']['ENABLED'], 1) self.assertEqual(t.task['payload']['env']['FOO'], 'BAZ') - fn = morph.apply_jsone_templates({'env': {'ENABLED': 0}}) + try_task_config['templates']['env'] = { + 'ENABLED': 0, + } + fn = morph.apply_jsone_templates(try_task_config) morphed = fn(tg, label_to_taskid)[0] self.assertEqual(len(morphed.tasks), 2) @@ -176,6 +192,28 @@ class TestApplyJSONeTemplates(MorphTestCase): self.assertEqual(t.task['payload']['env']['ENABLED'], 0) self.assertEqual(t.task['payload']['env']['FOO'], 'BAZ') + def test_template_rebuild(self): + tg, label_to_taskid = self.make_taskgraph({ + t['label']: Task(**t) for t in self.tasks[:] + }) + + try_task_config = { + 'tasks': ['b'], + 'templates': { + 'rebuild': 4, + }, + } + fn = morph.apply_jsone_templates(try_task_config) + tasks = fn(tg, label_to_taskid)[0].tasks.values() + self.assertEqual(len(tasks), 2) + + for t in tasks: + if t.label == 'a': + self.assertNotIn('task_duplicates', t.attributes) + elif t.label == 'b': + self.assertIn('task_duplicates', t.attributes) + self.assertEqual(t.attributes['task_duplicates'], 4) + if __name__ == '__main__': main()