From f4f04b7f556a8ccdd59e404736b1ac94cb70f252 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Wed, 22 Apr 2026 22:30:00 +0200 Subject: [PATCH] Add a way to prevent some actions from getting generated Right now taskgraph always generates some generic actions that are used on fxci on some projects. Projects that do not need to use said actions are forced to add `rm actions.json` at the end of their decision task to not get basic taskcluster features overridden by taskgraph (rerun/retrigger mainly). This adds a `disabled_actions` graph configuration that allows giving a list of actions that should not be emitted in the actions.json. --- src/taskgraph/actions/registry.py | 17 ++++++- src/taskgraph/config.py | 3 ++ test/test_actions_registry.py | 73 +++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/taskgraph/actions/registry.py b/src/taskgraph/actions/registry.py index 13e218097..19bdc4710 100644 --- a/src/taskgraph/actions/registry.py +++ b/src/taskgraph/actions/registry.py @@ -273,12 +273,27 @@ def render_actions_json(parameters, graph_config, decision_task_id): artifact. """ assert isinstance(parameters, Parameters), "requires instance of Parameters" + + all_actions = _get_actions(graph_config) + disabled = set(graph_config["taskgraph"].get("disabled-actions") or []) + known_cb_names = {action.cb_name for action in all_actions} + unknown = disabled - known_cb_names + if unknown: + raise ValueError( + "Unknown action(s) in `taskgraph.disabled-actions`: " + f"{sorted(unknown)}. Known actions: {sorted(known_cb_names)}" + ) + actions = [] - for action in sorted(_get_actions(graph_config), key=lambda action: action.order): + for action in sorted(all_actions, key=lambda action: action.order): + if action.cb_name in disabled: + continue + action = action.action_builder(parameters, graph_config, decision_task_id) if action: assert is_json(action), "action must be a JSON compatible object" actions.append(action) + return { "version": 1, "variables": {}, diff --git a/src/taskgraph/config.py b/src/taskgraph/config.py index 11154e4b6..88a927744 100644 --- a/src/taskgraph/config.py +++ b/src/taskgraph/config.py @@ -57,6 +57,9 @@ class TaskgraphConfig(Schema): index_path_regexes: Optional[list[str]] = None # Configuration related to the 'run' transforms. run: Optional[RunConfig] = None + # List of action `cb_name`s to omit from `actions.json`, + # e.g. `["retrigger", "retrigger-disabled", "rerun"]`. + disabled_actions: Optional[list[str]] = None def __post_init__(self): # Validate repositories has at least 1 entry (was All(..., Length(min=1))) diff --git a/test/test_actions_registry.py b/test/test_actions_registry.py index 476ce8019..19f7687ee 100644 --- a/test/test_actions_registry.py +++ b/test/test_actions_registry.py @@ -4,6 +4,7 @@ from mozilla_repo_urls import InvalidRepoUrlError from taskgraph.actions import registry +from taskgraph.parameters import Parameters from test import does_not_raise @@ -126,3 +127,75 @@ def test_sanity_check_task_scope( ) with expectation: registry.sanity_check_task_scope(callback, parameters, graph_config={}) + + +def _make_action(cb_name): + return registry.Action( + order=42, + cb_name=cb_name, + permission="generic", + action_builder=lambda parameters, graph_config, decision_task_id: { + "cb_name": cb_name, + }, + ) + + +@pytest.fixture +def fake_actions(monkeypatch): + fake = [ + _make_action("retrigger"), + _make_action("retrigger-disabled"), + _make_action("rerun"), + _make_action("cancel"), + ] + monkeypatch.setattr(registry, "_get_actions", lambda graph_config: fake) + return fake + + +def _graph_config(disabled_actions): + taskgraph = {} + if disabled_actions is not None: + taskgraph["disabled-actions"] = disabled_actions + return {"taskgraph": taskgraph} + + +def test_render_actions_json_no_disabled(fake_actions): + result = registry.render_actions_json( + Parameters(strict=False), _graph_config(None), "DECISION-TASK" + ) + assert [a["cb_name"] for a in result["actions"]] == [ + "retrigger", + "retrigger-disabled", + "rerun", + "cancel", + ] + + +def test_render_actions_json_filters_disabled(fake_actions): + result = registry.render_actions_json( + Parameters(strict=False), + _graph_config(["retrigger", "retrigger-disabled", "rerun"]), + "DECISION-TASK", + ) + assert [a["cb_name"] for a in result["actions"]] == ["cancel"] + + +def test_render_actions_json_empty_disabled(fake_actions): + result = registry.render_actions_json( + Parameters(strict=False), _graph_config([]), "DECISION-TASK" + ) + assert [a["cb_name"] for a in result["actions"]] == [ + "retrigger", + "retrigger-disabled", + "rerun", + "cancel", + ] + + +def test_render_actions_json_unknown_disabled_raises(fake_actions): + with pytest.raises(ValueError, match="does-not-exist"): + registry.render_actions_json( + Parameters(strict=False), + _graph_config(["retrigger", "does-not-exist"]), + "DECISION-TASK", + )