`fetch_graph_and_labels` grabs the `label_to_taskid` mapping from the original decision task plus any action and cron tasks on the same revision. In that process it only keeps track of one task id per label (whichever it sees last). In most cases that's not a big deal, but there's a couple of instances where it matters: - the `rerun` action checks that the input task id is part of the mapping, and doesn't do anything if it is not, so won't rerun a task that was part of the initial graph and whose label was re-used later (e.g. from a retrigger) - the `retrigger-multiple` action checks to see if a label should be rerun instead, and in that case uses the label_to_taskid mapping to decide which exact task to rerun. Again if there's more than one task on that revision with the same label (e.g. from a forced retrigger or cron), it might not pick the expected one. Fix this by having `fetch_graph_and_labels` also return a `label_to_taskids` mapping. The `rerun` action's check now looks for the task id there instead of the incomplete `label_to_taskid`, and `retrigger-multiple` attempts to rerun all tasks with the given label instead of just one. Differential Revision: https://phabricator.services.mozilla.com/D194600
186 lines
6.2 KiB
Python
186 lines
6.2 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
import json
|
|
import logging
|
|
|
|
from taskgraph.util.parameterization import resolve_task_references
|
|
from taskgraph.util.taskcluster import get_task_definition
|
|
|
|
from .registry import register_callback_action
|
|
from .util import create_task_from_def, fetch_graph_and_labels
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Properties available for custom retrigger of any supported test suites
|
|
basic_properties = {
|
|
"path": {
|
|
"type": "string",
|
|
"maxLength": 255,
|
|
"default": "",
|
|
"title": "Path name",
|
|
"description": "Path of test(s) to retrigger",
|
|
},
|
|
"logLevel": {
|
|
"type": "string",
|
|
"enum": ["debug", "info", "warning", "error", "critical"],
|
|
"default": "info",
|
|
"title": "Log level",
|
|
"description": "Log level for output (INFO is normal, DEBUG gives more detail)",
|
|
},
|
|
"environment": {
|
|
"type": "object",
|
|
"default": {"MOZ_LOG": ""},
|
|
"title": "Extra environment variables",
|
|
"description": "Extra environment variables to use for this run",
|
|
"additionalProperties": {"type": "string"},
|
|
},
|
|
}
|
|
|
|
# Additional properties available for custom retrigger of some additional test suites
|
|
extended_properties = basic_properties.copy()
|
|
extended_properties.update(
|
|
{
|
|
"runUntilFail": {
|
|
"type": "boolean",
|
|
"default": False,
|
|
"title": "Run until failure",
|
|
"description": (
|
|
"Runs the specified set of tests repeatedly "
|
|
"until failure (up to REPEAT times)"
|
|
),
|
|
},
|
|
"repeat": {
|
|
"type": "integer",
|
|
"default": 0,
|
|
"minimum": 0,
|
|
"title": "Repeat test(s) N times",
|
|
"description": (
|
|
"Run test(s) repeatedly (usually used in "
|
|
"conjunction with runUntilFail)"
|
|
),
|
|
},
|
|
"preferences": {
|
|
"type": "object",
|
|
"default": {"remote.log.level": "Info"},
|
|
"title": "Extra gecko (about:config) preferences",
|
|
"description": "Extra gecko (about:config) preferences to use for this run",
|
|
"additionalProperties": {"type": "string"},
|
|
},
|
|
}
|
|
)
|
|
|
|
|
|
@register_callback_action(
|
|
name="retrigger-custom",
|
|
title="Retrigger task with custom parameters",
|
|
symbol="rt",
|
|
description="Retriggers the specified task with custom environment and parameters",
|
|
context=[
|
|
{"test-type": "mochitest", "worker-implementation": "docker-worker"},
|
|
{"test-type": "reftest", "worker-implementation": "docker-worker"},
|
|
{"test-type": "geckoview-junit", "worker-implementation": "docker-worker"},
|
|
],
|
|
order=10,
|
|
schema={
|
|
"type": "object",
|
|
"properties": extended_properties,
|
|
"additionalProperties": False,
|
|
"required": ["path"],
|
|
},
|
|
)
|
|
def extended_custom_retrigger_action(
|
|
parameters, graph_config, input, task_group_id, task_id
|
|
):
|
|
handle_custom_retrigger(parameters, graph_config, input, task_group_id, task_id)
|
|
|
|
|
|
@register_callback_action(
|
|
name="retrigger-custom (gtest)",
|
|
title="Retrigger gtest task with custom parameters",
|
|
symbol="rt",
|
|
description="Retriggers the specified task with custom environment and parameters",
|
|
context=[{"test-type": "gtest", "worker-implementation": "docker-worker"}],
|
|
order=10,
|
|
schema={
|
|
"type": "object",
|
|
"properties": basic_properties,
|
|
"additionalProperties": False,
|
|
"required": ["path"],
|
|
},
|
|
)
|
|
def basic_custom_retrigger_action_basic(
|
|
parameters, graph_config, input, task_group_id, task_id
|
|
):
|
|
handle_custom_retrigger(parameters, graph_config, input, task_group_id, task_id)
|
|
|
|
|
|
def handle_custom_retrigger(parameters, graph_config, input, task_group_id, task_id):
|
|
task = get_task_definition(task_id)
|
|
decision_task_id, full_task_graph, label_to_taskid, _ = fetch_graph_and_labels(
|
|
parameters, graph_config
|
|
)
|
|
|
|
pre_task = full_task_graph.tasks[task["metadata"]["name"]]
|
|
|
|
# fix up the task's dependencies, similar to how optimization would
|
|
# have done in the decision
|
|
dependencies = {
|
|
name: label_to_taskid[label] for name, label in pre_task.dependencies.items()
|
|
}
|
|
new_task_definition = resolve_task_references(
|
|
pre_task.label, pre_task.task, task_id, decision_task_id, dependencies
|
|
)
|
|
new_task_definition.setdefault("dependencies", []).extend(dependencies.values())
|
|
|
|
# don't want to run mozharness tests, want a custom mach command instead
|
|
new_task_definition["payload"]["command"] += ["--no-run-tests"]
|
|
|
|
custom_mach_command = [task["tags"]["test-type"]]
|
|
|
|
# mochitests may specify a flavor
|
|
if new_task_definition["payload"]["env"].get("MOCHITEST_FLAVOR"):
|
|
custom_mach_command += [
|
|
"--keep-open=false",
|
|
"-f",
|
|
new_task_definition["payload"]["env"]["MOCHITEST_FLAVOR"],
|
|
]
|
|
|
|
enable_e10s = json.loads(
|
|
new_task_definition["payload"]["env"].get("ENABLE_E10S", "true")
|
|
)
|
|
if not enable_e10s:
|
|
custom_mach_command += ["--disable-e10s"]
|
|
|
|
custom_mach_command += [
|
|
"--log-tbpl=-",
|
|
"--log-tbpl-level={}".format(input.get("logLevel", "debug")),
|
|
]
|
|
if input.get("runUntilFail"):
|
|
custom_mach_command += ["--run-until-failure"]
|
|
if input.get("repeat"):
|
|
custom_mach_command += ["--repeat", str(input.get("repeat", 30))]
|
|
|
|
# add any custom gecko preferences
|
|
for key, val in input.get("preferences", {}).items():
|
|
custom_mach_command += ["--setpref", f"{key}={val}"]
|
|
|
|
custom_mach_command += [input["path"]]
|
|
new_task_definition["payload"]["env"]["CUSTOM_MACH_COMMAND"] = " ".join(
|
|
custom_mach_command
|
|
)
|
|
|
|
# update environment
|
|
new_task_definition["payload"]["env"].update(input.get("environment", {}))
|
|
|
|
# tweak the treeherder symbol
|
|
new_task_definition["extra"]["treeherder"]["symbol"] += "-custom"
|
|
|
|
logging.info("New task definition: %s", new_task_definition)
|
|
|
|
create_task_from_def(
|
|
new_task_definition, parameters["level"], action_tag="retrigger-custom-task"
|
|
)
|