@intentius/chant-lexicon-terraform 0.124.52 → 0.124.55
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 +14 -10
- 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/ci-setup.d.ts +11 -0
- package/dist/ci-setup.d.ts.map +1 -0
- package/dist/ci-setup.js +41 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/components/capability-plugin.d.ts +105 -9
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +357 -36
- 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/components/release-inputs.d.ts +29 -0
- package/dist/components/release-inputs.d.ts.map +1 -0
- package/dist/components/release-inputs.js +57 -0
- package/dist/components/trace-facts.d.ts +16 -0
- package/dist/components/trace-facts.d.ts.map +1 -0
- package/dist/components/trace-facts.js +19 -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/cone.d.ts +53 -0
- package/dist/cone.d.ts.map +1 -0
- package/dist/cone.js +119 -0
- package/dist/config.d.ts +59 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -9
- package/dist/cost-hold.d.ts +27 -0
- package/dist/cost-hold.d.ts.map +1 -0
- package/dist/cost-hold.js +21 -0
- 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/drift-rows.d.ts +61 -0
- package/dist/drift-rows.d.ts.map +1 -0
- package/dist/drift-rows.js +108 -0
- package/dist/exit-codes.d.ts +55 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +48 -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 +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/integrity.json +8 -5
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-catalog.js +27 -3
- package/dist/lint/audit-lineage.d.ts +14 -2
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +4 -0
- package/dist/lint/post-synth/record-store.d.ts +54 -0
- package/dist/lint/post-synth/record-store.d.ts.map +1 -0
- package/dist/lint/post-synth/record-store.js +104 -0
- package/dist/lint/post-synth/tf001.d.ts +2 -2
- package/dist/lint/post-synth/tf001.js +2 -2
- package/dist/lint/post-synth/tf024.d.ts +35 -11
- package/dist/lint/post-synth/tf024.d.ts.map +1 -1
- package/dist/lint/post-synth/tf024.js +92 -20
- package/dist/lint/post-synth/tf046.d.ts +64 -0
- package/dist/lint/post-synth/tf046.d.ts.map +1 -0
- package/dist/lint/post-synth/tf046.js +175 -0
- package/dist/lint/post-synth/tf047.d.ts +36 -0
- package/dist/lint/post-synth/tf047.d.ts.map +1 -0
- package/dist/lint/post-synth/tf047.js +94 -0
- 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/lock-rows.d.ts +36 -0
- package/dist/lock-rows.d.ts.map +1 -0
- package/dist/lock-rows.js +60 -0
- package/dist/lock-timeout.d.ts +22 -0
- package/dist/lock-timeout.d.ts.map +1 -0
- package/dist/lock-timeout.js +32 -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/module-catalog/index.d.ts +69 -0
- package/dist/module-catalog/index.d.ts.map +1 -0
- package/dist/module-catalog/index.js +110 -0
- package/dist/module-catalog/refresh-cli.d.ts +4 -0
- package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
- package/dist/module-catalog/refresh-cli.js +64 -0
- package/dist/module-catalog/static-tier.d.ts +6 -0
- package/dist/module-catalog/static-tier.d.ts.map +1 -0
- package/dist/module-catalog/static-tier.js +1650 -0
- package/dist/module-catalog/types.d.ts +65 -0
- package/dist/module-catalog/types.d.ts.map +1 -0
- package/dist/module-catalog/types.js +33 -0
- package/dist/okf/index.md +3 -1
- package/dist/okf/rules/TF024.md +2 -2
- package/dist/okf/rules/TF046.md +11 -0
- package/dist/okf/rules/TF047.md +11 -0
- 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 +182 -5
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +224 -24
- 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/consumers.d.ts +35 -0
- package/dist/pin/consumers.d.ts.map +1 -0
- package/dist/pin/consumers.js +70 -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 +37 -18
- package/dist/registry/address.d.ts +63 -0
- package/dist/registry/address.d.ts.map +1 -0
- package/dist/registry/address.js +65 -0
- package/dist/registry/catalog-read.d.ts +14 -0
- package/dist/registry/catalog-read.d.ts.map +1 -0
- package/dist/registry/catalog-read.js +58 -0
- package/dist/registry/deprecated.d.ts +37 -0
- package/dist/registry/deprecated.d.ts.map +1 -0
- package/dist/registry/deprecated.js +43 -0
- package/dist/registry/docs.d.ts +96 -0
- package/dist/registry/docs.d.ts.map +1 -0
- package/dist/registry/docs.js +210 -0
- package/dist/registry/edge/edge.d.ts +46 -0
- package/dist/registry/edge/edge.d.ts.map +1 -0
- package/dist/registry/edge/edge.js +194 -0
- package/dist/registry/edge/index.d.ts +11 -0
- package/dist/registry/edge/index.d.ts.map +1 -0
- package/dist/registry/edge/index.js +10 -0
- package/dist/registry/edge/lambda-edge.d.ts +76 -0
- package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
- package/dist/registry/edge/lambda-edge.js +95 -0
- package/dist/registry/edge/sigv4-web.d.ts +33 -0
- package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
- package/dist/registry/edge/sigv4-web.js +56 -0
- package/dist/registry/edge/token-source.d.ts +73 -0
- package/dist/registry/edge/token-source.d.ts.map +1 -0
- package/dist/registry/edge/token-source.js +115 -0
- package/dist/registry/edge/worker.d.ts +45 -0
- package/dist/registry/edge/worker.d.ts.map +1 -0
- package/dist/registry/edge/worker.js +26 -0
- package/dist/registry/handler.d.ts +25 -0
- package/dist/registry/handler.d.ts.map +1 -0
- package/dist/registry/handler.js +75 -0
- package/dist/registry/headers-file.d.ts +21 -0
- package/dist/registry/headers-file.d.ts.map +1 -0
- package/dist/registry/headers-file.js +57 -0
- package/dist/registry/index.d.ts +31 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +30 -0
- package/dist/registry/mirror-paths.d.ts +9 -0
- package/dist/registry/mirror-paths.d.ts.map +1 -0
- package/dist/registry/mirror-paths.js +8 -0
- package/dist/registry/mirror.d.ts +130 -0
- package/dist/registry/mirror.d.ts.map +1 -0
- package/dist/registry/mirror.js +319 -0
- package/dist/registry/proxies.d.ts +73 -0
- package/dist/registry/proxies.d.ts.map +1 -0
- package/dist/registry/proxies.js +111 -0
- package/dist/registry/reader.d.ts +57 -0
- package/dist/registry/reader.d.ts.map +1 -0
- package/dist/registry/reader.js +198 -0
- package/dist/registry/semver.d.ts +16 -0
- package/dist/registry/semver.d.ts.map +1 -0
- package/dist/registry/semver.js +24 -0
- package/dist/registry/serve.d.ts +24 -0
- package/dist/registry/serve.d.ts.map +1 -0
- package/dist/registry/serve.js +64 -0
- package/dist/registry/source-forms.d.ts +79 -0
- package/dist/registry/source-forms.d.ts.map +1 -0
- package/dist/registry/source-forms.js +202 -0
- package/dist/registry/targets/artifactory.d.ts +28 -0
- package/dist/registry/targets/artifactory.d.ts.map +1 -0
- package/dist/registry/targets/artifactory.js +206 -0
- package/dist/registry/targets/fake-artifactory.d.ts +30 -0
- package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
- package/dist/registry/targets/fake-artifactory.js +142 -0
- package/dist/registry/targets/fake-gitlab.d.ts +39 -0
- package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
- package/dist/registry/targets/fake-gitlab.js +136 -0
- package/dist/registry/targets/fake-hcp.d.ts +50 -0
- package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
- package/dist/registry/targets/fake-hcp.js +202 -0
- package/dist/registry/targets/fake-http.d.ts +31 -0
- package/dist/registry/targets/fake-http.d.ts.map +1 -0
- package/dist/registry/targets/fake-http.js +87 -0
- package/dist/registry/targets/fake-nexus.d.ts +27 -0
- package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
- package/dist/registry/targets/fake-nexus.js +137 -0
- package/dist/registry/targets/gitlab.d.ts +53 -0
- package/dist/registry/targets/gitlab.d.ts.map +1 -0
- package/dist/registry/targets/gitlab.js +187 -0
- package/dist/registry/targets/hcp.d.ts +29 -0
- package/dist/registry/targets/hcp.d.ts.map +1 -0
- package/dist/registry/targets/hcp.js +310 -0
- package/dist/registry/targets/hosted.d.ts +62 -0
- package/dist/registry/targets/hosted.d.ts.map +1 -0
- package/dist/registry/targets/hosted.js +74 -0
- package/dist/registry/targets/index.d.ts +18 -0
- package/dist/registry/targets/index.d.ts.map +1 -0
- package/dist/registry/targets/index.js +17 -0
- package/dist/registry/targets/module-target.d.ts +68 -0
- package/dist/registry/targets/module-target.d.ts.map +1 -0
- package/dist/registry/targets/module-target.js +63 -0
- package/dist/registry/targets/nexus.d.ts +43 -0
- package/dist/registry/targets/nexus.d.ts.map +1 -0
- package/dist/registry/targets/nexus.js +250 -0
- package/dist/registry/targets/zip.d.ts +55 -0
- package/dist/registry/targets/zip.d.ts.map +1 -0
- package/dist/registry/targets/zip.js +278 -0
- package/dist/registry/writer.d.ts +101 -0
- package/dist/registry/writer.d.ts.map +1 -0
- package/dist/registry/writer.js +109 -0
- package/dist/report.d.ts +15 -6
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +28 -55
- package/dist/rules/record-store.ts +122 -0
- package/dist/rules/tf001.ts +2 -2
- package/dist/rules/tf024.ts +105 -22
- package/dist/rules/tf046.ts +204 -0
- package/dist/rules/tf047.ts +114 -0
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/state/azure-blob.d.ts +9 -0
- package/dist/state/azure-blob.d.ts.map +1 -0
- package/dist/state/azure-blob.js +8 -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 +8 -0
- package/dist/state/gcs.d.ts.map +1 -0
- package/dist/state/gcs.js +7 -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 +8 -0
- package/dist/state/object-store.d.ts.map +1 -0
- package/dist/state/object-store.js +7 -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 +21 -0
- package/dist/state/s3.d.ts.map +1 -0
- package/dist/state/s3.js +19 -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/state-ops.d.ts +255 -0
- package/dist/state-ops.d.ts.map +1 -0
- package/dist/state-ops.js +305 -0
- package/dist/state-reads.d.ts +57 -0
- package/dist/state-reads.d.ts.map +1 -0
- package/dist/state-reads.js +104 -0
- package/dist/terragrunt/affected.d.ts.map +1 -1
- package/dist/terragrunt/affected.js +2 -1
- package/dist/used-sources.d.ts +54 -0
- package/dist/used-sources.d.ts.map +1 -0
- package/dist/used-sources.js +157 -0
- package/package.json +24 -4
- 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 +16 -0
- package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
- package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
- package/src/__fixtures__/drift-rows/refresh-plan.json +61 -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/__fixtures__/used-sources/root/extra.tofu +1 -0
- package/src/__fixtures__/used-sources/root/main.tf +31 -0
- package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
- package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
- package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -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/ci-setup.ts +42 -0
- package/src/commands.ts +4 -3
- package/src/components/capability-plugin.test.ts +198 -19
- package/src/components/capability-plugin.ts +383 -35
- 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 +113 -57
- package/src/components/release-inputs.ts +69 -0
- package/src/components/trace-facts.test.ts +21 -0
- package/src/components/trace-facts.ts +27 -0
- 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/cone.ts +138 -0
- package/src/config-file-listers.test.ts +265 -0
- package/src/config.ts +44 -9
- package/src/cost-hold.ts +29 -0
- package/src/describe-resources.engine-facts.test.ts +411 -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/drift-rows.test.ts +135 -0
- package/src/drift-rows.ts +137 -0
- package/src/exit-codes.test.ts +23 -0
- package/src/exit-codes.ts +59 -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 +79 -0
- package/src/lint/audit-catalog.ts +29 -3
- package/src/lint/audit-lineage.ts +14 -2
- package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
- package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
- package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/record-store.ts +122 -0
- package/src/lint/post-synth/tf001.ts +2 -2
- package/src/lint/post-synth/tf024.test.ts +26 -5
- package/src/lint/post-synth/tf024.ts +105 -22
- package/src/lint/post-synth/tf046.test.ts +137 -0
- package/src/lint/post-synth/tf046.ts +204 -0
- package/src/lint/post-synth/tf047.test.ts +56 -0
- package/src/lint/post-synth/tf047.ts +114 -0
- package/src/live-plan-reasons.ts +54 -0
- package/src/lock-rows.test.ts +70 -0
- package/src/lock-rows.ts +82 -0
- package/src/lock-timeout.ts +34 -0
- package/src/lsp/completions.test.ts +1 -1
- package/src/lsp/option-keys.ts +2 -0
- package/src/module-catalog/index.test.ts +93 -0
- package/src/module-catalog/index.ts +159 -0
- package/src/module-catalog/refresh-cli.ts +68 -0
- package/src/module-catalog/static-tier.ts +1659 -0
- package/src/module-catalog/types.ts +88 -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 +312 -27
- 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/op-wave-step.test.ts +109 -0
- package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
- package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
- package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
- package/src/pin/bundle.test.ts +2 -0
- package/src/pin/consumers.test.ts +57 -0
- package/src/pin/consumers.ts +95 -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 +39 -19
- package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
- package/src/registry/__fixtures__/docs/documented/README.md +1 -0
- package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
- package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
- package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
- package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
- package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
- package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
- package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
- package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
- package/src/registry/address.ts +100 -0
- package/src/registry/catalog-read.ts +56 -0
- package/src/registry/deprecated.test.ts +139 -0
- package/src/registry/deprecated.ts +76 -0
- package/src/registry/docs.test.ts +140 -0
- package/src/registry/docs.ts +299 -0
- package/src/registry/edge/bundle.test.ts +50 -0
- package/src/registry/edge/edge.test.ts +176 -0
- package/src/registry/edge/edge.ts +211 -0
- package/src/registry/edge/index.ts +10 -0
- package/src/registry/edge/lambda-edge.ts +127 -0
- package/src/registry/edge/sigv4-web.ts +79 -0
- package/src/registry/edge/token-source.test.ts +258 -0
- package/src/registry/edge/token-source.ts +169 -0
- package/src/registry/edge/worker.ts +61 -0
- package/src/registry/handler.ts +89 -0
- package/src/registry/headers-file.ts +61 -0
- package/src/registry/index.ts +31 -0
- package/src/registry/mirror-paths.ts +10 -0
- package/src/registry/mirror.test.ts +198 -0
- package/src/registry/mirror.ts +395 -0
- package/src/registry/proxies.test.ts +153 -0
- package/src/registry/proxies.ts +132 -0
- package/src/registry/reader.ts +225 -0
- package/src/registry/registry.test.ts +262 -0
- package/src/registry/semver.ts +34 -0
- package/src/registry/serve.ts +82 -0
- package/src/registry/source-forms.test.ts +87 -0
- package/src/registry/source-forms.ts +216 -0
- package/src/registry/targets/artifactory.test.ts +248 -0
- package/src/registry/targets/artifactory.ts +257 -0
- package/src/registry/targets/fake-artifactory.ts +158 -0
- package/src/registry/targets/fake-gitlab.ts +161 -0
- package/src/registry/targets/fake-hcp.ts +233 -0
- package/src/registry/targets/fake-http.ts +97 -0
- package/src/registry/targets/fake-nexus.ts +152 -0
- package/src/registry/targets/gitlab.test.ts +208 -0
- package/src/registry/targets/gitlab.ts +223 -0
- package/src/registry/targets/hcp.test.ts +230 -0
- package/src/registry/targets/hcp.ts +360 -0
- package/src/registry/targets/hosted.ts +117 -0
- package/src/registry/targets/index.ts +17 -0
- package/src/registry/targets/module-target.ts +131 -0
- package/src/registry/targets/nexus.test.ts +220 -0
- package/src/registry/targets/nexus.ts +314 -0
- package/src/registry/targets/zip.test.ts +65 -0
- package/src/registry/targets/zip.ts +287 -0
- package/src/registry/writer.ts +155 -0
- 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 +8 -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 +7 -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 +7 -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 +21 -0
- package/src/state/store.ts +225 -0
- package/src/state-ops.test.ts +182 -0
- package/src/state-ops.ts +462 -0
- package/src/state-reads.ts +116 -0
- package/src/terragrunt/affected.ts +2 -1
- package/src/used-sources.test.ts +75 -0
- package/src/used-sources.ts +204 -0
- 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,586 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composed root (chant#4441, epic #4419): the temporary root a composed
|
|
3
|
+
* run plans, one `module` call per member, written into the checkout under
|
|
4
|
+
* `.chant-compose/`, and every file put back once the run ends.
|
|
5
|
+
*
|
|
6
|
+
* Lifted from terragucci's `packages/terragucci/src/compose.ts` at c493e0e
|
|
7
|
+
* (the composed root section: `writeComposedRoot`, `writeEstateRoot`,
|
|
8
|
+
* `unionLock`, `liftBlock`, `rewriteJson`, `hclAttributes`, `cliVarFiles`,
|
|
9
|
+
* `withoutVarFiles`, `rootVarValues`, `declaredVariables`,
|
|
10
|
+
* `declaredOutputs`; `linked.ts` `refRe`, `hclValue`), taking the
|
|
11
|
+
* {@link Composition} of `../compose.ts` (#4438). What changed:
|
|
12
|
+
*
|
|
13
|
+
* - The directory is `.chant-compose/` and the file each root gains is
|
|
14
|
+
* `chant_compose.tf`; a read becomes `var.chant_read_<label>` (#4419
|
|
15
|
+
* ruling 5).
|
|
16
|
+
* - A member is a component; its root's directory is `Composition.dirs`, so a
|
|
17
|
+
* module's `source` is that directory relative to the composed root.
|
|
18
|
+
* - A root's var files are `terraform.roots.<name>.varFiles` as well as its
|
|
19
|
+
* tfvars, auto tfvars and `TF_CLI_ARGS` `-var-file`s, and its step's
|
|
20
|
+
* `vars` win over all of them, as `-var` does today.
|
|
21
|
+
* - A `stackOutput()` in a member's `vars` that names another member becomes
|
|
22
|
+
* `module.<upstream>.<output>`; one that names a component outside the
|
|
23
|
+
* group stays the literal value the step would pass.
|
|
24
|
+
* - A write that throws partway puts back what it changed before it throws,
|
|
25
|
+
* and each root file is kept as bytes, so `restore()` leaves it identical.
|
|
26
|
+
*
|
|
27
|
+
* While a root is composed its `backend` block, its `terraform_remote_state`
|
|
28
|
+
* blocks that read another member, and its `import` and `removed` blocks are
|
|
29
|
+
* cut from its files. `moved` blocks stay: a module takes them.
|
|
30
|
+
*/
|
|
31
|
+
import { createHash } from "node:crypto";
|
|
32
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
33
|
+
import { join, resolve } from "node:path";
|
|
34
|
+
import { resolveWiring } from "@intentius/chant/components/driver";
|
|
35
|
+
import { blankComments, blockBody, jsonBlocks, relPath, rootTexts } from "./hcl.js";
|
|
36
|
+
/** Where the composed root is written, in the checkout (#4419 ruling 5). */
|
|
37
|
+
export const COMPOSE_DIR = ".chant-compose";
|
|
38
|
+
/** The file a composed run adds to each root it composes, declaring the variables its reads become. */
|
|
39
|
+
export const COMPOSE_FILE = "chant_compose.tf";
|
|
40
|
+
/** The prefix of the variable a member's read of another member becomes. */
|
|
41
|
+
export const READ_VAR_PREFIX = "chant_read_";
|
|
42
|
+
const HEADER = "# Written by chant for a composed run (terraform.compose), and removed once it ends.\n";
|
|
43
|
+
// ── HCL text ──────────────────────────────────────────────────────────────
|
|
44
|
+
/** The end (exclusive) of the expression that starts at `i`: to the end of its line, or further while a bracket or a string is open. */
|
|
45
|
+
function exprEnd(text, i) {
|
|
46
|
+
let depth = 0;
|
|
47
|
+
let inString = false;
|
|
48
|
+
for (; i < text.length; i++) {
|
|
49
|
+
const c = text[i];
|
|
50
|
+
if (inString) {
|
|
51
|
+
if (c === "\\")
|
|
52
|
+
i++;
|
|
53
|
+
else if (c === '"')
|
|
54
|
+
inString = false;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (c === '"')
|
|
58
|
+
inString = true;
|
|
59
|
+
else if (c === "(" || c === "[" || c === "{")
|
|
60
|
+
depth++;
|
|
61
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
62
|
+
if (depth === 0)
|
|
63
|
+
return i;
|
|
64
|
+
depth--;
|
|
65
|
+
}
|
|
66
|
+
else if (c === "\n" && depth === 0)
|
|
67
|
+
return i;
|
|
68
|
+
}
|
|
69
|
+
return i;
|
|
70
|
+
}
|
|
71
|
+
/** The top-level `name = expression` attributes of an HCL attribute file (a `.tfvars`), comments blanked. */
|
|
72
|
+
export function hclAttributes(text) {
|
|
73
|
+
const t = blankComments(text);
|
|
74
|
+
const out = new Map();
|
|
75
|
+
const re = /(^|\n)[ \t]*([A-Za-z_][\w-]*)[ \t]*=(?!=)/g;
|
|
76
|
+
for (let m = re.exec(t); m; m = re.exec(t)) {
|
|
77
|
+
const start = m.index + m[0].length;
|
|
78
|
+
const end = exprEnd(t, start);
|
|
79
|
+
out.set(m[2], t.slice(start, end).trim());
|
|
80
|
+
re.lastIndex = end;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/** A known string as an HCL quoted string: JSON's escapes, and `${` and `%{` escaped so nothing in it is a template. */
|
|
85
|
+
function hclString(s) {
|
|
86
|
+
return JSON.stringify(s).replace(/\$\{/g, () => "$${").replace(/%\{/g, () => "%%{");
|
|
87
|
+
}
|
|
88
|
+
/** A JSON value as an HCL expression. */
|
|
89
|
+
export function hclValue(value) {
|
|
90
|
+
if (value === undefined || value === null)
|
|
91
|
+
return "null";
|
|
92
|
+
if (Array.isArray(value))
|
|
93
|
+
return `[${value.map(hclValue).join(", ")}]`;
|
|
94
|
+
if (typeof value === "object") {
|
|
95
|
+
const keys = Object.keys(value).sort();
|
|
96
|
+
return `{ ${keys.map((k) => `${hclString(k)} = ${hclValue(value[k])}`).join(", ")} }`;
|
|
97
|
+
}
|
|
98
|
+
if (typeof value === "string")
|
|
99
|
+
return hclString(value);
|
|
100
|
+
return JSON.stringify(value);
|
|
101
|
+
}
|
|
102
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
103
|
+
/** A reference to the `terraform_remote_state` block `name`, not to one whose label starts with it. */
|
|
104
|
+
export const refRe = (name, flags = "g") => new RegExp(`\\bdata\\.terraform_remote_state\\.${escapeRe(name)}(?![\\w-])`, flags);
|
|
105
|
+
/** A root's declared variables: the type expression and whether it is sensitive. */
|
|
106
|
+
export function declaredVariables(texts) {
|
|
107
|
+
const out = new Map();
|
|
108
|
+
for (const t of texts) {
|
|
109
|
+
if (t.json) {
|
|
110
|
+
try {
|
|
111
|
+
const v = JSON.parse(t.text).variable ?? {};
|
|
112
|
+
for (const [name, body] of Object.entries(v)) {
|
|
113
|
+
const b = Array.isArray(body) ? body[0] : body;
|
|
114
|
+
out.set(name, { ...(typeof b?.type === "string" ? { type: b.type.replace(/^\$\{(.*)\}$/, "$1") } : {}), sensitive: b?.sensitive === true });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Not JSON the binary reads either; its plan says so.
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
for (const m of t.text.matchAll(/\bvariable\s+"([^"]+)"\s*\{/g)) {
|
|
123
|
+
const body = blockBody(t.text, m.index);
|
|
124
|
+
const at = body.match(/(^|\n)\s*type\s*=/);
|
|
125
|
+
const type = at ? body.slice(at.index + at[0].length, exprEnd(body, at.index + at[0].length)).trim() : undefined;
|
|
126
|
+
out.set(m[1], { ...(type ? { type } : {}), sensitive: /(^|\n)\s*sensitive\s*=\s*true\b/.test(body) });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/** A root's outputs and whether each is sensitive. */
|
|
132
|
+
export function declaredOutputs(texts) {
|
|
133
|
+
const out = new Map();
|
|
134
|
+
for (const t of texts) {
|
|
135
|
+
if (t.json) {
|
|
136
|
+
try {
|
|
137
|
+
const o = JSON.parse(t.text).output ?? {};
|
|
138
|
+
for (const [name, body] of Object.entries(o))
|
|
139
|
+
out.set(name, (Array.isArray(body) ? body[0] : body)?.sensitive === true);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// As above.
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
for (const m of t.text.matchAll(/\boutput\s+"([^"]+)"\s*\{/g))
|
|
147
|
+
out.set(m[1], /(^|\n)\s*sensitive\s*=\s*true\b/.test(blockBody(t.text, m.index)));
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
// ── variable values ───────────────────────────────────────────────────────
|
|
152
|
+
/** The `-var-file` paths `TF_CLI_ARGS` and `TF_CLI_ARGS_plan` name, as the binary reads them, relative to the root. */
|
|
153
|
+
export function cliVarFiles(env) {
|
|
154
|
+
const s = `${env.TF_CLI_ARGS ?? ""} ${env.TF_CLI_ARGS_plan ?? ""}`;
|
|
155
|
+
return [...s.matchAll(/(?:^|\s)-{1,2}var-file(?:=|\s+)("([^"]*)"|'([^']*)'|(\S+))/g)].map((m) => m[2] ?? m[3] ?? m[4]).filter(Boolean);
|
|
156
|
+
}
|
|
157
|
+
/** `env` with the `-var-file` flags taken out of `TF_CLI_ARGS` and `TF_CLI_ARGS_plan`: the composed run passes those files' values as module arguments. */
|
|
158
|
+
export function withoutVarFiles(env) {
|
|
159
|
+
const out = { ...env };
|
|
160
|
+
for (const k of ["TF_CLI_ARGS", "TF_CLI_ARGS_plan"]) {
|
|
161
|
+
if (out[k] === undefined)
|
|
162
|
+
continue;
|
|
163
|
+
out[k] = out[k].replace(/(?:^|\s)-{1,2}var-file(?:=|\s+)("[^"]*"|'[^']*'|\S+)/g, "").trim();
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A root's variable values as the binary would read them, by name, each an
|
|
169
|
+
* HCL expression: its tfvars files, its auto tfvars files, the `TF_CLI_ARGS`
|
|
170
|
+
* `-var-file`s, then `varFiles` (the `-var-file`s chant passes), later over
|
|
171
|
+
* earlier.
|
|
172
|
+
*/
|
|
173
|
+
export function rootVarValues(dir, env, varFiles = []) {
|
|
174
|
+
const out = new Map();
|
|
175
|
+
let names = [];
|
|
176
|
+
try {
|
|
177
|
+
names = readdirSync(dir).filter((n) => statSync(join(dir, n)).isFile());
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
const files = [
|
|
183
|
+
...["terraform.tfvars", "terraform.tfvars.json"].filter((n) => names.includes(n)),
|
|
184
|
+
...names.filter((n) => n.endsWith(".auto.tfvars") || n.endsWith(".auto.tfvars.json")).sort(),
|
|
185
|
+
...cliVarFiles(env),
|
|
186
|
+
...varFiles,
|
|
187
|
+
];
|
|
188
|
+
for (const f of files) {
|
|
189
|
+
let text;
|
|
190
|
+
try {
|
|
191
|
+
text = readFileSync(resolve(dir, f), "utf-8");
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (f.endsWith(".json")) {
|
|
197
|
+
try {
|
|
198
|
+
for (const [k, v] of Object.entries(JSON.parse(text)))
|
|
199
|
+
out.set(k, hclValue(v));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// The binary would refuse it too; the plan says so.
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
for (const [k, v] of hclAttributes(text))
|
|
207
|
+
out.set(k, v);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
/** `module.<m>.<output>`, each part of a dotted output a traversal, or an index when it is no identifier. */
|
|
213
|
+
function moduleRef(module, output) {
|
|
214
|
+
return `module.${module}${output
|
|
215
|
+
.split(".")
|
|
216
|
+
.map((p) => (/^[A-Za-z_][\w-]*$/.test(p) ? `.${p}` : `[${hclString(p)}]`))
|
|
217
|
+
.join("")}`;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* A step's `vars` value as a module argument: a `stackOutput()` or
|
|
221
|
+
* `@<component>.publish.*` naming a member becomes a reference to that
|
|
222
|
+
* member's module output; one naming any other component is resolved
|
|
223
|
+
* against `componentOutputs` to the literal the step would pass. Throws when
|
|
224
|
+
* such a value is not known.
|
|
225
|
+
*/
|
|
226
|
+
function varExpr(value, modules, componentOutputs, at) {
|
|
227
|
+
if (typeof value === "string") {
|
|
228
|
+
const pub = value.match(/^@([a-z0-9]+(?:-[a-z0-9]+)*)\.publish\.(uri|digest|key)$/);
|
|
229
|
+
if (pub && modules.has(pub[1]))
|
|
230
|
+
return moduleRef(modules.get(pub[1]), `publish.${pub[2]}`);
|
|
231
|
+
const v = resolveWiring(value, {}, componentOutputs);
|
|
232
|
+
if (v === undefined)
|
|
233
|
+
throw new Error(`${at} reads \`${value}\`, which has no value yet`);
|
|
234
|
+
return hclValue(v);
|
|
235
|
+
}
|
|
236
|
+
if (Array.isArray(value))
|
|
237
|
+
return `[${value.map((v, i) => varExpr(v, modules, componentOutputs, `${at}[${i}]`)).join(", ")}]`;
|
|
238
|
+
if (value && typeof value === "object") {
|
|
239
|
+
if ("stackOutput" in value) {
|
|
240
|
+
const { stack, name } = value.stackOutput;
|
|
241
|
+
if (modules.has(stack))
|
|
242
|
+
return moduleRef(modules.get(stack), name);
|
|
243
|
+
const v = resolveWiring(value, {}, componentOutputs);
|
|
244
|
+
if (v === undefined)
|
|
245
|
+
throw new Error(`${at} reads \`${stack}.${name}\`, an output of a component outside the composed run that has no value yet`);
|
|
246
|
+
return hclValue(v);
|
|
247
|
+
}
|
|
248
|
+
const o = value;
|
|
249
|
+
return `{ ${Object.keys(o)
|
|
250
|
+
.sort()
|
|
251
|
+
.map((k) => `${hclString(k)} = ${varExpr(o[k], modules, componentOutputs, `${at}.${k}`)}`)
|
|
252
|
+
.join(", ")} }`;
|
|
253
|
+
}
|
|
254
|
+
return hclValue(value);
|
|
255
|
+
}
|
|
256
|
+
/** Every leaf step of a deploy, in order. */
|
|
257
|
+
function leafSteps(phases) {
|
|
258
|
+
const out = [];
|
|
259
|
+
const walk = (steps) => {
|
|
260
|
+
for (const s of steps) {
|
|
261
|
+
if (typeof s.phase === "string" && Array.isArray(s.steps))
|
|
262
|
+
walk(s.steps);
|
|
263
|
+
else
|
|
264
|
+
out.push(s);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
for (const p of phases)
|
|
268
|
+
walk(p.steps);
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
/** Each member's `terraform-apply` step `vars`, as written, for {@link ComposedRootInput.vars}. */
|
|
272
|
+
export function memberVars(components, c) {
|
|
273
|
+
const out = {};
|
|
274
|
+
for (const comp of components) {
|
|
275
|
+
if (!c.members.includes(comp.name))
|
|
276
|
+
continue;
|
|
277
|
+
const vars = leafSteps(comp.deploy).find((s) => s.kind === "terraform-apply")?.vars;
|
|
278
|
+
if (vars && typeof vars === "object" && !Array.isArray(vars))
|
|
279
|
+
out[comp.name] = vars;
|
|
280
|
+
}
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
const sha256 = (s) => createHash("sha256").update(s).digest("hex");
|
|
284
|
+
/** Cut ranges out of a text, from the end so positions hold. */
|
|
285
|
+
function cut(text, ranges) {
|
|
286
|
+
let out = text;
|
|
287
|
+
for (const [a, b] of [...ranges].sort((x, y) => y[0] - x[0]))
|
|
288
|
+
out = out.slice(0, a) + out.slice(b);
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
291
|
+
/** A module's `source`: the member's directory relative to the composed root, as a local path. */
|
|
292
|
+
function moduleSource(composeDir, dir) {
|
|
293
|
+
const rel = relPath(composeDir, dir);
|
|
294
|
+
return JSON.stringify(rel.startsWith(".") ? rel : `./${rel}`);
|
|
295
|
+
}
|
|
296
|
+
/** The composed root's `output` blocks: each member's outputs as `<module>__<name>`. */
|
|
297
|
+
function reExports(c, outputs) {
|
|
298
|
+
return c.order.flatMap((m) => [...(outputs.get(m) ?? [])].map(([o, sensitive]) => `output "${c.modules.get(m)}__${o}" {\n value = module.${c.modules.get(m)}.${o}\n${sensitive ? " sensitive = true\n" : ""}}\n`));
|
|
299
|
+
}
|
|
300
|
+
/** Tracks what a write changed so all of it goes back. */
|
|
301
|
+
class Undo {
|
|
302
|
+
constructor(write) {
|
|
303
|
+
this.write = write;
|
|
304
|
+
this.originals = new Map();
|
|
305
|
+
this.generated = [];
|
|
306
|
+
}
|
|
307
|
+
dir(dir) {
|
|
308
|
+
if (!existsSync(dir)) {
|
|
309
|
+
mkdirSync(dir, { recursive: true });
|
|
310
|
+
this.madeDir = dir;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Rewrite a root file, keeping its bytes first. */
|
|
314
|
+
rewrite(file, text) {
|
|
315
|
+
if (!this.originals.has(file))
|
|
316
|
+
this.originals.set(file, readFileSync(file));
|
|
317
|
+
this.write(file, text);
|
|
318
|
+
}
|
|
319
|
+
/** Write a file the run generates, noted before it is written so a partial write is taken away too. */
|
|
320
|
+
generate(file, text) {
|
|
321
|
+
this.generated.push(file);
|
|
322
|
+
this.write(file, text);
|
|
323
|
+
}
|
|
324
|
+
rewritten(projectRoot) {
|
|
325
|
+
return [...this.originals.keys()].map((f) => relPath(projectRoot, f)).sort();
|
|
326
|
+
}
|
|
327
|
+
generatedFiles() {
|
|
328
|
+
return this.generated;
|
|
329
|
+
}
|
|
330
|
+
restore() {
|
|
331
|
+
const errors = [];
|
|
332
|
+
for (const [f, bytes] of this.originals) {
|
|
333
|
+
try {
|
|
334
|
+
writeFileSync(f, bytes);
|
|
335
|
+
}
|
|
336
|
+
catch (e) {
|
|
337
|
+
errors.push(e);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
for (const f of this.generated) {
|
|
341
|
+
try {
|
|
342
|
+
rmSync(f, { force: true });
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
errors.push(e);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (this.madeDir) {
|
|
349
|
+
try {
|
|
350
|
+
if (readdirSync(this.madeDir).length === 0)
|
|
351
|
+
rmdirSync(this.madeDir);
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Gone already, or the run left its working files there.
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (errors.length > 0)
|
|
358
|
+
throw errors[0];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function digests(projectRoot, files) {
|
|
362
|
+
return files.map((f) => [relPath(projectRoot, f), sha256(readFileSync(f))]).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
363
|
+
}
|
|
364
|
+
function assertComposed(c, estate) {
|
|
365
|
+
if (c.fallback || c.members.length < 2)
|
|
366
|
+
throw new Error(`nothing composes${c.fallback ? `: ${c.fallback.reason}` : ""}`);
|
|
367
|
+
if (!!c.estate !== estate)
|
|
368
|
+
throw new Error(estate ? "the composition is not one of estates; write it with writeComposedRoot" : "the composition is one of estates; write it with writeEstateRoot");
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Write the composed root of `composition` into `.chant-compose/` and rewrite
|
|
372
|
+
* each member: its backend block cut, its `terraform_remote_state` reads of
|
|
373
|
+
* other members cut and their references turned into a variable the composed
|
|
374
|
+
* root fills with `{ outputs = module.<upstream> }`, and its `import` and
|
|
375
|
+
* `removed` blocks lifted into the composed root with `module.<m>.` in front
|
|
376
|
+
* of their addresses. Each root's variable values, then its step's `vars`,
|
|
377
|
+
* become the module's arguments. Throws, changing nothing, when a root
|
|
378
|
+
* already has a `chant_compose.tf`; throws after putting everything back
|
|
379
|
+
* when a write fails partway.
|
|
380
|
+
*/
|
|
381
|
+
export function writeComposedRoot(input) {
|
|
382
|
+
const c = input.composition;
|
|
383
|
+
assertComposed(c, false);
|
|
384
|
+
const projectRoot = resolve(input.projectRoot);
|
|
385
|
+
const dir = join(projectRoot, COMPOSE_DIR);
|
|
386
|
+
const env = input.env;
|
|
387
|
+
for (const m of c.order) {
|
|
388
|
+
if (existsSync(join(c.dirs.get(m), COMPOSE_FILE)))
|
|
389
|
+
throw new Error(`${relPath(projectRoot, c.dirs.get(m))}: ${COMPOSE_FILE} is already in the root`);
|
|
390
|
+
}
|
|
391
|
+
const undo = new Undo(input.write ?? ((f, t) => writeFileSync(f, t)));
|
|
392
|
+
const outputs = new Map();
|
|
393
|
+
const lifted = [];
|
|
394
|
+
const passed = new Map();
|
|
395
|
+
const modules = [];
|
|
396
|
+
try {
|
|
397
|
+
for (const member of c.order) {
|
|
398
|
+
const m = c.modules.get(member);
|
|
399
|
+
const rdir = c.dirs.get(member);
|
|
400
|
+
const texts = rootTexts(rdir, input.terraform.binary);
|
|
401
|
+
outputs.set(member, declaredOutputs(texts));
|
|
402
|
+
const variables = declaredVariables(texts);
|
|
403
|
+
const remote = (c.reads.get(member) ?? []).flatMap((r) => (r.via === "remote-state" ? [{ name: r.name, upstream: r.upstream }] : []));
|
|
404
|
+
for (const t of texts) {
|
|
405
|
+
const raw = readFileSync(t.file, "utf-8");
|
|
406
|
+
let next;
|
|
407
|
+
if (t.json)
|
|
408
|
+
next = rewriteJson(raw, remote, m, lifted);
|
|
409
|
+
else {
|
|
410
|
+
const ranges = [];
|
|
411
|
+
for (const b of t.text.matchAll(/\bbackend\s+"[^"]+"\s*\{/g))
|
|
412
|
+
ranges.push([b.index, b.index + blockBody(t.text, b.index).length]);
|
|
413
|
+
for (const b of t.text.matchAll(/\bdata\s+"terraform_remote_state"\s+"([^"]+)"\s*\{/g)) {
|
|
414
|
+
if (remote.some((x) => x.name === b[1]))
|
|
415
|
+
ranges.push([b.index, b.index + blockBody(t.text, b.index).length]);
|
|
416
|
+
}
|
|
417
|
+
for (const b of t.text.matchAll(/(^|\n)([ \t]*)(import|removed)\s*\{/g)) {
|
|
418
|
+
const at = b.index + b[1].length;
|
|
419
|
+
const body = raw.slice(at, at + blockBody(t.text, at).length);
|
|
420
|
+
ranges.push([at, at + body.length]);
|
|
421
|
+
lifted.push(liftBlock(body, b[3], m));
|
|
422
|
+
}
|
|
423
|
+
next = cut(raw, ranges);
|
|
424
|
+
for (const x of remote)
|
|
425
|
+
next = next.replace(refRe(x.name), `var.${READ_VAR_PREFIX}${x.name}`);
|
|
426
|
+
}
|
|
427
|
+
if (next !== raw)
|
|
428
|
+
undo.rewrite(t.file, next);
|
|
429
|
+
}
|
|
430
|
+
const readNames = [...new Set(remote.map((x) => x.name))];
|
|
431
|
+
undo.generate(join(rdir, COMPOSE_FILE), `${HEADER}${readNames.map((n) => `variable "${READ_VAR_PREFIX}${n}" {\n type = any\n}\n`).join("\n")}`);
|
|
432
|
+
// Arguments: the root's variable values, then its step's vars over them, then a TF_VAR_ the job sets for a variable still without one, then its reads.
|
|
433
|
+
const rootKey = c.roots.get(member);
|
|
434
|
+
const args = new Map();
|
|
435
|
+
for (const [k, v] of rootVarValues(rdir, env, input.terraform.roots[rootKey]?.varFiles ?? []))
|
|
436
|
+
if (variables.has(k))
|
|
437
|
+
args.set(k, v);
|
|
438
|
+
for (const [k, v] of Object.entries(input.vars?.[member] ?? {})) {
|
|
439
|
+
if (v === undefined)
|
|
440
|
+
continue;
|
|
441
|
+
args.set(k, varExpr(v, c.modules, input.componentOutputs ?? {}, `\`${member}\`'s var \`${k}\``));
|
|
442
|
+
}
|
|
443
|
+
for (const [k, v] of variables) {
|
|
444
|
+
if (args.has(k) || env[`TF_VAR_${k}`] === undefined)
|
|
445
|
+
continue;
|
|
446
|
+
if (!passed.has(k))
|
|
447
|
+
passed.set(k, v);
|
|
448
|
+
args.set(k, `var.${k}`);
|
|
449
|
+
}
|
|
450
|
+
for (const n of readNames)
|
|
451
|
+
args.set(`${READ_VAR_PREFIX}${n}`, `{ outputs = module.${c.modules.get(remote.find((x) => x.name === n).upstream)} }`);
|
|
452
|
+
const lines = [` source = ${moduleSource(dir, rdir)}`, ...[...args].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)).map(([k, v]) => ` ${k} = ${v}`)];
|
|
453
|
+
modules.push(`module "${m}" {\n${lines.join("\n")}\n}\n`);
|
|
454
|
+
}
|
|
455
|
+
undo.dir(dir);
|
|
456
|
+
const vars = [...passed].map(([k, v]) => `variable "${k}" {\n${v.type ? ` type = ${v.type}\n` : ""}${v.sensitive ? " sensitive = true\n" : ""}}\n`);
|
|
457
|
+
undo.generate(join(dir, "main.tf"), [`${HEADER}# Each root a module, its state its own.\n`, ...vars, ...modules, ...reExports(c, outputs), ...lifted].join("\n"));
|
|
458
|
+
const lock = unionLock(c.order.map((m) => c.dirs.get(m)));
|
|
459
|
+
if (lock)
|
|
460
|
+
undo.generate(join(dir, ".terraform.lock.hcl"), lock);
|
|
461
|
+
}
|
|
462
|
+
catch (e) {
|
|
463
|
+
undo.restore();
|
|
464
|
+
throw e;
|
|
465
|
+
}
|
|
466
|
+
return { dir, rewritten: undo.rewritten(projectRoot), generated: digests(projectRoot, undo.generatedFiles()), outputs, restore: () => undo.restore() };
|
|
467
|
+
}
|
|
468
|
+
/** An `import` or `removed` block of module `m`, lifted into the composed root: its address with `module.<m>.` in front. */
|
|
469
|
+
export function liftBlock(body, kind, m) {
|
|
470
|
+
const key = kind === "import" ? "to" : "from";
|
|
471
|
+
return `${body.replace(new RegExp(`(^|\\n)(\\s*)${key}(\\s*)=(\\s*)`), `$1$2${key}$3=$4module.${m}.`).trim()}\n`;
|
|
472
|
+
}
|
|
473
|
+
/** A JSON-syntax file rewritten as {@link writeComposedRoot} rewrites HCL: its backend, its reads of members, and its import and removed blocks out. */
|
|
474
|
+
export function rewriteJson(raw, reads, m, lifted) {
|
|
475
|
+
let doc;
|
|
476
|
+
try {
|
|
477
|
+
doc = JSON.parse(raw);
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
return raw;
|
|
481
|
+
}
|
|
482
|
+
let changed = false;
|
|
483
|
+
for (const t of Array.isArray(doc.terraform) ? doc.terraform : [doc.terraform]) {
|
|
484
|
+
if (t && typeof t === "object" && "backend" in t) {
|
|
485
|
+
delete t.backend;
|
|
486
|
+
changed = true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const data = doc.data;
|
|
490
|
+
const rs = data?.terraform_remote_state;
|
|
491
|
+
if (rs && typeof rs === "object") {
|
|
492
|
+
for (const x of reads) {
|
|
493
|
+
if (x.name in rs) {
|
|
494
|
+
delete rs[x.name];
|
|
495
|
+
changed = true;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (Object.keys(rs).length === 0)
|
|
499
|
+
delete data.terraform_remote_state;
|
|
500
|
+
if (data && Object.keys(data).length === 0)
|
|
501
|
+
delete doc.data;
|
|
502
|
+
}
|
|
503
|
+
for (const kind of ["import", "removed"]) {
|
|
504
|
+
for (const b of jsonBlocks(doc, kind)) {
|
|
505
|
+
const key = kind === "import" ? "to" : "from";
|
|
506
|
+
const addr = String(b[key] ?? "").replace(/^\$\{(.*)\}$/, "$1");
|
|
507
|
+
const rest = kind === "import" ? ` id = ${JSON.stringify(b.id)}/n` : b.lifecycle ? ` lifecycle {/n destroy = ${b.lifecycle.destroy === false ? "false" : "true"}\n }\n` : "";
|
|
508
|
+
lifted.push(`${kind} {\n ${key} = module.${m}.${addr}\n${rest}}\n`);
|
|
509
|
+
changed = true;
|
|
510
|
+
}
|
|
511
|
+
if (kind in doc)
|
|
512
|
+
delete doc[kind];
|
|
513
|
+
}
|
|
514
|
+
let text = changed ? JSON.stringify(doc, null, 2) + "\n" : raw;
|
|
515
|
+
for (const x of reads)
|
|
516
|
+
text = text.replace(refRe(x.name), `var.${READ_VAR_PREFIX}${x.name}`);
|
|
517
|
+
return text;
|
|
518
|
+
}
|
|
519
|
+
/** The union of the roots' `.terraform.lock.hcl`: one block per provider, with every hash any root's file holds for it. */
|
|
520
|
+
export function unionLock(dirs) {
|
|
521
|
+
const blocks = new Map();
|
|
522
|
+
for (const d of dirs) {
|
|
523
|
+
let text;
|
|
524
|
+
try {
|
|
525
|
+
text = readFileSync(join(d, ".terraform.lock.hcl"), "utf-8");
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
for (const m of text.matchAll(/^provider\s+"([^"]+)"\s*\{/gm)) {
|
|
531
|
+
const body = blockBody(text, m.index);
|
|
532
|
+
const version = body.match(/\bversion\s*=\s*"([^"]+)"/)?.[1];
|
|
533
|
+
if (!version)
|
|
534
|
+
continue;
|
|
535
|
+
const constraints = body.match(/\bconstraints\s*=\s*"([^"]*)"/)?.[1];
|
|
536
|
+
const hashes = [...(body.match(/\bhashes\s*=\s*\[([\s\S]*?)\]/)?.[1] ?? "").matchAll(/"([^"]+)"/g)].map((h) => h[1]);
|
|
537
|
+
const had = blocks.get(m[1]);
|
|
538
|
+
if (had)
|
|
539
|
+
for (const h of hashes)
|
|
540
|
+
had.hashes.add(h);
|
|
541
|
+
else
|
|
542
|
+
blocks.set(m[1], { version, ...(constraints !== undefined ? { constraints } : {}), hashes: new Set(hashes) });
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (blocks.size === 0)
|
|
546
|
+
return undefined;
|
|
547
|
+
const out = ["# Written by chant for a composed run: the union of its roots' lock files.\n"];
|
|
548
|
+
for (const [p, b] of [...blocks].sort(([a], [c]) => (a < c ? -1 : 1))) {
|
|
549
|
+
out.push(`provider "${p}" {\n version = "${b.version}"\n${b.constraints !== undefined ? ` constraints = "${b.constraints}"\n` : ""} hashes = [\n${[...b.hashes]
|
|
550
|
+
.sort()
|
|
551
|
+
.map((h) => ` "${h}",`)
|
|
552
|
+
.join("\n")}\n ]\n}\n`);
|
|
553
|
+
}
|
|
554
|
+
return out.join("\n");
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* The composed root of an estate run (`Composition.estate`), written into
|
|
558
|
+
* `.chant-compose/`: one `module` call per estate whose `source` is the
|
|
559
|
+
* estate's own directory and nothing else, and each estate's outputs
|
|
560
|
+
* re-exported as `<module>__<name>`, which is where the plan shows what an
|
|
561
|
+
* estate's output will be. No estate file is changed, so `restore()` only
|
|
562
|
+
* takes the generated files away. choudoufu reads each called directory's
|
|
563
|
+
* own `live` block, and resolves a `terraform_estate_outputs` read of
|
|
564
|
+
* another estate inside the run.
|
|
565
|
+
*/
|
|
566
|
+
export function writeEstateRoot(input) {
|
|
567
|
+
const c = input.composition;
|
|
568
|
+
assertComposed(c, true);
|
|
569
|
+
const projectRoot = resolve(input.projectRoot);
|
|
570
|
+
const dir = join(projectRoot, COMPOSE_DIR);
|
|
571
|
+
const undo = new Undo(input.write ?? ((f, t) => writeFileSync(f, t)));
|
|
572
|
+
const outputs = new Map(c.order.map((m) => [m, declaredOutputs(rootTexts(c.dirs.get(m), "choudoufu"))]));
|
|
573
|
+
try {
|
|
574
|
+
const modules = c.order.map((m) => `module "${c.modules.get(m)}" {\n source = ${moduleSource(dir, c.dirs.get(m))}\n}\n`);
|
|
575
|
+
undo.dir(dir);
|
|
576
|
+
undo.generate(join(dir, "main.tf"), [`${HEADER}# Each estate's directory a module, its records its own.\n`, ...modules, ...reExports(c, outputs)].join("\n"));
|
|
577
|
+
const lock = unionLock(c.order.map((m) => c.dirs.get(m)));
|
|
578
|
+
if (lock)
|
|
579
|
+
undo.generate(join(dir, ".terraform.lock.hcl"), lock);
|
|
580
|
+
}
|
|
581
|
+
catch (e) {
|
|
582
|
+
undo.restore();
|
|
583
|
+
throw e;
|
|
584
|
+
}
|
|
585
|
+
return { dir, rewritten: [], generated: digests(projectRoot, undo.generatedFiles()), outputs, restore: () => undo.restore() };
|
|
586
|
+
}
|