Bug 1380306 - Create a new 'try_task_config' method for scheduling tasks on try, r=dustin

This introduces a 'try_task_config' method of scheduling. En lieu of (or in addition to) try
syntax, you can now check in a file called 'try_task_config.json' to the root of the source
tree. The format is either a list of task labels, or dict where task labels are the keys.
Taskcluster will simply schedule any tasks that are listed there.

This file is primarily meant to be generated by tools (which don't exist yet), as the json
format is much easier for tools to generate or consume. These tools should use an in-memory
commit to add the file so it is automatically removed again after the push.

A server-side hook will be added in bug 1380357 to prevent this file from accidentally
landing on non-try trees.

MozReview-Commit-ID: 2zKfZXuuDhH

--HG--
extra : rebase_source : b5d5ff47c607288657418fd041603093f8c29e85
This commit is contained in:
Andrew Halberstadt 2017-06-27 13:33:20 -07:00
Родитель 96e02d5de5
Коммит d4babdee91
4 изменённых файлов: 112 добавлений и 9 удалений

Просмотреть файл

@ -252,3 +252,54 @@ Something Else?
If you make another change not described here that turns out to be simple or
common, please include an update to this file in your patch.
Schedule a Task on Try
----------------------
There are two methods for scheduling a task on try.
The first method is a command line string called ``try syntax`` which is passed
into the decision task via the commit message. An example try syntax might look
like:
.. parsed-literal::
try: -b o -p linux64 -u mochitest-1 -t none
This gets parsed by ``taskgraph.try_option_syntax:TryOptionSyntax`` and returns
a list of matching task labels. For more information see the
`TryServer wiki page <https://wiki.mozilla.org/Try>`_.
The second method uses a checked-in file called ``try_task_config.json`` which
lives at the root of the source dir. The format of this file is either a list
of task labels, or a JSON object where task labels make up the keys. For
example, the ``try_task_config.json`` file might look like:
.. parsed-literal::
[
"test-windows10-64/opt-web-platform-tests-12",
"test-windows7-32/opt-reftest-1",
"test-windows7-32/opt-reftest-2",
"test-windows7-32/opt-reftest-3",
"build-linux64/debug",
"source-test-mozlint-eslint"
]
Very simply, this will run any task label that gets passed in as well as their
dependencies. While it is possible to manually commit this file and push to
try, it is mainly meant to be a generation target for various trychooser tools.
A list of all possible task labels can be obtained by running:
.. parsed-literal::
$ ./mach taskgraph tasks
A list of task labels relevant to a tree (defaults to mozilla-central) can be
obtained with:
.. parsed-literal::
$ ./mach taskgraph target

Просмотреть файл

@ -34,7 +34,7 @@ ARTIFACTS_DIR = 'artifacts'
# See `taskcluster/docs/parameters.rst` for information on parameters.
PER_PROJECT_PARAMETERS = {
'try': {
'target_tasks_method': 'try_option_syntax',
'target_tasks_method': 'try_tasks',
# Always perform optimization. This makes it difficult to use try
# pushes to run a task that would otherwise be optimized, but is a
# compromise to avoid essentially disabling optimization in try.

Просмотреть файл

@ -5,6 +5,10 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, print_function, unicode_literals
import os
import json
from taskgraph import try_option_syntax
from taskgraph.util.attributes import match_run_on_projects
@ -48,8 +52,24 @@ def standard_filter(task, parameters):
)
@_target_task('try_option_syntax')
def target_tasks_try_option_syntax(full_task_graph, parameters):
def _try_task_config(full_task_graph, parameters):
task_config_file = os.path.join(os.getcwd(), 'try_task_config.json')
if not os.path.isfile(task_config_file):
return []
with open(task_config_file, 'r') as fh:
task_config = json.load(fh)
target_task_labels = []
for task in full_task_graph.tasks.itervalues():
if task.label in task_config:
target_task_labels.append(task.label)
return target_task_labels
def _try_option_syntax(full_task_graph, parameters):
"""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['message'], full_task_graph)
@ -97,6 +117,16 @@ def target_tasks_try_option_syntax(full_task_graph, parameters):
return target_tasks_labels
@_target_task('try_tasks')
def target_tasks_try(full_task_graph, parameters):
labels = _try_task_config(full_task_graph, parameters)
if 'try:' in parameters['message'] or not labels:
labels.extend(_try_option_syntax(full_task_graph, parameters))
return labels
@_target_task('default')
def target_tasks_default(full_task_graph, parameters):
"""Target the tasks which have indicated they should be run on this project

Просмотреть файл

@ -4,6 +4,7 @@
from __future__ import absolute_import, print_function, unicode_literals
import os
import unittest
from taskgraph import target_tasks
@ -53,7 +54,7 @@ class TestTargetTasks(unittest.TestCase):
self.assertTrue(self.default_matches(['integration'], 'mozilla-inbound'))
self.assertFalse(self.default_matches(['integration'], 'baobab'))
def test_default_relesae(self):
def test_default_release(self):
"""run_on_projects=[release] includes release projects"""
self.assertTrue(self.default_matches(['release'], 'mozilla-central'))
self.assertFalse(self.default_matches(['release'], 'mozilla-inbound'))
@ -65,22 +66,43 @@ class TestTargetTasks(unittest.TestCase):
self.assertFalse(self.default_matches([], 'mozilla-inbound'))
self.assertFalse(self.default_matches([], 'baobab'))
def test_try_option_syntax(self):
def test_try_tasks(self):
tasks = {
'a': Task(kind=None, label='a', attributes={}, task={}),
'b': Task(kind=None, label='b', attributes={'at-at': 'yep'}, task={}),
'c': Task(kind=None, label='c', attributes={}, task={}),
}
graph = Graph(nodes=set('ab'), edges=set())
graph = Graph(nodes=set('abc'), edges=set())
tg = TaskGraph(tasks, graph)
params = {'message': 'try me'}
method = target_tasks.get_method('try_tasks')
config = os.path.join(os.getcwd(), 'try_task_config.json')
orig_TryOptionSyntax = try_option_syntax.TryOptionSyntax
try:
try_option_syntax.TryOptionSyntax = FakeTryOptionSyntax
method = target_tasks.get_method('try_option_syntax')
self.assertEqual(method(tg, params), ['b'])
# no try specifier
self.assertEqual(method(tg, {'message': ''}), ['b'])
# try syntax only
self.assertEqual(method(tg, {'message': 'try: me'}), ['b'])
# try task config only
with open(config, 'w') as fh:
fh.write('["c"]')
self.assertEqual(method(tg, {'message': ''}), ['c'])
with open(config, 'w') as fh:
fh.write('{"c": {}}')
self.assertEqual(method(tg, {'message': ''}), ['c'])
# both syntax and config
self.assertEqual(set(method(tg, {'message': 'try: me'})), set(['b', 'c']))
finally:
try_option_syntax.TryOptionSyntax = orig_TryOptionSyntax
if os.path.isfile(config):
os.remove(config)
if __name__ == '__main__':