Bug 1414921 - Add --geckoProfile to capture profiles from talos tasks to |mach try fuzzy|, r?dustin
Enables |./mach try fuzzy --talos-profile|. This template only applies to talos
tasks. It also provides --geckoProfile for consistency with |mach try syntax|,
but I don't like this name so it's hidden from the help.
The 'talos-profile.yml' template is also very specific (only applies to Talos
tasks). Ideally I'd like a general 'command.yml' template that just appends
arguments to the command for any arbitrary tasks. But then we'd need to invent
an expression syntax in try_task_config.json so we could make sure it only
applies to Talos. Then I thought rather than implement it for a specific
template, we should have a general way of doing this which could apply to any
and all of the templates.
Needless to say, it's a rabbit hole and something that's best left to a
follow-up so we don't delay this bug.
MozReview-Commit-ID: GhllZ7sr0ar
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/templates/talos-profile.yml
@@ -0,0 +1,36 @@
+---
+$if: input && task["extra"]
+then:
+ $if: task.extra["suite"]
+ then:
+ $if: task.extra.suite["name"] == "talos"
+ then:
+ task:
+ # We can't use mergeDeep as that will append the command below
+ # instead of overwriting the original command.
+ $merge:
+ - $eval: task
+ - payload:
+ $merge:
+ - $eval: task.payload
+ - command:
+ $if: typeof(task.payload.command[0]) == 'array'
+ then:
+ # Command is an array of arrays. Assumes the command we want
+ # to append --geckoProfile to is the first one. Also assumes
+ # that we can't have a space delimited string here (which is
+ # the case for now at least).
+ - $flatten:
+ - $eval: task.payload.command[0]
+ - ["--geckoProfile"]
+ else:
+ $if: len(task.payload.command) == 1
+ then:
+ # Command is an array with a single space delimited string.
+ # This only happens on Windows.
+ - "${task.payload.command[0]} --geckoProfile"
+ else:
+ # Command is an array of strings.
+ $flatten:
+ - $eval: task.payload.command
+ - ["--geckoProfile"]
--- a/taskcluster/taskgraph/test/test_morph.py
+++ b/taskcluster/taskgraph/test/test_morph.py
@@ -108,16 +108,17 @@ TASKS = [
}
},
{
'kind': 'test',
'label': 'b',
'attributes': {},
'task': {
'extra': {
+ 'suite': {'name': 'talos'},
'treeherder': {
'group': 'tc',
'symbol': 't'
}
},
'payload': {
'env': {
'FOO': 'BAR'
@@ -127,25 +128,23 @@ TASKS = [
'kind': 'test'
}
}
},
]
@pytest.fixture
-def taskgraph(make_taskgraph):
- return make_taskgraph({
- t['label']: Task(**t) for t in TASKS[:]
- })
+def get_morphed(make_taskgraph):
+ def inner(try_task_config, tasks=None):
+ tasks = tasks or TASKS
+ taskgraph = make_taskgraph({
+ t['label']: Task(**t) for t in tasks[:]
+ })
-
-@pytest.fixture
-def get_morphed(taskgraph):
- def inner(try_task_config):
fn = morph.apply_jsone_templates(try_task_config)
return fn(*taskgraph)[0]
return inner
def test_template_artifact(get_morphed):
morphed = get_morphed({
'templates': {
@@ -211,10 +210,39 @@ def test_template_rebuild(get_morphed):
for t in tasks:
if t.label == 'a':
assert 'task_duplicates' not in t.attributes
elif t.label == 'b':
assert 'task_duplicates' in t.attributes
assert t.attributes['task_duplicates'] == 4
+@pytest.mark.parametrize('command', (
+ ['foo --bar'],
+ ['foo', '--bar'],
+ [['foo']],
+ [['foo', '--bar']],
+))
+def test_template_talos_profile(get_morphed, command):
+ tasks = TASKS[:]
+ for t in tasks:
+ t['task']['payload']['command'] = command
+
+ morphed = get_morphed({
+ 'templates': {
+ 'talos-profile': True,
+ }
+ }, tasks)
+
+ for t in morphed.tasks.values():
+ command = t.task['payload']['command']
+ if isinstance(command[0], list):
+ command = command[0]
+ command = ' '.join(command)
+
+ if t.label == 'a':
+ assert not command.endswith('--geckoProfile')
+ elif t.label == 'b':
+ assert command.endswith('--geckoProfile')
+
+
if __name__ == '__main__':
main()
--- a/tools/tryselect/selectors/fuzzy.py
+++ b/tools/tryselect/selectors/fuzzy.py
@@ -86,17 +86,17 @@ class FuzzyParser(BaseTryParser):
}],
[['-u', '--update'],
{'action': 'store_true',
'default': False,
'help': "Update fzf before running.",
}],
]
common_groups = ['push', 'task', 'preset']
- templates = ['artifact', 'path', 'env', 'rebuild', 'chemspill-prio']
+ templates = ['artifact', 'path', 'env', 'rebuild', 'chemspill-prio', 'talos-profile']
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):
--- a/tools/tryselect/templates.py
+++ b/tools/tryselect/templates.py
@@ -7,17 +7,17 @@ Templates provide a way of modifying the
tasks. They live under taskcluster/taskgraph/templates.
"""
from __future__ import absolute_import, print_function, unicode_literals
import os
import sys
from abc import ABCMeta, abstractmethod
-from argparse import Action
+from argparse import Action, SUPPRESS
import mozpack.path as mozpath
from mozbuild.base import BuildEnvironmentNotFoundException, MozbuildObject
here = os.path.abspath(os.path.dirname(__file__))
build = MozbuildObject.from_environment(cwd=here)
@@ -139,15 +139,31 @@ class ChemspillPrio(Template):
def context(self, chemspill_prio, **kwargs):
if chemspill_prio:
return {
'chemspill-prio': {}
}
+class TalosProfile(Template):
+
+ def add_arguments(self, parser):
+ parser.add_argument('--talos-profile', dest='profile', action='store_true', default=False,
+ help='Create and upload a gecko profile during talos tasks.')
+ # This is added for consistency with the 'syntax' selector
+ parser.add_argument('--geckoProfile', dest='profile', action='store_true', default=False,
+ help=SUPPRESS)
+
+ def context(self, profile, **kwargs):
+ if not profile:
+ return
+ return {'talos-profile': profile}
+
+
all_templates = {
'artifact': Artifact,
'path': Path,
'env': Environment,
'rebuild': Rebuild,
'chemspill-prio': ChemspillPrio,
+ 'talos-profile': TalosProfile,
}
--- a/tools/tryselect/test/test_templates.py
+++ b/tools/tryselect/test/test_templates.py
@@ -14,16 +14,20 @@ from tryselect.templates import all_temp
# templates have a list of tests of the form (input, expected)
TEMPLATE_TESTS = {
'artifact': [
(['--no-artifact'], None),
(['--artifact'], {'artifact': {'enabled': '1'}}),
],
+ 'chemspill-prio': [
+ ([], None),
+ (['--chemspill-prio'], {'chemspill-prio': {}}),
+ ],
'env': [
([], None),
(['--env', 'foo=bar', '--env', 'num=10'], {'env': {'foo': 'bar', 'num': '10'}}),
],
'path': [
([], None),
(['dom/indexedDB'], {'env': {'MOZHARNESS_TEST_PATHS': 'dom/indexedDB'}}),
(['dom/indexedDB', 'testing'],
@@ -31,16 +35,21 @@ TEMPLATE_TESTS = {
(['invalid/path'], SystemExit),
],
'rebuild': [
([], None),
(['--rebuild', '10'], {'rebuild': 10}),
(['--rebuild', '1'], SystemExit),
(['--rebuild', '21'], SystemExit),
],
+ 'talos-profile': [
+ ([], None),
+ (['--talos-profile'], {'talos-profile': True}),
+ (['--geckoProfile'], {'talos-profile': True}),
+ ],
}
def test_templates(template, args, expected):
parser = ArgumentParser()
t = all_templates[template]()
t.add_arguments(parser)