@intentius/chant 0.124.51 → 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 +17 -3
- 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 +224 -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/covered-round.d.ts +173 -0
- package/dist/components/covered-round.d.ts.map +1 -0
- package/dist/components/covered-round.js +200 -0
- 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 +42 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +74 -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 +7 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -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 +62 -7
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +354 -53
- 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/components/wave-plan.d.ts +2 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +4 -1
- 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 +92 -3
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +62 -3
- 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 +76 -3
- 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 +16 -3
- 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 +238 -0
- package/src/components/cli-support.ts +70 -14
- package/src/components/covered-round.test.ts +166 -0
- package/src/components/covered-round.ts +293 -0
- 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 +101 -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 +59 -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 +728 -4
- package/src/components/pr-run.ts +395 -55
- 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/components/wave-plan.ts +5 -2
- 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 +57 -1
- package/src/pr-loop.ts +154 -6
- 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 +76 -3
- 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
|
@@ -18,6 +18,9 @@ const readReleaseLedgerMock = vi.fn();
|
|
|
18
18
|
const pushLifecycleMock = vi.fn();
|
|
19
19
|
const resolveTargetsMock = vi.fn();
|
|
20
20
|
const ran: string[] = [];
|
|
21
|
+
/** #4516: the reads the fake `import-apply` declares, and the order its steps ran in. */
|
|
22
|
+
let importReads: Array<{ reader: string; upstream: string; output: string; at: string }> = [];
|
|
23
|
+
const importApplied: Array<{ component: string; input: unknown }> = [];
|
|
21
24
|
const stepInputs: Array<{ kind: string; input: unknown }> = [];
|
|
22
25
|
let releaseFixture: { release: import("../../lifecycle/release-store").Release; label: string | null } | null = null;
|
|
23
26
|
let storedTemplate: string | null = null;
|
|
@@ -64,6 +67,15 @@ vi.mock("../../components/fan-out-support", () => ({
|
|
|
64
67
|
if (ctx.component === failApplyFor) throw applyError ?? new Error("apply failed");
|
|
65
68
|
return {};
|
|
66
69
|
});
|
|
70
|
+
// #4516: a stack step whose template imports another component's export, found by `declaredReads`.
|
|
71
|
+
registry.register({
|
|
72
|
+
kind: "import-apply",
|
|
73
|
+
declaredReads: (_ctx: unknown, members: ReadonlyArray<{ component: string }>) => importReads.filter((r) => members.some((m) => m.component === r.reader)),
|
|
74
|
+
async run(ctx: DeployContext, input: unknown) {
|
|
75
|
+
importApplied.push({ component: ctx.component, input });
|
|
76
|
+
return { outputs: { VpcId: `${ctx.component}-vpc` } };
|
|
77
|
+
},
|
|
78
|
+
} as never);
|
|
67
79
|
// #4045: a planner whose member is provisional.
|
|
68
80
|
registry.register({
|
|
69
81
|
kind: "plan-provisional",
|
|
@@ -226,6 +238,8 @@ beforeEach(() => {
|
|
|
226
238
|
removedTemplates.length = 0;
|
|
227
239
|
ran.length = 0;
|
|
228
240
|
stepInputs.length = 0;
|
|
241
|
+
importReads = [];
|
|
242
|
+
importApplied.length = 0;
|
|
229
243
|
writtenTemplates.length = 0;
|
|
230
244
|
releaseFixture = null;
|
|
231
245
|
storedTemplate = null;
|
|
@@ -429,6 +443,56 @@ describe("chant components promote", () => {
|
|
|
429
443
|
});
|
|
430
444
|
});
|
|
431
445
|
|
|
446
|
+
describe("chant components promote orders an importer after its exporter (#4516)", () => {
|
|
447
|
+
/** A component that publishes its image and applies one stack. */
|
|
448
|
+
const stackComponent = (name: string): DriverComponent => ({
|
|
449
|
+
name,
|
|
450
|
+
deploy: [
|
|
451
|
+
{ phase: "Build", steps: [{ kind: "docker-build", context: ".", into: "api.tar" }] },
|
|
452
|
+
{ phase: "Publish", steps: [{ kind: "publish-image", from: "archive:api.tar" }] },
|
|
453
|
+
{ phase: "Apply", steps: [{ kind: "import-apply", stack: name }] },
|
|
454
|
+
],
|
|
455
|
+
});
|
|
456
|
+
// Discovered importer first, so only the read can put network ahead of it.
|
|
457
|
+
const app = stackComponent("app");
|
|
458
|
+
const network = stackComponent("network");
|
|
459
|
+
const read = { reader: "app", upstream: "network", output: "VpcId", at: "/imports/Net-VpcId" };
|
|
460
|
+
|
|
461
|
+
beforeEach(() => {
|
|
462
|
+
readReleaseLedgerMock.mockResolvedValue({ records: [{ ...staging, component: "app" }, { ...staging, component: "network" }], malformed: 0 });
|
|
463
|
+
resolveTargetsMock.mockResolvedValue({ success: true, targets: [app, network] });
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test("a template's Fn::ImportValue of another promoted component's export deploys the exporter first and hands the importer its output", async () => {
|
|
467
|
+
importReads = [read];
|
|
468
|
+
expect(await runComponentsPromote(ctx({}))).toBe(0);
|
|
469
|
+
expect(importApplied.map((a) => a.component)).toEqual(["network", "app"]);
|
|
470
|
+
expect(importApplied[1]!.input).toMatchObject({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
|
|
471
|
+
expect(appendReleaseRecordMock).toHaveBeenCalledTimes(2);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("with no declared read the two deploy as one wave and the importer gets no imports", async () => {
|
|
475
|
+
expect(await runComponentsPromote(ctx({}))).toBe(0);
|
|
476
|
+
expect(importApplied.map((a) => a.component).sort()).toEqual(["app", "network"]);
|
|
477
|
+
expect((importApplied.find((a) => a.component === "app")!.input as Record<string, unknown>).imports).toBeUndefined();
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test("a read of a component this promote does not deploy is left out: the importer deploys alone", async () => {
|
|
481
|
+
importReads = [read];
|
|
482
|
+
resolveTargetsMock.mockResolvedValue({ success: true, targets: [app] });
|
|
483
|
+
expect(await runComponentsPromote(ctx({ component: "app" }))).toBe(0);
|
|
484
|
+
expect(importApplied.map((a) => a.component)).toEqual(["app"]);
|
|
485
|
+
expect((importApplied[0]!.input as Record<string, unknown>).imports).toBeUndefined();
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
test("--dry-run with a declared read still deploys nothing", async () => {
|
|
489
|
+
importReads = [read];
|
|
490
|
+
expect(await runComponentsPromote(ctx({ dryRun: true, json: true }))).toBe(0);
|
|
491
|
+
expect(importApplied).toEqual([]);
|
|
492
|
+
expect(appendReleaseRecordMock).not.toHaveBeenCalled();
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
432
496
|
describe("chant components promote --release (#4026)", () => {
|
|
433
497
|
const prodTemplate = `{"env":"prod"}\n`;
|
|
434
498
|
const withTemplate: DriverComponent = {
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
} from "../../lifecycle/release-ledger";
|
|
40
40
|
import { isComponentList, resolveComponentTargets } from "../../components/cli-support";
|
|
41
41
|
import { applyConfigDefaults } from "../../components/config-defaults";
|
|
42
|
+
import { withDeclaredReads } from "../../components/declared-reads";
|
|
42
43
|
import { fanOutRegistry } from "../../components/fan-out-support";
|
|
43
44
|
import { renderDriverHuman } from "../../components/driver-output";
|
|
44
45
|
import { ndjsonProgressSink } from "../../components/run-progress";
|
|
@@ -172,6 +173,9 @@ interface BoundReleaseGate {
|
|
|
172
173
|
unknownInputs?: Record<string, string[]>;
|
|
173
174
|
/** The approval a resume record carried on, when it still covers what is left. */
|
|
174
175
|
resumedFrom?: string;
|
|
176
|
+
/** The groups the plan planned as one (#4465), and the components that could have grouped and did not. */
|
|
177
|
+
groups?: import("../../components/release-gate").ReleasePlanGroup[];
|
|
178
|
+
fallbacks?: import("../../components/fan-out").FanOutGroupFallback[];
|
|
175
179
|
replan: (only: ReadonlySet<string>, outputs: Record<string, Record<string, unknown>>) => Promise<ChangeSetDocument>;
|
|
176
180
|
bind: (doc: ChangeSetDocument, gates: string[]) => Promise<ReleaseGateBinding>;
|
|
177
181
|
}
|
|
@@ -200,6 +204,10 @@ async function bindReleaseGate(input: {
|
|
|
200
204
|
projectPath: string;
|
|
201
205
|
head: string | undefined;
|
|
202
206
|
resume?: import("../../components/promote-rounds").PromoteResume;
|
|
207
|
+
/** The grouped fan-out (#4465): its groups plan as one. */
|
|
208
|
+
grouped?: import("../../components/fan-out").FanOutPlan;
|
|
209
|
+
/** Each group plan this binding makes is added here, the newest first, for the run to apply. */
|
|
210
|
+
groupRuns: import("../../components/capability").GroupRun[];
|
|
203
211
|
}): Promise<BoundReleaseGate | number | undefined> {
|
|
204
212
|
const { plan, under, port } = input;
|
|
205
213
|
const gate = await import("../../components/release-gate");
|
|
@@ -230,8 +238,8 @@ async function bindReleaseGate(input: {
|
|
|
230
238
|
}
|
|
231
239
|
|
|
232
240
|
const digests = new Map(plan.items.map((i) => [i.component, i.digest]));
|
|
233
|
-
const planSet = (only: ReadonlySet<string> | undefined, outputs: Record<string, Record<string, unknown>>) =>
|
|
234
|
-
gate.planReleaseSet({
|
|
241
|
+
const planSet = async (only: ReadonlySet<string> | undefined, outputs: Record<string, Record<string, unknown>>) => {
|
|
242
|
+
const planned = await gate.planReleaseSet({
|
|
235
243
|
release: under.release,
|
|
236
244
|
env,
|
|
237
245
|
components: input.prepared,
|
|
@@ -241,7 +249,13 @@ async function bindReleaseGate(input: {
|
|
|
241
249
|
unsettled,
|
|
242
250
|
seededOutputs: outputs,
|
|
243
251
|
...(only ? { only } : {}),
|
|
252
|
+
...(input.grouped ? { grouped: input.grouped } : {}),
|
|
244
253
|
});
|
|
254
|
+
// #4465: the run applies the plan the gate bound, the newest one for a group planned again.
|
|
255
|
+
for (const g of planned.groups ?? []) if (g.run) input.groupRuns.unshift(g.run);
|
|
256
|
+
return planned;
|
|
257
|
+
};
|
|
258
|
+
const groupsOf = (p: Awaited<ReturnType<typeof planSet>>) => ({ ...(p.groups ? { groups: p.groups } : {}), ...(p.fallbacks ? { fallbacks: p.fallbacks } : {}) });
|
|
245
259
|
|
|
246
260
|
const { storeGateChangeSet } = await import("../../lifecycle/gate-change-set");
|
|
247
261
|
const { readStoredChangeSet } = await import("../../lifecycle/change-set-store");
|
|
@@ -322,6 +336,7 @@ async function bindReleaseGate(input: {
|
|
|
322
336
|
binding: { op: gate.RELEASE_GATE_OP, planDigest: stored.document.digest, releaseDigest, verifyEmpty },
|
|
323
337
|
reads: fresh.reads,
|
|
324
338
|
resumedFrom: stored.document.digest,
|
|
339
|
+
...groupsOf(fresh),
|
|
325
340
|
...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}),
|
|
326
341
|
...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}),
|
|
327
342
|
...later,
|
|
@@ -331,7 +346,7 @@ async function bindReleaseGate(input: {
|
|
|
331
346
|
}
|
|
332
347
|
const bound = await bindDoc(fresh.doc, gates, "change set");
|
|
333
348
|
if (typeof bound === "number") return bound;
|
|
334
|
-
return { doc: fresh.doc, ...bound, reads: fresh.reads, ...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}), ...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}), ...later };
|
|
349
|
+
return { doc: fresh.doc, ...bound, reads: fresh.reads, ...groupsOf(fresh), ...(fresh.plannedOutputs ? { plannedOutputs: fresh.plannedOutputs } : {}), ...(fresh.unknownInputs ? { unknownInputs: fresh.unknownInputs } : {}), ...later };
|
|
335
350
|
}
|
|
336
351
|
|
|
337
352
|
const first = await planSet(undefined, input.seededOutputs);
|
|
@@ -340,7 +355,7 @@ async function bindReleaseGate(input: {
|
|
|
340
355
|
for (const [component, refs] of Object.entries(first.unknownInputs ?? {})) {
|
|
341
356
|
console.error(formatInfo(`${component} reads ${refs.join(", ")}, known only once its upstream applies; it is planned again then, and needs its own approval if its plan moves`));
|
|
342
357
|
}
|
|
343
|
-
return { doc: first.doc, ...bound, reads: first.reads, ...(first.plannedOutputs ? { plannedOutputs: first.plannedOutputs } : {}), ...(first.unknownInputs ? { unknownInputs: first.unknownInputs } : {}), ...later };
|
|
358
|
+
return { doc: first.doc, ...bound, reads: first.reads, ...groupsOf(first), ...(first.plannedOutputs ? { plannedOutputs: first.plannedOutputs } : {}), ...(first.unknownInputs ? { unknownInputs: first.unknownInputs } : {}), ...later };
|
|
344
359
|
}
|
|
345
360
|
|
|
346
361
|
/** A later round's or wave's plan was refused (provisional or failed members); the refusal is already printed. */
|
|
@@ -518,6 +533,12 @@ async function deployPlanIn(
|
|
|
518
533
|
}
|
|
519
534
|
|
|
520
535
|
const registry = await fanOutRegistry(project.projectPath, project.config);
|
|
536
|
+
// #4516: the reads a capability finds in its steps' files (a template's
|
|
537
|
+
// Fn::ImportValue) order the promote as `deriveFanOut` orders a fan-out, so
|
|
538
|
+
// an importer deploys after the exporter it reads. Read once the release's
|
|
539
|
+
// templates are written, so they are the files read; a read of a component
|
|
540
|
+
// this promote does not deploy is left out.
|
|
541
|
+
prepared.splice(0, prepared.length, ...(await withDeclaredReads(prepared, registry, project.projectPath)));
|
|
521
542
|
const port = gitGateLedgerPort();
|
|
522
543
|
// #4045: under a release, every gate binds the release's change set for this environment.
|
|
523
544
|
let releaseGate: ReleaseGateBinding | undefined;
|
|
@@ -536,10 +557,51 @@ async function deployPlanIn(
|
|
|
536
557
|
console.error(formatWarning({ message: `could not read the resume record ${resumePath}: ${err instanceof Error ? err.message : String(err)}` }));
|
|
537
558
|
}
|
|
538
559
|
}
|
|
560
|
+
// ws-107 (#4465): under a release, the components a capability takes as one
|
|
561
|
+
// plan and apply as one group; under --wave-gate none forms (ruling 1).
|
|
562
|
+
// A resume groups again what is left of each group.
|
|
563
|
+
let grouped: import("../../components/fan-out").FanOutPlan | undefined;
|
|
564
|
+
const groupRuns: import("../../components/capability").GroupRun[] = [];
|
|
565
|
+
if (under) {
|
|
566
|
+
const groups = await import("../../components/groups");
|
|
567
|
+
const whole = await groups.formRunGroups({
|
|
568
|
+
components: prepared,
|
|
569
|
+
plan: groups.componentSetFanOut(prepared),
|
|
570
|
+
registry,
|
|
571
|
+
env: plan.to,
|
|
572
|
+
...(args.waveGate !== undefined ? { waveGate: true } : {}),
|
|
573
|
+
});
|
|
574
|
+
if (resume && whole.groups?.length) {
|
|
575
|
+
const { remainingFanOut } = await import("../../components/fan-out");
|
|
576
|
+
grouped = await groups.regroupRemaining({
|
|
577
|
+
components: prepared,
|
|
578
|
+
plan: remainingFanOut(whole, prepared, { completed: resume.completed }),
|
|
579
|
+
registry,
|
|
580
|
+
env: plan.to,
|
|
581
|
+
groups: whole.groups,
|
|
582
|
+
...(whole.fallbacks ? { fallbacks: whole.fallbacks } : {}),
|
|
583
|
+
});
|
|
584
|
+
} else {
|
|
585
|
+
grouped = whole;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
539
588
|
let pullRequests: Array<import("../../lifecycle/merge-record").MergeRecord> = [];
|
|
540
589
|
if (under) {
|
|
541
590
|
try {
|
|
542
|
-
const result = await bindReleaseGate({
|
|
591
|
+
const result = await bindReleaseGate({
|
|
592
|
+
plan,
|
|
593
|
+
prepared,
|
|
594
|
+
under,
|
|
595
|
+
registry,
|
|
596
|
+
port,
|
|
597
|
+
seededOutputs,
|
|
598
|
+
actor: actor!,
|
|
599
|
+
projectPath: project.projectPath,
|
|
600
|
+
head,
|
|
601
|
+
...(resume ? { resume } : {}),
|
|
602
|
+
...(grouped ? { grouped } : {}),
|
|
603
|
+
groupRuns,
|
|
604
|
+
});
|
|
543
605
|
if (typeof result === "number") {
|
|
544
606
|
tidy();
|
|
545
607
|
return result;
|
|
@@ -594,6 +656,7 @@ async function deployPlanIn(
|
|
|
594
656
|
...(args.waveGate ? { waveGate: args.waveGate } : {}),
|
|
595
657
|
replan: bound.replan,
|
|
596
658
|
bind: bound.bind,
|
|
659
|
+
...(grouped?.groups?.length ? { grouped } : {}),
|
|
597
660
|
run: (components, outputs, binding) =>
|
|
598
661
|
runPromotion({
|
|
599
662
|
plan: { ...plan, items: plan.items.filter((i) => components.some((c) => c.name === i.component)) },
|
|
@@ -602,6 +665,7 @@ async function deployPlanIn(
|
|
|
602
665
|
componentOutputs: outputs,
|
|
603
666
|
gates: port,
|
|
604
667
|
releaseGate: binding,
|
|
668
|
+
...(grouped?.groups?.length ? { grouped, groupRuns } : {}),
|
|
605
669
|
...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
|
|
606
670
|
...(events ? { onRunEvent: events.emit } : {}),
|
|
607
671
|
}),
|
|
@@ -615,6 +679,8 @@ async function deployPlanIn(
|
|
|
615
679
|
componentOutputs: seededOutputs,
|
|
616
680
|
gates: port,
|
|
617
681
|
...(releaseGate ? { releaseGate } : {}),
|
|
682
|
+
// #4465: with no release gate to bind, nothing planned the groups beforehand, so each plans in its wave.
|
|
683
|
+
...(grouped?.groups?.length ? { grouped, groupRuns, planGroupsAtWave: bound === undefined } : {}),
|
|
618
684
|
...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
|
|
619
685
|
...(events ? { onRunEvent: events.emit } : {}),
|
|
620
686
|
});
|
|
@@ -653,6 +719,15 @@ async function deployPlanIn(
|
|
|
653
719
|
console.error(formatInfo(`resume record: ${resumePath}; the same promote carries on from here`));
|
|
654
720
|
}
|
|
655
721
|
}
|
|
722
|
+
// #4465: the groups applied as one, and how each member ended, as pr-report says it.
|
|
723
|
+
const { runGroupsReport, renderRunGroups } = await import("../../components/run-groups");
|
|
724
|
+
const groupsReport = runGroupsReport({
|
|
725
|
+
grouped,
|
|
726
|
+
...(bound?.groups ? { planned: bound.groups } : {}),
|
|
727
|
+
...(bound ? { doc: bound.doc } : {}),
|
|
728
|
+
...(run.groupOutcomes ? { outcomes: run.groupOutcomes } : {}),
|
|
729
|
+
});
|
|
730
|
+
if (!args.json) for (const line of renderRunGroups(groupsReport, `the same ${verb}`)) console.error(formatInfo(line));
|
|
656
731
|
// The driver settles the stream; this only ends one it left open.
|
|
657
732
|
events?.settle(run.status === "fail" ? "failed" : run.status);
|
|
658
733
|
if (!args.json) renderDriverHuman(run);
|
|
@@ -690,7 +765,7 @@ async function deployPlanIn(
|
|
|
690
765
|
const withChangeSet = under && changeSetJson ? { release: { ...releaseJson.release!, ...changeSetJson } } : releaseJson;
|
|
691
766
|
const stagedJson = staged ? { stages: staged.stages, ...(bound?.plannedOutputs ? { plannedOutputs: bound.plannedOutputs } : {}), ...(bound?.unknownInputs ? { unknownInputs: bound.unknownInputs } : {}) } : {};
|
|
692
767
|
const prJson = pullRequests.length > 0 ? { pullRequests: pullRequests.map((r) => ({ commit: r.commit, source: r.source, plan: r.plan, digest: r.digest, approvedBy: r.approvedBy, ...(r.authorApproved ? { authorApproved: r.authorApproved } : {}) })) } : {};
|
|
693
|
-
console.log(JSON.stringify({ ...planJson(plan, removed), ...withChangeSet, ...stagedJson, ...prJson, run, recorded, ...(outcome ? { outcome } : {}) }, null, 2));
|
|
768
|
+
console.log(JSON.stringify({ ...planJson(plan, removed), ...withChangeSet, ...stagedJson, ...prJson, ...groupsReport, run, recorded, ...(outcome ? { outcome } : {}) }, null, 2));
|
|
694
769
|
} else {
|
|
695
770
|
for (const r of recorded) {
|
|
696
771
|
console.error(formatSuccess(
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `chant query "<sql>" [dir] [--member <name>] [--json]` (#4297): one
|
|
3
|
-
* read-only SQL statement over the snapshots
|
|
4
|
-
* releases on the local `chant/lifecycle`
|
|
3
|
+
* read-only SQL statement over the snapshots in the index store (#4519) and
|
|
4
|
+
* the Op runs, gates, deploys and releases on the local `chant/lifecycle`
|
|
5
|
+
* branch. The tables and the engine
|
|
5
6
|
* live in `../../lifecycle/query.ts`; this reads the ledgers and prints.
|
|
6
7
|
*
|
|
7
8
|
* Inside a workspace every member's ledger is read, each row naming its
|
|
@@ -34,7 +35,11 @@ export async function queryLedgers(cwd: string, members?: readonly string[], at?
|
|
|
34
35
|
const commit = resolveLedgerRevision(repo, at);
|
|
35
36
|
return (member: string | null) => revisionLedgerReadPort(repo, commit, member === null ? "" : memberLedgerPrefix([member]));
|
|
36
37
|
})();
|
|
37
|
-
|
|
38
|
+
// Snapshots come from the index store (#4519). `--at` names a commit of
|
|
39
|
+
// chant/lifecycle, so it reads that commit's snapshots as before.
|
|
40
|
+
const { resolveSnapshotStore, snapshotReadPort } = await import("../../lifecycle/snapshot-store");
|
|
41
|
+
const store = at === undefined ? await resolveSnapshotStore({ cwd: found?.dir ?? cwd }) : undefined;
|
|
42
|
+
if (!found) return [{ member: null, port: atPort ? atPort(null) : gitLedgerReadPort({ cwd }), ...(store ? { snapshots: snapshotReadPort(store, { cwd }) } : {}) }];
|
|
38
43
|
// Workspace code loads only when there is a workspace, so a level-0 project never pays for it.
|
|
39
44
|
const { readDeclaration, WorkspaceReadError } = await import("../../workspace/declaration");
|
|
40
45
|
const { workingTree } = await import("../../workspace/tree");
|
|
@@ -51,9 +56,27 @@ export async function queryLedgers(cwd: string, members?: readonly string[], at?
|
|
|
51
56
|
const unknown = [...wanted].filter((n) => !declaration.members.some((m) => m.name === n));
|
|
52
57
|
if (unknown.length > 0) throw new QueryError(`--member ${unknown.join(", ")} names no member of the workspace`);
|
|
53
58
|
}
|
|
59
|
+
// #4482: a TerraformApplyOp run names its root's directory; the member that holds it is `root_member`.
|
|
60
|
+
const { ownerOf, resolveGroups } = await import("../../workspace/declaration");
|
|
61
|
+
const groups = (() => {
|
|
62
|
+
try {
|
|
63
|
+
return resolveGroups(declaration, workingTree(found.dir));
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
})();
|
|
68
|
+
const ownerOfPath = (path: string): string | null => {
|
|
69
|
+
const owner = ownerOf(declaration, groups, path);
|
|
70
|
+
return owner && "member" in owner ? owner.member.name : null;
|
|
71
|
+
};
|
|
54
72
|
return declaration.members
|
|
55
73
|
.filter((m) => !wanted || wanted.has(m.name))
|
|
56
|
-
.map((m) => ({
|
|
74
|
+
.map((m) => ({
|
|
75
|
+
member: m.name,
|
|
76
|
+
port: atPort ? atPort(m.dir === "." ? null : m.name) : gitLedgerReadPort({ cwd: found.dir, member: m.dir === "." ? "." : m.name }),
|
|
77
|
+
...(store ? { snapshots: snapshotReadPort(store, { cwd: found.dir, member: m.dir === "." ? "." : m.name }) } : {}),
|
|
78
|
+
ownerOfPath,
|
|
79
|
+
}));
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
export async function runQueryCommand(ctx: CommandContext): Promise<number> {
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant run --components` and `chant components fan-out` order an importer
|
|
3
|
+
* after its exporter when the read is one a capability declares (chant#4516):
|
|
4
|
+
* a template's `Fn::ImportValue` of another component's export, which
|
|
5
|
+
* `declaredReads` (#4466a) finds and core writes into the reader's step as a
|
|
6
|
+
* `stackOutput()` plus a `dependsOn`. Driven through the CLI handlers, as
|
|
7
|
+
* run-groups-cli.test.ts drives group formation (chant#4505).
|
|
8
|
+
*
|
|
9
|
+
* Discovery, config, the capability registry and the gate ledger are fakes.
|
|
10
|
+
* app is discovered first and declares no `dependsOn`, so only the declared
|
|
11
|
+
* read can put network ahead of it. edge reads nothing.
|
|
12
|
+
*/
|
|
13
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
14
|
+
import type { Component } from "../../components/component";
|
|
15
|
+
import type { ParsedArgs } from "../registry";
|
|
16
|
+
|
|
17
|
+
const affectedStacksMock = vi.fn();
|
|
18
|
+
const discoverComponentsMock = vi.fn();
|
|
19
|
+
const buildCapabilityRegistryMock = vi.fn();
|
|
20
|
+
|
|
21
|
+
vi.mock("../../lifecycle/affected", () => ({
|
|
22
|
+
affectedStacks: (...args: unknown[]) => affectedStacksMock(...args),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock("../../components/discover", () => ({
|
|
26
|
+
discoverComponents: (...args: unknown[]) => discoverComponentsMock(...args),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
vi.mock("../../config", async () => {
|
|
30
|
+
const actual = await vi.importActual<typeof import("../../config")>("../../config");
|
|
31
|
+
return { ...actual, loadChantConfig: async () => ({ config: { lexicons: ["aws"] } }) };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
vi.mock("../../components/capability-plugin-loader", () => ({
|
|
35
|
+
buildCapabilityRegistry: (...args: unknown[]) => buildCapabilityRegistryMock(...args),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
/** The real gate ledger is this repository's `chant/lifecycle` branch; a test never appends to it. */
|
|
39
|
+
vi.mock("../../op/gate", async () => {
|
|
40
|
+
const actual = await vi.importActual<typeof import("../../op/gate")>("../../op/gate");
|
|
41
|
+
return { ...actual, gitGateLedgerPort: () => actual.memoryGateLedgerPort(), gateIsSealed: async () => false };
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** The release ledger, for the same reason. */
|
|
45
|
+
vi.mock("../../components/auto-release", async () => {
|
|
46
|
+
const actual = await vi.importActual<typeof import("../../components/auto-release")>("../../components/auto-release");
|
|
47
|
+
return { ...actual, maybeRecordAutoRelease: async () => ({ recorded: false, reason: "opted-out" }) };
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/** `run --components` on the local runtime: the real `runComponents`, with the test's registry. */
|
|
51
|
+
vi.mock("../../op/runtimes/local", async () => {
|
|
52
|
+
const { runComponents } = await import("../../components/cli-support");
|
|
53
|
+
const { memoryGateLedgerPort } = await import("../../op/gate");
|
|
54
|
+
return {
|
|
55
|
+
createLocalOpRuntime: () => ({
|
|
56
|
+
name: "local",
|
|
57
|
+
runComponents: async (path: string, selector: string, options: object) =>
|
|
58
|
+
runComponents(path, selector, { ...options, registry: await buildCapabilityRegistryMock(), config: {}, revision: null, gates: memoryGateLedgerPort() }),
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const { CapabilityRegistry } = await import("../../components/capability");
|
|
64
|
+
const { computePlanDigest } = await import("../../lifecycle/plan-digest");
|
|
65
|
+
const { runComponentsFanOut } = await import("./fan-out");
|
|
66
|
+
const { runOpComponents } = await import("./run");
|
|
67
|
+
|
|
68
|
+
interface StackInput {
|
|
69
|
+
stack: string;
|
|
70
|
+
imports?: Record<string, unknown>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const stack = (name: string): Component => ({
|
|
74
|
+
name,
|
|
75
|
+
dependsOn: [],
|
|
76
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy", stack: name, template: `${name}.template.json` }] }],
|
|
77
|
+
});
|
|
78
|
+
const COMPONENTS = [stack("app"), stack("network"), stack("edge")];
|
|
79
|
+
/** app's template imports `Net-VpcId`, which network's template exports from its `VpcId` output. */
|
|
80
|
+
const READ = { reader: "app", index: 0, upstream: "network", output: "VpcId", at: "/imports/Net-VpcId" };
|
|
81
|
+
|
|
82
|
+
let declares = true;
|
|
83
|
+
let applied: Array<{ stack: string; imports?: Record<string, unknown> }> = [];
|
|
84
|
+
let stderrLines: string[] = [];
|
|
85
|
+
|
|
86
|
+
function registry() {
|
|
87
|
+
const r = new CapabilityRegistry();
|
|
88
|
+
r.register({
|
|
89
|
+
kind: "cfn-deploy",
|
|
90
|
+
async plan(_ctx: unknown, input: StackInput) {
|
|
91
|
+
const planDigest = computePlanDigest("cfn-deploy", { stack: input.stack, imports: input.imports ?? null });
|
|
92
|
+
return {
|
|
93
|
+
member: input.stack,
|
|
94
|
+
planDigest,
|
|
95
|
+
artifact: { planDigest },
|
|
96
|
+
outputs: { known: {}, unknown: ["VpcId"] },
|
|
97
|
+
changeSet: {
|
|
98
|
+
member: { member: input.stack, lexicon: "aws", planner: "tofu" as const, status: "planned" as const, planDigest, holes: [] },
|
|
99
|
+
entries: [{ member: input.stack, lexicon: "aws", planner: "tofu" as const, address: "res.x", type: "res", action: "create" as const, attributes: [] }],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
async run(_ctx: unknown, input: StackInput) {
|
|
104
|
+
applied.push({ stack: input.stack, ...(input.imports ? { imports: input.imports } : {}) });
|
|
105
|
+
return { outputs: { VpcId: `${input.stack}-vpc` } };
|
|
106
|
+
},
|
|
107
|
+
...(declares
|
|
108
|
+
? {
|
|
109
|
+
declaredReads(_ctx: unknown, members: ReadonlyArray<{ component: string }>) {
|
|
110
|
+
return members.some((m) => m.component === READ.reader) ? [READ] : [];
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
: {}),
|
|
114
|
+
} as never);
|
|
115
|
+
return r;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const baseArgs = { format: "", fix: false, watch: false, verbose: false, help: false, live: false };
|
|
119
|
+
const fanOutCtx = (overrides: Partial<ParsedArgs> = {}) => ({ args: { command: "components", path: "fan-out", ...baseArgs, ...overrides } as ParsedArgs, plugins: [], serializers: [] }) as never;
|
|
120
|
+
const runCtx = (selector: string) => ({ args: { command: "run", path: selector, components: true, on: "local", ...baseArgs } as ParsedArgs, plugins: [] }) as never;
|
|
121
|
+
const stderr = () => stderrLines.join("\n");
|
|
122
|
+
const order = () => applied.map((a) => a.stack);
|
|
123
|
+
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
vi.clearAllMocks();
|
|
126
|
+
declares = true;
|
|
127
|
+
applied = [];
|
|
128
|
+
stderrLines = [];
|
|
129
|
+
discoverComponentsMock.mockResolvedValue({
|
|
130
|
+
components: new Map(COMPONENTS.map((c) => [c.name, { component: c, exportName: c.name, filePath: `${c.name}.component.ts` }])),
|
|
131
|
+
sourceFiles: [],
|
|
132
|
+
errors: [],
|
|
133
|
+
});
|
|
134
|
+
buildCapabilityRegistryMock.mockImplementation(async () => registry());
|
|
135
|
+
affectedStacksMock.mockResolvedValue({ changed: ["network"], dependents: [], indeterminate: [] });
|
|
136
|
+
vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
|
|
137
|
+
stderrLines.push(args.map(String).join(" "));
|
|
138
|
+
});
|
|
139
|
+
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
140
|
+
vi.spyOn(process.stderr, "write").mockImplementation((chunk: unknown) => {
|
|
141
|
+
stderrLines.push(String(chunk));
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
afterEach(() => {
|
|
148
|
+
vi.restoreAllMocks();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("chant run --components orders an importer after its exporter (chant#4516)", () => {
|
|
152
|
+
test("all: network applies before app, and app's step gets network's output under imports", async () => {
|
|
153
|
+
expect(await runOpComponents(runCtx("all"))).toBe(0);
|
|
154
|
+
expect(order().indexOf("network")).toBeLessThan(order().indexOf("app"));
|
|
155
|
+
expect(applied.find((a) => a.stack === "app")).toEqual({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
|
|
156
|
+
expect(order().sort()).toEqual(["app", "edge", "network"]);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("a list naming the importer pulls in its exporter, says so, and runs it first", async () => {
|
|
160
|
+
expect(await runOpComponents(runCtx("app,edge"))).toBe(0);
|
|
161
|
+
expect(stderr()).toContain("added as dependencies: network");
|
|
162
|
+
expect(stderr()).toMatch(/run order: .*network.*, then app/);
|
|
163
|
+
expect(order().indexOf("network")).toBeLessThan(order().indexOf("app"));
|
|
164
|
+
expect(applied.find((a) => a.stack === "app")?.imports).toEqual({ "Net-VpcId": "network-vpc" });
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("a single name runs that component alone; a read of a component outside the run is left out", async () => {
|
|
168
|
+
expect(await runOpComponents(runCtx("app"))).toBe(0);
|
|
169
|
+
expect(applied).toEqual([{ stack: "app" }]);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("without declaredReads a list adds nothing and app gets no imports, as before", async () => {
|
|
173
|
+
declares = false;
|
|
174
|
+
expect(await runOpComponents(runCtx("app,edge"))).toBe(0);
|
|
175
|
+
expect(stderr()).not.toContain("added as dependencies");
|
|
176
|
+
expect(order().sort()).toEqual(["app", "edge"]);
|
|
177
|
+
expect(applied.find((a) => a.stack === "app")?.imports).toBeUndefined();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("chant components fan-out orders an importer after its exporter (chant#4516)", () => {
|
|
182
|
+
test("a changed network pulls in app, which applies after it with network's output", async () => {
|
|
183
|
+
expect(await runComponentsFanOut(fanOutCtx({ base: "main" }))).toBe(0);
|
|
184
|
+
expect(order()).toEqual(["network", "app"]);
|
|
185
|
+
expect(applied[1]).toEqual({ stack: "app", imports: { "Net-VpcId": "network-vpc" } });
|
|
186
|
+
});
|
|
187
|
+
});
|