@intentius/chant-lexicon-terraform 0.124.52 → 0.124.54
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 +7 -6
- package/dist/__fixtures__/pr-loop/estate.component.d.ts +7 -0
- package/dist/__fixtures__/pr-loop/estate.component.d.ts.map +1 -0
- package/dist/__fixtures__/pr-loop/estate.component.js +7 -0
- package/dist/__fixtures__/report/generate.d.ts +26 -0
- package/dist/__fixtures__/report/generate.d.ts.map +1 -0
- package/dist/__fixtures__/report/generate.js +58 -0
- package/dist/applied-state.d.ts +27 -0
- package/dist/applied-state.d.ts.map +1 -0
- package/dist/applied-state.js +44 -0
- package/dist/backend-config.d.ts +53 -0
- package/dist/backend-config.d.ts.map +1 -0
- package/dist/backend-config.js +136 -0
- package/dist/behaviour/kinds.d.ts.map +1 -1
- package/dist/behaviour/kinds.js +4 -0
- package/dist/behaviour/predict.d.ts.map +1 -1
- package/dist/behaviour/predict.js +6 -2
- package/dist/behaviour/reference-catalog.d.ts +16 -5
- package/dist/behaviour/reference-catalog.d.ts.map +1 -1
- package/dist/behaviour/reference-catalog.js +16 -5
- package/dist/behaviour/request.d.ts.map +1 -1
- package/dist/behaviour/request.js +3 -2
- package/dist/changed-roots.d.ts +6 -4
- package/dist/changed-roots.d.ts.map +1 -1
- package/dist/changed-roots.js +14 -18
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/components/capability-plugin.d.ts +65 -3
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +197 -13
- package/dist/components/compose-group.d.ts +145 -0
- package/dist/components/compose-group.d.ts.map +1 -0
- package/dist/components/compose-group.js +407 -0
- package/dist/components/placeholder-preview.d.ts +78 -0
- package/dist/components/placeholder-preview.d.ts.map +1 -0
- package/dist/components/placeholder-preview.js +254 -0
- package/dist/compose/apply-events.d.ts +46 -0
- package/dist/compose/apply-events.d.ts.map +1 -0
- package/dist/compose/apply-events.js +77 -0
- package/dist/compose/estate.d.ts +194 -0
- package/dist/compose/estate.d.ts.map +1 -0
- package/dist/compose/estate.js +363 -0
- package/dist/compose/hcl.d.ts +99 -0
- package/dist/compose/hcl.d.ts.map +1 -0
- package/dist/compose/hcl.js +302 -0
- package/dist/compose/module-address.d.ts +24 -0
- package/dist/compose/module-address.d.ts.map +1 -0
- package/dist/compose/module-address.js +43 -0
- package/dist/compose/root.d.ts +127 -0
- package/dist/compose/root.d.ts.map +1 -0
- package/dist/compose/root.js +586 -0
- package/dist/compose/run.d.ts +183 -0
- package/dist/compose/run.d.ts.map +1 -0
- package/dist/compose/run.js +447 -0
- package/dist/compose/slice.d.ts +102 -0
- package/dist/compose/slice.d.ts.map +1 -0
- package/dist/compose/slice.js +249 -0
- package/dist/compose/state-address.d.ts +28 -0
- package/dist/compose/state-address.d.ts.map +1 -0
- package/dist/compose/state-address.js +154 -0
- package/dist/compose/state-merge.d.ts +52 -0
- package/dist/compose/state-merge.d.ts.map +1 -0
- package/dist/compose/state-merge.js +135 -0
- package/dist/compose.d.ts +179 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +482 -0
- package/dist/composites/terraform-apply-op.d.ts.map +1 -1
- package/dist/composites/terraform-apply-op.js +7 -3
- package/dist/config.d.ts +59 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -9
- package/dist/describe-resources.d.ts +74 -12
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +374 -66
- package/dist/drift-read.d.ts +33 -0
- package/dist/drift-read.d.ts.map +1 -0
- package/dist/drift-read.js +243 -0
- package/dist/drift-record.d.ts +147 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +383 -0
- package/dist/hcl/edges.d.ts.map +1 -1
- package/dist/hcl/edges.js +24 -1
- package/dist/hcl/files.d.ts +61 -0
- package/dist/hcl/files.d.ts.map +1 -0
- package/dist/hcl/files.js +221 -0
- package/dist/hcl/instances.d.ts +82 -0
- package/dist/hcl/instances.d.ts.map +1 -0
- package/dist/hcl/instances.js +390 -0
- package/dist/hcl/parse.d.ts +81 -9
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +114 -16
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/roots.js +5 -0
- package/dist/hcl/suppressions.d.ts.map +1 -1
- package/dist/hcl/suppressions.js +8 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -2
- package/dist/integrity.json +3 -3
- package/dist/live-plan-reasons.d.ts +21 -0
- package/dist/live-plan-reasons.d.ts.map +1 -0
- package/dist/live-plan-reasons.js +47 -0
- package/dist/lsp/option-keys.d.ts.map +1 -1
- package/dist/lsp/option-keys.js +2 -0
- package/dist/manifest.json +1 -1
- package/dist/op/activities/index.d.ts +6 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +5 -1
- package/dist/op/activities/live-detect.d.ts +4 -3
- package/dist/op/activities/live-detect.d.ts.map +1 -1
- package/dist/op/activities/live-detect.js +57 -32
- package/dist/op/activities/pin-rollout.d.ts +2 -0
- package/dist/op/activities/pin-rollout.d.ts.map +1 -1
- package/dist/op/activities/pin-rollout.js +1 -0
- package/dist/op/activities/terraform.d.ts +153 -5
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +205 -20
- package/dist/op/activity-contracts.d.ts +27 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +19 -1
- package/dist/op/builders.d.ts +7 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -0
- package/dist/pin/edit.d.ts.map +1 -1
- package/dist/pin/edit.js +35 -0
- package/dist/pin/rollout.d.ts +2 -0
- package/dist/pin/rollout.d.ts.map +1 -1
- package/dist/pin/rollout.js +14 -11
- package/dist/plan-shape.d.ts +30 -0
- package/dist/plan-shape.d.ts.map +1 -0
- package/dist/plan-shape.js +125 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +32 -18
- package/dist/report.d.ts +15 -6
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +28 -55
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/state/azure-blob.d.ts +68 -0
- package/dist/state/azure-blob.d.ts.map +1 -0
- package/dist/state/azure-blob.js +201 -0
- package/dist/state/backend.d.ts +158 -0
- package/dist/state/backend.d.ts.map +1 -0
- package/dist/state/backend.js +406 -0
- package/dist/state/exec.d.ts +39 -0
- package/dist/state/exec.d.ts.map +1 -0
- package/dist/state/exec.js +80 -0
- package/dist/state/gcs.d.ts +62 -0
- package/dist/state/gcs.d.ts.map +1 -0
- package/dist/state/gcs.js +224 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +14 -0
- package/dist/state/locks.d.ts +105 -0
- package/dist/state/locks.d.ts.map +1 -0
- package/dist/state/locks.js +130 -0
- package/dist/state/object-store.d.ts +37 -0
- package/dist/state/object-store.d.ts.map +1 -0
- package/dist/state/object-store.js +20 -0
- package/dist/state/root-states.d.ts +131 -0
- package/dist/state/root-states.d.ts.map +1 -0
- package/dist/state/root-states.js +241 -0
- package/dist/state/s3.d.ts +68 -0
- package/dist/state/s3.d.ts.map +1 -0
- package/dist/state/s3.js +170 -0
- package/dist/state/store.d.ts +51 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +185 -0
- package/dist/terragrunt/affected.d.ts.map +1 -1
- package/dist/terragrunt/affected.js +2 -1
- package/package.json +7 -3
- package/src/__fixtures__/ACCEPTANCE.md +69 -7
- package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
- package/src/__fixtures__/compose/state-app.json +66 -0
- package/src/__fixtures__/compose/state-edge.json +40 -0
- package/src/__fixtures__/compose/state-net.json +58 -0
- package/src/__fixtures__/compose/three-app.plan.json +184 -0
- package/src/__fixtures__/compose/three-composed.plan.json +509 -0
- package/src/__fixtures__/compose/three-edge.plan.json +144 -0
- package/src/__fixtures__/compose/three-net.plan.json +174 -0
- package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
- package/src/__fixtures__/compose/working-after-apply.json +145 -0
- package/src/__fixtures__/config-blocks/app/main.tf +61 -0
- package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
- package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
- package/src/__fixtures__/config-files/shadow/main.tf +3 -0
- package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
- package/src/__fixtures__/config-files/shadow/other.tf +3 -0
- package/src/__fixtures__/config-files/tf/main.tf +11 -0
- package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
- package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
- package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
- package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
- package/src/__fixtures__/drift-record/README.md +11 -0
- package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
- package/src/__fixtures__/instance-forms/app/main.tf +110 -0
- package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/main.tf +52 -0
- package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
- package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
- package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
- package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
- package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
- package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
- package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
- package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
- package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
- package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
- package/src/__fixtures__/pr-loop/README.md +50 -0
- package/src/__fixtures__/pr-loop/chant.config.json +13 -0
- package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
- package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
- package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
- package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
- package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
- package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
- package/src/__fixtures__/report/applied.show.json +51 -0
- package/src/__fixtures__/report/generate.ts +63 -0
- package/src/__fixtures__/report/plan.show.json +200 -0
- package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
- package/src/__fixtures__/report/tf-apply/report.json +338 -0
- package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
- package/src/__fixtures__/report/tf-plan/report.json +320 -0
- package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
- package/src/applied-state.ts +52 -0
- package/src/backend-config.test.ts +105 -0
- package/src/backend-config.ts +133 -0
- package/src/behaviour/kinds.ts +4 -0
- package/src/behaviour/predict.ts +5 -2
- package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
- package/src/behaviour/reference-catalog.ts +16 -5
- package/src/behaviour/request.ts +3 -2
- package/src/change-set-instances.test.ts +98 -0
- package/src/changed-roots.ts +14 -16
- package/src/commands.ts +4 -3
- package/src/components/capability-plugin.test.ts +172 -5
- package/src/components/capability-plugin.ts +212 -11
- package/src/components/change-set-graph.e2e.test.ts +11 -5
- package/src/components/compose-group.test.ts +486 -0
- package/src/components/compose-group.ts +489 -0
- package/src/components/demo-composed-roots.e2e.test.ts +440 -0
- package/src/components/member-outputs.test.ts +76 -0
- package/src/components/placeholder-preview.test.ts +147 -0
- package/src/components/placeholder-preview.ts +257 -0
- package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
- package/src/components/pr-loop.tofu.test.ts +112 -56
- package/src/compose/apply-events.test.ts +62 -0
- package/src/compose/apply-events.ts +100 -0
- package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
- package/src/compose/estate.test.ts +421 -0
- package/src/compose/estate.ts +443 -0
- package/src/compose/hcl.ts +311 -0
- package/src/compose/module-address.ts +49 -0
- package/src/compose/root.test.ts +416 -0
- package/src/compose/root.ts +592 -0
- package/src/compose/run.test.ts +440 -0
- package/src/compose/run.tofu.test.ts +176 -0
- package/src/compose/run.ts +527 -0
- package/src/compose/slice.test.ts +184 -0
- package/src/compose/slice.ts +290 -0
- package/src/compose/state-address.ts +157 -0
- package/src/compose/state-merge.test.ts +131 -0
- package/src/compose/state-merge.ts +148 -0
- package/src/compose.test.ts +248 -0
- package/src/compose.ts +627 -0
- package/src/composites/terraform-apply-op.test.ts +9 -0
- package/src/composites/terraform-apply-op.ts +7 -3
- package/src/config-file-listers.test.ts +265 -0
- package/src/config.ts +44 -9
- package/src/describe-resources.engine-facts.test.ts +412 -0
- package/src/describe-resources.live-module-keyed.test.ts +290 -0
- package/src/describe-resources.ts +416 -70
- package/src/drift-read.ts +284 -0
- package/src/drift-record.test.ts +223 -0
- package/src/drift-record.ts +455 -0
- package/src/hcl/config-blocks.test.ts +174 -0
- package/src/hcl/edges.ts +21 -1
- package/src/hcl/files.ts +234 -0
- package/src/hcl/instance-forms.test.ts +94 -0
- package/src/hcl/instances.test.ts +137 -0
- package/src/hcl/instances.ts +422 -0
- package/src/hcl/parse.test.ts +139 -1
- package/src/hcl/parse.ts +149 -16
- package/src/hcl/roots.ts +6 -0
- package/src/hcl/suppressions.ts +8 -2
- package/src/index.ts +76 -0
- package/src/live-plan-reasons.ts +54 -0
- package/src/lsp/completions.test.ts +1 -1
- package/src/lsp/option-keys.ts +2 -0
- package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/live-detect.ts +55 -26
- package/src/op/activities/pin-rollout.ts +3 -0
- package/src/op/activities/registry.test.ts +2 -1
- package/src/op/activities/terraform.test.ts +55 -0
- package/src/op/activities/terraform.ts +266 -22
- package/src/op/activity-contracts.test.ts +1 -0
- package/src/op/activity-contracts.ts +24 -1
- package/src/op/builders.ts +14 -0
- package/src/pin/bundle.test.ts +2 -0
- package/src/pin/edit.ts +30 -0
- package/src/pin/rollout.ts +16 -11
- package/src/plan-shape.test.ts +148 -0
- package/src/plan-shape.ts +128 -0
- package/src/plugin.ts +33 -19
- package/src/report.test.ts +82 -1
- package/src/report.ts +31 -54
- package/src/signal-only-root.test.ts +72 -0
- package/src/skills/chant-terraform.md +1 -1
- package/src/state/azure-blob.ts +223 -0
- package/src/state/backend-verdict.test.ts +187 -0
- package/src/state/backend.test.ts +127 -0
- package/src/state/backend.ts +488 -0
- package/src/state/exec.ts +111 -0
- package/src/state/gcs.ts +254 -0
- package/src/state/index.ts +15 -0
- package/src/state/locks.test.ts +84 -0
- package/src/state/locks.ts +201 -0
- package/src/state/object-store.ts +35 -0
- package/src/state/root-states-floci.e2e.test.ts +66 -0
- package/src/state/root-states.test.ts +462 -0
- package/src/state/root-states.ts +309 -0
- package/src/state/s3.ts +193 -0
- package/src/state/store.ts +225 -0
- package/src/terragrunt/affected.ts +2 -1
- package/src/workspace-kinds.test.ts +4 -17
- package/workspace-kinds.json +1 -24
- package/dist/workspace-member.d.ts +0 -30
- package/dist/workspace-member.d.ts.map +0 -1
- package/dist/workspace-member.js +0 -91
- package/schemas/pulumi.schema.json +0 -34
- package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
- package/src/testdata/pulumi-member/stack-export.json +0 -53
- package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
- package/src/workspace-member.test.ts +0 -89
- package/src/workspace-member.ts +0 -126
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Previewing a root whose `vars` read outputs not known yet (#4463).
|
|
3
|
+
*
|
|
4
|
+
* terraform takes no unknown variable, so such a root used to get no plan at
|
|
5
|
+
* pull-request time, only a hole. Now it is planned with a stand-in for each
|
|
6
|
+
* variable that holds no value yet, typed from the root's own `variable`
|
|
7
|
+
* block ({@link terraformPlaceholder}). Every attribute and output the
|
|
8
|
+
* stand-ins drive is then marked unknown after apply in the plan JSON
|
|
9
|
+
* ({@link markPlaceholderDriven}) before the change set, the shape and the
|
|
10
|
+
* planned outputs are read from it, so no stand-in value reaches the note or
|
|
11
|
+
* the digest. The member's change-set part lists the variables under
|
|
12
|
+
* `placeholders`.
|
|
13
|
+
*
|
|
14
|
+
* What a stand-in drives is read from the plan's own `configuration`: an
|
|
15
|
+
* attribute whose expression references `var.<name>`, through module inputs
|
|
16
|
+
* too, plus any string attribute or output whose planned value carries
|
|
17
|
+
* {@link TERRAFORM_UNKNOWN_MARK}. A value that reaches an attribute another
|
|
18
|
+
* way (a number through a `local`) is not marked; the fresh plan at apply
|
|
19
|
+
* then differs from the preview and asks for an approval of its own, which
|
|
20
|
+
* costs a round and never applies a change nobody approved.
|
|
21
|
+
*
|
|
22
|
+
* A preview is not possible when a variable that holds the unknown read is
|
|
23
|
+
* not declared, when the unknown sits inside a larger value, when a `count`
|
|
24
|
+
* or `for_each` reads a stand-in (the preview would show a count the real
|
|
25
|
+
* value does not have), or when the placeholder plan fails, say on a
|
|
26
|
+
* `validation` block. The member then stays a hole, as before, and the
|
|
27
|
+
* hole's reason says why (the 2026-10-25 ruling on #4463).
|
|
28
|
+
*/
|
|
29
|
+
/** The marker every string stand-in carries, so a reader can tell it from a real value. */
|
|
30
|
+
export const TERRAFORM_UNKNOWN_MARK = "known-after-apply";
|
|
31
|
+
const isObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
32
|
+
/** Split `text` on `sep` where no bracket is open. */
|
|
33
|
+
function splitTop(text, sep) {
|
|
34
|
+
const out = [];
|
|
35
|
+
let depth = 0;
|
|
36
|
+
let quoted = false;
|
|
37
|
+
let start = 0;
|
|
38
|
+
for (let i = 0; i < text.length; i++) {
|
|
39
|
+
const c = text[i];
|
|
40
|
+
if (c === '"' && text[i - 1] !== "\\")
|
|
41
|
+
quoted = !quoted;
|
|
42
|
+
if (quoted)
|
|
43
|
+
continue;
|
|
44
|
+
if (c === "(" || c === "[" || c === "{")
|
|
45
|
+
depth++;
|
|
46
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
47
|
+
depth--;
|
|
48
|
+
else if (depth === 0 && (typeof sep === "string" ? c === sep : sep.test(c))) {
|
|
49
|
+
out.push(text.slice(start, i));
|
|
50
|
+
start = i + 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
out.push(text.slice(start));
|
|
54
|
+
return out.map((s) => s.trim()).filter((s) => s !== "");
|
|
55
|
+
}
|
|
56
|
+
/** `name(inner)` read off a type expression, or `undefined` when it is not one. */
|
|
57
|
+
function call(type, name) {
|
|
58
|
+
const m = type.match(new RegExp(`^${name}\\s*\\(([\\s\\S]*)\\)$`));
|
|
59
|
+
return m ? m[1].trim() : undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A stand-in for a variable of `type`, a Terraform type expression as the
|
|
63
|
+
* `variable` block writes it (`string`, `list(string)`, `object({ id = string })`).
|
|
64
|
+
*
|
|
65
|
+
* - `string`, `any` or no type: {@link TERRAFORM_UNKNOWN_MARK}.
|
|
66
|
+
* - `number`: 0. `bool`: false.
|
|
67
|
+
* - `list(...)`, `set(...)`: an empty list. `map(...)`: an empty map.
|
|
68
|
+
* - `tuple([a, b])`: one stand-in per element type.
|
|
69
|
+
* - `object({ a = t })`: one stand-in per attribute, `optional(t)` read as `t`.
|
|
70
|
+
*
|
|
71
|
+
* An empty collection plans no element, so a resource that iterates one
|
|
72
|
+
* plans none; the fresh plan at apply then asks for its own approval.
|
|
73
|
+
*/
|
|
74
|
+
export function terraformPlaceholder(type) {
|
|
75
|
+
const t = (type ?? "").trim().replace(/^\$\{([\s\S]*)\}$/, "$1").trim();
|
|
76
|
+
if (t === "" || t === "any" || t === "string")
|
|
77
|
+
return TERRAFORM_UNKNOWN_MARK;
|
|
78
|
+
if (t === "number")
|
|
79
|
+
return 0;
|
|
80
|
+
if (t === "bool")
|
|
81
|
+
return false;
|
|
82
|
+
const optional = call(t, "optional");
|
|
83
|
+
if (optional !== undefined)
|
|
84
|
+
return terraformPlaceholder(splitTop(optional, ",")[0]);
|
|
85
|
+
if (call(t, "list") !== undefined || call(t, "set") !== undefined)
|
|
86
|
+
return [];
|
|
87
|
+
if (call(t, "map") !== undefined)
|
|
88
|
+
return {};
|
|
89
|
+
const tuple = call(t, "tuple");
|
|
90
|
+
if (tuple !== undefined) {
|
|
91
|
+
const inner = tuple.replace(/^\[([\s\S]*)\]$/, "$1");
|
|
92
|
+
return splitTop(inner, ",").map((e) => terraformPlaceholder(e));
|
|
93
|
+
}
|
|
94
|
+
const object = call(t, "object");
|
|
95
|
+
if (object !== undefined) {
|
|
96
|
+
const inner = object.replace(/^\{([\s\S]*)\}$/, "$1");
|
|
97
|
+
const out = {};
|
|
98
|
+
for (const attr of splitTop(inner, /[,\n]/)) {
|
|
99
|
+
const at = attr.indexOf("=");
|
|
100
|
+
if (at < 0)
|
|
101
|
+
continue;
|
|
102
|
+
const name = attr.slice(0, at).trim().replace(/^"(.*)"$/, "$1");
|
|
103
|
+
out[name] = terraformPlaceholder(attr.slice(at + 1));
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
return TERRAFORM_UNKNOWN_MARK;
|
|
108
|
+
}
|
|
109
|
+
const containsUndefined = (v) => v === undefined || (Array.isArray(v) ? v.some(containsUndefined) : isObject(v) ? Object.values(v).some(containsUndefined) : false);
|
|
110
|
+
/**
|
|
111
|
+
* The stand-ins for a step's `vars` (#4463): each variable whose value is
|
|
112
|
+
* `undefined` (a `stackOutput()` read with nothing to read yet) gets
|
|
113
|
+
* {@link terraformPlaceholder} of its declared type. Returns why instead when
|
|
114
|
+
* no preview can be made: no variable holds the unknown read, one that does
|
|
115
|
+
* is not declared in the root, or the unknown sits inside a larger value.
|
|
116
|
+
*/
|
|
117
|
+
export function placeholderVars(vars, declared) {
|
|
118
|
+
const given = vars ?? {};
|
|
119
|
+
const placeholders = [];
|
|
120
|
+
const out = {};
|
|
121
|
+
for (const [name, value] of Object.entries(given)) {
|
|
122
|
+
if (value === undefined) {
|
|
123
|
+
const decl = declared.get(name);
|
|
124
|
+
if (!decl)
|
|
125
|
+
return `var.${name} holds the unknown read and the root declares no variable "${name}" to type a stand-in from`;
|
|
126
|
+
placeholders.push(name);
|
|
127
|
+
out[name] = terraformPlaceholder(decl.type);
|
|
128
|
+
}
|
|
129
|
+
else if (containsUndefined(value)) {
|
|
130
|
+
return `the unknown read sits inside var.${name}, which a stand-in cannot fill in part`;
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
out[name] = value;
|
|
134
|
+
}
|
|
135
|
+
if (placeholders.length === 0)
|
|
136
|
+
return "no variable of the step holds the unknown read";
|
|
137
|
+
return { placeholders: placeholders.sort(), vars: out };
|
|
138
|
+
}
|
|
139
|
+
/** Every `references` entry under an expression, at any depth (nested blocks are arrays of expression objects). */
|
|
140
|
+
function referencesIn(expr, out = []) {
|
|
141
|
+
if (Array.isArray(expr))
|
|
142
|
+
for (const e of expr)
|
|
143
|
+
referencesIn(e, out);
|
|
144
|
+
else if (isObject(expr)) {
|
|
145
|
+
if (Array.isArray(expr.references))
|
|
146
|
+
for (const r of expr.references)
|
|
147
|
+
if (typeof r === "string")
|
|
148
|
+
out.push(r);
|
|
149
|
+
for (const [k, v] of Object.entries(expr))
|
|
150
|
+
if (k !== "references" && k !== "constant_value")
|
|
151
|
+
referencesIn(v, out);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
const readsVar = (expr, vars) => referencesIn(expr).some((r) => {
|
|
156
|
+
const m = r.match(/^var\.([^.[]+)/);
|
|
157
|
+
return m !== null && vars.has(m[1]);
|
|
158
|
+
});
|
|
159
|
+
const resourceKey = (modulePath, mode, type, name) => `${modulePath}|${mode === "data" ? "data." : ""}${type}.${name}`;
|
|
160
|
+
function walkModule(mod, path, vars, driven) {
|
|
161
|
+
if (!isObject(mod) || vars.size === 0)
|
|
162
|
+
return;
|
|
163
|
+
const at = (address) => (path ? `${path}.${address}` : address);
|
|
164
|
+
for (const r of Array.isArray(mod.resources) ? mod.resources : []) {
|
|
165
|
+
if (!isObject(r))
|
|
166
|
+
continue;
|
|
167
|
+
const mode = String(r.mode ?? "managed");
|
|
168
|
+
const address = String(r.address ?? `${r.type}.${r.name}`);
|
|
169
|
+
if (readsVar(r.count_expression, vars) || readsVar(r.for_each_expression, vars))
|
|
170
|
+
driven.expansions.push(at(address));
|
|
171
|
+
const exprs = isObject(r.expressions) ? r.expressions : {};
|
|
172
|
+
const attrs = new Set(Object.entries(exprs).filter(([, e]) => readsVar(e, vars)).map(([k]) => k));
|
|
173
|
+
if (attrs.size > 0)
|
|
174
|
+
driven.attributes.set(resourceKey(path, mode, String(r.type), String(r.name)), attrs);
|
|
175
|
+
}
|
|
176
|
+
for (const [name, c] of Object.entries(isObject(mod.module_calls) ? mod.module_calls : {})) {
|
|
177
|
+
if (!isObject(c))
|
|
178
|
+
continue;
|
|
179
|
+
if (readsVar(c.count_expression, vars) || readsVar(c.for_each_expression, vars))
|
|
180
|
+
driven.expansions.push(at(`module.${name}`));
|
|
181
|
+
const exprs = isObject(c.expressions) ? c.expressions : {};
|
|
182
|
+
const inputs = new Set(Object.entries(exprs).filter(([, e]) => readsVar(e, vars)).map(([k]) => k));
|
|
183
|
+
walkModule(c.module, at(`module.${name}`), inputs, driven);
|
|
184
|
+
}
|
|
185
|
+
if (path === "") {
|
|
186
|
+
for (const [name, o] of Object.entries(isObject(mod.outputs) ? mod.outputs : {})) {
|
|
187
|
+
if (isObject(o) && readsVar(o.expression, vars))
|
|
188
|
+
driven.outputs.add(name);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const carriesMark = (v) => typeof v === "string" ? v.includes(TERRAFORM_UNKNOWN_MARK) : Array.isArray(v) ? v.some(carriesMark) : isObject(v) ? Object.values(v).some(carriesMark) : false;
|
|
193
|
+
/** A `resource_changes` item's key in {@link Driven.attributes}: its module path without instance keys. */
|
|
194
|
+
function changeKey(rc) {
|
|
195
|
+
const modulePath = typeof rc.module_address === "string" ? rc.module_address.replace(/\[[^\]]*\]/g, "") : "";
|
|
196
|
+
return resourceKey(modulePath, String(rc.mode ?? "managed"), String(rc.type), String(rc.name));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* `planJson` (`show -json` of the placeholder plan) with every attribute and
|
|
200
|
+
* root output the stand-ins for `placeholders` drive marked unknown after
|
|
201
|
+
* apply, their planned values dropped. Returns why instead when a `count` or
|
|
202
|
+
* `for_each` reads a stand-in. The input is not changed.
|
|
203
|
+
*/
|
|
204
|
+
export function markPlaceholderDriven(planJson, placeholders) {
|
|
205
|
+
const plan = structuredClone(isObject(planJson) ? planJson : {});
|
|
206
|
+
const driven = { attributes: new Map(), outputs: new Set(), expansions: [] };
|
|
207
|
+
const config = isObject(plan.configuration) ? plan.configuration : {};
|
|
208
|
+
walkModule(config.root_module, "", new Set(placeholders), driven);
|
|
209
|
+
if (driven.expansions.length > 0) {
|
|
210
|
+
return { refused: `the count or for_each of ${[...new Set(driven.expansions)].sort().join(", ")} reads a stand-in, so the preview cannot say how many instances there are` };
|
|
211
|
+
}
|
|
212
|
+
for (const r of Array.isArray(plan.resource_changes) ? plan.resource_changes : []) {
|
|
213
|
+
if (!isObject(r) || !isObject(r.change))
|
|
214
|
+
continue;
|
|
215
|
+
const change = r.change;
|
|
216
|
+
const after = isObject(change.after) ? change.after : undefined;
|
|
217
|
+
const attrs = new Set(driven.attributes.get(changeKey(r)) ?? []);
|
|
218
|
+
for (const [k, v] of Object.entries(after ?? {}))
|
|
219
|
+
if (carriesMark(v))
|
|
220
|
+
attrs.add(k);
|
|
221
|
+
if (attrs.size === 0)
|
|
222
|
+
continue;
|
|
223
|
+
const afterUnknown = isObject(change.after_unknown) ? change.after_unknown : {};
|
|
224
|
+
for (const k of attrs) {
|
|
225
|
+
afterUnknown[k] = true;
|
|
226
|
+
if (after)
|
|
227
|
+
delete after[k];
|
|
228
|
+
}
|
|
229
|
+
change.after_unknown = afterUnknown;
|
|
230
|
+
}
|
|
231
|
+
const outputChanges = isObject(plan.output_changes) ? plan.output_changes : {};
|
|
232
|
+
const plannedOutputs = isObject(plan.planned_values) && isObject(plan.planned_values.outputs) ? plan.planned_values.outputs : {};
|
|
233
|
+
for (const [name, o] of Object.entries(outputChanges))
|
|
234
|
+
if (isObject(o) && carriesMark(o.after))
|
|
235
|
+
driven.outputs.add(name);
|
|
236
|
+
for (const [name, o] of Object.entries(plannedOutputs))
|
|
237
|
+
if (isObject(o) && carriesMark(o.value))
|
|
238
|
+
driven.outputs.add(name);
|
|
239
|
+
for (const name of driven.outputs) {
|
|
240
|
+
const o = isObject(outputChanges[name]) ? outputChanges[name] : (outputChanges[name] = {});
|
|
241
|
+
delete o.after;
|
|
242
|
+
o.after_unknown = true;
|
|
243
|
+
delete plannedOutputs[name];
|
|
244
|
+
}
|
|
245
|
+
return { plan };
|
|
246
|
+
}
|
|
247
|
+
/** The hole a root keeps when its preview is not possible: the old reason, and why there is no preview. */
|
|
248
|
+
export function waitingHole(root, unresolved, why) {
|
|
249
|
+
return {
|
|
250
|
+
address: root,
|
|
251
|
+
type: "terraform_root",
|
|
252
|
+
reason: `inputs from ${unresolved.join(", ")}; planned again once they apply${why ? `; no preview: ${why}` : ""}`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How each member's part of a composed apply ended (chant#4442, epic #4419),
|
|
3
|
+
* read from the binary's `apply -json` lines: `applied`, `partial`,
|
|
4
|
+
* `failed`, `not-started` or `no-changes`, core's `GroupMemberStatus`
|
|
5
|
+
* (ws-107).
|
|
6
|
+
*
|
|
7
|
+
* Lifted from terragucci's `packages/terragucci/src/compose.ts` at c493e0e
|
|
8
|
+
* (`readApplyEvents`, `memberApply`).
|
|
9
|
+
*/
|
|
10
|
+
import type { GroupMemberStatus } from "@intentius/chant/components/capability";
|
|
11
|
+
import type { Composition } from "../compose.js";
|
|
12
|
+
/** How one member's part of the apply ended. */
|
|
13
|
+
export type MemberApply = GroupMemberStatus;
|
|
14
|
+
/** What `apply -json` said of each module: the changes that completed, started, or errored, and the first error. */
|
|
15
|
+
export interface ApplyEvents {
|
|
16
|
+
done: Map<string, number>;
|
|
17
|
+
started: Map<string, number>;
|
|
18
|
+
errored: Map<string, string>;
|
|
19
|
+
/** Errors no module's resource names. */
|
|
20
|
+
other: string[];
|
|
21
|
+
}
|
|
22
|
+
/** Read `apply -json` lines into each module's progress. A line that is not JSON is skipped. */
|
|
23
|
+
export declare function readApplyEvents(out: string, modules: readonly string[]): ApplyEvents;
|
|
24
|
+
/** How a member's part of the apply ended, from its planned changes and the events. */
|
|
25
|
+
export declare function memberApply(m: string, planned: number, ev: ApplyEvents): {
|
|
26
|
+
apply: MemberApply;
|
|
27
|
+
done: number;
|
|
28
|
+
};
|
|
29
|
+
/** One member's outcome of a composed apply. */
|
|
30
|
+
export interface MemberApplyOutcome {
|
|
31
|
+
status: MemberApply;
|
|
32
|
+
/** Its planned changes that completed. */
|
|
33
|
+
done: number;
|
|
34
|
+
/** The first error its part named. */
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Every member's outcome of a composed apply, by component, from the
|
|
39
|
+
* `apply -json` output and each member's planned changes
|
|
40
|
+
* (`PlanCounts.changes` of its slice).
|
|
41
|
+
*/
|
|
42
|
+
export declare function composedApplyOutcomes(c: Pick<Composition, "order" | "modules">, planned: ReadonlyMap<string, number>, out: string): {
|
|
43
|
+
members: Record<string, MemberApplyOutcome>;
|
|
44
|
+
other: string[];
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=apply-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-events.d.ts","sourceRoot":"","sources":["../../src/compose/apply-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,gDAAgD;AAChD,MAAM,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE5C,oHAAoH;AACpH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,yCAAyC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AASD,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CA6BpF;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAO7G;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAUpM"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How each member's part of a composed apply ended (chant#4442, epic #4419),
|
|
3
|
+
* read from the binary's `apply -json` lines: `applied`, `partial`,
|
|
4
|
+
* `failed`, `not-started` or `no-changes`, core's `GroupMemberStatus`
|
|
5
|
+
* (ws-107).
|
|
6
|
+
*
|
|
7
|
+
* Lifted from terragucci's `packages/terragucci/src/compose.ts` at c493e0e
|
|
8
|
+
* (`readApplyEvents`, `memberApply`).
|
|
9
|
+
*/
|
|
10
|
+
import { stripModule, topModule } from "./module-address.js";
|
|
11
|
+
/** Read `apply -json` lines into each module's progress. A line that is not JSON is skipped. */
|
|
12
|
+
export function readApplyEvents(out, modules) {
|
|
13
|
+
const ev = { done: new Map(), started: new Map(), errored: new Map(), other: [] };
|
|
14
|
+
const known = new Set(modules);
|
|
15
|
+
const moduleOf = (addr) => {
|
|
16
|
+
const m = addr !== undefined ? topModule(addr) : undefined;
|
|
17
|
+
return m !== undefined && known.has(m) && addr !== `module.${m}` ? m : undefined;
|
|
18
|
+
};
|
|
19
|
+
const bump = (map, m) => map.set(m, (map.get(m) ?? 0) + 1);
|
|
20
|
+
for (const line of out.split("\n")) {
|
|
21
|
+
if (!line.startsWith("{"))
|
|
22
|
+
continue;
|
|
23
|
+
let e;
|
|
24
|
+
try {
|
|
25
|
+
e = JSON.parse(line);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const addr = e.hook?.resource?.addr;
|
|
31
|
+
const m = moduleOf(addr);
|
|
32
|
+
if (e.type === "apply_start" && m)
|
|
33
|
+
bump(ev.started, m);
|
|
34
|
+
else if (e.type === "apply_complete" && m)
|
|
35
|
+
bump(ev.done, m);
|
|
36
|
+
else if (e.type === "apply_errored" && m && !ev.errored.has(m))
|
|
37
|
+
ev.errored.set(m, `${stripModule(addr)}: ${e.hook?.error ?? e["@message"] ?? "errored"}`);
|
|
38
|
+
else if (e.type === "diagnostic" && e.diagnostic?.severity === "error") {
|
|
39
|
+
const dm = moduleOf(e.diagnostic.address);
|
|
40
|
+
const text = `${e.diagnostic.summary ?? "Error"}${e.diagnostic.detail ? `: ${e.diagnostic.detail.split("\n")[0]}` : ""}`;
|
|
41
|
+
if (dm && !ev.errored.has(dm))
|
|
42
|
+
ev.errored.set(dm, `${stripModule(e.diagnostic.address)}: Error: ${text}`);
|
|
43
|
+
else if (!dm)
|
|
44
|
+
ev.other.push(text);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return ev;
|
|
48
|
+
}
|
|
49
|
+
/** How a member's part of the apply ended, from its planned changes and the events. */
|
|
50
|
+
export function memberApply(m, planned, ev) {
|
|
51
|
+
const done = Math.min(ev.done.get(m) ?? 0, planned);
|
|
52
|
+
if (planned === 0)
|
|
53
|
+
return { apply: "no-changes", done: 0 };
|
|
54
|
+
if (done >= planned)
|
|
55
|
+
return { apply: "applied", done };
|
|
56
|
+
if (done > 0)
|
|
57
|
+
return { apply: "partial", done };
|
|
58
|
+
if (ev.errored.has(m) || (ev.started.get(m) ?? 0) > 0)
|
|
59
|
+
return { apply: "failed", done };
|
|
60
|
+
return { apply: "not-started", done };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Every member's outcome of a composed apply, by component, from the
|
|
64
|
+
* `apply -json` output and each member's planned changes
|
|
65
|
+
* (`PlanCounts.changes` of its slice).
|
|
66
|
+
*/
|
|
67
|
+
export function composedApplyOutcomes(c, planned, out) {
|
|
68
|
+
const ev = readApplyEvents(out, c.order.map((member) => c.modules.get(member)));
|
|
69
|
+
const members = {};
|
|
70
|
+
for (const member of c.order) {
|
|
71
|
+
const m = c.modules.get(member);
|
|
72
|
+
const { apply, done } = memberApply(m, planned.get(member) ?? 0, ev);
|
|
73
|
+
const error = ev.errored.get(m);
|
|
74
|
+
members[member] = { status: apply, done, ...(error && apply !== "applied" ? { error } : {}) };
|
|
75
|
+
}
|
|
76
|
+
return { members, other: ev.other };
|
|
77
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composed run of choudoufu estates (chant#4445, epic #4419): when every
|
|
3
|
+
* member runs choudoufu against a `live` estate (`Composition.estate`), one
|
|
4
|
+
* `choudoufu plan` and one `choudoufu apply` from a composed root of `module`
|
|
5
|
+
* calls (choudoufu#2059).
|
|
6
|
+
*
|
|
7
|
+
* An estate has no state file, so nothing is pulled, locked, split or
|
|
8
|
+
* written back: each resource's record goes to its own estate as it applies,
|
|
9
|
+
* and a `terraform_estate_outputs` read of another estate in the run is
|
|
10
|
+
* answered inside the run. The composed root is `writeEstateRoot`'s
|
|
11
|
+
* (./root.ts, #4441). The run takes the job's environment and assumes no
|
|
12
|
+
* role of its own: each estate's provider blocks name its role.
|
|
13
|
+
*
|
|
14
|
+
* choudoufu refuses a bare `show` under a `live` block, so the values the
|
|
15
|
+
* plan left unknown are read after the apply from a second plan of the
|
|
16
|
+
* composed root: its `prior_state`, sliced per module (./slice.ts, #4442) and
|
|
17
|
+
* read through `../applied-state`, the reader `chant terraform report` uses.
|
|
18
|
+
* The same plan says how far a failed apply got: a member whose part plans
|
|
19
|
+
* no change any more applied.
|
|
20
|
+
*
|
|
21
|
+
* Lifted from terragucci's `packages/terragucci/src/compose.ts` at c493e0e
|
|
22
|
+
* (`ComposedRun` with `estate` set: `plan`, `apply`, `finishEstate`,
|
|
23
|
+
* `showEstateMembers`, `composedEnv`). The state-backed run is #4444; this one
|
|
24
|
+
* has the same `plan()`, `apply()` and `release()` and returns the same
|
|
25
|
+
* shapes, and #4447 picks one by `Composition.estate`.
|
|
26
|
+
*/
|
|
27
|
+
import type { CapabilityGroupOutcome, CapabilityGroupPlan, GroupMemberOutcome } from "@intentius/chant/components/capability";
|
|
28
|
+
import type { ComposeFallback, Composition } from "../compose.js";
|
|
29
|
+
import type { TerraformConfig } from "../config.js";
|
|
30
|
+
import { type StateResourceValues } from "../applied-state.js";
|
|
31
|
+
import { type BinaryExec } from "../state/exec.js";
|
|
32
|
+
import { type ApplyEvents, type MemberApply } from "./apply-events.js";
|
|
33
|
+
import { type ComposedMemberPlan, type PlanCounts } from "./slice.js";
|
|
34
|
+
/** What a composed run's `plan()` answers. Assignable to core's `CapabilityGroupPlan` (ws-107). */
|
|
35
|
+
export interface ComposedRunPlan extends CapabilityGroupPlan {
|
|
36
|
+
/** Each member's part of the plan, by component. Empty when the run fell back or the plan failed. */
|
|
37
|
+
members: Record<string, ComposedMemberPlan>;
|
|
38
|
+
/** What the approval binds beside the members' own plans: the composed plan and the generated files. Empty when nothing planned. */
|
|
39
|
+
digest: string;
|
|
40
|
+
/** Why the run did not plan as one: the members plan wave by wave instead. Decided before anything planned. */
|
|
41
|
+
fallback?: ComposeFallback;
|
|
42
|
+
/** Why the composed plan failed: every member is plan-failed. */
|
|
43
|
+
error?: string;
|
|
44
|
+
/** The member {@link error} is about, when it is about one (a hook, an init, a lock). */
|
|
45
|
+
member?: string;
|
|
46
|
+
/** The composed plan's `show -json`. */
|
|
47
|
+
plan?: unknown;
|
|
48
|
+
/** The saved plan file `apply()` applies. */
|
|
49
|
+
planFile: string;
|
|
50
|
+
/** The composed plan's `show` text. */
|
|
51
|
+
text: string;
|
|
52
|
+
/** Each member's part of the `show` text, by component. */
|
|
53
|
+
texts: Record<string, string>;
|
|
54
|
+
/** sha256 of each generated file of the composed root, as `ComposedRoot.generated`. */
|
|
55
|
+
generated: [string, string][];
|
|
56
|
+
/** The whole run's counts. */
|
|
57
|
+
counts: PlanCounts;
|
|
58
|
+
/** The binary's `Plan:` line for the whole run. */
|
|
59
|
+
summary: string;
|
|
60
|
+
}
|
|
61
|
+
/** One member's outcome of a composed apply. Assignable to core's `GroupMemberOutcome` (ws-107). */
|
|
62
|
+
export interface ComposedMemberOutcome extends GroupMemberOutcome {
|
|
63
|
+
status: MemberApply;
|
|
64
|
+
/** Its planned changes. */
|
|
65
|
+
planned: number;
|
|
66
|
+
/** Its planned changes that completed. */
|
|
67
|
+
done: number;
|
|
68
|
+
/** Each resource of its part of the state after the apply, by address with its module taken off. */
|
|
69
|
+
resources?: Map<string, StateResourceValues>;
|
|
70
|
+
}
|
|
71
|
+
/** What a composed run's `apply()` answers. Assignable to core's `CapabilityGroupOutcome` (ws-107). */
|
|
72
|
+
export interface ComposedRunApply extends CapabilityGroupOutcome {
|
|
73
|
+
/** Every member applied or had no changes, and the binary exited 0. */
|
|
74
|
+
ok: boolean;
|
|
75
|
+
members: Record<string, ComposedMemberOutcome>;
|
|
76
|
+
/** `show -json` of the plan made after the apply. Absent when it could not be made. */
|
|
77
|
+
after?: unknown;
|
|
78
|
+
}
|
|
79
|
+
/** The surface #4447 drives, whichever run `Composition.estate` picks. */
|
|
80
|
+
export interface ComposedRunner {
|
|
81
|
+
plan(): Promise<ComposedRunPlan>;
|
|
82
|
+
apply(): Promise<ComposedRunApply>;
|
|
83
|
+
release(): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
export interface EstateRunOptions {
|
|
86
|
+
/** The checkout's root: where `chant.config.*` was loaded from. `.chant-compose/` is written here. */
|
|
87
|
+
projectRoot: string;
|
|
88
|
+
/** What `compositionFor` answered, with `estate` set and two or more members. */
|
|
89
|
+
composition: Composition;
|
|
90
|
+
/** The config's `terraform` namespace: a root's `estate`. */
|
|
91
|
+
terraform: TerraformConfig;
|
|
92
|
+
/** The job's environment. The run adds no role to it. */
|
|
93
|
+
env: NodeJS.ProcessEnv;
|
|
94
|
+
/** The choudoufu binary, by name or path. Default `terraform.binary`, else `choudoufu`. */
|
|
95
|
+
binary?: string;
|
|
96
|
+
/** Where the plan files go. Default: a new directory under the system's temp directory. */
|
|
97
|
+
work?: string;
|
|
98
|
+
/** How the binary runs. Default {@link runBinary}; a test injects a fake. */
|
|
99
|
+
exec?: BinaryExec;
|
|
100
|
+
log?: (line: string) => void;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Why a choudoufu's `version` output cannot run a composed run of estates, or
|
|
104
|
+
* undefined when it can. A release older than
|
|
105
|
+
* {@link MIN_CHOUDOUFU_ESTATES_VERSION} falls back; a dev build names no
|
|
106
|
+
* release and passes.
|
|
107
|
+
*/
|
|
108
|
+
export declare function estateVersionFallback(versionOutput: string): ComposeFallback | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* What choudoufu's human `apply` output says of each module: the changes
|
|
111
|
+
* that completed (`<addr>: Creation complete`, `Modifications complete`,
|
|
112
|
+
* `Destruction complete`), started (`Creating...` and the rest) or errored
|
|
113
|
+
* (an `Error:` box naming `with <addr>,`). An estate's apply runs under live
|
|
114
|
+
* resource markers and prints no `-json` lines, so this reads the text.
|
|
115
|
+
*/
|
|
116
|
+
export declare function readEstateApplyText(out: string, modules: readonly string[]): ApplyEvents;
|
|
117
|
+
/**
|
|
118
|
+
* Each member's outcome from its planned changes, what the apply printed, its
|
|
119
|
+
* exit code and, when the post-apply plan was made, the changes each member's
|
|
120
|
+
* part still plans. A clean exit means every planned change applied. After a
|
|
121
|
+
* failure, a member's changes left in the post-apply plan say how many of its
|
|
122
|
+
* planned changes applied; without that plan the printed completions do.
|
|
123
|
+
*/
|
|
124
|
+
export declare function estateOutcomes(c: Pick<Composition, "order" | "modules">, planned: ReadonlyMap<string, number>, out: string, code: number, remaining?: ReadonlyMap<string, number>): {
|
|
125
|
+
members: Record<string, {
|
|
126
|
+
status: MemberApply;
|
|
127
|
+
done: number;
|
|
128
|
+
planned: number;
|
|
129
|
+
error?: string;
|
|
130
|
+
}>;
|
|
131
|
+
other: string[];
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* One composed run of estates: `plan()`, then `apply()` once the approval is
|
|
135
|
+
* given, then `release()` whatever happened. No call reads, locks or writes
|
|
136
|
+
* a state.
|
|
137
|
+
*/
|
|
138
|
+
export declare class EstateRun implements ComposedRunner {
|
|
139
|
+
private readonly o;
|
|
140
|
+
private readonly exec;
|
|
141
|
+
private readonly binary;
|
|
142
|
+
private readonly composeDir;
|
|
143
|
+
private readonly work;
|
|
144
|
+
private readonly madeWork;
|
|
145
|
+
private planned?;
|
|
146
|
+
private root?;
|
|
147
|
+
constructor(o: EstateRunOptions);
|
|
148
|
+
private get c();
|
|
149
|
+
private log;
|
|
150
|
+
/**
|
|
151
|
+
* The composed root's environment: the job's, with no role added (each
|
|
152
|
+
* estate's provider blocks name its role) and its `-var-file` flags taken
|
|
153
|
+
* out. With a shared provider cache and no lock file to check a cached
|
|
154
|
+
* provider against, the cache may fill the lock file.
|
|
155
|
+
*/
|
|
156
|
+
private env;
|
|
157
|
+
/** The estate each member's records go to: its root's `estate`, else its `live` block's. */
|
|
158
|
+
private estateOf;
|
|
159
|
+
private notPlanned;
|
|
160
|
+
/**
|
|
161
|
+
* Why this choudoufu cannot run the composition, or undefined. Runs
|
|
162
|
+
* `choudoufu version`; what #4447's `groupFallback` asks before planning.
|
|
163
|
+
*/
|
|
164
|
+
fallback(): Promise<ComposeFallback | undefined>;
|
|
165
|
+
private writeRoot;
|
|
166
|
+
private restoreRoot;
|
|
167
|
+
/**
|
|
168
|
+
* Check the binary's version, write the composed root, init it and plan
|
|
169
|
+
* once, then cut the plan into each member's part. The composed root is
|
|
170
|
+
* taken away again before this returns.
|
|
171
|
+
*/
|
|
172
|
+
plan(): Promise<ComposedRunPlan>;
|
|
173
|
+
/**
|
|
174
|
+
* Apply the saved plan from the composed root, then plan again and read
|
|
175
|
+
* each member's values from that plan's `prior_state`. A failed apply
|
|
176
|
+
* leaves what applied applied, and each member's outcome says how far its
|
|
177
|
+
* part got.
|
|
178
|
+
*/
|
|
179
|
+
apply(): Promise<ComposedRunApply>;
|
|
180
|
+
/**
|
|
181
|
+
* `show -json` of a plan of the composed root made after the apply, whose
|
|
182
|
+
* `prior_state` choudoufu builds from the records and the live system.
|
|
183
|
+
* Undefined when it cannot be made: the values unknown at plan then stay
|
|
184
|
+
* unknown. Never fails the run.
|
|
185
|
+
*/
|
|
186
|
+
private planAfter;
|
|
187
|
+
/**
|
|
188
|
+
* Take the composed root away if a call left it, with the binary's working
|
|
189
|
+
* files under `.chant-compose/`, and the plan files. There is no lock to
|
|
190
|
+
* let go of. Safe to call more than once.
|
|
191
|
+
*/
|
|
192
|
+
release(): Promise<void>;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=estate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estate.d.ts","sourceRoot":"","sources":["../../src/compose/estate.ts"],"names":[],"mappings":"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"}
|