diff --git a/src/taskgraph/morph.py b/src/taskgraph/morph.py --- a/src/taskgraph/morph.py +++ b/src/taskgraph/morph.py @@ -164,14 +164,80 @@ logger.info('Added {} index tasks'.format(len(added))) return taskgraph, label_to_taskid +def _get_morph_url(): + """ + Guess a URL for the current file, for source metadata for created tasks. + + If we checked out the taskgraph code with run-task in the decision task, + we can use TASKGRAPH_* to find the right version, which covers the + existing use case. + """ + taskgraph_repo = os.environ.get( + 'TASKGRAPH_HEAD_REPOSITORY', 'https://hg.mozilla.org/ci/taskgraph' + ) + taskgraph_rev = os.environ.get('TASKGRAPH_HEAD_REV', 'default') + return '{}/raw-file/{}/src/taskgraph/morph.py'.format(taskgraph_repo, taskgraph_rev) + + +def add_code_review_task(taskgraph, label_to_taskid, parameters, graph_config): + logger.debug('Morphing: adding index tasks') + + diff = parameters.get('phabricator_diff') + if not diff: + return taskgraph, label_to_taskid + + code_review_tasks = {} + for label, task in taskgraph.tasks.iteritems(): + if task.attributes.get('code-review'): + code_review_tasks[task.label] = task.task_id + + if code_review_tasks: + code_review_task_def = { + 'provisionerId': 'built-in', + 'workerType': 'succeed', + 'dependencies': sorted(code_review_tasks.values()), + # This option permits to run the task + # regardless of the dependencies tasks exit status + # as we are interested in the task failures + 'requires': 'all-resolved', + 'created': {'relative-datestamp': '0 seconds'}, + 'deadline': {'relative-datestamp': '1 day'}, + # no point existing past the parent task's deadline + 'expires': {'relative-datestamp': '1 day'}, + 'metadata': { + 'name': 'code-review', + 'description': "List all issues found in static analysis and linting tasks", + 'owner': parameters['owner'], + 'source': _get_morph_url(), + }, + 'scopes': [], + 'payload': {}, + 'routes': ['project.relman.codereview.v1.try_ending'], + 'extra': { + 'code-review': { + 'phabricator-diff': diff, + } + } + } + task = Task(kind='misc', label='code-review', attributes={}, task=code_review_task_def, + dependencies=code_review_tasks) + task.task_id = slugid() + taskgraph, label_to_taskid = amend_taskgraph( + taskgraph, label_to_taskid, [task]) + logger.info('Added code review task.') + + return taskgraph, label_to_taskid + + def morph(taskgraph, label_to_taskid, parameters, graph_config): """Apply all morphs""" morphs = [ add_index_tasks, + add_code_review_task, ] for m in morphs: taskgraph, label_to_taskid = m(taskgraph, label_to_taskid, parameters, graph_config) return taskgraph, label_to_taskid diff --git a/src/taskgraph/parameters.py b/src/taskgraph/parameters.py --- a/src/taskgraph/parameters.py +++ b/src/taskgraph/parameters.py @@ -8,18 +8,22 @@ import json import time from datetime import datetime +from six import text_type + from taskgraph.util.schema import validate_schema from taskgraph.util.vcs import calculate_head_rev, get_repo_path, get_repository_type from taskgraph.util.memoize import memoize from taskgraph.util.readonlydict import ReadOnlyDict from voluptuous import ( ALLOW_EXTRA, Required, + Optional, Schema, + Any, ) class ParameterMismatch(Exception): """Raised when a parameters.yml has extra or missing parameters.""" @@ -59,10 +63,11 @@ Required('pushdate'): int, Required('pushlog_id'): basestring, Required('repository_type'): basestring, Required('target_tasks_method'): basestring, Required('tasks_for'): basestring, + Optional('phabricator_diff'): Any(None, text_type), }) def extend_parameters_schema(schema): """ diff --git a/src/taskgraph/target_tasks.py b/src/taskgraph/target_tasks.py --- a/src/taskgraph/target_tasks.py +++ b/src/taskgraph/target_tasks.py @@ -54,9 +54,18 @@ via the `run_on_projects` attributes.""" return [l for l, t in full_task_graph.tasks.iteritems() if standard_filter(t, parameters)] +@_target_task('codereview') +def target_tasks_codereview(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) + and t.attributes.get('code-review')] + + @_target_task('nothing') def target_tasks_nothing(full_task_graph, parameters, graph_config): """Select nothing, for DONTBUILD pushes""" return [] diff --git a/src/taskgraph/test/test_parameters.py b/src/taskgraph/test/test_parameters.py --- a/src/taskgraph/test/test_parameters.py +++ b/src/taskgraph/test/test_parameters.py @@ -36,10 +36,12 @@ 'pushdate': 0, 'pushlog_id': '0', 'repository_type': 'hg', 'target_tasks_method': 'default', 'tasks_for': 'github-push', + 'phabricator_diff': None, + 'broken': None, } def test_Parameters_immutable(self): p = Parameters(**self.vals) diff --git a/taskcluster/ci/tests/kind.yml b/taskcluster/ci/tests/kind.yml --- a/taskcluster/ci/tests/kind.yml +++ b/taskcluster/ci/tests/kind.yml @@ -10,10 +10,11 @@ - taskgraph.transforms.task:transforms job-defaults: attributes: retrigger: true + code-review: true worker-type: t-linux worker: docker-image: {in-tree: python2.7} max-run-time: 3600 treeherder: