commit 892b6f147d7636997f4b5b5e7288090277866e70
parent aacb4231f4e83711eca543405ec798f6015b700d
Author: Ben Hearsum <ben@mozilla.com>
Date: Thu, 13 Nov 2025 01:50:17 +0000
Bug 1999355: add support for outputting mermaid flowcharts of kinds r=taskgraph-reviewers,ahal
taskgraph recently gained support for outputting mermaid flowchart source files for kinds. This can be particularly useful for understanding certain sequences of tasks in Gecko, where we have complex webs of kinds. Let's add support for dumping them with `./mach taskgraph`, and as an output to `./mach decision` as well.
Differential Revision: https://phabricator.services.mozilla.com/D272099
Diffstat:
3 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/taskcluster/gecko_taskgraph/decision.py b/taskcluster/gecko_taskgraph/decision.py
@@ -15,6 +15,7 @@ from redo import retry
from taskgraph import create
from taskgraph.create import create_tasks
from taskgraph.generator import TaskGraphGenerator
+from taskgraph.main import format_kind_graph_mermaid
from taskgraph.parameters import Parameters
from taskgraph.taskgraph import TaskGraph
from taskgraph.util import json
@@ -204,6 +205,9 @@ def taskgraph_decision(options, parameters=None):
full_task_json = tgg.full_task_graph.to_json()
write_artifact("full-task-graph.json", full_task_json)
+ # write out kind graph
+ write_artifact("kind-graph.mm", format_kind_graph_mermaid(tgg.kind_graph))
+
# write out the public/runnable-jobs.json file
write_artifact(
"runnable-jobs.json", full_task_graph_to_runnable_jobs(full_task_json)
@@ -506,7 +510,8 @@ def write_artifact(filename, data):
with gzip.open(path, "wb") as f:
f.write(json.dumps(data).encode("utf-8"))
else:
- raise TypeError(f"Don't know how to write to {filename}")
+ with open(path, "w") as f:
+ f.write(data)
def read_artifact(filename):
diff --git a/taskcluster/gecko_taskgraph/main.py b/taskcluster/gecko_taskgraph/main.py
@@ -22,7 +22,9 @@ from taskgraph.main import (
command,
commands,
dump_output,
+ format_kind_graph_mermaid,
generate_taskgraph,
+ get_taskgraph_generator,
)
from gecko_taskgraph import GECKO
@@ -48,6 +50,80 @@ FORMAT_METHODS["yaml"] = format_taskgraph_yaml
@command(
+ "kind-graph",
+ help="Show the kind dependency graph as a Mermaid flowchart diagram.",
+)
+@argument("--root", "-r", help="root of the taskgraph definition relative to topsrcdir")
+@argument("--quiet", "-q", action="store_true", help="suppress all logging output")
+@argument(
+ "--verbose", "-v", action="store_true", help="include debug-level logging output"
+)
+@argument(
+ "--parameters",
+ "-p",
+ default=None,
+ help="Parameters to use for the generation. Can be a path to file (.yml or "
+ ".json; see `taskcluster/docs/parameters.rst`), a url, of the form "
+ "`project=mozilla-central` to download latest parameters file for the specified "
+ "project from CI, or of the form `task-id=<decision task id>` to download "
+ "parameters from the specified decision task.",
+)
+@argument(
+ "-o",
+ "--output-file",
+ default=None,
+ help="file path to store generated output.",
+)
+@argument(
+ "-k",
+ "--target-kind",
+ dest="target_kinds",
+ action="append",
+ default=[],
+ help="only return kinds and their dependencies.",
+)
+def show_kinds(options):
+ from taskgraph.parameters import parameters_loader # noqa: PLC0415
+
+ if options.pop("verbose", False):
+ logging.root.setLevel(logging.DEBUG)
+
+ setup_logging()
+
+ target_kinds = options.get("target_kinds", [])
+ parameters = options.get("parameters")
+ if not parameters:
+ parameters = parameters_loader(
+ None, strict=False, overrides={"target-kinds": target_kinds}
+ )
+ elif isinstance(parameters, str):
+ parameters = parameters_loader(
+ parameters,
+ overrides={"target-kinds": target_kinds},
+ strict=False,
+ )
+ else:
+ # Parameters object already exists (from tests)
+ if target_kinds:
+ parameters["target-kinds"] = target_kinds
+
+ tgg = get_taskgraph_generator(options.get("root"), parameters)
+ kind_graph = tgg.kind_graph
+
+ output = format_kind_graph_mermaid(kind_graph)
+
+ output_file = options.get("output_file")
+ if output_file:
+ with open(output_file, "w") as fh:
+ print(output, file=fh)
+ print(f"Kind graph written to {output_file}", file=sys.stderr)
+ else:
+ print(output)
+
+ return 0
+
+
+@command(
"tasks",
help="Show all tasks in the taskgraph.",
defaults={"graph_attr": "full_task_set"},
diff --git a/taskcluster/mach_commands.py b/taskcluster/mach_commands.py
@@ -118,6 +118,21 @@ def taskgraph_command(command_context):
@SubCommand(
"taskgraph",
+ "kind-graph",
+ description="Generate a graph of the relationship between taskgraph kinds",
+ parser=partial(get_taskgraph_command_parser, "kind-graph"),
+)
+def taskgraph_kind_graph(command_context, **options):
+ try:
+ setup_logging(command_context)
+ return taskgraph_commands["kind-graph"].func(options)
+ except Exception:
+ traceback.print_exc()
+ sys.exit(1)
+
+
+@SubCommand(
+ "taskgraph",
"tasks",
description="Show all tasks in the taskgraph",
parser=partial(get_taskgraph_command_parser, "tasks"),