@intentius/terragucci 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/audit.schema.json +3 -3
- package/dist/dora.schema.json +104 -0
- package/dist/estate.schema.json +153 -2
- package/dist/report-index.schema.json +11 -1
- package/dist/report.schema.json +176 -2
- package/dist/run.schema.json +110 -0
- package/dist/state-edges.schema.json +52 -0
- package/dist/state-versions.schema.json +42 -0
- package/dist/terragucci.mjs +878 -444
- package/dist/terragucci.mjs.map +4 -4
- package/dist/terragucci.schema.json +3005 -0
- package/dist/types.d.ts +292 -10
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @intentius/terragucci
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
terragucci writes the pipeline that runs the whole lifecycle of your Terraform or Terragrunt repo on GitHub, GitLab or Forgejo.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm i -D @intentius/terragucci
|
|
7
7
|
npx terragucci init
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
`init` reads the repo
|
|
10
|
+
`init` reads the repo and writes the pipeline it needs, then reports what it found:
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
found 15 roots in 2 layers, tofu 1.13.1 (.opentofu-version), forge github (the origin remote (github.com))
|
|
@@ -23,6 +23,7 @@ A root is a directory whose Terraform files declare a backend or configure a pro
|
|
|
23
23
|
|---|---|
|
|
24
24
|
| `terragucci init` | sets one repo up; `--forge` and `--binary` override detection, `--dry-run` writes nothing |
|
|
25
25
|
| `terragucci reconcile --config <file>` | from a control repo, previews every project's pipeline; `--mode apply` opens a pull request in each project that changes |
|
|
26
|
+
| `terragucci generate` | writes each root's backend, provider and version files from the `generate` key; `--check` fails on one that differs |
|
|
26
27
|
| `terragucci plan` | plans this repo's roots in apply order; `--root <glob>` narrows it |
|
|
27
28
|
|
|
28
29
|
| Exit code | Means |
|
package/dist/audit.schema.json
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://intentius.io/terragucci/schemas/audit/v1/audit.schema.json",
|
|
4
4
|
"title": "terragucci.audit/v1",
|
|
5
|
-
"description": "One line of audit.jsonl at the top of a reports prefix: an approval, apply, policy override or
|
|
5
|
+
"description": "One line of audit.jsonl at the top of a reports prefix: an approval, apply, policy override, refused wave, state migration or state export. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["schema", "id", "kind", "project", "at", "who", "what", "digest", "result", "evidence"],
|
|
8
8
|
"properties": {
|
|
9
9
|
"schema": { "const": "terragucci.audit/v1" },
|
|
10
10
|
"id": { "type": "string", "description": "sha256: over where the entry came from; the same records give the same id." },
|
|
11
|
-
"kind": { "enum": ["approval-requested", "approval", "approval-revoked", "override-requested", "override", "override-revoked", "apply", "refused"] },
|
|
11
|
+
"kind": { "enum": ["approval-requested", "approval", "approval-revoked", "override-requested", "override", "override-revoked", "apply", "refused", "migration", "unlock", "state-export", "ephemeral-apply", "ephemeral-destroy"] },
|
|
12
12
|
"project": { "type": "string", "description": "<host>/<path> of the repo." },
|
|
13
13
|
"at": { "type": "string", "description": "When it happened, ISO 8601." },
|
|
14
14
|
"who": { "type": ["string", "null"], "description": "The approver, the overrider, whoever removed the line, or for an apply the approver it applied under. Null when nobody did." },
|
|
15
|
-
"what": { "type": "string", "description": "The gate (wave-<k
|
|
15
|
+
"what": { "type": "string", "description": "The gate (wave-<k>, or a migration's name) or, for an override or a state export, the root." },
|
|
16
16
|
"digest": { "type": ["string", "null"], "description": "The wave's set digest, or the digest an override binds. Null when a root failed to plan." },
|
|
17
17
|
"result": { "type": "string" },
|
|
18
18
|
"evidence": {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/dora/v1/dora.schema.json",
|
|
4
|
+
"title": "terragucci.dora/v1",
|
|
5
|
+
"description": "dora.json at the top of a reports prefix, beside estate.json: the four DORA metrics per project and for the estate, which terragucci estate builds from audit.jsonl and each project's index.json. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "generated", "weeks", "window", "drift_window_seconds", "audit", "estate", "projects"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.dora/v1" },
|
|
10
|
+
"generated": { "type": "string", "description": "When the metrics were built, ISO 8601." },
|
|
11
|
+
"weeks": { "type": "integer", "description": "How many weeks the metrics cover, the current one included." },
|
|
12
|
+
"window": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["from", "to"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"from": { "type": "string", "description": "The Monday, 00:00 UTC, the window starts on." },
|
|
17
|
+
"to": { "type": "string", "description": "When it ends: generated." }
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"drift_window_seconds": { "type": "integer", "description": "An applied wave whose roots drift within this long counts as a failed change." },
|
|
21
|
+
"audit": { "type": "boolean", "description": "Whether audit.jsonl was read. Without it no apply counts." },
|
|
22
|
+
"estate": { "$ref": "#/$defs/metrics" },
|
|
23
|
+
"projects": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"required": ["project", "deployments", "per_week", "lead_time", "change_failure", "restore", "trend"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"project": { "type": "string" },
|
|
30
|
+
"deployments": { "type": "integer" },
|
|
31
|
+
"per_week": { "type": "number" },
|
|
32
|
+
"lead_time": { "$ref": "#/$defs/lead_time" },
|
|
33
|
+
"change_failure": { "$ref": "#/$defs/change_failure" },
|
|
34
|
+
"restore": { "$ref": "#/$defs/restore" },
|
|
35
|
+
"trend": { "$ref": "#/$defs/trend" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"$defs": {
|
|
41
|
+
"seconds": { "type": ["integer", "null"], "description": "A median in seconds; null when nothing counts." },
|
|
42
|
+
"metrics": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"required": ["deployments", "per_week", "lead_time", "change_failure", "restore", "trend"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"deployments": { "type": "integer", "description": "Applied waves in the window." },
|
|
47
|
+
"per_week": { "type": "number", "description": "Deployment frequency: applied waves per week over the window." },
|
|
48
|
+
"lead_time": { "$ref": "#/$defs/lead_time" },
|
|
49
|
+
"change_failure": { "$ref": "#/$defs/change_failure" },
|
|
50
|
+
"restore": { "$ref": "#/$defs/restore" },
|
|
51
|
+
"trend": { "$ref": "#/$defs/trend" }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"lead_time": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"description": "From a change's first plan to its wave applied.",
|
|
57
|
+
"required": ["changes", "median_seconds", "before_gate_seconds", "at_gate_seconds", "after_gate_seconds"],
|
|
58
|
+
"properties": {
|
|
59
|
+
"changes": { "type": "integer", "description": "Applied waves whose first plan was found." },
|
|
60
|
+
"median_seconds": { "$ref": "#/$defs/seconds" },
|
|
61
|
+
"before_gate_seconds": { "$ref": "#/$defs/seconds" },
|
|
62
|
+
"at_gate_seconds": { "$ref": "#/$defs/seconds" },
|
|
63
|
+
"after_gate_seconds": { "$ref": "#/$defs/seconds" }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"change_failure": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": ["applies", "failed", "drifted", "rate"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"applies": { "type": "integer", "description": "Waves that applied or failed. A refused or waiting wave is not an apply." },
|
|
71
|
+
"failed": { "type": "integer" },
|
|
72
|
+
"drifted": { "type": "integer", "description": "Applied waves whose roots drifted within drift_window_seconds." },
|
|
73
|
+
"rate": { "type": ["number", "null"], "description": "(failed + drifted) / applies; null with no applies." }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"restore": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"required": ["restored", "open", "median_seconds", "apply_restored", "drift_restored"],
|
|
79
|
+
"properties": {
|
|
80
|
+
"restored": { "type": "integer", "description": "Failed applies and drift restored in the window." },
|
|
81
|
+
"open": { "type": "integer", "description": "Failed roots no apply has restored yet, and drift no check has cleared." },
|
|
82
|
+
"median_seconds": { "$ref": "#/$defs/seconds" },
|
|
83
|
+
"apply_restored": { "type": "integer" },
|
|
84
|
+
"drift_restored": { "type": "integer" }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"trend": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"description": "One row per week, oldest first.",
|
|
90
|
+
"items": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"required": ["week", "deployments", "applies", "failures", "lead_time_seconds", "restore_seconds"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"week": { "type": "string", "description": "The Monday the week starts on, YYYY-MM-DD." },
|
|
95
|
+
"deployments": { "type": "integer" },
|
|
96
|
+
"applies": { "type": "integer" },
|
|
97
|
+
"failures": { "type": "integer", "description": "Failed applies and applied waves followed by drift." },
|
|
98
|
+
"lead_time_seconds": { "$ref": "#/$defs/seconds" },
|
|
99
|
+
"restore_seconds": { "$ref": "#/$defs/seconds" }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
package/dist/estate.schema.json
CHANGED
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"failed_roots": { "type": "integer" },
|
|
20
20
|
"unreadable": { "type": "integer", "description": "Projects whose index could not be read." },
|
|
21
21
|
"overridden_roots": { "type": "integer", "description": "Roots the newest apply waves applied under a policy override. Absent when none." },
|
|
22
|
-
"resources": { "type": "integer", "description": "Resources across every project's inventory. Absent when no project has one." }
|
|
22
|
+
"resources": { "type": "integer", "description": "Resources across every project's inventory. Absent when no project has one." },
|
|
23
|
+
"ephemeral": { "type": "integer", "description": "Live ephemeral environments across every project. Absent when none is live." }
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
"projects": { "type": "array", "items": { "$ref": "#/$defs/project" } },
|
|
@@ -43,9 +44,58 @@
|
|
|
43
44
|
"resources": { "type": "integer", "description": "Addresses with at least one apply." },
|
|
44
45
|
"generated": { "type": "string" }
|
|
45
46
|
}
|
|
47
|
+
},
|
|
48
|
+
"dora": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"description": "The DORA metrics beside the page (dora.json, terragucci.dora/v1).",
|
|
51
|
+
"required": ["file", "generated", "deployments"],
|
|
52
|
+
"properties": {
|
|
53
|
+
"file": { "type": "string" },
|
|
54
|
+
"generated": { "type": "string" },
|
|
55
|
+
"deployments": { "type": "integer", "description": "The estate's applied waves in the metrics' window." }
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"graph": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"description": "The dependency graph, from the run view of each project's newest applied commit: every root by wave, and an edge from each root to each root that reads its state through terraform_remote_state. An edge between two projects matched a read of a state outside the reader's project to the root of the other that holds it. Absent when no project has a run view.",
|
|
61
|
+
"required": ["nodes", "edges"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"nodes": {
|
|
64
|
+
"type": "array",
|
|
65
|
+
"items": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"required": ["project", "root", "wave"],
|
|
68
|
+
"properties": {
|
|
69
|
+
"project": { "type": "string" },
|
|
70
|
+
"root": { "type": "string" },
|
|
71
|
+
"wave": { "type": "integer" }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"edges": {
|
|
76
|
+
"type": "array",
|
|
77
|
+
"description": "Each edge: to reads the state of from.",
|
|
78
|
+
"items": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"required": ["from", "to"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"from": { "$ref": "#/$defs/graphRoot" },
|
|
83
|
+
"to": { "$ref": "#/$defs/graphRoot" }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
46
88
|
}
|
|
47
89
|
},
|
|
48
90
|
"$defs": {
|
|
91
|
+
"graphRoot": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"required": ["project", "root"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"project": { "type": "string" },
|
|
96
|
+
"root": { "type": "string" }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
49
99
|
"totals": {
|
|
50
100
|
"type": "object",
|
|
51
101
|
"required": ["create", "update", "replace", "delete"],
|
|
@@ -65,6 +115,7 @@
|
|
|
65
115
|
"commit": { "type": "string" },
|
|
66
116
|
"stage": { "enum": ["tf-plan", "tf-apply", "tf-drift"] },
|
|
67
117
|
"wave": { "type": "integer" },
|
|
118
|
+
"share": { "type": "integer", "description": "The share of a tf-apply wave split across jobs." },
|
|
68
119
|
"finished": { "type": "string" },
|
|
69
120
|
"roots": { "type": "integer" },
|
|
70
121
|
"changed": { "type": "integer" },
|
|
@@ -117,7 +168,107 @@
|
|
|
117
168
|
"drifted": { "type": "integer", "description": "Roots that drifted in the latest drift check." },
|
|
118
169
|
"failed": { "type": "integer", "description": "Roots that failed in the latest plan, drift check and apply waves." },
|
|
119
170
|
"overridden": { "type": "integer", "description": "Roots the newest commit's apply waves applied under a policy override. Absent when none." },
|
|
120
|
-
"inventory": { "$ref": "#/$defs/inventory", "description": "The resources its roots hold, from its inventory.json. Absent until an apply records them." }
|
|
171
|
+
"inventory": { "$ref": "#/$defs/inventory", "description": "The resources its roots hold, from its inventory.json. Absent until an apply records them." },
|
|
172
|
+
"states": { "type": "array", "description": "Each root's state versions, from its states.json. Absent until an apply records them.", "items": { "$ref": "#/$defs/stateRoot" } },
|
|
173
|
+
"edges": { "type": "array", "description": "Each cross-state edge, from its edges.json: a consumer root, the producer root whose state it reads, the consumer's last plan and the producer's last apply that changed it. Absent until a run records an edge.", "items": { "$ref": "#/$defs/edge" } },
|
|
174
|
+
"run_view": {
|
|
175
|
+
"type": "object",
|
|
176
|
+
"description": "The run view of the project's newest applied commit, which the dependency graph read: its commit, when a wave last wrote it, and its run.html when the page can link it. Absent until a wave writes one.",
|
|
177
|
+
"required": ["commit", "updated"],
|
|
178
|
+
"properties": {
|
|
179
|
+
"commit": { "type": "string" },
|
|
180
|
+
"updated": { "type": "string" },
|
|
181
|
+
"page": { "type": "string" }
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"applying": {
|
|
185
|
+
"type": "array",
|
|
186
|
+
"description": "The waves of that run view still applying whose resources are followed (a choudoufu wave): how many are done, in flight and waiting at the last read of the records.",
|
|
187
|
+
"items": {
|
|
188
|
+
"type": "object",
|
|
189
|
+
"required": ["wave", "read", "total", "done", "in_flight", "waiting"],
|
|
190
|
+
"properties": {
|
|
191
|
+
"wave": { "type": "integer" },
|
|
192
|
+
"read": { "type": "string" },
|
|
193
|
+
"total": { "type": "integer" },
|
|
194
|
+
"done": { "type": "integer" },
|
|
195
|
+
"in_flight": { "type": "integer" },
|
|
196
|
+
"waiting": { "type": "integer" }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"ephemeral": {
|
|
201
|
+
"type": "array",
|
|
202
|
+
"description": "The live ephemeral environments, from its ephemeral.json: each pull request's copy of the ephemeral roots, their state keys, and when it expires. Absent when none is live.",
|
|
203
|
+
"items": {
|
|
204
|
+
"type": "object",
|
|
205
|
+
"required": ["pull_request", "suffix", "roots", "commit", "applied", "expires", "status"],
|
|
206
|
+
"properties": {
|
|
207
|
+
"pull_request": { "type": "integer" },
|
|
208
|
+
"pull_request_url": { "type": "string" },
|
|
209
|
+
"suffix": { "type": "string", "description": "What the copy's state keys end in: pr-<n>." },
|
|
210
|
+
"roots": { "type": "array", "items": { "type": "object", "required": ["root", "location"], "properties": { "root": { "type": "string" }, "location": { "type": "string" } } } },
|
|
211
|
+
"commit": { "type": "string", "description": "The head the copy last applied from." },
|
|
212
|
+
"applied": { "type": "string" },
|
|
213
|
+
"expires": { "type": "string" },
|
|
214
|
+
"approved_by": { "type": "string" },
|
|
215
|
+
"status": { "enum": ["live", "destroy-failed"] }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"edgeRun": {
|
|
222
|
+
"type": "object",
|
|
223
|
+
"required": ["stage", "commit", "finished"],
|
|
224
|
+
"properties": {
|
|
225
|
+
"stage": { "type": "string" },
|
|
226
|
+
"commit": { "type": "string" },
|
|
227
|
+
"finished": { "type": "string" },
|
|
228
|
+
"wave": { "type": "integer" },
|
|
229
|
+
"pull_request": { "type": "string" },
|
|
230
|
+
"version_id": { "type": "string" },
|
|
231
|
+
"report": { "type": "string", "description": "The run's report.html, when the page can link it." }
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"edge": {
|
|
235
|
+
"type": "object",
|
|
236
|
+
"description": "One root reading another's state. stale: the producer applied a change after the consumer's last plan; current: the consumer's last plan is newer than that apply; unknown: either run is not recorded.",
|
|
237
|
+
"required": ["consumer", "producer", "via", "status"],
|
|
238
|
+
"properties": {
|
|
239
|
+
"consumer": { "type": "string" },
|
|
240
|
+
"producer": { "type": "string" },
|
|
241
|
+
"via": { "enum": ["terraform_remote_state", "dependency"] },
|
|
242
|
+
"consumer_planned": { "$ref": "#/$defs/edgeRun" },
|
|
243
|
+
"producer_applied": { "$ref": "#/$defs/edgeRun" },
|
|
244
|
+
"status": { "enum": ["current", "stale", "unknown"] }
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"stateRoot": {
|
|
248
|
+
"type": "object",
|
|
249
|
+
"description": "One root's state: where it is, whether its backend keeps versions, and the version ids its applies left, newest first. Never the state's contents.",
|
|
250
|
+
"required": ["root", "backend", "versioning", "checked", "versions"],
|
|
251
|
+
"properties": {
|
|
252
|
+
"root": { "type": "string" },
|
|
253
|
+
"backend": { "type": "string" },
|
|
254
|
+
"location": { "type": "string" },
|
|
255
|
+
"versioning": { "enum": ["on", "off", "unknown"] },
|
|
256
|
+
"note": { "type": "string" },
|
|
257
|
+
"checked": { "type": "string", "description": "When the newest apply that recorded the root finished." },
|
|
258
|
+
"versions": {
|
|
259
|
+
"type": "array",
|
|
260
|
+
"items": {
|
|
261
|
+
"type": "object",
|
|
262
|
+
"required": ["version_id", "commit", "finished"],
|
|
263
|
+
"properties": {
|
|
264
|
+
"version_id": { "type": "string" },
|
|
265
|
+
"commit": { "type": "string" },
|
|
266
|
+
"finished": { "type": "string" },
|
|
267
|
+
"wave": { "type": "integer" },
|
|
268
|
+
"report": { "type": "string", "description": "The wave's report.html, when the page can link it." }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
121
272
|
}
|
|
122
273
|
},
|
|
123
274
|
"inventory": {
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"commit": { "type": "string" },
|
|
33
33
|
"stage": { "enum": ["tf-plan", "tf-apply", "tf-drift"] },
|
|
34
34
|
"wave": { "type": "integer", "description": "The wave of a tf-apply run." },
|
|
35
|
+
"share": { "type": "integer", "description": "The share of a tf-apply wave split across jobs." },
|
|
35
36
|
"finished": { "type": "string", "description": "When the run finished, ISO 8601." },
|
|
36
|
-
"path": { "type": "string", "description": "The run's directory, relative to this index: <yyyy>/<mm>/<commit>/<stage>[-wave-N] in a project's index, prefixed with the project in the top index." },
|
|
37
|
+
"path": { "type": "string", "description": "The run's directory, relative to this index: <yyyy>/<mm>/<commit>/<stage>[-wave-N[-share-S]] in a project's index, prefixed with the project in the top index." },
|
|
37
38
|
"roots": { "type": "integer" },
|
|
38
39
|
"groups": { "type": "integer" },
|
|
39
40
|
"totals": { "$ref": "#/$defs/totals" },
|
|
@@ -44,6 +45,15 @@
|
|
|
44
45
|
"waiting_since": { "type": "string", "description": "When a waiting wave began waiting for an approval of its digest." },
|
|
45
46
|
"applied": { "type": "string", "description": "When a tf-apply wave finished applying." },
|
|
46
47
|
"overridden": { "type": "integer", "description": "Roots the policy denied that a recorded override let through. Absent when none." },
|
|
48
|
+
"wave_digests": { "type": "array", "items": { "type": "string" }, "description": "A tf-plan row: each wave's set digest and review digest, the digests an apply of the same plans binds. Absent when no wave has one." },
|
|
49
|
+
"drifted_roots": { "type": "array", "items": { "type": "string" }, "description": "A tf-drift row: the roots that drifted, at most 50. Absent when none drifted." },
|
|
50
|
+
"drift_since": { "type": "string", "description": "A tf-drift row that found drift: when the project's open drift was first found, by this run or an earlier one." },
|
|
51
|
+
"drift_cleared": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "A tf-drift row that found none after a row that found some: when that drift was first found, and its roots.",
|
|
54
|
+
"required": ["since", "roots"],
|
|
55
|
+
"properties": { "since": { "type": "string" }, "roots": { "type": "array", "items": { "type": "string" } } }
|
|
56
|
+
},
|
|
47
57
|
"destroys": { "type": "array", "items": { "type": "string" }, "description": "Destroys and replacements as `<root>: <address>`, at most 50." },
|
|
48
58
|
"destroys_total": { "type": "integer", "description": "How many destroys and replacements there are, when there are more than the row lists." },
|
|
49
59
|
"commit_url": { "type": "string" },
|
package/dist/report.schema.json
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"base": { "type": "string" },
|
|
18
18
|
"stage": { "enum": ["tf-plan", "tf-apply", "tf-drift"] },
|
|
19
19
|
"wave": { "type": "integer" },
|
|
20
|
+
"share": { "type": "integer", "minimum": 1, "description": "On a tf-apply wave split across jobs (waves.jobs), the share this report applied; waves[0].roots are its roots (minor 20)." },
|
|
20
21
|
"binary": { "type": "string" },
|
|
21
22
|
"runtime": { "type": "string" },
|
|
22
23
|
"started": { "type": "string" },
|
|
@@ -70,12 +71,32 @@
|
|
|
70
71
|
"required": ["path", "status", "plan_digest", "counts", "plan", "changes", "highlights", "fold", "why"],
|
|
71
72
|
"properties": {
|
|
72
73
|
"path": { "type": "string" },
|
|
74
|
+
"binary": {
|
|
75
|
+
"description": "The binary the root ran, its version, and where the root pinned that version when it did (minor 18).",
|
|
76
|
+
"type": "object",
|
|
77
|
+
"required": ["name"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"name": { "type": "string" },
|
|
80
|
+
"version": { "type": "string" },
|
|
81
|
+
"pin": { "type": "string" },
|
|
82
|
+
"terragrunt": {
|
|
83
|
+
"description": "A Terragrunt unit: the Terragrunt release that ran it, and terragrunt_version_constraint when the unit pinned it (minor 24).",
|
|
84
|
+
"type": "object",
|
|
85
|
+
"required": ["version"],
|
|
86
|
+
"properties": {
|
|
87
|
+
"version": { "type": "string" },
|
|
88
|
+
"pin": { "type": "string" }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
73
93
|
"terragrunt": {
|
|
74
94
|
"description": "Set when the root is a Terragrunt unit (minor 1).",
|
|
75
95
|
"type": "object",
|
|
76
96
|
"required": ["stack", "selection", "provisional", "run_result"],
|
|
77
97
|
"properties": {
|
|
78
98
|
"stack": { "type": "string" },
|
|
99
|
+
"stack_file": { "description": "The terragrunt.stack.hcl that generates the unit, when an explicit stack does (minor 29).", "type": "string" },
|
|
79
100
|
"selection": { "type": "string" },
|
|
80
101
|
"provisional": { "type": "boolean" },
|
|
81
102
|
"run_result": { "type": "string" }
|
|
@@ -189,7 +210,67 @@
|
|
|
189
210
|
"previous_address": { "type": "string" }
|
|
190
211
|
}
|
|
191
212
|
}
|
|
192
|
-
}
|
|
213
|
+
},
|
|
214
|
+
"dependencies": {
|
|
215
|
+
"description": "A Terragrunt unit's dependency and dependencies blocks: the units whose outputs it reads, as plain paths in its terragrunt.hcl (minor 23). For a plain root, the roots waves.after puts before it. Absent when it names none.",
|
|
216
|
+
"type": "array",
|
|
217
|
+
"items": { "type": "string" }
|
|
218
|
+
},
|
|
219
|
+
"state": {
|
|
220
|
+
"description": "On a tf-apply wave, a root that applied or had nothing to apply: the state version its backend holds afterwards, read from the object's metadata, never its contents (minor 20).",
|
|
221
|
+
"type": "object",
|
|
222
|
+
"required": ["backend", "versioning"],
|
|
223
|
+
"properties": {
|
|
224
|
+
"backend": { "type": "string" },
|
|
225
|
+
"location": { "type": "string" },
|
|
226
|
+
"version_id": { "type": "string" },
|
|
227
|
+
"versioning": { "enum": ["on", "off", "unknown"] },
|
|
228
|
+
"note": { "type": "string" }
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"steps": {
|
|
232
|
+
"description": "The steps that ran for the root, in the order they ran (minor 17). failed: the root failed; approval: an on_failure: approve step failed, so the root's wave waits for an approval.",
|
|
233
|
+
"type": "array",
|
|
234
|
+
"items": {
|
|
235
|
+
"type": "object",
|
|
236
|
+
"required": ["name", "when", "status", "exit", "seconds"],
|
|
237
|
+
"properties": {
|
|
238
|
+
"name": { "type": "string" },
|
|
239
|
+
"when": { "enum": ["before-init", "after-init", "before-plan", "after-plan", "before-apply", "after-apply", "before-drift", "after-drift"] },
|
|
240
|
+
"status": { "enum": ["passed", "failed", "approval"] },
|
|
241
|
+
"exit": { "type": ["integer", "null"] },
|
|
242
|
+
"seconds": { "type": "number" }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
"reads": {
|
|
247
|
+
"description": "The roots whose state the root reads through terraform_remote_state, and which outputs it planned on: planned, the upstream's plan in this run, with the outputs known only once it applies under unknown; applied, its state as it stands (minor 21).",
|
|
248
|
+
"type": "array",
|
|
249
|
+
"items": {
|
|
250
|
+
"type": "object",
|
|
251
|
+
"required": ["upstream", "data", "outputs"],
|
|
252
|
+
"properties": {
|
|
253
|
+
"upstream": { "type": "string" },
|
|
254
|
+
"data": { "type": "string" },
|
|
255
|
+
"outputs": { "enum": ["planned", "applied"] },
|
|
256
|
+
"unknown": { "type": "array", "items": { "type": "string" } },
|
|
257
|
+
"why": { "type": "string" }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"unknown_reads": {
|
|
262
|
+
"description": "Its terraform_remote_state blocks whose state the code does not address, an expression or a value the backend takes from the environment: no edge orders the root after the root that writes that state, so the edge is unknown (minor 30).",
|
|
263
|
+
"type": "array",
|
|
264
|
+
"items": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"required": ["data", "why"],
|
|
267
|
+
"properties": {
|
|
268
|
+
"data": { "type": "string", "description": "The block's label." },
|
|
269
|
+
"why": { "type": "string" }
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
"unaddressed": { "type": "string", "description": "Why the code does not address the root's own state, when a root of the run reads state through terraform_remote_state: a reader of it is not ordered after it (minor 30)." }
|
|
193
274
|
}
|
|
194
275
|
}
|
|
195
276
|
},
|
|
@@ -230,6 +311,47 @@
|
|
|
230
311
|
"pull_request": { "type": "integer" },
|
|
231
312
|
"url": { "type": "string" }
|
|
232
313
|
}
|
|
314
|
+
},
|
|
315
|
+
"held_by_steps": {
|
|
316
|
+
"type": "array",
|
|
317
|
+
"items": { "type": "string" },
|
|
318
|
+
"description": "The roots whose on_failure: approve step failed: the gate holds the wave whatever the gate policy says, when it changes anything (minor 17)."
|
|
319
|
+
},
|
|
320
|
+
"cost": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"description": "The wave's monthly cost, when cost is on (minor 19): the sums over its roots estimated, and with cost.approve_above at base whether the change is over it, so the wave waits for an approval whatever the gate.",
|
|
323
|
+
"required": ["currency", "monthly_delta", "monthly_total", "past_monthly_total"],
|
|
324
|
+
"properties": {
|
|
325
|
+
"currency": { "type": "string" },
|
|
326
|
+
"monthly_delta": { "type": ["number", "null"] },
|
|
327
|
+
"monthly_total": { "type": ["number", "null"] },
|
|
328
|
+
"past_monthly_total": { "type": ["number", "null"] },
|
|
329
|
+
"unestimated": { "type": "array", "items": { "type": "string" } },
|
|
330
|
+
"approve_above": { "type": "number" },
|
|
331
|
+
"over": { "type": "boolean" }
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
"state": { "enum": ["planned", "waiting", "applying", "applied", "refused", "failed"], "description": "Where the wave stands (minor 21): a tf-plan wave is planned; a tf-apply wave waiting, applying, applied, refused or failed." },
|
|
335
|
+
"reads": { "type": "array", "items": { "type": "integer" }, "description": "The waves whose roots' state its roots read (minor 21)." },
|
|
336
|
+
"replans_after": { "type": "array", "items": { "type": "integer" }, "description": "A tf-plan wave whose plans read outputs known only once these waves apply: it plans again after they apply and waits for an approval of that plan; its review digest is null (minor 21)." },
|
|
337
|
+
"preview": {
|
|
338
|
+
"type": "object",
|
|
339
|
+
"required": ["pull_request", "units"],
|
|
340
|
+
"description": "A tf-apply wave of Terragrunt units: its plans against the preview of them the merged pull request's plan note showed (minor 25).",
|
|
341
|
+
"properties": {
|
|
342
|
+
"pull_request": { "type": "integer" },
|
|
343
|
+
"units": {
|
|
344
|
+
"type": "array",
|
|
345
|
+
"items": {
|
|
346
|
+
"type": "object",
|
|
347
|
+
"required": ["unit"],
|
|
348
|
+
"properties": {
|
|
349
|
+
"unit": { "type": "string" },
|
|
350
|
+
"differences": { "type": "array", "items": { "type": "string" }, "description": "How its plan differs from the preview. Absent when it plans as previewed." }
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
233
355
|
}
|
|
234
356
|
}
|
|
235
357
|
}
|
|
@@ -278,8 +400,60 @@
|
|
|
278
400
|
"overriders": { "type": "array", "items": { "type": "string" }, "description": "Who may override a denial, from policy.override at base (minor 10)." }
|
|
279
401
|
}
|
|
280
402
|
},
|
|
403
|
+
"blast": {
|
|
404
|
+
"description": "A tf-plan run's blast radius (minor 22): the roots whose plan changes a resource or an output, and every root of the repo that reads their state through terraform_remote_state (in a Terragrunt repo, every unit that depends on them through a dependency or dependencies block), followed through, nearest first. Absent when no root's plan changes anything, and on other stages.",
|
|
405
|
+
"type": "object",
|
|
406
|
+
"required": ["roots", "downstream"],
|
|
407
|
+
"properties": {
|
|
408
|
+
"roots": { "type": "array", "items": { "type": "string" } },
|
|
409
|
+
"downstream": {
|
|
410
|
+
"type": "array",
|
|
411
|
+
"items": {
|
|
412
|
+
"type": "object",
|
|
413
|
+
"required": ["root", "reads", "depth", "planned"],
|
|
414
|
+
"properties": {
|
|
415
|
+
"root": { "type": "string" },
|
|
416
|
+
"reads": { "type": "array", "items": { "type": "string" }, "description": "The roots in the radius whose state it reads." },
|
|
417
|
+
"depth": { "type": "integer", "minimum": 1, "description": "1 when it reads a changed root's state itself, 2 when it reads such a reader's, and so on." },
|
|
418
|
+
"wave": { "type": "integer", "description": "The apply wave it is in." },
|
|
419
|
+
"planned": { "type": "boolean", "description": "Whether this run planned it." }
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
"resources": {
|
|
424
|
+
"description": "The radius by resource (minor 31), when a root is downstream: each resource a plan changes and the resources that depend on it, from the plans' references and the outputs each root reads, nearest first. A changed resource that nothing depends on is left out. Absent in a Terragrunt repo.",
|
|
425
|
+
"type": "array",
|
|
426
|
+
"items": {
|
|
427
|
+
"type": "object",
|
|
428
|
+
"required": ["root", "address", "actions", "reaches"],
|
|
429
|
+
"properties": {
|
|
430
|
+
"root": { "type": "string" },
|
|
431
|
+
"address": { "type": "string", "description": "The changed resource instance's address." },
|
|
432
|
+
"actions": { "type": "array", "items": { "type": "string" } },
|
|
433
|
+
"reaches": {
|
|
434
|
+
"type": "array",
|
|
435
|
+
"items": {
|
|
436
|
+
"type": "object",
|
|
437
|
+
"required": ["root", "address"],
|
|
438
|
+
"properties": {
|
|
439
|
+
"root": { "type": "string" },
|
|
440
|
+
"address": { "type": "string", "description": "Its address in the root's configuration, with no instance key." },
|
|
441
|
+
"through": {
|
|
442
|
+
"type": "object",
|
|
443
|
+
"required": ["root", "output"],
|
|
444
|
+
"description": "In another root: the output it reads, and the root that makes it.",
|
|
445
|
+
"properties": { "root": { "type": "string" }, "output": { "type": "string" } }
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
},
|
|
281
455
|
"cost": {
|
|
282
|
-
"description": "The cost estimate of a tf-plan run, when cost is on (minor 12): each root's monthly cost from the estimator, and the sums over the roots estimated.",
|
|
456
|
+
"description": "The cost estimate of a tf-plan run, or of a tf-apply wave's plans (minor 19), when cost is on (minor 12): each root's monthly cost from the estimator, and the sums over the roots estimated.",
|
|
283
457
|
"type": "object",
|
|
284
458
|
"required": ["estimator", "currency", "monthly_delta", "monthly_total", "past_monthly_total", "roots"],
|
|
285
459
|
"properties": {
|