-
Couldn't load subscription status.
- Fork 109
feat: list --format {text,json,dot} --label stack.{id,name,dir} #2219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
b5e73d6 to
3ab99f5
Compare
46f424a to
0aa3955
Compare
Signed-off-by: timsolovev <[email protected]>
|
Hey @timsolovev, thanks for your Pull Request - we really like your suggested changes. While @snakster will review the PR in detail, I wanted to ask if you would be willing to sign our Contributor license agreement? if so, please send me an email to [email protected] so I can initiate the process. Thank you |
|
@timsolovev thanks a lot for providing this PR. We love it. We see some conflicts with planned features that we would need to address here. Nothing fundamental, mainly user facing format and naming topics. Let me align with the team and compile a list of high level feedback points. FYI, I am not the one to give feedback on code but on the product side of things here ;) |
|
@soerenmartius I will gladly sign the contributor agreement after this PR is preliminarily approved. |
fanstastic - thank you |
Which issue(s) this PR fixes:
Fixes #2069, Fixes #723
Supersedes #2073
What this PR does / why we need it:
This PR introduces several new non-breaking features to
terramate listcommand:Multiple output formats via
--formatflag:text(default): Traditional line-by-line stack listingjson: JSON output with complete stack metadata and direct execution dependenciesdot: GraphViz DOT format for visual dependency graph generationCustomizable labels via
-l/--labelflag:stack.dir(default): Display stack directory pathsstack.id: Display stack IDsstack.name: Display stack names (not available with--format=jsondue to possible name duplication).JSON Format
The recommendation in #2069 suggested very minimalist map-of-lists structure, but since #723 requested a more exhaustive JSON structure, I went with something like this:
{ "A/B1/C": { "dir": "A", "id": "a1111111-1111-1111-1111-111111111111", "name": "A", "description": "", "tags": [], "dependencies": ["A/B1", "D"], "reason": "", "is_changed": false } }In combination with
--label stack.idit will use stack ids as references:Dot format
Then I realised that the stack aggregation for JSON format can be useful for Dot graph generation.
experimental run-graphalways graphed only explicit dependencies of the stacks (i.e.before/after) and suffered fromstack.namecollisions. This PR addresses both these issues, but since the recursive implementation ofdotformatting ofterramate experimental run-graphis too divergent from JSON stack aggregation, it was essentially re-implemented and (as expected) produces deeper execution graph that also cover the dir hierarchy.Comparison on the example project described below. Before:
terramate experimental run-graph --label stack.dirAfter:
terramate list --format dotExample
Consider a simple Terramate project:
The explicit dependencies are introduced with
beforeinD/stack.tm.hcl:and
afterin CA/B1/C/stack.tm.hcl:The outputs for all possible combinations of
--formatand--labelare provided below.terramate list- equivalent toterramate list --format text --label stack.dirterramate list --format json{ "A": { "dir": "A", "id": "a1111111-1111-1111-1111-111111111111", "name": "A", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false }, "A/B1": { "dir": "A/B1", "id": "b1111111-1111-1111-1111-111111111111", "name": "B1", "description": "", "tags": [], "dependencies": [ "A" ], "reason": "", "is_changed": false }, "A/B1/C": { "dir": "A/B1/C", "id": "c1111111-1111-1111-1111-111111111111", "name": "C", "description": "", "tags": [], "dependencies": [ "A/B1", "D" ], "reason": "", "is_changed": false }, "A/B2": { "dir": "A/B2", "id": "b2222222-2222-2222-2222-222222222222", "name": "B2", "description": "", "tags": [], "dependencies": [ "A", "D" ], "reason": "", "is_changed": false }, "D": { "dir": "D", "id": "d1111111-1111-1111-1111-111111111111", "name": "D", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false } }terramate list --format dotterramate list --label stack.idterramate list --label stack.nameterramate list --label stack.dirterramate list --format json --label stack.id{ "a1111111-1111-1111-1111-111111111111": { "dir": "A", "id": "a1111111-1111-1111-1111-111111111111", "name": "A", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false }, "b1111111-1111-1111-1111-111111111111": { "dir": "A/B1", "id": "b1111111-1111-1111-1111-111111111111", "name": "B1", "description": "", "tags": [], "dependencies": [ "a1111111-1111-1111-1111-111111111111" ], "reason": "", "is_changed": false }, "b2222222-2222-2222-2222-222222222222": { "dir": "A/B2", "id": "b2222222-2222-2222-2222-222222222222", "name": "B2", "description": "", "tags": [], "dependencies": [ "a1111111-1111-1111-1111-111111111111", "d1111111-1111-1111-1111-111111111111" ], "reason": "", "is_changed": false }, "c1111111-1111-1111-1111-111111111111": { "dir": "A/B1/C", "id": "c1111111-1111-1111-1111-111111111111", "name": "C", "description": "", "tags": [], "dependencies": [ "b1111111-1111-1111-1111-111111111111", "d1111111-1111-1111-1111-111111111111" ], "reason": "", "is_changed": false }, "d1111111-1111-1111-1111-111111111111": { "dir": "D", "id": "d1111111-1111-1111-1111-111111111111", "name": "D", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false } }terramate list --format json --label stack.nameterramate list --format json --label stack.dir{ "A": { "dir": "A", "id": "a1111111-1111-1111-1111-111111111111", "name": "A", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false }, "A/B1": { "dir": "A/B1", "id": "b1111111-1111-1111-1111-111111111111", "name": "B1", "description": "", "tags": [], "dependencies": [ "A" ], "reason": "", "is_changed": false }, "A/B1/C": { "dir": "A/B1/C", "id": "c1111111-1111-1111-1111-111111111111", "name": "C", "description": "", "tags": [], "dependencies": [ "A/B1", "D" ], "reason": "", "is_changed": false }, "A/B2": { "dir": "A/B2", "id": "b2222222-2222-2222-2222-222222222222", "name": "B2", "description": "", "tags": [], "dependencies": [ "A", "D" ], "reason": "", "is_changed": false }, "D": { "dir": "D", "id": "d1111111-1111-1111-1111-111111111111", "name": "D", "description": "", "tags": [], "dependencies": [], "reason": "", "is_changed": false } }terramate list --format dot --label stack.idterramate list --format dot --label stack.nameterramate list --format dot --label stack.dirSpecial notes for your reviewer:
Since this PR turned out to be bigger than I thought, I'm certainly open to reworking or completely discarding some of the features.
Since #2069 mentioned that returning dependency edge nodes would be a sensible approach, I took the liberty of introducing a new method
DirectAncestorsOf()in dag.go to implement transitive reduction of ancestors.It is still missing a few tests, but I wanted to get your feedback before proceeding.
Does this PR introduce a user-facing change?
This PR introduces explicit formatting options for
terraform listthrough--format {text,json,dot}and--label stack.{id,name,dir}parameters. It does not introduce breaking changes to the previous behaviour ofterraform list.Note
Adds selectable output formats (text/json/dot) and labeling (stack.id/name/dir) to
terramate list, including JSON metadata and DOT graphs with direct dependencies.commands/stack/list):--format {text,json,dot}and--label stack.{id,name,dir}; blocks--format jsonwith--label stack.name.text: now uses selected label;--whyprints<label> - <reason>.json: emits map[label] -> stack metadata (dir,id,name,description,tags,dependencies,reason,is_changed).dot: emits GraphViz graph of stacks with edges for direct dependencies.StackInfo, label resolution, and printers wiring.run/dag/dag.go):DirectAncestorsOf()with transitive reduction and helper to find reachable ancestors.cli_spec.go: addslistflags--formatand--label.cli_handler.go: wires flags tolistspec and telemetry; passes printers.namein generated test configs.Written by Cursor Bugbot for commit 39da876. This will update automatically on new commits. Configure here.