@intentius/chant 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/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/discover.js +3 -1
- package/dist/behaviour.d.ts +1 -1
- package/dist/behaviour.d.ts.map +1 -1
- package/dist/capabilities/templates.d.ts +65 -0
- package/dist/capabilities/templates.d.ts.map +1 -0
- package/dist/capabilities/templates.js +193 -0
- package/dist/capabilities/templates.json +145 -0
- package/dist/change-set-graph.d.ts +35 -3
- package/dist/change-set-graph.d.ts.map +1 -1
- package/dist/change-set-graph.js +60 -9
- package/dist/change-set.d.ts +65 -7
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +23 -12
- package/dist/ci-identity.d.ts +7 -2
- package/dist/ci-identity.d.ts.map +1 -1
- package/dist/ci-identity.js +4 -1
- package/dist/cli/commands/import-index.d.ts +52 -0
- package/dist/cli/commands/import-index.d.ts.map +1 -0
- package/dist/cli/commands/import-index.js +226 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +4 -2
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/components.js +11 -2
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +16 -3
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +22 -4
- package/dist/cli/handlers/index-cloud.d.ts +14 -0
- package/dist/cli/handlers/index-cloud.d.ts.map +1 -0
- package/dist/cli/handlers/index-cloud.js +22 -0
- package/dist/cli/handlers/index-diff.d.ts +18 -0
- package/dist/cli/handlers/index-diff.d.ts.map +1 -0
- package/dist/cli/handlers/index-diff.js +142 -0
- package/dist/cli/handlers/lifecycle-drift.d.ts +25 -0
- package/dist/cli/handlers/lifecycle-drift.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-drift.js +64 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.js +188 -28
- package/dist/cli/handlers/misc.d.ts +9 -0
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/misc.js +77 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +15 -2
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +89 -15
- package/dist/cli/handlers/query.d.ts.map +1 -1
- package/dist/cli/handlers/query.js +28 -4
- package/dist/cli/handlers/scenario.d.ts.map +1 -1
- package/dist/cli/handlers/scenario.js +8 -7
- package/dist/cli/handlers/search.d.ts +34 -4
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +216 -36
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +55 -1
- package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -1
- package/dist/cli/mcp/lifecycle-tools.js +3 -2
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.js +4 -3
- package/dist/cli/mcp/workspace-tools.js +1 -1
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +55 -2
- package/dist/cli/registry.d.ts +19 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cloud-lister/aws.d.ts +35 -0
- package/dist/cloud-lister/aws.d.ts.map +1 -0
- package/dist/cloud-lister/aws.js +203 -0
- package/dist/cloud-lister/azure.d.ts +34 -0
- package/dist/cloud-lister/azure.d.ts.map +1 -0
- package/dist/cloud-lister/azure.js +129 -0
- package/dist/cloud-lister/common.d.ts +40 -0
- package/dist/cloud-lister/common.d.ts.map +1 -0
- package/dist/cloud-lister/common.js +83 -0
- package/dist/cloud-lister/credentials.d.ts +50 -0
- package/dist/cloud-lister/credentials.d.ts.map +1 -0
- package/dist/cloud-lister/credentials.js +86 -0
- package/dist/cloud-lister/fakes.d.ts +27 -0
- package/dist/cloud-lister/fakes.d.ts.map +1 -0
- package/dist/cloud-lister/fakes.js +50 -0
- package/dist/cloud-lister/gcp.d.ts +42 -0
- package/dist/cloud-lister/gcp.d.ts.map +1 -0
- package/dist/cloud-lister/gcp.js +143 -0
- package/dist/cloud-lister/guard.d.ts +49 -0
- package/dist/cloud-lister/guard.d.ts.map +1 -0
- package/dist/cloud-lister/guard.js +103 -0
- package/dist/cloud-lister/ids.d.ts +23 -0
- package/dist/cloud-lister/ids.d.ts.map +1 -0
- package/dist/cloud-lister/ids.js +42 -0
- package/dist/cloud-lister/index.d.ts +67 -0
- package/dist/cloud-lister/index.d.ts.map +1 -0
- package/dist/cloud-lister/index.js +102 -0
- package/dist/cloud-lister/kubernetes.d.ts +64 -0
- package/dist/cloud-lister/kubernetes.d.ts.map +1 -0
- package/dist/cloud-lister/kubernetes.js +276 -0
- package/dist/cloud-lister/markers.d.ts +31 -0
- package/dist/cloud-lister/markers.d.ts.map +1 -0
- package/dist/cloud-lister/markers.js +73 -0
- package/dist/cloud-lister/mask.d.ts +31 -0
- package/dist/cloud-lister/mask.d.ts.map +1 -0
- package/dist/cloud-lister/mask.js +74 -0
- package/dist/cloud-lister/sigv4.d.ts +29 -0
- package/dist/cloud-lister/sigv4.d.ts.map +1 -0
- package/dist/cloud-lister/sigv4.js +54 -0
- package/dist/cloud-lister/transport.d.ts +55 -0
- package/dist/cloud-lister/transport.d.ts.map +1 -0
- package/dist/cloud-lister/transport.js +86 -0
- package/dist/cloud-lister/types.d.ts +121 -0
- package/dist/cloud-lister/types.d.ts.map +1 -0
- package/dist/cloud-lister/types.js +24 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.js +6 -0
- package/dist/components/capability-plugin.d.ts +9 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability.d.ts +215 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +21 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/cli-support.js +58 -14
- package/dist/components/declared-reads.d.ts +38 -0
- package/dist/components/declared-reads.d.ts.map +1 -0
- package/dist/components/declared-reads.js +131 -0
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/deploy-units.js +4 -0
- package/dist/components/driver.d.ts +34 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +66 -3
- package/dist/components/fan-out-run.d.ts +23 -1
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-run.js +82 -14
- package/dist/components/fan-out-support.d.ts +6 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out-support.js +4 -1
- package/dist/components/fan-out.d.ts +28 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/groups.d.ts +229 -0
- package/dist/components/groups.d.ts.map +1 -0
- package/dist/components/groups.js +760 -0
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -0
- package/dist/components/plan-shape-conformance.d.ts +48 -0
- package/dist/components/plan-shape-conformance.d.ts.map +1 -0
- package/dist/components/plan-shape-conformance.js +122 -0
- package/dist/components/pr-run.d.ts +41 -4
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +209 -39
- package/dist/components/promote-rounds.d.ts +9 -0
- package/dist/components/promote-rounds.d.ts.map +1 -1
- package/dist/components/promote-rounds.js +23 -2
- package/dist/components/promote.d.ts +17 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +36 -6
- package/dist/components/release-gate.d.ts +23 -1
- package/dist/components/release-gate.d.ts.map +1 -1
- package/dist/components/release-gate.js +97 -33
- package/dist/components/run-groups.d.ts +58 -0
- package/dist/components/run-groups.d.ts.map +1 -0
- package/dist/components/run-groups.js +78 -0
- package/dist/components/starter-plugin.d.ts +1 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/starter-plugin.js +6 -1
- package/dist/components/verbs/index.d.ts +1 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/index.js +1 -0
- package/dist/components/verbs/member-outputs.d.ts +187 -0
- package/dist/components/verbs/member-outputs.d.ts.map +1 -0
- package/dist/components/verbs/member-outputs.js +218 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -0
- package/dist/deep-observation.d.ts +1 -13
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/deep-observation.js +5 -22
- package/dist/drift-record.d.ts +542 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +886 -0
- package/dist/engine-facts.d.ts +144 -0
- package/dist/engine-facts.d.ts.map +1 -0
- package/dist/engine-facts.js +14 -0
- package/dist/graph-ir.d.ts +153 -2
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-ir.js +224 -6
- package/dist/graph-refs.d.ts +145 -0
- package/dist/graph-refs.d.ts.map +1 -1
- package/dist/graph-refs.js +305 -0
- package/dist/graph-schema/fixtures/adopt.json +15 -0
- package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
- package/dist/graph-schema/fixtures/index.json +68 -0
- package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
- package/dist/graph-schema/fixtures.d.ts +23 -0
- package/dist/graph-schema/fixtures.d.ts.map +1 -0
- package/dist/graph-schema/fixtures.js +246 -0
- package/dist/graph-schema/generate.d.ts +15 -0
- package/dist/graph-schema/generate.d.ts.map +1 -0
- package/dist/graph-schema/generate.js +267 -0
- package/dist/graph-schema/graph.schema.json +1387 -0
- package/dist/health.schema.json +2 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/instance-nodes.d.ts +159 -0
- package/dist/instance-nodes.d.ts.map +1 -0
- package/dist/instance-nodes.js +231 -0
- package/dist/lexicon.d.ts +72 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/adoption-file.d.ts +56 -0
- package/dist/lifecycle/adoption-file.d.ts.map +1 -0
- package/dist/lifecycle/adoption-file.js +123 -0
- package/dist/lifecycle/cloud-index.d.ts +186 -0
- package/dist/lifecycle/cloud-index.d.ts.map +1 -0
- package/dist/lifecycle/cloud-index.js +618 -0
- package/dist/lifecycle/derive-edges.d.ts +59 -0
- package/dist/lifecycle/derive-edges.d.ts.map +1 -0
- package/dist/lifecycle/derive-edges.js +126 -0
- package/dist/lifecycle/git.d.ts +10 -9
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/git.js +7 -1
- package/dist/lifecycle/identity-match.d.ts +133 -0
- package/dist/lifecycle/identity-match.d.ts.map +1 -0
- package/dist/lifecycle/identity-match.js +147 -0
- package/dist/lifecycle/index-diff.d.ts +224 -0
- package/dist/lifecycle/index-diff.d.ts.map +1 -0
- package/dist/lifecycle/index-diff.js +327 -0
- package/dist/lifecycle/index-document.d.ts +130 -0
- package/dist/lifecycle/index-document.d.ts.map +1 -0
- package/dist/lifecycle/index-document.js +189 -0
- package/dist/lifecycle/index-drift.d.ts +121 -0
- package/dist/lifecycle/index-drift.d.ts.map +1 -0
- package/dist/lifecycle/index-drift.js +178 -0
- package/dist/lifecycle/index-import.d.ts +168 -0
- package/dist/lifecycle/index-import.d.ts.map +1 -0
- package/dist/lifecycle/index-import.js +515 -0
- package/dist/lifecycle/index-join.d.ts +129 -0
- package/dist/lifecycle/index-join.d.ts.map +1 -0
- package/dist/lifecycle/index-join.js +248 -0
- package/dist/lifecycle/index.d.ts +4 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +4 -0
- package/dist/lifecycle/observation-baseline.d.ts +61 -21
- package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
- package/dist/lifecycle/observation-baseline.js +144 -19
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/observe.js +6 -1
- package/dist/lifecycle/query.d.ts +45 -4
- package/dist/lifecycle/query.d.ts.map +1 -1
- package/dist/lifecycle/query.js +89 -7
- package/dist/lifecycle/replay.d.ts +10 -3
- package/dist/lifecycle/replay.d.ts.map +1 -1
- package/dist/lifecycle/replay.js +10 -6
- package/dist/lifecycle/scenario.d.ts +4 -3
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
- package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store-fake.js +21 -0
- package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
- package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store-s3.js +254 -0
- package/dist/lifecycle/snapshot-store.d.ts +170 -0
- package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store.js +832 -0
- package/dist/lifecycle/snapshot.d.ts +11 -0
- package/dist/lifecycle/snapshot.d.ts.map +1 -1
- package/dist/lifecycle/snapshot.js +18 -5
- package/dist/lifecycle/type-listing.d.ts +148 -0
- package/dist/lifecycle/type-listing.d.ts.map +1 -0
- package/dist/lifecycle/type-listing.js +166 -0
- package/dist/lint/component-checks.d.ts +15 -1
- package/dist/lint/component-checks.d.ts.map +1 -1
- package/dist/lint/component-checks.js +1 -0
- package/dist/lint/presets/relaxed.json +2 -1
- package/dist/lint/presets/strict.json +2 -1
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
- package/dist/lint/rules/comp/index.d.ts +2 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/comp/index.js +4 -1
- package/dist/observation.d.ts +19 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +18 -1
- package/dist/op/activities/activity-contracts.d.ts +1 -1
- package/dist/op/activities/activity-contracts.js +1 -1
- package/dist/op/activities/change-set.d.ts +6 -4
- package/dist/op/activities/change-set.d.ts.map +1 -1
- package/dist/op/activities/change-set.js +4 -2
- package/dist/op/activity-failure.d.ts +27 -0
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +1 -1
- package/dist/op/local-executor.d.ts +5 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +22 -8
- package/dist/pr-loop.d.ts +56 -1
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +51 -1
- package/dist/pulumi-urn.d.ts +101 -0
- package/dist/pulumi-urn.d.ts.map +1 -0
- package/dist/pulumi-urn.js +131 -0
- package/dist/release-floors.d.ts +23 -0
- package/dist/release-floors.d.ts.map +1 -0
- package/dist/release-floors.js +22 -0
- package/dist/sensitive-key.d.ts +23 -0
- package/dist/sensitive-key.d.ts.map +1 -0
- package/dist/sensitive-key.js +31 -0
- package/dist/wave-runtime.mjs +234 -234
- package/dist/workspace/adoption-report.d.ts +53 -0
- package/dist/workspace/adoption-report.d.ts.map +1 -0
- package/dist/workspace/adoption-report.js +76 -0
- package/dist/workspace/capabilities-contract.d.ts +7 -0
- package/dist/workspace/capabilities-contract.d.ts.map +1 -1
- package/dist/workspace/capabilities-contract.js +2 -1
- package/dist/workspace/capabilities.schema.json +98 -0
- package/dist/workspace/change-set.schema.json +42 -3
- package/dist/workspace/ci-cloud-identity.d.ts +13 -1
- package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
- package/dist/workspace/ci-cloud-identity.js +30 -1
- package/dist/workspace/compose-graph.d.ts +10 -1
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/compose-graph.js +6 -1
- package/dist/workspace/conformance/index.d.ts +1 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/index.js +6 -1
- package/dist/workspace/drift-cli.d.ts +81 -0
- package/dist/workspace/drift-cli.d.ts.map +1 -0
- package/dist/workspace/drift-cli.js +317 -0
- package/dist/workspace/drift.schema.json +672 -0
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +3 -0
- package/dist/workspace/graph.schema.json +72 -0
- package/dist/workspace/init.d.ts +5 -1
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/init.js +55 -9
- package/dist/workspace/ledger.schema.json +1 -1
- package/dist/workspace/nested-graph.d.ts.map +1 -1
- package/dist/workspace/nested-graph.js +2 -0
- package/dist/workspace/pr-report.schema.json +51 -2
- package/dist/workspace/promote-waves.d.ts +112 -0
- package/dist/workspace/promote-waves.d.ts.map +1 -0
- package/dist/workspace/promote-waves.js +290 -0
- package/dist/workspace/promote.d.ts +84 -2
- package/dist/workspace/promote.d.ts.map +1 -1
- package/dist/workspace/promote.js +347 -61
- package/dist/workspace/reason-codes.d.ts +12 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +14 -0
- package/dist/workspace/search-contract.d.ts +3 -3
- package/dist/workspace/search-contract.d.ts.map +1 -1
- package/dist/workspace/search-contract.js +2 -0
- package/dist/workspace/search.schema.json +103 -5
- package/package.json +14 -1
- package/src/__fixtures__/drift-record/README.md +58 -0
- package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
- package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
- package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
- package/src/__fixtures__/drift-record/component-status.json +91 -0
- package/src/__fixtures__/drift-record/deep-diff.json +259 -0
- package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
- package/src/__fixtures__/drift-record/live-diff.json +125 -0
- package/src/audit/discover.e2e.test.ts +14 -0
- package/src/audit/discover.ts +3 -1
- package/src/behaviour.ts +1 -1
- package/src/capabilities/templates.json +145 -0
- package/src/capabilities/templates.test.ts +212 -0
- package/src/capabilities/templates.ts +204 -0
- package/src/change-set-bundle.test.ts +83 -0
- package/src/change-set-graph.ts +80 -9
- package/src/change-set.test.ts +24 -0
- package/src/change-set.ts +77 -14
- package/src/ci-identity-targets.test.ts +23 -0
- package/src/ci-identity.ts +10 -4
- package/src/cli/commands/import-index.test.ts +117 -0
- package/src/cli/commands/import-index.ts +265 -0
- package/src/cli/commands/lint.ts +4 -2
- package/src/cli/handlers/components.test.ts +9 -0
- package/src/cli/handlers/components.ts +12 -2
- package/src/cli/handlers/fan-out.ts +17 -3
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +26 -4
- package/src/cli/handlers/index-cloud.ts +32 -0
- package/src/cli/handlers/index-diff.test.ts +68 -0
- package/src/cli/handlers/index-diff.ts +146 -0
- package/src/cli/handlers/ledger-root-member.test.ts +161 -0
- package/src/cli/handlers/lifecycle-drift.ts +68 -0
- package/src/cli/handlers/lifecycle.test.ts +33 -11
- package/src/cli/handlers/lifecycle.ts +205 -30
- package/src/cli/handlers/misc.ts +73 -0
- package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
- package/src/cli/handlers/pr.ts +14 -2
- package/src/cli/handlers/promote.test.ts +64 -0
- package/src/cli/handlers/promote.ts +81 -6
- package/src/cli/handlers/query.ts +27 -4
- package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
- package/src/cli/handlers/run-groups-cli.test.ts +229 -0
- package/src/cli/handlers/scenario.test.ts +13 -0
- package/src/cli/handlers/scenario.ts +8 -7
- package/src/cli/handlers/search-index.test.ts +255 -0
- package/src/cli/handlers/search-json.test.ts +1 -1
- package/src/cli/handlers/search-ownership.test.ts +194 -0
- package/src/cli/handlers/search.ts +271 -38
- package/src/cli/main.test.ts +7 -0
- package/src/cli/main.ts +56 -1
- package/src/cli/mcp/lifecycle-tools.ts +3 -2
- package/src/cli/mcp/resource-handlers.ts +4 -3
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/cli/parse-args.ts +40 -2
- package/src/cli/registry.ts +19 -1
- package/src/cloud-lister/aws.test.ts +202 -0
- package/src/cloud-lister/aws.ts +226 -0
- package/src/cloud-lister/azure.test.ts +132 -0
- package/src/cloud-lister/azure.ts +142 -0
- package/src/cloud-lister/common.ts +115 -0
- package/src/cloud-lister/credentials.ts +110 -0
- package/src/cloud-lister/fakes.ts +66 -0
- package/src/cloud-lister/gcp.test.ts +121 -0
- package/src/cloud-lister/gcp.ts +159 -0
- package/src/cloud-lister/guard.test.ts +198 -0
- package/src/cloud-lister/guard.ts +111 -0
- package/src/cloud-lister/ids.ts +54 -0
- package/src/cloud-lister/index.ts +134 -0
- package/src/cloud-lister/kubernetes.test.ts +160 -0
- package/src/cloud-lister/kubernetes.ts +284 -0
- package/src/cloud-lister/markers.ts +74 -0
- package/src/cloud-lister/mask.ts +77 -0
- package/src/cloud-lister/shape.test.ts +81 -0
- package/src/cloud-lister/sigv4.ts +70 -0
- package/src/cloud-lister/transport.ts +118 -0
- package/src/cloud-lister/types.ts +135 -0
- package/src/components/capability-plugin-loader.ts +4 -0
- package/src/components/capability-plugin.ts +10 -0
- package/src/components/capability.ts +229 -0
- package/src/components/cli-support.ts +70 -14
- package/src/components/declared-reads.test.ts +103 -0
- package/src/components/declared-reads.ts +134 -0
- package/src/components/deploy-units.ts +4 -0
- package/src/components/driver.ts +89 -4
- package/src/components/fan-out-run.ts +95 -15
- package/src/components/fan-out-support.ts +10 -1
- package/src/components/fan-out.ts +30 -0
- package/src/components/groups.test.ts +320 -0
- package/src/components/groups.ts +880 -0
- package/src/components/index.ts +42 -0
- package/src/components/plan-shape-conformance.ts +130 -0
- package/src/components/pr-env-run-bundle.test.ts +2 -0
- package/src/components/pr-run.test.ts +516 -3
- package/src/components/pr-run.ts +231 -41
- package/src/components/promote-rounds.ts +25 -2
- package/src/components/promote.ts +55 -5
- package/src/components/registry.test.ts +1 -1
- package/src/components/release-gate.ts +115 -30
- package/src/components/release-groups.test.ts +362 -0
- package/src/components/run-groups.ts +113 -0
- package/src/components/starter-plugin.ts +6 -0
- package/src/components/verbs/index.ts +1 -0
- package/src/components/verbs/member-outputs.test.ts +205 -0
- package/src/components/verbs/member-outputs.ts +308 -0
- package/src/config.ts +44 -0
- package/src/deep-observation.ts +5 -23
- package/src/drift-record.test.ts +596 -0
- package/src/drift-record.ts +1206 -0
- package/src/engine-facts.guard.test.ts +111 -0
- package/src/engine-facts.test.ts +178 -0
- package/src/engine-facts.ts +154 -0
- package/src/gated-waves-bundle.test.ts +2 -0
- package/src/graph-ir-live.test.ts +92 -0
- package/src/graph-ir.ts +317 -7
- package/src/graph-refs.ts +416 -0
- package/src/graph-schema/fixtures/adopt.json +15 -0
- package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
- package/src/graph-schema/fixtures/index.json +68 -0
- package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
- package/src/graph-schema/fixtures.ts +267 -0
- package/src/graph-schema/generate.ts +263 -0
- package/src/graph-schema/graph-schema.test.ts +153 -0
- package/src/graph-schema/graph.schema.json +1387 -0
- package/src/health.schema.json +2 -1
- package/src/identity.ts +2 -0
- package/src/index.ts +2 -0
- package/src/instance-nodes.ts +288 -0
- package/src/lexicon.ts +76 -0
- package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
- package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
- package/src/lifecycle/adoption-file.test.ts +100 -0
- package/src/lifecycle/adoption-file.ts +154 -0
- package/src/lifecycle/cloud-index.test.ts +517 -0
- package/src/lifecycle/cloud-index.ts +736 -0
- package/src/lifecycle/derive-edges.test.ts +193 -0
- package/src/lifecycle/derive-edges.ts +182 -0
- package/src/lifecycle/git.ts +10 -4
- package/src/lifecycle/identity-match.test.ts +308 -0
- package/src/lifecycle/identity-match.ts +257 -0
- package/src/lifecycle/index-diff.test.ts +198 -0
- package/src/lifecycle/index-diff.ts +476 -0
- package/src/lifecycle/index-document.test.ts +64 -0
- package/src/lifecycle/index-document.ts +299 -0
- package/src/lifecycle/index-drift.test.ts +191 -0
- package/src/lifecycle/index-drift.ts +304 -0
- package/src/lifecycle/index-import.test.ts +255 -0
- package/src/lifecycle/index-import.ts +634 -0
- package/src/lifecycle/index-join.test.ts +250 -0
- package/src/lifecycle/index-join.ts +304 -0
- package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
- package/src/lifecycle/index.ts +4 -0
- package/src/lifecycle/member-ledger.test.ts +25 -7
- package/src/lifecycle/observation-baseline.test.ts +72 -1
- package/src/lifecycle/observation-baseline.ts +190 -27
- package/src/lifecycle/observe.ts +6 -1
- package/src/lifecycle/query.test.ts +69 -1
- package/src/lifecycle/query.ts +103 -10
- package/src/lifecycle/replay.test.ts +9 -5
- package/src/lifecycle/replay.ts +9 -5
- package/src/lifecycle/scenario.ts +4 -3
- package/src/lifecycle/snapshot-store-fake.ts +29 -0
- package/src/lifecycle/snapshot-store-s3.ts +316 -0
- package/src/lifecycle/snapshot-store.test.ts +385 -0
- package/src/lifecycle/snapshot-store.ts +981 -0
- package/src/lifecycle/snapshot.test.ts +13 -0
- package/src/lifecycle/snapshot.ts +23 -6
- package/src/lifecycle/type-listing.test.ts +166 -0
- package/src/lifecycle/type-listing.ts +309 -0
- package/src/lint/component-checks.ts +17 -1
- package/src/lint/config.test.ts +3 -0
- package/src/lint/presets/relaxed.json +2 -1
- package/src/lint/presets/strict.json +2 -1
- package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
- package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
- package/src/lint/rules/comp/comp.test.ts +2 -1
- package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
- package/src/lint/rules/comp/comp008.test.ts +77 -0
- package/src/lint/rules/comp/index.ts +4 -1
- package/src/observation-edges.test.ts +33 -0
- package/src/observation.ts +36 -1
- package/src/op/activities/activity-contracts.ts +1 -1
- package/src/op/activities/change-set.ts +8 -5
- package/src/op/activity-failure.ts +36 -0
- package/src/op/index.ts +2 -1
- package/src/op/local-executor.test.ts +80 -0
- package/src/op/local-executor.ts +27 -9
- package/src/pr-loop-bundle.test.ts +5 -2
- package/src/pr-loop.test.ts +43 -0
- package/src/pr-loop.ts +111 -2
- package/src/pulumi-urn.ts +151 -0
- package/src/release-floors.ts +22 -0
- package/src/sensitive-key.ts +34 -0
- package/src/workspace/adoption-report.test.ts +61 -0
- package/src/workspace/adoption-report.ts +103 -0
- package/src/workspace/capabilities-contract.test.ts +4 -0
- package/src/workspace/capabilities-contract.ts +9 -1
- package/src/workspace/capabilities.schema.json +98 -0
- package/src/workspace/change-set.schema.json +42 -3
- package/src/workspace/ci-cloud-identity.ts +31 -1
- package/src/workspace/compose-graph.test.ts +12 -0
- package/src/workspace/compose-graph.ts +12 -1
- package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
- package/src/workspace/conformance/index.ts +6 -1
- package/src/workspace/drift-cli.test.ts +65 -0
- package/src/workspace/drift-cli.ts +365 -0
- package/src/workspace/drift.schema.json +672 -0
- package/src/workspace/graph-cli.ts +5 -0
- package/src/workspace/graph.schema.json +72 -0
- package/src/workspace/init.test.ts +38 -1
- package/src/workspace/init.ts +50 -8
- package/src/workspace/intent-gaps.test.ts +18 -2
- package/src/workspace/ledger.schema.json +1 -1
- package/src/workspace/nested-graph.ts +1 -0
- package/src/workspace/pr-report.schema.json +51 -2
- package/src/workspace/promote-waves.test.ts +296 -0
- package/src/workspace/promote-waves.ts +340 -0
- package/src/workspace/promote.test.ts +158 -4
- package/src/workspace/promote.ts +398 -57
- package/src/workspace/reason-codes.test.ts +4 -1
- package/src/workspace/reason-codes.ts +14 -0
- package/src/workspace/search-contract.ts +2 -0
- package/src/workspace/search.schema.json +103 -5
package/src/op/local-executor.ts
CHANGED
|
@@ -35,6 +35,7 @@ import { contentDigest } from "../content-digest";
|
|
|
35
35
|
import { parseDuration } from "./duration";
|
|
36
36
|
import { stepLabel, withRunConsole, withStepConsole } from "./step-console";
|
|
37
37
|
import { stepTimeoutProblem } from "./activity-profiles";
|
|
38
|
+
import { knownOutputsOf } from "./activity-failure";
|
|
38
39
|
import { describeGateMismatch, evaluateGate, gateIsSealed, gitGateLedgerPort, type GateApprovalRule, type GateCheck, type GateLedgerPort, type WorkspaceGateStandIn } from "./gate";
|
|
39
40
|
import { resolveWorkspaceRun, type WorkspaceRunCitation } from "./workspace-run-env";
|
|
40
41
|
import { gateName } from "./gate-name";
|
|
@@ -98,7 +99,11 @@ export interface StepRecord {
|
|
|
98
99
|
* predates the plural form. {@link StepRecord.outcomes} is the whole list.
|
|
99
100
|
*/
|
|
100
101
|
outcome?: { name: string; value: unknown };
|
|
101
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Every outcome attribute the step published, in authored order (#2105).
|
|
104
|
+
* Absent when it published none. A failed step publishes the ones its
|
|
105
|
+
* activity knew before it failed (#4512; see `withKnownOutputs`).
|
|
106
|
+
*/
|
|
102
107
|
outcomes?: Array<{ name: string; value: unknown }>;
|
|
103
108
|
error?: string;
|
|
104
109
|
/** Set on a `gate` step that passed (#2119): who resolved it, when, and at what address. */
|
|
@@ -522,13 +527,7 @@ async function runStep(
|
|
|
522
527
|
const result = await callWithTimeout(fn, args, timeoutMs, signal);
|
|
523
528
|
if (step.id) resultsById.set(step.id, result);
|
|
524
529
|
const record: StepRecord = { ...base, status: "ok", durationMs: Date.now() - start };
|
|
525
|
-
|
|
526
|
-
// An attribute whose path the result does not hold is left off, rather than recorded as undefined.
|
|
527
|
-
const outcomes = attrs.map((a) => ({ name: a.name, value: resolvePath(result, a.from) })).filter((o) => o.value !== undefined);
|
|
528
|
-
if (outcomes.length > 0) {
|
|
529
|
-
record.outcomes = outcomes;
|
|
530
|
-
record.outcome = outcomes[0];
|
|
531
|
-
}
|
|
530
|
+
captureOutcomes(step, record, result);
|
|
532
531
|
return { record, result };
|
|
533
532
|
} catch (err) {
|
|
534
533
|
// An open decision point (#2749) is not a failure and not worth a retry:
|
|
@@ -554,7 +553,26 @@ async function runStep(
|
|
|
554
553
|
break;
|
|
555
554
|
}
|
|
556
555
|
}
|
|
557
|
-
|
|
556
|
+
const failed: StepRecord = { ...base, status: "fail", durationMs: Date.now() - start, error: errMessage(lastErr) };
|
|
557
|
+
// #4512: a failed step still records the outcomes its activity knew before it
|
|
558
|
+
// failed, read off the last attempt's error, as terraformInit's root path.
|
|
559
|
+
const known = knownOutputsOf(lastErr);
|
|
560
|
+
if (known) captureOutcomes(step, failed, known);
|
|
561
|
+
return { record: failed };
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Set `record`'s outcomes from the step's `outcomeAttribute` paths over
|
|
567
|
+
* `source`: the activity's result, or for a failed step the outputs it knew
|
|
568
|
+
* before it failed (#4512). An attribute whose path `source` does not hold is
|
|
569
|
+
* left off, rather than recorded as undefined.
|
|
570
|
+
*/
|
|
571
|
+
function captureOutcomes(step: ActivityStep, record: StepRecord, source: unknown): void {
|
|
572
|
+
const outcomes = outcomeAttributesOf(step).map((a) => ({ name: a.name, value: resolvePath(source, a.from) })).filter((o) => o.value !== undefined);
|
|
573
|
+
if (outcomes.length > 0) {
|
|
574
|
+
record.outcomes = outcomes;
|
|
575
|
+
record.outcome = outcomes[0];
|
|
558
576
|
}
|
|
559
577
|
}
|
|
560
578
|
|
|
@@ -41,8 +41,11 @@ describe("the pull-request loop bundle", () => {
|
|
|
41
41
|
"packages/core/src/pr-forge.ts",
|
|
42
42
|
"packages/core/src/pr-loop.ts",
|
|
43
43
|
"packages/core/src/pr-migrations.ts",
|
|
44
|
+
// The next-release floor constant (#4480): no imports.
|
|
45
|
+
"packages/core/src/release-floors.ts",
|
|
44
46
|
]);
|
|
45
|
-
// About 89 KB today, after the hooks line (#4288), the blocked set (#4291), the scheduled-run reads (#4289) the requires checks (#4301) and the migration notes (#4407), about 97 KB.
|
|
46
|
-
|
|
47
|
+
// About 89 KB today, after the hooks line (#4288), the blocked set (#4291), the scheduled-run reads (#4289) the requires checks (#4301) and the migration notes (#4407), about 97 KB; with the group lines (#4446), about 100 KB.
|
|
48
|
+
// 110 KB is the ruled ceiling (#4481, ruling 12, 2026-10-25), not a figure to lower by trimming note text.
|
|
49
|
+
expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(110 * 1024);
|
|
47
50
|
});
|
|
48
51
|
});
|
package/src/pr-loop.test.ts
CHANGED
|
@@ -489,3 +489,46 @@ describe("new migration files in the plan note (#4407)", () => {
|
|
|
489
489
|
expect(note).toContain("- not read: bad # heading `x`");
|
|
490
490
|
});
|
|
491
491
|
});
|
|
492
|
+
|
|
493
|
+
describe("groups and fallbacks in the report and the note (#4446)", () => {
|
|
494
|
+
const groupDigest = `jcs1-sha256:${hex(7)}`;
|
|
495
|
+
const grouped: PrReport = {
|
|
496
|
+
...planReport,
|
|
497
|
+
groups: [{ capability: "terraform-apply", components: ["a", "app"], wave: 1, digest: groupDigest, reads: [{ component: "app", ref: "a.id" }] }],
|
|
498
|
+
fallbacks: [{ component: "net", capability: "terraform-apply", kind: "backend", reason: "net keeps its state in another backend" }],
|
|
499
|
+
members: planReport.members.map((m) => ({ ...m, group: 0 })),
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
test("a report with a group and a fallback validates, and one without them still does", () => {
|
|
503
|
+
expect(schema.required).not.toContain("groups");
|
|
504
|
+
expect(schema.required).not.toContain("fallbacks");
|
|
505
|
+
expectValid(grouped);
|
|
506
|
+
expectValid(planReport);
|
|
507
|
+
expectValid({ ...grouped, groups: [{ ...grouped.groups![0]!, digest: null, error: "cannot compose" }] });
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test("the note names the group and the reads its apply computes, and why a component fell back", () => {
|
|
511
|
+
const note = renderPrNote(grouped);
|
|
512
|
+
expect(note).toContain("`a` and `app` plan and apply as one (`terraform-apply`, wave 1); `app` reads `a.id`, known when the group applies.");
|
|
513
|
+
expect(note).toContain("Planned one by one, not as a group: `net` (`backend`): net keeps its state in another backend.");
|
|
514
|
+
expect(renderPrNote({ ...grouped, fallbacks: [{ ...grouped.fallbacks![0]!, kind: "off" }] })).not.toContain("not as a group");
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
test("an apply that stopped part way validates with each member's group outcome, and the note says what stays applied", () => {
|
|
518
|
+
const stopped: PrReport = {
|
|
519
|
+
...grouped,
|
|
520
|
+
stage: "apply",
|
|
521
|
+
status: "failed",
|
|
522
|
+
approval: { status: "approved", approvedBy: ["github:alice"] },
|
|
523
|
+
members: [
|
|
524
|
+
{ ...grouped.members[0]!, status: "applied", groupOutcome: "applied" },
|
|
525
|
+
{ ...grouped.members[1]!, status: "failed", groupOutcome: "partial", error: "app: quota exceeded" },
|
|
526
|
+
],
|
|
527
|
+
};
|
|
528
|
+
expectValid(stopped);
|
|
529
|
+
expectValid({ ...stopped, members: [stopped.members[0]!, { ...stopped.members[1]!, status: "not-started", groupOutcome: "not-started" }] });
|
|
530
|
+
const note = renderPrNote(stopped);
|
|
531
|
+
expect(note).toContain("The group's apply stopped part way: `a` applied and stays applied; `app` applied in part, and what applied stays. Nothing that applied is undone.");
|
|
532
|
+
expect(note).toContain("`pr-apply --resume` plans `app` again");
|
|
533
|
+
});
|
|
534
|
+
});
|
package/src/pr-loop.ts
CHANGED
|
@@ -51,6 +51,7 @@ import type { ChangeSetAction, ChangeSetDocument } from "./change-set";
|
|
|
51
51
|
import type { PrRequireOutcome } from "./pr-requires";
|
|
52
52
|
import { renderMigrationLines, type PrMigrationFile } from "./pr-migrations";
|
|
53
53
|
import { GITHUB_COMMENT_LIMIT, groupChangeSet, renderPlanSummaryMarkdown } from "./plan-summary";
|
|
54
|
+
import { NEXT_RELEASE } from "./release-floors";
|
|
54
55
|
|
|
55
56
|
/** The schema a pull-request report names in `$schema`. */
|
|
56
57
|
export const PR_REPORT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/pr-report/v1/pr-report.schema.json";
|
|
@@ -91,6 +92,12 @@ export const PR_REPORT_MIGRATIONS_FLOOR = "0.124.49";
|
|
|
91
92
|
/** The first chant whose report can carry a member's `reads`, known at plan or not. */
|
|
92
93
|
export const PR_REPORT_READS_FLOOR = "0.124.52";
|
|
93
94
|
|
|
95
|
+
/** The first chant whose report can carry the `not-started` member status (ws-107, #4440). */
|
|
96
|
+
export const PR_REPORT_NOT_STARTED_FLOOR = NEXT_RELEASE;
|
|
97
|
+
|
|
98
|
+
/** The first chant whose report can carry `groups`, `fallbacks`, and a member's `group` and `groupOutcome` (ws-107, #4446). */
|
|
99
|
+
export const PR_REPORT_GROUPS_FLOOR = NEXT_RELEASE;
|
|
100
|
+
|
|
94
101
|
/** The gate a pull request's apply waits on, unless the pipeline names another. */
|
|
95
102
|
export const PR_APPLY_GATE = "pr-apply";
|
|
96
103
|
|
|
@@ -156,7 +163,13 @@ export type PrMemberStatus =
|
|
|
156
163
|
* that applied as another value, or was known only after apply. It waits
|
|
157
164
|
* on an approval of the plan the apply made for it afterwards (`rounds`).
|
|
158
165
|
*/
|
|
159
|
-
| "waiting"
|
|
166
|
+
| "waiting"
|
|
167
|
+
/**
|
|
168
|
+
* Apply stage (ws-107, #4440): a member of a group whose apply stopped
|
|
169
|
+
* before its part began. Written by chant {@link PR_REPORT_NOT_STARTED_FLOOR}
|
|
170
|
+
* and newer.
|
|
171
|
+
*/
|
|
172
|
+
| "not-started";
|
|
160
173
|
|
|
161
174
|
/** One upstream a member reads outputs of (`PrMember.reads`). */
|
|
162
175
|
export interface PrMemberRead {
|
|
@@ -168,6 +181,38 @@ export interface PrMemberRead {
|
|
|
168
181
|
unknown?: string[];
|
|
169
182
|
}
|
|
170
183
|
|
|
184
|
+
/** How a member's part of a group apply ended, as its capability said (ws-107): `PrMember.groupOutcome`. */
|
|
185
|
+
export type PrGroupOutcome = "applied" | "partial" | "failed" | "not-started" | "no-changes";
|
|
186
|
+
|
|
187
|
+
/** Components one capability planned and applied as one (ws-107, #4446): the report's `groups`. */
|
|
188
|
+
export interface PrGroup {
|
|
189
|
+
/** The kind of the capability every member's one step names. */
|
|
190
|
+
capability: string;
|
|
191
|
+
/** The members, by component, in apply order: upstreams first. */
|
|
192
|
+
components: string[];
|
|
193
|
+
/** The 1-based wave of `selection.waves` it ran in. */
|
|
194
|
+
wave: number;
|
|
195
|
+
/** The group digest folded into each member's `planDigest`. `null` when the group failed to plan. */
|
|
196
|
+
digest: string | null;
|
|
197
|
+
/** Why the group failed to plan. Every member is then `plan-failed`. */
|
|
198
|
+
error?: string;
|
|
199
|
+
/** Each read of another member its plan did not know, which the group's apply computes, sorted. Absent when none. */
|
|
200
|
+
reads?: Array<{ component: string; ref: string }>;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* A component that could have joined a group and did not (ws-107, ruling 1,
|
|
205
|
+
* #4446): the report's `fallbacks`. `kind` is core's `steps`, `split` or
|
|
206
|
+
* `cycle`, or the capability's own; `off` means the capability's setting
|
|
207
|
+
* turns grouping off, and the note does not print it.
|
|
208
|
+
*/
|
|
209
|
+
export interface PrGroupFallback {
|
|
210
|
+
component: string;
|
|
211
|
+
capability: string;
|
|
212
|
+
kind: string;
|
|
213
|
+
reason: string;
|
|
214
|
+
}
|
|
215
|
+
|
|
171
216
|
export interface PrMember {
|
|
172
217
|
/** The member's name in the change set: a root, for a terraform-family step. */
|
|
173
218
|
member: string;
|
|
@@ -217,6 +262,10 @@ export interface PrMember {
|
|
|
217
262
|
held?: string;
|
|
218
263
|
/** A blocked member's (#4291): the component whose failure held it, past any component blocked in between. */
|
|
219
264
|
blockedBy?: string;
|
|
265
|
+
/** The index in the report's `groups` of the group it planned and applied with (#4446). Added within contract 1 by chant {@link PR_REPORT_GROUPS_FLOOR}. */
|
|
266
|
+
group?: number;
|
|
267
|
+
/** Apply stage (#4446): how its part of the group's apply ended. Absent when the group did not run. */
|
|
268
|
+
groupOutcome?: PrGroupOutcome;
|
|
220
269
|
}
|
|
221
270
|
|
|
222
271
|
/** A round of plans an apply made after an upstream applied (#3999), the report's `rounds`. */
|
|
@@ -480,6 +529,15 @@ export interface PrReport {
|
|
|
480
529
|
* {@link PR_REPORT_MIGRATIONS_FLOOR}.
|
|
481
530
|
*/
|
|
482
531
|
migrations?: PrMigrationFile[];
|
|
532
|
+
/**
|
|
533
|
+
* The groups a capability planned and applied as one (ws-107, #4446), in
|
|
534
|
+
* plan order of their first member. On a resume, what is left of a group,
|
|
535
|
+
* grouped again. Absent when none formed. Added within contract 1 by chant
|
|
536
|
+
* {@link PR_REPORT_GROUPS_FLOOR}.
|
|
537
|
+
*/
|
|
538
|
+
groups?: PrGroup[];
|
|
539
|
+
/** The components that could have grouped and did not, with why (#4446), sorted. Absent when none. Since {@link PR_REPORT_GROUPS_FLOOR}. */
|
|
540
|
+
fallbacks?: PrGroupFallback[];
|
|
483
541
|
/** Component names: which changed, which run because they depend on one, and what the change touched that no component deploys. */
|
|
484
542
|
selection: {
|
|
485
543
|
changed: string[];
|
|
@@ -555,6 +613,7 @@ const STATUS_WORDS: Record<PrMemberStatus, string> = {
|
|
|
555
613
|
failed: "apply failed",
|
|
556
614
|
blocked: "blocked",
|
|
557
615
|
waiting: "waiting on its new plan",
|
|
616
|
+
"not-started": "not started",
|
|
558
617
|
};
|
|
559
618
|
|
|
560
619
|
function headline(report: PrReport): string {
|
|
@@ -574,7 +633,8 @@ function headline(report: PrReport): string {
|
|
|
574
633
|
return `Applied ${members}.`;
|
|
575
634
|
case "failed": {
|
|
576
635
|
const blocked = report.members.filter((m) => m.status === "blocked").length;
|
|
577
|
-
|
|
636
|
+
const notStarted = report.members.filter((m) => m.status === "not-started").length;
|
|
637
|
+
return `The apply failed: ${report.members.filter((m) => m.status === "failed").length} failed, ${blocked > 0 ? `${blocked} blocked, ` : ""}${notStarted > 0 ? `${notStarted} not started, ` : ""}${report.members.filter((m) => m.status === "applied").length} applied.`;
|
|
578
638
|
}
|
|
579
639
|
case "wave-applied": {
|
|
580
640
|
const applied = (report.waves ?? []).filter((w) => w.status === "applied").map((w) => w.wave);
|
|
@@ -609,6 +669,50 @@ function blockedLine(members: readonly PrMember[]): string | undefined {
|
|
|
609
669
|
return `Blocked, so not applied: ${groups.join("; ")}. A failure blocks only the members that depend on it, so the rest went on.`;
|
|
610
670
|
}
|
|
611
671
|
|
|
672
|
+
/** `a`, `b` and `c`. */
|
|
673
|
+
const listed = (items: string[]): string => (items.length > 1 ? `${items.slice(0, -1).join(", ")} and ${items.at(-1)}` : (items[0] ?? ""));
|
|
674
|
+
|
|
675
|
+
const GROUP_OUTCOME_WORDS: Record<PrGroupOutcome, string> = {
|
|
676
|
+
applied: "applied and stays applied",
|
|
677
|
+
"no-changes": "had no changes",
|
|
678
|
+
partial: "applied in part, and what applied stays",
|
|
679
|
+
failed: "failed",
|
|
680
|
+
"not-started": "did not start",
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* The groups and fallbacks (#4446): a line per group naming its members and
|
|
685
|
+
* the reads its apply computes, how a group that stopped part way left each
|
|
686
|
+
* member, and why the components that could have grouped did not.
|
|
687
|
+
*/
|
|
688
|
+
function groupLines(report: PrReport): string[] {
|
|
689
|
+
const out: string[] = [];
|
|
690
|
+
for (const g of report.groups ?? []) {
|
|
691
|
+
const reads = (g.reads ?? []).map((r) => `${code(r.component)} reads ${code(r.ref)}`);
|
|
692
|
+
out.push(
|
|
693
|
+
"",
|
|
694
|
+
`${listed(g.components.map(code))} plan and apply as one (${code(g.capability)}, wave ${g.wave})` +
|
|
695
|
+
(g.error ? `; the group failed to plan, so nothing applies: ${g.error}.` : reads.length > 0 ? `; ${listed(reads)}, known when the group applies.` : "."),
|
|
696
|
+
);
|
|
697
|
+
const outcome = new Map(report.members.filter((m) => m.groupOutcome && g.components.includes(m.component)).map((m) => [m.component, m.groupOutcome!]));
|
|
698
|
+
const left = g.components.filter((c) => outcome.has(c) && outcome.get(c) !== "applied" && outcome.get(c) !== "no-changes");
|
|
699
|
+
if (left.length === 0) continue;
|
|
700
|
+
out.push(
|
|
701
|
+
"",
|
|
702
|
+
`The group's apply stopped part way: ${g.components.filter((c) => outcome.has(c)).map((c) => `${code(c)} ${GROUP_OUTCOME_WORDS[outcome.get(c)!]}`).join("; ")}. ` +
|
|
703
|
+
`Nothing that applied is undone. \`pr-apply --resume\` plans ${listed(left.map(code))} again, as one group where they still join, and applies them under this approval when the new plans are covered.`,
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
const byWhy = new Map<string, string[]>();
|
|
707
|
+
for (const f of report.fallbacks ?? []) {
|
|
708
|
+
if (f.kind === "off") continue;
|
|
709
|
+
const why = `(${code(f.kind)}): ${f.reason}`;
|
|
710
|
+
byWhy.set(why, [...(byWhy.get(why) ?? []), code(f.component)]);
|
|
711
|
+
}
|
|
712
|
+
if (byWhy.size > 0) out.push("", `Planned one by one, not as a group: ${[...byWhy].map(([why, names]) => `${names.join(", ")} ${why}`).join("; ")}.`);
|
|
713
|
+
return out;
|
|
714
|
+
}
|
|
715
|
+
|
|
612
716
|
/** The policy's lines in the note (#4294): what denied or held the plan, and how a denial is overridden. */
|
|
613
717
|
function policyLines(report: PrReport): string[] {
|
|
614
718
|
const p = report.policy;
|
|
@@ -708,10 +812,14 @@ export function renderPrNote(report: PrReport, options: { limit?: number; approv
|
|
|
708
812
|
out.push("", "| Member | Component | Status | Create | Update | Replace | Delete |", "|---|---|---|---:|---:|---:|---:|");
|
|
709
813
|
for (const m of report.members) {
|
|
710
814
|
const holes = memberHoleReasons(report, m.member);
|
|
815
|
+
// #4463: a member planned with stand-in values says so, naming them.
|
|
816
|
+
const placeholders = report.changeSet.members.find((x) => x.member === m.member)?.placeholders ?? [];
|
|
711
817
|
const status =
|
|
712
818
|
STATUS_WORDS[m.status] +
|
|
713
819
|
(m.status === "blocked" && m.blockedBy ? ` by ${code(m.blockedBy)}` : "") +
|
|
820
|
+
(m.groupOutcome === "partial" ? ", applied in part" : m.groupOutcome === "no-changes" ? ", no changes" : "") +
|
|
714
821
|
(m.inputsMoved?.length ? `, inputs from ${m.inputsMoved.join(", ")} moved` : "") +
|
|
822
|
+
(placeholders.length > 0 ? `, previewed with placeholders for ${placeholders.map(code).join(", ")}` : "") +
|
|
715
823
|
(holes.length > 0 ? `; ${holes.length > 2 ? `${holes[0]}; and ${holes.length - 1} more, listed under Holes` : holes.join("; ")}` : "");
|
|
716
824
|
// A member whose plan has holes and no entries says nothing about what
|
|
717
825
|
// it changes, so its counts are unknown, not zero (#4084).
|
|
@@ -725,6 +833,7 @@ export function renderPrNote(report: PrReport, options: { limit?: number; approv
|
|
|
725
833
|
}
|
|
726
834
|
const blocked = blockedLine(report.members);
|
|
727
835
|
if (blocked) out.push("", blocked);
|
|
836
|
+
out.push(...groupLines(report));
|
|
728
837
|
out.push(...waveLines(report, options.approver ?? "<you>"));
|
|
729
838
|
// #4288: the hooks that did not pass, by name; a passed hook is a count.
|
|
730
839
|
const hooks = report.hooks ?? [];
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulumi URN to graph node (#4456): the one rule every Pulumi reader uses.
|
|
3
|
+
*
|
|
4
|
+
* A Pulumi resource is named by its URN,
|
|
5
|
+
* `urn:pulumi:<stack>::<project>::<qualified type>::<name>`, where the
|
|
6
|
+
* qualified type is the parent type chain joined with `$` and the resource's
|
|
7
|
+
* own type last (`my:mod:Web$aws:lambda/function:Function`). The stack export
|
|
8
|
+
* the pulumi member kind renders, the steps of `pulumi preview --json` (the
|
|
9
|
+
* change set) and of `pulumi refresh --preview-only --json` (drift records)
|
|
10
|
+
* all carry that URN, and nothing else they all carry names the resource. So
|
|
11
|
+
* the node is a function of the URN alone:
|
|
12
|
+
*
|
|
13
|
+
* - The node key is the URN after its stack and project,
|
|
14
|
+
* `<qualified type>::<name>`: `aws:s3/bucket:Bucket::assets`,
|
|
15
|
+
* `my:mod:Web$aws:lambda/function:Function::handler`. Two stacks of one
|
|
16
|
+
* program give the same keys, and a key never changes with the stack or
|
|
17
|
+
* project name.
|
|
18
|
+
* - Inside a workspace the node id is `<member>/<key>`, as the terraform
|
|
19
|
+
* lexicon names a block `<root>/<block key>`.
|
|
20
|
+
* - Provider resources (`pulumi:providers:*`, at any depth) and the root
|
|
21
|
+
* `pulumi:pulumi:Stack` have no node: {@link pulumiNodeKey} is null, and a
|
|
22
|
+
* change-set entry or drift record for one gets `node: null`.
|
|
23
|
+
*
|
|
24
|
+
* A child sits under its component through the `parent` edge the export
|
|
25
|
+
* gives, not through its id. A component's name is not part of its
|
|
26
|
+
* children's URNs, and a preview narrowed with `--target`, or a delete step,
|
|
27
|
+
* need not carry the chain of parents, so an id built from parent names
|
|
28
|
+
* could differ between the export and a change set for the same resource.
|
|
29
|
+
* The parent's type is part of the key, through the qualified type.
|
|
30
|
+
*
|
|
31
|
+
* Like `./change-set.ts`, this imports nothing at run time, so the change-set
|
|
32
|
+
* and drift-record bundles can carry it. The pulumi lexicon imports it as
|
|
33
|
+
* `@intentius/chant/pulumi-urn`.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** A URN split into its parts. */
|
|
37
|
+
export interface PulumiUrn {
|
|
38
|
+
stack: string;
|
|
39
|
+
project: string;
|
|
40
|
+
/** The parent type chain and the resource's own type, joined with `$`. */
|
|
41
|
+
qualifiedType: string;
|
|
42
|
+
/** The resource's own type, the last of the chain. */
|
|
43
|
+
type: string;
|
|
44
|
+
/** The parent types, outermost first; empty for a resource whose parent is the stack. */
|
|
45
|
+
parentTypes: string[];
|
|
46
|
+
/** The resource's name; it may itself hold `::`. */
|
|
47
|
+
name: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const PREFIX = "urn:pulumi:";
|
|
51
|
+
const PROVIDER_TYPE = /^pulumi:providers:/;
|
|
52
|
+
/** The type of the root resource every stack has. */
|
|
53
|
+
export const PULUMI_STACK_TYPE = "pulumi:pulumi:Stack";
|
|
54
|
+
|
|
55
|
+
/** The parts of a Pulumi URN, or undefined when `urn` is not one. */
|
|
56
|
+
export function parsePulumiUrn(urn: string): PulumiUrn | undefined {
|
|
57
|
+
if (!urn.startsWith(PREFIX)) return undefined;
|
|
58
|
+
const parts = urn.slice(PREFIX.length).split("::");
|
|
59
|
+
if (parts.length < 4) return undefined;
|
|
60
|
+
const [stack, project, qualifiedType] = parts;
|
|
61
|
+
const name = parts.slice(3).join("::");
|
|
62
|
+
if (!stack || !project || !qualifiedType || !name) return undefined;
|
|
63
|
+
const chain = qualifiedType.split("$");
|
|
64
|
+
return { stack, project, qualifiedType, type: chain[chain.length - 1], parentTypes: chain.slice(0, -1), name };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** True for a resource that never gets a node: a provider or the root stack. */
|
|
68
|
+
export function isPulumiNodeless(type: string): boolean {
|
|
69
|
+
return PROVIDER_TYPE.test(type) || type === PULUMI_STACK_TYPE;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The node key of a URN in its member's graph, `<qualified type>::<name>`.
|
|
74
|
+
* Null for a provider resource or the root stack. A string that is not a
|
|
75
|
+
* Pulumi URN is its own key, so a reader that holds something else still
|
|
76
|
+
* gets a stable id.
|
|
77
|
+
*/
|
|
78
|
+
export function pulumiNodeKey(urn: string): string | null {
|
|
79
|
+
const parsed = parsePulumiUrn(urn);
|
|
80
|
+
if (!parsed) return urn;
|
|
81
|
+
if (isPulumiNodeless(parsed.type)) return null;
|
|
82
|
+
return `${parsed.qualifiedType}::${parsed.name}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The node id of a URN inside a workspace, `<member>/<key>`, or null when it has no node. */
|
|
86
|
+
export function pulumiNodeId(member: string, urn: string): string | null {
|
|
87
|
+
const key = pulumiNodeKey(urn);
|
|
88
|
+
return key === null ? null : `${member}/${key}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const MAY_APPEAR_TYPE = "$*";
|
|
92
|
+
const MAY_APPEAR_NAME = "/*";
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The address of a change-set entry that stands for the resources a
|
|
96
|
+
* component may register inside an `apply()` that preview could not run
|
|
97
|
+
* (#4453): the component's URN with `$*` after its qualified type and `/*`
|
|
98
|
+
* after its name, `urn:pulumi:dev::site::my:web:Site$*::site/*`. It reads as
|
|
99
|
+
* any resource, of any type and name, whose parent chain is the component,
|
|
100
|
+
* and stays unique per component, since a component's URN is.
|
|
101
|
+
*/
|
|
102
|
+
export function pulumiMayAppearAddress(componentUrn: string): string {
|
|
103
|
+
const parsed = parsePulumiUrn(componentUrn);
|
|
104
|
+
if (!parsed) return `${componentUrn}${MAY_APPEAR_NAME}`;
|
|
105
|
+
return `${PREFIX}${parsed.stack}::${parsed.project}::${parsed.qualifiedType}${MAY_APPEAR_TYPE}::${parsed.name}${MAY_APPEAR_NAME}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** The component URN a {@link pulumiMayAppearAddress} was made from, or undefined for any other address. */
|
|
109
|
+
export function pulumiMayAppearParent(address: string): string | undefined {
|
|
110
|
+
const parsed = parsePulumiUrn(address);
|
|
111
|
+
if (!parsed || !parsed.qualifiedType.endsWith(MAY_APPEAR_TYPE) || !parsed.name.endsWith(MAY_APPEAR_NAME)) return undefined;
|
|
112
|
+
const qualifiedType = parsed.qualifiedType.slice(0, -MAY_APPEAR_TYPE.length);
|
|
113
|
+
const name = parsed.name.slice(0, -MAY_APPEAR_NAME.length);
|
|
114
|
+
if (!qualifiedType || !name) return undefined;
|
|
115
|
+
return `${PREFIX}${parsed.stack}::${parsed.project}::${qualifiedType}::${name}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The ids, in the order tried, that a Pulumi change-set entry or drift
|
|
120
|
+
* record can have in its member's graph IR, in the shape of
|
|
121
|
+
* `changeSetNodeCandidates` (`./change-set-graph.ts`): `<member>/<key>`.
|
|
122
|
+
* Empty for a provider or the root stack, so mapping leaves `node: null`.
|
|
123
|
+
* A may-appear entry ({@link pulumiMayAppearAddress}) is on its component's
|
|
124
|
+
* node, since nothing names the resources it stands for.
|
|
125
|
+
*/
|
|
126
|
+
export function pulumiNodeCandidates(entry: { member: string; address: string }): string[] {
|
|
127
|
+
const id = pulumiNodeId(entry.member, pulumiMayAppearParent(entry.address) ?? entry.address);
|
|
128
|
+
return id === null ? [] : [id];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** One step of `pulumi preview --json` (or `refresh --preview-only --json`), as far as the node rule reads it. */
|
|
132
|
+
export interface PulumiPreviewStep {
|
|
133
|
+
op?: string;
|
|
134
|
+
urn?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The URN and node id of each step of a `pulumi preview --json` document
|
|
139
|
+
* (`{ steps: [...] }`). A replace shows as several steps on one URN; each
|
|
140
|
+
* gets the same node. Steps with no URN are skipped.
|
|
141
|
+
*/
|
|
142
|
+
export function pulumiPreviewNodes(preview: unknown, member: string): { urn: string; op: string; node: string | null }[] {
|
|
143
|
+
const steps = (preview as { steps?: unknown } | null)?.steps;
|
|
144
|
+
if (!Array.isArray(steps)) return [];
|
|
145
|
+
const out: { urn: string; op: string; node: string | null }[] = [];
|
|
146
|
+
for (const s of steps as PulumiPreviewStep[]) {
|
|
147
|
+
if (typeof s?.urn !== "string") continue;
|
|
148
|
+
out.push({ urn: s.urn, op: typeof s.op === "string" ? s.op : "", node: pulumiNodeId(member, s.urn) });
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The version of the next chant release (#4480, #4473).
|
|
3
|
+
*
|
|
4
|
+
* A contract floor added since the last release, the first chant that can
|
|
5
|
+
* write a field, names the release that ships it. That release has no number
|
|
6
|
+
* until the maintainer cuts it, so every such floor is this constant, and the
|
|
7
|
+
* schema and docs text that repeats a floor ("written by chant X and newer",
|
|
8
|
+
* the "Fields added within version 1" rows) is listed in
|
|
9
|
+
* scripts/release-floors.ts, which checks it agrees.
|
|
10
|
+
*
|
|
11
|
+
* To set the number: `npx tsx scripts/release-floors.ts --set <version>`
|
|
12
|
+
* rewrites this constant and every listed text. `just release` refuses to
|
|
13
|
+
* cut a version when any floor names a version that is neither a published
|
|
14
|
+
* release nor the one being cut.
|
|
15
|
+
*
|
|
16
|
+
* After the cut, a floor stays at the value it was released with. Once the
|
|
17
|
+
* release is published, `just release-floors --freeze <version>` writes the
|
|
18
|
+
* version into every floor that names this constant as a literal, and moves
|
|
19
|
+
* this constant to the next patch (#4501). The check fails while a floor
|
|
20
|
+
* still names this constant after its version shipped.
|
|
21
|
+
*/
|
|
22
|
+
export const NEXT_RELEASE = "0.124.54";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which property names carry a secret, by name alone.
|
|
3
|
+
*
|
|
4
|
+
* One list for every path that redacts by key: the deep observation's
|
|
5
|
+
* normalization pass (`./deep-observation.ts`), the thin snapshot path's
|
|
6
|
+
* warning (`./lifecycle/snapshot.ts`), and the drift record's second
|
|
7
|
+
* redaction pass (`./drift-record.ts`). This module imports nothing, so the
|
|
8
|
+
* drift record can use it inside the change-set bundle (#3421).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Property-name patterns that mark a value secret-bearing. Deliberately narrow
|
|
13
|
+
* and key-name based: broadening this to e.g. `/key/i` would mask an AWS tag's
|
|
14
|
+
* `Key` field and every `*KeyName` reference, which is how masking turns into
|
|
15
|
+
* its own drift signal.
|
|
16
|
+
*
|
|
17
|
+
* Shared with the thin snapshot path (`./lifecycle/snapshot.ts`), which warns
|
|
18
|
+
* on the same names — one list, so the two paths cannot disagree about what
|
|
19
|
+
* counts as a secret.
|
|
20
|
+
*/
|
|
21
|
+
export const SENSITIVE_KEY_PATTERNS: readonly RegExp[] = [
|
|
22
|
+
/password/i,
|
|
23
|
+
/secret/i,
|
|
24
|
+
/token/i,
|
|
25
|
+
/private.?key/i,
|
|
26
|
+
/credential/i,
|
|
27
|
+
/connection.?string/i,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/** True when a property name looks secret-bearing (see {@link SENSITIVE_KEY_PATTERNS}). */
|
|
31
|
+
export function isSensitiveKey(key: string): boolean {
|
|
32
|
+
return SENSITIVE_KEY_PATTERNS.some((p) => p.test(key));
|
|
33
|
+
}
|
|
34
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { parseLiveImportReport } from "./adoption-report";
|
|
3
|
+
|
|
4
|
+
// The text choudoufu's LiveImportHuman.Ratification prints
|
|
5
|
+
// (choudoufu internal/command/views/live_import.go), one group per status.
|
|
6
|
+
const REPORT = [
|
|
7
|
+
"",
|
|
8
|
+
'Ratifying /work/prod.tfstate for estate "prod" against the live system. This was read-only: nothing was written.',
|
|
9
|
+
"",
|
|
10
|
+
"VERIFIED (1) - verified against the live system:",
|
|
11
|
+
" aws_vpc.main aws_vpc live id: vpc-0a1b",
|
|
12
|
+
" every attribute matched the live system",
|
|
13
|
+
"",
|
|
14
|
+
"DRIFTED (1) - verified, but drifted from the live system:",
|
|
15
|
+
' module.api.aws_sqs_queue.work["a b"] aws_sqs_queue live id: https://sqs/work',
|
|
16
|
+
" 2 attribute(s) differ: visibility_timeout_seconds, delay_seconds",
|
|
17
|
+
"",
|
|
18
|
+
"MISSING (1) - could not be verified:",
|
|
19
|
+
" aws_s3_bucket.gone aws_s3_bucket live id: -",
|
|
20
|
+
" the live system has no bucket gone-123",
|
|
21
|
+
"",
|
|
22
|
+
"UNTAGGABLE (1) - outside the taggable subset:",
|
|
23
|
+
" aws_s3_bucket_versioning.artifacts aws_s3_bucket_versioning live id: artifacts",
|
|
24
|
+
" the provider schema has no tags argument",
|
|
25
|
+
"",
|
|
26
|
+
"UNADMITTED_TYPE (1) - outside the admitted type set:",
|
|
27
|
+
" aws_kms_alias.estate aws_kms_alias live id: alias/estate",
|
|
28
|
+
" aws_kms_alias has no row in the admission table",
|
|
29
|
+
"",
|
|
30
|
+
"2 of 5 resource instance(s) are eligible for stamping (VERIFIED or DRIFTED).",
|
|
31
|
+
"",
|
|
32
|
+
"/work/prod.tfstate was opened once, read-only, and will not be opened again by this run - not to write it, and not to read it a second time.",
|
|
33
|
+
"No tag has been written. Rerun with -approve to stamp tofu-estate and tofu-address onto every eligible resource above.",
|
|
34
|
+
].join("\n");
|
|
35
|
+
|
|
36
|
+
describe("parseLiveImportReport (behold#999)", () => {
|
|
37
|
+
test("every resource, with its status, live id, reason and whether -approve stamps it", () => {
|
|
38
|
+
const r = parseLiveImportReport(REPORT)!;
|
|
39
|
+
expect(r.estate).toBe("prod");
|
|
40
|
+
expect(r.state).toBe("/work/prod.tfstate");
|
|
41
|
+
expect(r.total).toBe(5);
|
|
42
|
+
expect(r.claimed).toBe(2);
|
|
43
|
+
expect(r.entries.map((e) => [e.address, e.type, e.status, e.liveId, e.claimed])).toEqual([
|
|
44
|
+
["aws_vpc.main", "aws_vpc", "VERIFIED", "vpc-0a1b", true],
|
|
45
|
+
['module.api.aws_sqs_queue.work["a b"]', "aws_sqs_queue", "DRIFTED", "https://sqs/work", true],
|
|
46
|
+
["aws_s3_bucket.gone", "aws_s3_bucket", "MISSING", null, false],
|
|
47
|
+
["aws_s3_bucket_versioning.artifacts", "aws_s3_bucket_versioning", "UNTAGGABLE", "artifacts", false],
|
|
48
|
+
["aws_kms_alias.estate", "aws_kms_alias", "UNADMITTED_TYPE", "alias/estate", false],
|
|
49
|
+
]);
|
|
50
|
+
expect(r.entries[2].detail).toBe("the live system has no bucket gone-123");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("a state with no managed resources is a report with no entries", () => {
|
|
54
|
+
const r = parseLiveImportReport('\nRatifying s for estate "e" against the live system. This was read-only: nothing was written.\n\nThe state file names no managed resource instances. Nothing to ratify.\n');
|
|
55
|
+
expect(r).toEqual({ estate: "e", state: "s", entries: [], claimed: 0, total: 0 });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("text with no report in it is undefined", () => {
|
|
59
|
+
expect(parseLiveImportReport("Error: no such file\n")).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
});
|