зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1383880: parse try config during the decision task; r=ahal
This sets the try_mode property, and parses the try message (if given), early in the decision task and puts the results into the parameters. The proximate need is to set optimze_target_tasks for some try modes and not others. This also replaces the existing logic for parsing messages for certain kinds, and makes the distinction between the different try modes a little clearer. MozReview-Commit-ID: AXJEGLh6pEV --HG-- extra : rebase_source : 03a10610aa3337269fe76a1196bb9b1665e1ab20 extra : source : b53ff084c2d7968a1d9864d1343f2d9381fb652b
This commit is contained in:
Родитель
8009d846d4
Коммит
7e1b6b079a
|
@ -21,5 +21,3 @@ jobs-from:
|
|||
- linux.yml
|
||||
- macosx.yml
|
||||
- windows.yml
|
||||
|
||||
parse-commit: taskgraph.try_option_syntax:parse_message
|
||||
|
|
|
@ -9,5 +9,3 @@ transforms:
|
|||
- taskgraph.transforms.job:transforms
|
||||
- taskgraph.transforms.coalesce:transforms
|
||||
- taskgraph.transforms.task:transforms
|
||||
|
||||
parse-commit: taskgraph.try_option_syntax:parse_message
|
||||
|
|
|
@ -32,12 +32,3 @@ task-graph generation infrastructure expects.
|
|||
The ``transforms`` key in ``kind.yml`` is further documented in
|
||||
:doc:`transforms`. For more information on how all of this works, consult the
|
||||
docstrings and comments in the source code itself.
|
||||
|
||||
Try option syntax
|
||||
-----------------
|
||||
|
||||
The ``parse-commit`` optional field specified in ``kind.yml`` links to a
|
||||
function to parse the command line options in the ``--message`` mach parameter.
|
||||
Currently, the only valid value is ``taskgraph.try_option_syntax:parse_message``.
|
||||
The parsed arguments are stored in ``config.config['args']``, it corresponds
|
||||
to the same object returned by ``parse_args`` from ``argparse`` Python module.
|
||||
|
|
|
@ -79,6 +79,22 @@ Tree Information
|
|||
associated with this tree. This dictates the names of resources used in the
|
||||
generated tasks, and those tasks will fail if it is incorrect.
|
||||
|
||||
Try Configuration
|
||||
-----------------
|
||||
|
||||
``try_mode``
|
||||
The mode in which a try push is operating. This can be one of
|
||||
``"try_task_config"``, ``"try_option_syntax"``, or ``None`` meaning no try
|
||||
input was provided.
|
||||
|
||||
``try_options``
|
||||
The arguments given as try syntax (as a dictionary), or ``None`` if
|
||||
``try_mode`` is not ``try_option_syntax``.
|
||||
|
||||
``try_task_config``
|
||||
The contents of the ``try_task_config.json`` file, or ``None`` if
|
||||
``try_mode`` is not ``try_task_config``.
|
||||
|
||||
Target Set
|
||||
----------
|
||||
|
||||
|
@ -93,10 +109,6 @@ syntax or reading a project-specific configuration file).
|
|||
apply. This is usually defined internally, as filters are typically
|
||||
global.
|
||||
|
||||
``target_task_labels``
|
||||
List of task labels to select. Labels not listed will be filtered out.
|
||||
Enabled on try only.
|
||||
|
||||
``target_tasks_method``
|
||||
The method to use to determine the target task set. This is the suffix of
|
||||
one of the functions in ``taskcluster/taskgraph/target_tasks.py``.
|
||||
|
@ -112,12 +124,3 @@ syntax or reading a project-specific configuration file).
|
|||
partial updates for nightly releases.
|
||||
Suitable contents can be generated with ``mach release-history``,
|
||||
which will print to the console by default.
|
||||
|
||||
Morphed Set
|
||||
-----------
|
||||
|
||||
``morph_templates``
|
||||
Dict of JSON-e templates to apply to each task, keyed by template name.
|
||||
Values are extra context that will be available to the template under the
|
||||
``input.<template>`` key. Available templates live in
|
||||
``taskcluster/taskgraph/templates``. Enabled on try only.
|
||||
|
|
|
@ -17,6 +17,7 @@ from .generator import TaskGraphGenerator
|
|||
from .create import create_tasks
|
||||
from .parameters import Parameters
|
||||
from .taskgraph import TaskGraph
|
||||
from .try_option_syntax import parse_message
|
||||
from .actions import render_actions_json
|
||||
from taskgraph.util.partials import populate_release_history
|
||||
from . import GECKO
|
||||
|
@ -36,10 +37,6 @@ ARTIFACTS_DIR = 'artifacts'
|
|||
PER_PROJECT_PARAMETERS = {
|
||||
'try': {
|
||||
'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.
|
||||
'optimize_target_tasks': True,
|
||||
# By default, the `try_option_syntax` `target_task_method` ignores this
|
||||
# parameter, and enables/disables nightlies depending whether
|
||||
# `--include-nightly` is specified in the commit message.
|
||||
|
@ -168,8 +165,6 @@ def get_decision_parameters(options):
|
|||
'check_servo',
|
||||
'target_tasks_method',
|
||||
]
|
||||
parameters['target_task_labels'] = []
|
||||
parameters['morph_templates'] = {}
|
||||
|
||||
# owner must be an email, but sometimes (e.g., for ffxbld) it is not, in which
|
||||
# case, fake it
|
||||
|
@ -191,15 +186,6 @@ def get_decision_parameters(options):
|
|||
"for this project".format(project, __file__))
|
||||
parameters.update(PER_PROJECT_PARAMETERS['default'])
|
||||
|
||||
# morph_templates and target_task_labels are only used on try, so don't
|
||||
# bother loading them elsewhere
|
||||
task_config_file = os.path.join(GECKO, 'try_task_config.json')
|
||||
if project == 'try' and os.path.isfile(task_config_file):
|
||||
with open(task_config_file, 'r') as fh:
|
||||
task_config = json.load(fh)
|
||||
parameters['morph_templates'] = task_config.get('templates', {})
|
||||
parameters['target_task_labels'] = task_config.get('tasks')
|
||||
|
||||
# `target_tasks_method` has higher precedence than `project` parameters
|
||||
if options.get('target_tasks_method'):
|
||||
parameters['target_tasks_method'] = options['target_tasks_method']
|
||||
|
@ -211,6 +197,42 @@ def get_decision_parameters(options):
|
|||
if 'nightly' in parameters.get('target_tasks_method', ''):
|
||||
parameters['release_history'] = populate_release_history('Firefox', project)
|
||||
|
||||
# if try_task_config.json is present, load it
|
||||
task_config_file = os.path.join(os.getcwd(), 'try_task_config.json')
|
||||
|
||||
# load try settings
|
||||
parameters['try_mode'] = None
|
||||
if os.path.isfile(task_config_file):
|
||||
parameters['try_mode'] = 'try_task_config'
|
||||
with open(task_config_file, 'r') as fh:
|
||||
parameters['try_task_config'] = json.load(fh)
|
||||
else:
|
||||
parameters['try_task_config'] = None
|
||||
|
||||
if 'try:' in parameters['message']:
|
||||
parameters['try_mode'] = 'try_option_syntax'
|
||||
args = parse_message(parameters['message'])
|
||||
parameters['try_options'] = args
|
||||
else:
|
||||
parameters['try_options'] = None
|
||||
|
||||
parameters['optimize_target_tasks'] = {
|
||||
# The user has explicitly requested a set of jobs, so run them all
|
||||
# regardless of optimization. Their dependencies can be optimized,
|
||||
# though.
|
||||
'try_task_config': False,
|
||||
|
||||
# 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.
|
||||
# to run tasks that would otherwise be optimized, ues try_task_config.
|
||||
'try_option_syntax': True,
|
||||
|
||||
# since no try jobs have been specified, the standard target task will
|
||||
# be applied, and tasks should be optimized out of that.
|
||||
None: True,
|
||||
}[parameters['try_mode']]
|
||||
|
||||
return Parameters(parameters)
|
||||
|
||||
|
||||
|
|
|
@ -42,12 +42,6 @@ class Kind(object):
|
|||
loader = self._get_loader()
|
||||
config = copy.deepcopy(self.config)
|
||||
|
||||
if 'parse-commit' in self.config:
|
||||
parse_commit = find_object(config['parse-commit'])
|
||||
config['args'] = parse_commit(parameters['message'])
|
||||
else:
|
||||
config['args'] = None
|
||||
|
||||
kind_dependencies = config.get('kind-dependencies', [])
|
||||
kind_dependencies_tasks = [task for task in loaded_tasks
|
||||
if task.kind in kind_dependencies]
|
||||
|
|
|
@ -283,8 +283,10 @@ def morph(taskgraph, label_to_taskid, parameters):
|
|||
morphs = [
|
||||
add_index_tasks,
|
||||
add_s3_uploader_task,
|
||||
apply_jsone_templates(parameters.get('morph_templates')),
|
||||
]
|
||||
if parameters['try_mode'] == 'try_task_config':
|
||||
morphs.append(apply_jsone_templates(parameters['try_task_config'].get('templates')))
|
||||
|
||||
for m in morphs:
|
||||
taskgraph, label_to_taskid = m(taskgraph, label_to_taskid)
|
||||
return taskgraph, label_to_taskid
|
||||
|
|
|
@ -21,7 +21,6 @@ PARAMETER_NAMES = set([
|
|||
'include_nightly',
|
||||
'level',
|
||||
'message',
|
||||
'morph_templates',
|
||||
'moz_build_date',
|
||||
'optimize_target_tasks',
|
||||
'owner',
|
||||
|
@ -29,13 +28,10 @@ PARAMETER_NAMES = set([
|
|||
'pushdate',
|
||||
'pushlog_id',
|
||||
'release_history',
|
||||
'target_task_labels',
|
||||
'target_tasks_method',
|
||||
])
|
||||
|
||||
TRY_ONLY_PARAMETERS = set([
|
||||
'morph_templates',
|
||||
'target_task_labels',
|
||||
'try_mode',
|
||||
'try_options',
|
||||
'try_task_config',
|
||||
])
|
||||
|
||||
|
||||
|
@ -45,7 +41,7 @@ class Parameters(ReadOnlyDict):
|
|||
names = set(self)
|
||||
msg = []
|
||||
|
||||
missing = PARAMETER_NAMES - TRY_ONLY_PARAMETERS - names
|
||||
missing = PARAMETER_NAMES - names
|
||||
if missing:
|
||||
msg.append("missing parameters: " + ", ".join(missing))
|
||||
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from taskgraph import try_option_syntax
|
||||
from taskgraph.util.attributes import match_run_on_projects
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
_target_task_methods = {}
|
||||
|
||||
|
||||
|
@ -53,17 +50,14 @@ def standard_filter(task, parameters):
|
|||
|
||||
|
||||
def _try_task_config(full_task_graph, parameters):
|
||||
if not parameters.get('target_task_labels'):
|
||||
return []
|
||||
|
||||
return [t.label for t in full_task_graph.tasks.itervalues()
|
||||
if t.label in parameters['target_task_labels']]
|
||||
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):
|
||||
"""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)
|
||||
options = try_option_syntax.TryOptionSyntax(parameters, full_task_graph)
|
||||
target_tasks_labels = [t.label for t in full_task_graph.tasks.itervalues()
|
||||
if options.task_matches(t)]
|
||||
|
||||
|
@ -110,19 +104,23 @@ def _try_option_syntax(full_task_graph, parameters):
|
|||
|
||||
@_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
|
||||
try_mode = parameters['try_mode']
|
||||
if try_mode == 'try_task_config':
|
||||
return _try_task_config(full_task_graph, parameters)
|
||||
elif try_mode == 'try_option_syntax':
|
||||
return _try_option_syntax(full_task_graph, parameters)
|
||||
else:
|
||||
# With no try mode, we would like to schedule everything (following
|
||||
# run_on_projects) and let optimization trim it down. But optimization
|
||||
# isn't yet up to the task, so instead we use try_option_syntax with
|
||||
# an empty message (which basically just schedules `-j`objs)
|
||||
return _try_option_syntax(full_task_graph, parameters)
|
||||
|
||||
|
||||
@_target_task('default')
|
||||
def target_tasks_default(full_task_graph, parameters):
|
||||
"""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)]
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import unittest
|
|||
import tempfile
|
||||
|
||||
from taskgraph import decision
|
||||
from mozunit import main
|
||||
from mozunit import main, MockedOpen
|
||||
|
||||
|
||||
class TestDecision(unittest.TestCase):
|
||||
|
@ -44,5 +44,53 @@ class TestDecision(unittest.TestCase):
|
|||
decision.ARTIFACTS_DIR = 'artifacts'
|
||||
|
||||
|
||||
class TestGetDecisionParameters(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.options = {
|
||||
'base_repository': 'https://hg.mozilla.org/mozilla-unified',
|
||||
'head_repository': 'https://hg.mozilla.org/mozilla-central',
|
||||
'head_rev': 'abcd',
|
||||
'head_ref': 'ef01',
|
||||
'message': '',
|
||||
'project': 'mozilla-central',
|
||||
'pushlog_id': 143,
|
||||
'pushdate': 1503691511,
|
||||
'owner': 'nobody@mozilla.com',
|
||||
'level': 3,
|
||||
}
|
||||
|
||||
def test_simple_options(self):
|
||||
params = decision.get_decision_parameters(self.options)
|
||||
self.assertEqual(params['pushlog_id'], 143)
|
||||
self.assertEqual(params['build_date'], 1503691511)
|
||||
self.assertEqual(params['moz_build_date'], '20170825200511')
|
||||
self.assertEqual(params['try_mode'], None)
|
||||
self.assertEqual(params['try_options'], None)
|
||||
self.assertEqual(params['try_task_config'], None)
|
||||
|
||||
def test_no_email_owner(self):
|
||||
self.options['owner'] = 'ffxbld'
|
||||
params = decision.get_decision_parameters(self.options)
|
||||
self.assertEqual(params['owner'], 'ffxbld@noreply.mozilla.org')
|
||||
|
||||
def test_try_options(self):
|
||||
self.options['message'] = 'try: -b do -t all'
|
||||
params = decision.get_decision_parameters(self.options)
|
||||
self.assertEqual(params['try_mode'], 'try_option_syntax')
|
||||
self.assertEqual(params['try_options']['build_types'], 'do')
|
||||
self.assertEqual(params['try_options']['unittests'], 'all')
|
||||
self.assertEqual(params['try_task_config'], None)
|
||||
|
||||
def test_try_task_config(self):
|
||||
ttc = {'tasks': ['a', 'b'], 'templates': {}}
|
||||
ttc_file = os.path.join(os.getcwd(), 'try_task_config.json')
|
||||
with MockedOpen({ttc_file: json.dumps(ttc)}):
|
||||
params = decision.get_decision_parameters(self.options)
|
||||
self.assertEqual(params['try_mode'], 'try_task_config')
|
||||
self.assertEqual(params['try_options'], None)
|
||||
self.assertEqual(params['try_task_config'], ttc)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -59,6 +59,7 @@ class TestGenerator(unittest.TestCase):
|
|||
parameters = {
|
||||
'_kinds': kinds,
|
||||
'target_tasks_method': 'test_method',
|
||||
'try_mode': None,
|
||||
}
|
||||
|
||||
return WithFakeKind('/root', parameters)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import contextlib
|
||||
import unittest
|
||||
|
||||
from taskgraph import target_tasks
|
||||
|
@ -65,43 +66,56 @@ class TestTargetTasks(unittest.TestCase):
|
|||
self.assertFalse(self.default_matches([], 'mozilla-inbound'))
|
||||
self.assertFalse(self.default_matches([], 'baobab'))
|
||||
|
||||
def test_try_tasks(self):
|
||||
def make_task_graph(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={}),
|
||||
'c': Task(kind=None, label='c', attributes={'run_on_projects': ['try']}, task={}),
|
||||
}
|
||||
graph = Graph(nodes=set('abc'), edges=set())
|
||||
tg = TaskGraph(tasks, graph)
|
||||
|
||||
method = target_tasks.get_method('try_tasks')
|
||||
params = {
|
||||
'message': '',
|
||||
'target_task_labels': [],
|
||||
}
|
||||
return TaskGraph(tasks, graph)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def fake_TryOptionSyntax(self):
|
||||
orig_TryOptionSyntax = try_option_syntax.TryOptionSyntax
|
||||
try:
|
||||
try_option_syntax.TryOptionSyntax = FakeTryOptionSyntax
|
||||
|
||||
# no try specifier
|
||||
self.assertEqual(method(tg, params), ['b'])
|
||||
|
||||
# try syntax only
|
||||
params['message'] = 'try: me'
|
||||
self.assertEqual(method(tg, params), ['b'])
|
||||
|
||||
# try task config only
|
||||
params['message'] = ''
|
||||
params['target_task_labels'] = ['c']
|
||||
self.assertEqual(method(tg, params), ['c'])
|
||||
|
||||
# both syntax and config
|
||||
params['message'] = 'try: me'
|
||||
self.assertEqual(set(method(tg, params)), set(['b', 'c']))
|
||||
yield
|
||||
finally:
|
||||
try_option_syntax.TryOptionSyntax = orig_TryOptionSyntax
|
||||
|
||||
def test_just_try_it(self):
|
||||
"try_mode = None runs try optoin syntax with no options"
|
||||
tg = self.make_task_graph()
|
||||
method = target_tasks.get_method('try_tasks')
|
||||
with self.fake_TryOptionSyntax():
|
||||
params = {
|
||||
'try_mode': None,
|
||||
'message': '',
|
||||
}
|
||||
self.assertEqual(method(tg, params), ['b'])
|
||||
|
||||
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'])
|
||||
|
||||
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'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
import unittest
|
||||
|
||||
from taskgraph.try_option_syntax import TryOptionSyntax
|
||||
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
|
||||
|
@ -63,145 +63,136 @@ graph_with_jobs = TaskGraph(tasks, Graph(set(tasks), set()))
|
|||
|
||||
class TestTryOptionSyntax(unittest.TestCase):
|
||||
|
||||
def test_empty_message(self):
|
||||
"Given an empty message, it should return an empty value"
|
||||
tos = TryOptionSyntax('', graph_with_jobs)
|
||||
self.assertEqual(tos.build_types, [])
|
||||
self.assertEqual(tos.jobs, [])
|
||||
self.assertEqual(tos.unittests, [])
|
||||
self.assertEqual(tos.talos, [])
|
||||
self.assertEqual(tos.platforms, [])
|
||||
self.assertEqual(tos.trigger_tests, 0)
|
||||
self.assertEqual(tos.talos_trigger_tests, 0)
|
||||
self.assertEqual(tos.env, [])
|
||||
self.assertFalse(tos.profile)
|
||||
self.assertIsNone(tos.tag)
|
||||
self.assertFalse(tos.no_retry)
|
||||
|
||||
def test_message_without_try(self):
|
||||
"Given a non-try message, it should return an empty value"
|
||||
tos = TryOptionSyntax('Bug 1234: frobnicte the foo', graph_with_jobs)
|
||||
self.assertEqual(tos.build_types, [])
|
||||
self.assertEqual(tos.jobs, [])
|
||||
self.assertEqual(tos.unittests, [])
|
||||
self.assertEqual(tos.talos, [])
|
||||
self.assertEqual(tos.platforms, [])
|
||||
self.assertEqual(tos.trigger_tests, 0)
|
||||
self.assertEqual(tos.talos_trigger_tests, 0)
|
||||
self.assertEqual(tos.env, [])
|
||||
self.assertFalse(tos.profile)
|
||||
self.assertIsNone(tos.tag)
|
||||
self.assertFalse(tos.no_retry)
|
||||
|
||||
def test_unknown_args(self):
|
||||
"unknown arguments are ignored"
|
||||
tos = TryOptionSyntax('try: --doubledash -z extra', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --doubledash -z extra')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
# equilvant to "try:"..
|
||||
self.assertEqual(tos.build_types, [])
|
||||
self.assertEqual(tos.jobs, None)
|
||||
|
||||
def test_apostrophe_in_message(self):
|
||||
"apostrophe does not break parsing"
|
||||
tos = TryOptionSyntax('Increase spammy log\'s log level. try: -b do', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('Increase spammy log\'s log level. try: -b do')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['debug', 'opt'])
|
||||
|
||||
def test_b_do(self):
|
||||
"-b do should produce both build_types"
|
||||
tos = TryOptionSyntax('try: -b do', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -b do')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['debug', 'opt'])
|
||||
|
||||
def test_b_d(self):
|
||||
"-b d should produce build_types=['debug']"
|
||||
tos = TryOptionSyntax('try: -b d', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -b d')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['debug'])
|
||||
|
||||
def test_b_o(self):
|
||||
"-b o should produce build_types=['opt']"
|
||||
tos = TryOptionSyntax('try: -b o', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -b o')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['opt'])
|
||||
|
||||
def test_build_o(self):
|
||||
"--build o should produce build_types=['opt']"
|
||||
tos = TryOptionSyntax('try: --build o', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --build o')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['opt'])
|
||||
|
||||
def test_b_dx(self):
|
||||
"-b dx should produce build_types=['debug'], silently ignoring the x"
|
||||
tos = TryOptionSyntax('try: -b dx', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -b dx')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.build_types), ['debug'])
|
||||
|
||||
def test_j_job(self):
|
||||
"-j somejob sets jobs=['somejob']"
|
||||
tos = TryOptionSyntax('try: -j somejob', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -j somejob')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.jobs), ['somejob'])
|
||||
|
||||
def test_j_jobs(self):
|
||||
"-j job1,job2 sets jobs=['job1', 'job2']"
|
||||
tos = TryOptionSyntax('try: -j job1,job2', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -j job1,job2')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.jobs), ['job1', 'job2'])
|
||||
|
||||
def test_j_all(self):
|
||||
"-j all sets jobs=None"
|
||||
tos = TryOptionSyntax('try: -j all', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -j all')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.jobs, None)
|
||||
|
||||
def test_j_twice(self):
|
||||
"-j job1 -j job2 sets jobs=job1, job2"
|
||||
tos = TryOptionSyntax('try: -j job1 -j job2', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -j job1 -j job2')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.jobs), sorted(['job1', 'job2']))
|
||||
|
||||
def test_p_all(self):
|
||||
"-p all sets platforms=None"
|
||||
tos = TryOptionSyntax('try: -p all', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -p all')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.platforms, None)
|
||||
|
||||
def test_p_linux(self):
|
||||
"-p linux sets platforms=['linux', 'linux-l10n']"
|
||||
tos = TryOptionSyntax('try: -p linux', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -p linux')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.platforms, ['linux', 'linux-l10n'])
|
||||
|
||||
def test_p_linux_win32(self):
|
||||
"-p linux,win32 sets platforms=['linux', 'linux-l10n', 'win32']"
|
||||
tos = TryOptionSyntax('try: -p linux,win32', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -p linux,win32')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.platforms), ['linux', 'linux-l10n', 'win32'])
|
||||
|
||||
def test_p_expands_ridealongs(self):
|
||||
"-p linux,linux64 includes the RIDEALONG_BUILDS"
|
||||
tos = TryOptionSyntax('try: -p linux,linux64', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -p linux,linux64')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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=[]"
|
||||
tos = TryOptionSyntax('try: -u none', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u none')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), [])
|
||||
|
||||
def test_u_all(self):
|
||||
"-u all sets unittests=[..whole list..]"
|
||||
tos = TryOptionSyntax('try: -u all', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u all')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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]"
|
||||
tos = TryOptionSyntax('try: -u mochitest-webgl', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u mochitest-webgl')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([{'test': 'mochitest-webgl'}]))
|
||||
|
||||
def test_u_alias(self):
|
||||
"-u mochitest-gl sets unittests=[mochitest-webgl]"
|
||||
tos = TryOptionSyntax('try: -u mochitest-gl', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u mochitest-gl')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([{'test': 'mochitest-webgl'}]))
|
||||
|
||||
def test_u_multi_alias(self):
|
||||
"-u e10s sets unittests=[all e10s unittests]"
|
||||
tos = TryOptionSyntax('try: -u e10s', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u e10s')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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"
|
||||
tos = TryOptionSyntax('try: -u mochitest-webgl,gtest', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u mochitest-webgl,gtest')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([
|
||||
{'test': 'mochitest-webgl'},
|
||||
{'test': 'gtest'},
|
||||
|
@ -209,21 +200,24 @@ class TestTryOptionSyntax(unittest.TestCase):
|
|||
|
||||
def test_u_chunks(self):
|
||||
"-u gtest-3,gtest-4 selects the third and fourth chunk of gtest"
|
||||
tos = TryOptionSyntax('try: -u gtest-3,gtest-4', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest-3,gtest-4')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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"
|
||||
tos = TryOptionSyntax('try: -u gtest[linux]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest[linux]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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"
|
||||
tos = TryOptionSyntax('try: -u gtest[linux,win32]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest[linux,win32]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([
|
||||
{'test': 'gtest', 'platforms': ['linux', 'win32']},
|
||||
]))
|
||||
|
@ -231,7 +225,8 @@ class TestTryOptionSyntax(unittest.TestCase):
|
|||
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"""
|
||||
tos = TryOptionSyntax('try: -u gtest[Ubuntu]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest[Ubuntu]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([
|
||||
{'test': 'gtest', 'platforms': ['linux32', 'linux64', 'linux64-asan',
|
||||
'linux64-stylo-disabled', 'linux64-stylo-sequential']},
|
||||
|
@ -239,7 +234,8 @@ class TestTryOptionSyntax(unittest.TestCase):
|
|||
|
||||
def test_u_platforms_negated(self):
|
||||
"-u gtest[-linux] selects all platforms but linux for gtest"
|
||||
tos = TryOptionSyntax('try: -u gtest[-linux]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest[-linux]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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']
|
||||
|
@ -247,83 +243,99 @@ class TestTryOptionSyntax(unittest.TestCase):
|
|||
|
||||
def test_u_platforms_negated_pretty(self):
|
||||
"-u gtest[Ubuntu,-x64] selects just linux for gtest"
|
||||
tos = TryOptionSyntax('try: -u gtest[Ubuntu,-x64]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest[Ubuntu,-x64]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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"
|
||||
tos = TryOptionSyntax('try: -u gtest-1[linux,win32]', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -u gtest-1[linux,win32]')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.unittests), sorted([
|
||||
{'test': 'gtest', 'platforms': ['linux', 'win32'], 'only_chunks': set('1')},
|
||||
]))
|
||||
|
||||
def test_t_none(self):
|
||||
"-t none sets talos=[]"
|
||||
tos = TryOptionSyntax('try: -t none', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -t none')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(sorted(tos.talos), [])
|
||||
|
||||
def test_t_all(self):
|
||||
"-t all sets talos=[..whole list..]"
|
||||
tos = TryOptionSyntax('try: -t all', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -t all')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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]"
|
||||
tos = TryOptionSyntax('try: -t mochitest-webgl', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: -t mochitest-webgl')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
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"
|
||||
tos = TryOptionSyntax('try: --rebuild 10', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --rebuild 10')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.trigger_tests, 10)
|
||||
|
||||
def test_talos_trigger_tests(self):
|
||||
"--rebuild-talos 10 sets talos_trigger_tests"
|
||||
tos = TryOptionSyntax('try: --rebuild-talos 10', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --rebuild-talos 10')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.talos_trigger_tests, 10)
|
||||
|
||||
def test_interactive(self):
|
||||
"--interactive sets interactive"
|
||||
tos = TryOptionSyntax('try: --interactive', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --interactive')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.interactive, True)
|
||||
|
||||
def test_all_email(self):
|
||||
"--all-emails sets notifications"
|
||||
tos = TryOptionSyntax('try: --all-emails', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --all-emails')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.notifications, 'all')
|
||||
|
||||
def test_fail_email(self):
|
||||
"--failure-emails sets notifications"
|
||||
tos = TryOptionSyntax('try: --failure-emails', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --failure-emails')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.notifications, 'failure')
|
||||
|
||||
def test_no_email(self):
|
||||
"no email settings don't set notifications"
|
||||
tos = TryOptionSyntax('try:', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try:')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.notifications, None)
|
||||
|
||||
def test_setenv(self):
|
||||
"--setenv VAR=value adds a environment variables setting to env"
|
||||
tos = TryOptionSyntax('try: --setenv VAR1=value1 --setenv VAR2=value2', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message(
|
||||
'try: --setenv VAR1=value1 --setenv VAR2=value2')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.env, ['VAR1=value1', 'VAR2=value2'])
|
||||
|
||||
def test_profile(self):
|
||||
"--geckoProfile sets profile to true"
|
||||
tos = TryOptionSyntax('try: --geckoProfile', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --geckoProfile')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertTrue(tos.profile)
|
||||
|
||||
def test_tag(self):
|
||||
"--tag TAG sets tag to TAG value"
|
||||
tos = TryOptionSyntax('try: --tag tagName', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --tag tagName')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertEqual(tos.tag, 'tagName')
|
||||
|
||||
def test_no_retry(self):
|
||||
"--no-retry sets no_retry to true"
|
||||
tos = TryOptionSyntax('try: --no-retry', graph_with_jobs)
|
||||
parameters = {'try_options': parse_message('try: --no-retry')}
|
||||
tos = TryOptionSyntax(parameters, graph_with_jobs)
|
||||
self.assertTrue(tos.no_retry)
|
||||
|
||||
|
||||
|
|
|
@ -44,8 +44,10 @@ def set_defaults(config, jobs):
|
|||
@transforms.add
|
||||
def set_env(config, jobs):
|
||||
"""Set extra environment variables from try command line."""
|
||||
env = {}
|
||||
if config.params['try_mode'] == 'try_option_syntax':
|
||||
env = config.params['try_options']['env'] or {}
|
||||
for job in jobs:
|
||||
env = config.config['args'].env
|
||||
if env:
|
||||
job_env = {}
|
||||
if 'worker' in job:
|
||||
|
|
|
@ -759,8 +759,11 @@ def set_retry_exit_status(config, tests):
|
|||
@transforms.add
|
||||
def set_profile(config, tests):
|
||||
"""Set profiling mode for tests."""
|
||||
profile = None
|
||||
if config.params['try_mode'] == 'try_option_syntax':
|
||||
profile = config.params['try_options']['profile']
|
||||
for test in tests:
|
||||
if config.config['args'].profile and test['suite'] == 'talos':
|
||||
if profile and test['suite'] == 'talos':
|
||||
test['mozharness']['extra-options'].append('--geckoProfile')
|
||||
yield test
|
||||
|
||||
|
@ -768,8 +771,10 @@ def set_profile(config, tests):
|
|||
@transforms.add
|
||||
def set_tag(config, tests):
|
||||
"""Set test for a specific tag."""
|
||||
tag = None
|
||||
if config.params['try_mode'] == 'try_option_syntax':
|
||||
tag = config.params['try_options']['tag']
|
||||
for test in tests:
|
||||
tag = config.config['args'].tag
|
||||
if tag:
|
||||
test['mozharness']['extra-options'].extend(['--tag', tag])
|
||||
yield test
|
||||
|
@ -821,6 +826,7 @@ def set_worker_type(config, tests):
|
|||
# during the taskcluster migration, this is a bit tortured, but it
|
||||
# will get simpler eventually!
|
||||
test_platform = test['test-platform']
|
||||
try_options = config.params['try_options'] if config.params['try_options'] else {}
|
||||
if test.get('worker-type'):
|
||||
# This test already has its worker type defined, so just use that (yields below)
|
||||
pass
|
||||
|
@ -835,7 +841,7 @@ def set_worker_type(config, tests):
|
|||
WINDOWS_WORKER_TYPES[test_platform.split('/')[0]][test['virtualization']]
|
||||
elif test_platform.startswith('linux') or test_platform.startswith('android'):
|
||||
if test.get('suite', '') == 'talos' and test['build-platform'] != 'linux64-ccov/opt':
|
||||
if config.config['args'].taskcluster_worker:
|
||||
if try_options.get('taskcluster_worker'):
|
||||
test['worker-type'] = 'releng-hardware/gecko-t-linux-talos'
|
||||
else:
|
||||
test['worker-type'] = 'buildbot-bridge/buildbot-bridge'
|
||||
|
|
|
@ -257,16 +257,14 @@ 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 args
|
||||
return vars(args)
|
||||
|
||||
|
||||
class TryOptionSyntax(object):
|
||||
|
||||
def __init__(self, message, full_task_graph):
|
||||
def __init__(self, parameters, full_task_graph):
|
||||
"""
|
||||
Parse a "try syntax" formatted commit message. This is the old "-b do -p
|
||||
win32 -u all" format. Aliases are applied to map short names to full
|
||||
names.
|
||||
Apply the try options in parameters.
|
||||
|
||||
The resulting object has attributes:
|
||||
|
||||
|
@ -305,28 +303,22 @@ class TryOptionSyntax(object):
|
|||
self.tag = None
|
||||
self.no_retry = False
|
||||
|
||||
parts = split_try_msg(message)
|
||||
if not parts:
|
||||
return None
|
||||
|
||||
args = parse_message(message)
|
||||
assert args is not None
|
||||
|
||||
self.jobs = self.parse_jobs(args.jobs)
|
||||
self.build_types = self.parse_build_types(args.build_types, full_task_graph)
|
||||
self.platforms = self.parse_platforms(args.platforms, full_task_graph)
|
||||
options = parameters['try_options']
|
||||
self.jobs = self.parse_jobs(options['jobs'])
|
||||
self.build_types = self.parse_build_types(options['build_types'], full_task_graph)
|
||||
self.platforms = self.parse_platforms(options['platforms'], full_task_graph)
|
||||
self.unittests = self.parse_test_option(
|
||||
"unittest_try_name", args.unittests, full_task_graph)
|
||||
self.talos = self.parse_test_option("talos_try_name", args.talos, full_task_graph)
|
||||
self.trigger_tests = args.trigger_tests
|
||||
self.interactive = args.interactive
|
||||
self.notifications = args.notifications
|
||||
self.talos_trigger_tests = args.talos_trigger_tests
|
||||
self.env = args.env
|
||||
self.profile = args.profile
|
||||
self.tag = args.tag
|
||||
self.no_retry = args.no_retry
|
||||
self.include_nightly = args.include_nightly
|
||||
"unittest_try_name", options['unittests'], full_task_graph)
|
||||
self.talos = self.parse_test_option("talos_try_name", options['talos'], full_task_graph)
|
||||
self.trigger_tests = options['trigger_tests']
|
||||
self.interactive = options['interactive']
|
||||
self.notifications = options['notifications']
|
||||
self.talos_trigger_tests = options['talos_trigger_tests']
|
||||
self.env = options['env']
|
||||
self.profile = options['profile']
|
||||
self.tag = options['tag']
|
||||
self.no_retry = options['no_retry']
|
||||
self.include_nightly = options['include_nightly']
|
||||
|
||||
def parse_jobs(self, jobs_arg):
|
||||
if not jobs_arg or jobs_arg == ['all']:
|
||||
|
|
Загрузка…
Ссылка в новой задаче