@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
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { lexiconNames } from "../../lexicon-module";
|
|
2
|
-
import { resolve } from "node:path";
|
|
2
|
+
import { basename, resolve } from "node:path";
|
|
3
3
|
import { commandBuildParams } from "../build-params-cli";
|
|
4
4
|
import { build } from "../../build";
|
|
5
5
|
import { takeSnapshot } from "../../lifecycle/snapshot";
|
|
6
|
-
import {
|
|
6
|
+
import { snapshotStorageKey, StaleLifecycleBranchError } from "../../lifecycle/git";
|
|
7
|
+
import { readEnvironmentSnapshotsFrom, resolveSnapshotStore, type SnapshotStore } from "../../lifecycle/snapshot-store";
|
|
7
8
|
import { deepDiffForLexicon, type DeclaredEntities } from "../../lifecycle/deep-observe";
|
|
8
9
|
import { countUnclaimed, countPending, countPropertyDrift, countHeld, suspiciousHeld, type DeepDiffResult, type DeepEntityHeld } from "../../lifecycle/deep-diff";
|
|
9
10
|
import { describePathOrigin, getPathProvenance, getProvenance, type EntityProvenance } from "../../provenance";
|
|
@@ -13,12 +14,14 @@ import {
|
|
|
13
14
|
baselineForLexicon,
|
|
14
15
|
emptyBaseline,
|
|
15
16
|
readObservationBaseline,
|
|
16
|
-
|
|
17
|
-
OBSERVATION_BASELINE_FILE,
|
|
17
|
+
saveObservationBaseline,
|
|
18
18
|
type DeviationToAccept,
|
|
19
19
|
type ObservationBaseline,
|
|
20
20
|
} from "../../lifecycle/observation-baseline";
|
|
21
21
|
import { computeBuildDigest, declaredDefinitions, diffDigests } from "../../lifecycle/digest";
|
|
22
|
+
import { diffDeclaredAgainstIndex, indexDriftDocument, type IndexDriftResult } from "../../lifecycle/index-drift";
|
|
23
|
+
import { joinCell, parseIndexRef, readIndexRef, type IndexRead } from "../../lifecycle/index-join";
|
|
24
|
+
import { CHANT_VERSION } from "../../chant-version";
|
|
22
25
|
import { diffLive, diffLiveArtifacts, diffSnapshots, missingRow, type LiveDiffResult, type LiveArtifactDiffResult, type SnapshotDiffResult } from "../../lifecycle/live-diff";
|
|
23
26
|
import { buildChangeSet, renderChangeSet, renderChangeSetMarkdown, gitlabMrReport, unobservedPlanNotice, type ChangeSet, type HeldEntitySet } from "../../lifecycle/change-set";
|
|
24
27
|
import { mergeReceiptEntries, observedValueResolver, planReceipts, readReceiptValue, type ReceiptReading } from "../../lifecycle/receipt-plan";
|
|
@@ -53,6 +56,9 @@ import type { BuildResult } from "../../build";
|
|
|
53
56
|
import type { ParsedArgs } from "../registry";
|
|
54
57
|
import type { ChantConfig } from "../../config";
|
|
55
58
|
|
|
59
|
+
/** The config fields the observation baseline reads (#4519). */
|
|
60
|
+
type LoadedChantConfigLike = { observationBaseline?: unknown; snapshots?: unknown };
|
|
61
|
+
|
|
56
62
|
/**
|
|
57
63
|
* Resolve the build root for a lifecycle command. The project root (where
|
|
58
64
|
* chant.config.ts lives) is always ".", but the *build* can be scoped to a
|
|
@@ -146,6 +152,7 @@ export async function runLifecycleSnapshot(ctx: CommandContext): Promise<number>
|
|
|
146
152
|
// from its own scoped root — so its logical ids match what it deploys — and
|
|
147
153
|
// snapshots against its own live stack name (#932).
|
|
148
154
|
const targets = resolveStackTargets(args, config);
|
|
155
|
+
const store = await resolveSnapshotStore({ cwd: projectPath, config });
|
|
149
156
|
let anySnapshotSaved = false;
|
|
150
157
|
let anyHardError = false;
|
|
151
158
|
|
|
@@ -188,6 +195,7 @@ export async function runLifecycleSnapshot(ctx: CommandContext): Promise<number>
|
|
|
188
195
|
deep: args.deep,
|
|
189
196
|
ambient: args.ambient,
|
|
190
197
|
ambientKinds: projectKinds,
|
|
198
|
+
store,
|
|
191
199
|
});
|
|
192
200
|
} catch (err) {
|
|
193
201
|
if (err instanceof StaleLifecycleBranchError) {
|
|
@@ -213,7 +221,10 @@ export async function runLifecycleSnapshot(ctx: CommandContext): Promise<number>
|
|
|
213
221
|
const counts = result.snapshots
|
|
214
222
|
.map((s) => `${s.lexicon}(${Object.keys(s.resources).length})`)
|
|
215
223
|
.join(" ");
|
|
216
|
-
|
|
224
|
+
// `none` keeps nothing, and says so: the observation still ran (#4519).
|
|
225
|
+
console.error(result.store && !result.store.written
|
|
226
|
+
? formatWarning({ message: `${prefix}Snapshot observed, not kept: the store is ${result.store.where} (${counts})` })
|
|
227
|
+
: formatSuccess(`${prefix}Snapshot saved to ${store.where} (${counts})`));
|
|
217
228
|
}
|
|
218
229
|
if (result.errors.length > 0) anyHardError = true;
|
|
219
230
|
}
|
|
@@ -237,10 +248,11 @@ export async function runLifecycleShow(ctx: CommandContext): Promise<number> {
|
|
|
237
248
|
}
|
|
238
249
|
|
|
239
250
|
// Fetch from remote first
|
|
240
|
-
await
|
|
251
|
+
const store = await resolveSnapshotStore();
|
|
252
|
+
await store.fetch();
|
|
241
253
|
|
|
242
254
|
if (lexiconFilter) {
|
|
243
|
-
const content = await
|
|
255
|
+
const content = await store.readLatest(environment, lexiconFilter);
|
|
244
256
|
if (!content) {
|
|
245
257
|
console.error(formatError({ message: `No snapshot found for ${environment}/${lexiconFilter}` }));
|
|
246
258
|
return 1;
|
|
@@ -249,7 +261,7 @@ export async function runLifecycleShow(ctx: CommandContext): Promise<number> {
|
|
|
249
261
|
const snapshot: LifecycleSnapshot = JSON.parse(content);
|
|
250
262
|
printSnapshotTable(snapshot);
|
|
251
263
|
} else {
|
|
252
|
-
const snapshots = await
|
|
264
|
+
const snapshots = await readEnvironmentSnapshotsFrom(store, environment);
|
|
253
265
|
if (snapshots.size === 0) {
|
|
254
266
|
console.error(formatError({ message: `No snapshots found for environment "${environment}"` }));
|
|
255
267
|
return 1;
|
|
@@ -337,6 +349,22 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
337
349
|
});
|
|
338
350
|
}
|
|
339
351
|
|
|
352
|
+
// `--index <ref>` (#4526): the observed side is an index version in the
|
|
353
|
+
// store, not a live read and not a snapshot.
|
|
354
|
+
const indexMode = args.index !== undefined;
|
|
355
|
+
if (indexMode && (args.live || (args.betweenA && args.betweenB))) {
|
|
356
|
+
console.error(formatError({
|
|
357
|
+
message: `chant lifecycle diff takes --index or ${args.live ? "--live" : "--between"}, not both`,
|
|
358
|
+
hint: "--index compares source with an index version in the store; --live reads the estate now; --between compares two snapshots",
|
|
359
|
+
}));
|
|
360
|
+
return 1;
|
|
361
|
+
}
|
|
362
|
+
const indexRef = indexMode ? parseIndexRef(String(args.index)) : undefined;
|
|
363
|
+
if (indexRef && "error" in indexRef) {
|
|
364
|
+
console.error(formatError({ message: indexRef.error, hint: indexRef.hint }));
|
|
365
|
+
return 1;
|
|
366
|
+
}
|
|
367
|
+
|
|
340
368
|
// Filter serializers to target lexicon before building
|
|
341
369
|
const targetSerializers = lexiconFilter
|
|
342
370
|
? plugins.filter((p) => p.name === lexiconFilter).map((p) => p.serializer)
|
|
@@ -348,7 +376,19 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
348
376
|
// the caller asked for rather than the parameter defaults (#1483).
|
|
349
377
|
const declaredParams = await commandBuildParams(config.buildParams, args);
|
|
350
378
|
if (!declaredParams) return 1;
|
|
351
|
-
await
|
|
379
|
+
const store = await resolveSnapshotStore({ config });
|
|
380
|
+
await store.fetch();
|
|
381
|
+
|
|
382
|
+
let indexRead: Extract<IndexRead, { doc: unknown }> | undefined;
|
|
383
|
+
if (indexRef && !("error" in indexRef)) {
|
|
384
|
+
const read = await readIndexRef(store, indexRef);
|
|
385
|
+
if ("error" in read) {
|
|
386
|
+
console.error(formatError({ message: read.error, ...(read.hint ? { hint: read.hint } : {}) }));
|
|
387
|
+
return 1;
|
|
388
|
+
}
|
|
389
|
+
indexRead = read;
|
|
390
|
+
}
|
|
391
|
+
const indexResults: IndexDriftResult[] = [];
|
|
352
392
|
|
|
353
393
|
// One target per stack (single-stack projects: exactly one), each built from
|
|
354
394
|
// its own scoped root and diffed against its own live stack name (#932).
|
|
@@ -364,7 +404,7 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
364
404
|
// Accepted-deviation baseline (#1014). Read once for the whole run — it is
|
|
365
405
|
// env-keyed, not stack-keyed, and every deep pass subtracts from the same
|
|
366
406
|
// committed set. Absent is the normal state (nothing accepted yet).
|
|
367
|
-
const baseline = args.live ? await readObservationBaseline(environment) : null;
|
|
407
|
+
const baseline = args.live || indexRead ? await readObservationBaseline(environment, { config }) : null;
|
|
368
408
|
const accepted: Record<string, DeviationToAccept[]> = {};
|
|
369
409
|
// Effect receipts across every target's build (#1833) — `--update-baseline`
|
|
370
410
|
// refuses to accept drift on them (the effect step is their only writer),
|
|
@@ -375,7 +415,7 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
375
415
|
// Floci), so `--live` is self-sufficient even when the ambient shell never
|
|
376
416
|
// exported e.g. AWS_ENDPOINT_URL. Ambient always wins when it's already set.
|
|
377
417
|
// Scoped to just the live reads below — restored in `finally`.
|
|
378
|
-
const liveLexicons = args.live ? plugins.filter((p) => p.describeResources || p.listArtifacts) : [];
|
|
418
|
+
const liveLexicons = args.live && !indexRead ? plugins.filter((p) => p.describeResources || p.listArtifacts) : [];
|
|
379
419
|
const endpointResult = applyLiveEndpoint(config.environments, environment, liveLexicons);
|
|
380
420
|
if (endpointResult.notice) console.error(formatWarning({ message: endpointResult.notice }));
|
|
381
421
|
|
|
@@ -440,6 +480,7 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
440
480
|
plugins,
|
|
441
481
|
buildResult,
|
|
442
482
|
json,
|
|
483
|
+
store,
|
|
443
484
|
stack: target.stack,
|
|
444
485
|
region: target.region,
|
|
445
486
|
componentStacks,
|
|
@@ -461,16 +502,66 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
461
502
|
if (target.stack) perStackJson[target.stack] = r.byLexicon;
|
|
462
503
|
else combinedLexiconsJson = r.byLexicon;
|
|
463
504
|
}
|
|
505
|
+
} else if (indexRead) {
|
|
506
|
+
const r = runLifecycleDiffIndex({
|
|
507
|
+
read: indexRead,
|
|
508
|
+
lexicons: lexiconFilter ? [lexiconFilter] : builtLexicons,
|
|
509
|
+
plugins,
|
|
510
|
+
buildResult,
|
|
511
|
+
baseline,
|
|
512
|
+
member: basename(projectRoot),
|
|
513
|
+
stack: target.stack,
|
|
514
|
+
region: target.region,
|
|
515
|
+
json,
|
|
516
|
+
projectRoot,
|
|
517
|
+
});
|
|
518
|
+
indexResults.push(r);
|
|
519
|
+
for (const [lexicon, part] of Object.entries(r.byLexicon)) {
|
|
520
|
+
if (args.updateBaseline) (accepted[lexicon] ??= []).push(...deviationsToAccept(part.deep));
|
|
521
|
+
}
|
|
522
|
+
if (args.updateBaseline) {
|
|
523
|
+
for (const name of collectEffectReceipts(buildResult.entities).keys()) receiptEntities.add(name);
|
|
524
|
+
}
|
|
464
525
|
} else {
|
|
465
|
-
await runLifecycleDiffDigest({ environment, lexicons, buildResult, stack: target.stack });
|
|
526
|
+
await runLifecycleDiffDigest({ environment, lexicons, buildResult, stack: target.stack, store });
|
|
466
527
|
}
|
|
467
528
|
}
|
|
468
529
|
|
|
469
530
|
// `--update-baseline` (#1014): record what the deep pass just reported as
|
|
470
531
|
// accepted, so it stops re-alerting. Runs before the summary lines so the
|
|
471
532
|
// "no drift" verdict below still describes the run that produced it.
|
|
472
|
-
if (args.live && args.updateBaseline) {
|
|
473
|
-
await recordAcceptedBaseline(environment, baseline, accepted, json, receiptEntities);
|
|
533
|
+
if ((args.live || indexRead) && args.updateBaseline) {
|
|
534
|
+
await recordAcceptedBaseline(environment, baseline, accepted, json, receiptEntities, config);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (indexRead) {
|
|
538
|
+
// Drift records, drift document v1 (#4526).
|
|
539
|
+
if (json) console.log(JSON.stringify(indexDriftDocument(indexResults, CHANT_VERSION)));
|
|
540
|
+
else {
|
|
541
|
+
const sum = (k: keyof IndexDriftResult["counts"]) => indexResults.reduce((n, r) => n + r.counts[k], 0);
|
|
542
|
+
const ref = indexResults[0]?.ref;
|
|
543
|
+
const declaredCount = sum("declared");
|
|
544
|
+
const drift = sum("properties") + sum("pending");
|
|
545
|
+
const notObserved = sum("notObserved");
|
|
546
|
+
if (anyBuildError) {
|
|
547
|
+
// the build error is already printed
|
|
548
|
+
} else if (declaredCount === 0) {
|
|
549
|
+
console.error(formatWarning({ message: "No declared entities to compare with the index" }));
|
|
550
|
+
} else if (drift === 0) {
|
|
551
|
+
console.error(
|
|
552
|
+
notObserved > 0
|
|
553
|
+
? formatWarning({
|
|
554
|
+
message: `No drift detected against index ${ref} across ${sum("bound")} bound entity(ies), but ${notObserved} declared entity(ies) are not observed by it: that part of the estate is unknown, not clean`,
|
|
555
|
+
})
|
|
556
|
+
: formatSuccess(`No drift detected against index ${ref} across ${declaredCount} declared entity(ies)`),
|
|
557
|
+
);
|
|
558
|
+
} else {
|
|
559
|
+
console.error(formatWarning({
|
|
560
|
+
message: `Drift against index ${ref}: ${sum("properties")} property difference(s) on ${sum("drifted")} entity(ies), ${sum("pending")} declared entity(ies) absent from it, ${notObserved} not observed`,
|
|
561
|
+
}));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return anyBuildError ? 1 : 0;
|
|
474
565
|
}
|
|
475
566
|
|
|
476
567
|
if (args.live) {
|
|
@@ -523,6 +614,7 @@ async function recordAcceptedBaseline(
|
|
|
523
614
|
accepted: Record<string, DeviationToAccept[]>,
|
|
524
615
|
json: boolean,
|
|
525
616
|
receipts?: ReadonlySet<string>,
|
|
617
|
+
config?: ChantConfig | LoadedChantConfigLike,
|
|
526
618
|
): Promise<void> {
|
|
527
619
|
const total = Object.values(accepted).reduce((n, d) => n + d.length, 0);
|
|
528
620
|
if (total === 0) {
|
|
@@ -541,13 +633,16 @@ async function recordAcceptedBaseline(
|
|
|
541
633
|
for (const [lexicon, deviations] of Object.entries(accepted)) {
|
|
542
634
|
next = acceptDeviations(next, lexicon, deviations, { receipts });
|
|
543
635
|
}
|
|
544
|
-
|
|
545
|
-
|
|
636
|
+
// A file under .chant/observation-baseline/ by default (#4519): commit it
|
|
637
|
+
// with the change that needed it, so the acceptance is reviewed.
|
|
638
|
+
const saved = await saveObservationBaseline(next, config ? { config } : undefined);
|
|
546
639
|
if (!json) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
640
|
+
const note =
|
|
641
|
+
saved.published === "pushed" ? " (pushed)"
|
|
642
|
+
: saved.published === "file" ? " (commit it to keep it)"
|
|
643
|
+
: saved.published === "none" ? " (the baseline store is none: nothing kept)"
|
|
644
|
+
: " (local only — no remote configured or push refused)";
|
|
645
|
+
console.error(formatSuccess(`--update-baseline: accepted ${total} deviation(s) into ${saved.where}${note}`));
|
|
551
646
|
}
|
|
552
647
|
} catch (err) {
|
|
553
648
|
console.error(formatError({
|
|
@@ -571,8 +666,9 @@ interface BetweenDiffArgs {
|
|
|
571
666
|
* two-way delta per lexicon.
|
|
572
667
|
*/
|
|
573
668
|
async function runLifecycleDiffBetween(args: BetweenDiffArgs): Promise<number> {
|
|
574
|
-
await fetchLifecycle();
|
|
575
669
|
const { config } = await loadChantConfig(resolve("."));
|
|
670
|
+
const store = await resolveSnapshotStore({ config });
|
|
671
|
+
await store.fetch();
|
|
576
672
|
const lexicons = args.lexiconFilter ? [args.lexiconFilter] : lexiconNames(config.lexicons ?? []);
|
|
577
673
|
if (lexicons.length === 0) {
|
|
578
674
|
console.error(formatError({ message: "No lexicons to diff — pass a lexicon or declare `lexicons` in chant.config." }));
|
|
@@ -590,8 +686,8 @@ async function runLifecycleDiffBetween(args: BetweenDiffArgs): Promise<number> {
|
|
|
590
686
|
|
|
591
687
|
const byLexicon: Record<string, SnapshotDiffResult> = {};
|
|
592
688
|
for (const lexicon of lexicons) {
|
|
593
|
-
const prev = parseResources(await
|
|
594
|
-
const next = parseResources(await
|
|
689
|
+
const prev = parseResources(await store.readAt(args.environment, lexicon, args.refA));
|
|
690
|
+
const next = parseResources(await store.readAt(args.environment, lexicon, args.refB));
|
|
595
691
|
if (prev === null && next === null) {
|
|
596
692
|
if (!args.json) console.error(formatWarning({ message: `${lexicon}: not captured at either ref — skipping` }));
|
|
597
693
|
continue;
|
|
@@ -625,6 +721,8 @@ interface DigestDiffArgs {
|
|
|
625
721
|
environment: string;
|
|
626
722
|
lexicons: string[];
|
|
627
723
|
buildResult: BuildResult;
|
|
724
|
+
/** Where the previous digest is read (#4519). */
|
|
725
|
+
store: SnapshotStore;
|
|
628
726
|
/** Deployed stack name for a multi-stack project (#932); scopes the snapshot read. */
|
|
629
727
|
stack?: string;
|
|
630
728
|
}
|
|
@@ -634,7 +732,7 @@ async function runLifecycleDiffDigest(args: DigestDiffArgs): Promise<number> {
|
|
|
634
732
|
if (args.stack) console.log(`\n${formatBold(`■ stack ${args.stack}`)}`);
|
|
635
733
|
|
|
636
734
|
for (const lexicon of args.lexicons) {
|
|
637
|
-
const content = await
|
|
735
|
+
const content = await args.store.readLatest(args.environment, snapshotStorageKey(lexicon, args.stack));
|
|
638
736
|
let previousDigest = undefined;
|
|
639
737
|
if (content) {
|
|
640
738
|
const snapshot: LifecycleSnapshot = JSON.parse(content);
|
|
@@ -679,6 +777,8 @@ interface LiveDiffArgs {
|
|
|
679
777
|
lexicons: string[];
|
|
680
778
|
plugins: ObservationLexicon[];
|
|
681
779
|
buildResult: BuildResult;
|
|
780
|
+
/** Where the "then" side is read (#4519). */
|
|
781
|
+
store: SnapshotStore;
|
|
682
782
|
/** Emit machine-readable JSON on stdout instead of the human report (#852). */
|
|
683
783
|
json: boolean;
|
|
684
784
|
/** Deployed stack name for a multi-stack project (#932); scopes the live
|
|
@@ -857,7 +957,7 @@ async function runLifecycleDiffLive(args: LiveDiffArgs): Promise<LiveDiffOutcome
|
|
|
857
957
|
|
|
858
958
|
// Read previous snapshot once; both flows pull what they need.
|
|
859
959
|
let prevSnapshot: LifecycleSnapshot | undefined;
|
|
860
|
-
const content = await
|
|
960
|
+
const content = await args.store.readLatest(args.environment, snapshotStorageKey(lexiconName, args.stack));
|
|
861
961
|
if (content) prevSnapshot = JSON.parse(content);
|
|
862
962
|
|
|
863
963
|
let lexiconChecked = false;
|
|
@@ -971,6 +1071,76 @@ async function runLifecycleDiffLive(args: LiveDiffArgs): Promise<LiveDiffOutcome
|
|
|
971
1071
|
return { byLexicon, totalDrift, totalUnobserved, totalLexiconsChecked, toAccept };
|
|
972
1072
|
}
|
|
973
1073
|
|
|
1074
|
+
interface IndexDiffArgs {
|
|
1075
|
+
read: Extract<IndexRead, { doc: unknown }>;
|
|
1076
|
+
lexicons: string[];
|
|
1077
|
+
plugins: CommandContext["plugins"];
|
|
1078
|
+
buildResult: BuildResult;
|
|
1079
|
+
baseline: ObservationBaseline | null;
|
|
1080
|
+
member: string;
|
|
1081
|
+
stack?: string;
|
|
1082
|
+
region?: string;
|
|
1083
|
+
json: boolean;
|
|
1084
|
+
projectRoot: string;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* `chant lifecycle diff <env> --index <ref>` for one stack (#4526): every
|
|
1089
|
+
* declared entity joined to the index version, the bound ones deep-diffed
|
|
1090
|
+
* against their indexed trees, the rest reported with their join verdict.
|
|
1091
|
+
* Reads nothing but the store. See ../../lifecycle/index-drift.ts.
|
|
1092
|
+
*/
|
|
1093
|
+
function runLifecycleDiffIndex(args: IndexDiffArgs): IndexDriftResult {
|
|
1094
|
+
const entities = new Map<string, DeclaredEntities>();
|
|
1095
|
+
for (const lexicon of args.lexicons) entities.set(lexicon, new Map());
|
|
1096
|
+
for (const [name, entity] of args.buildResult.entities) {
|
|
1097
|
+
const forLexicon = entities.get(entity.lexicon);
|
|
1098
|
+
if (!forLexicon || !isObservableDeclarable(entity)) continue;
|
|
1099
|
+
const pathOrigins = getPathProvenance(entity);
|
|
1100
|
+
forLexicon.set(name, {
|
|
1101
|
+
entityType: entity.entityType,
|
|
1102
|
+
props: (entity.props != null ? entity.props : {}) as Record<string, unknown>,
|
|
1103
|
+
...(pathOrigins ? { pathOrigins } : {}),
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
const result = diffDeclaredAgainstIndex({
|
|
1107
|
+
doc: args.read.doc,
|
|
1108
|
+
version: args.read.version,
|
|
1109
|
+
entities,
|
|
1110
|
+
lexicons: args.plugins,
|
|
1111
|
+
baseline: args.baseline,
|
|
1112
|
+
member: args.member,
|
|
1113
|
+
...(args.stack ? { stack: args.stack } : {}),
|
|
1114
|
+
...(args.region ? { region: args.region } : {}),
|
|
1115
|
+
chant: CHANT_VERSION,
|
|
1116
|
+
});
|
|
1117
|
+
if (args.json) return result;
|
|
1118
|
+
|
|
1119
|
+
const { stamp } = args.read.doc;
|
|
1120
|
+
const by = stamp.source.version ? `${stamp.source.name} ${stamp.source.version}` : stamp.source.name;
|
|
1121
|
+
if (args.stack) console.log(`\n${formatBold(`■ stack ${args.stack}`)}`);
|
|
1122
|
+
console.log(`index ${result.ref}, read ${stamp.observedAt} by ${by}`);
|
|
1123
|
+
const provenanceOf = (name: string): EntityProvenance | undefined => {
|
|
1124
|
+
const entity = args.buildResult.entities.get(name);
|
|
1125
|
+
return entity ? getProvenance(entity) : undefined;
|
|
1126
|
+
};
|
|
1127
|
+
for (const [lexicon, part] of Object.entries(result.byLexicon)) {
|
|
1128
|
+
const rows = Object.entries(part.joins).sort(([a], [b]) => a.localeCompare(b));
|
|
1129
|
+
const bound = rows.filter(([, j]) => j.verdict === "bound").length;
|
|
1130
|
+
console.log(formatBold(`\n${lexicon}: ${bound}/${rows.length} declared entity(ies) bound to the index`));
|
|
1131
|
+
const unbound = rows.filter(([, j]) => j.verdict !== "bound");
|
|
1132
|
+
if (unbound.length > 0) {
|
|
1133
|
+
console.log(formatBold("\nNOT COMPARED (the join did not bind; never diffed):"));
|
|
1134
|
+
for (const [name, j] of unbound) {
|
|
1135
|
+
const detail = "detail" in j ? `: ${j.detail}` : j.verdict === "absent" ? ": the index listed its type and location and does not hold it" : "";
|
|
1136
|
+
console.log(` ? ${name} ${joinCell(j) ?? ""}${detail}`);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
renderDeepDiff(lexicon, part.deep, provenanceOf, args.projectRoot);
|
|
1140
|
+
}
|
|
1141
|
+
return result;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
974
1144
|
/**
|
|
975
1145
|
* Everything a deep diff reported this run, as deviations to record accepted.
|
|
976
1146
|
* `--update-baseline` accepts what was *reported*, never what was already
|
|
@@ -1264,7 +1434,8 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1264
1434
|
return 1;
|
|
1265
1435
|
}
|
|
1266
1436
|
|
|
1267
|
-
await
|
|
1437
|
+
const store = await resolveSnapshotStore({ config });
|
|
1438
|
+
await store.fetch();
|
|
1268
1439
|
|
|
1269
1440
|
const lexicons = lexiconFilter ? [lexiconFilter] : Array.from(buildResult.manifest.lexicons);
|
|
1270
1441
|
|
|
@@ -1424,7 +1595,8 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1424
1595
|
}
|
|
1425
1596
|
}
|
|
1426
1597
|
|
|
1427
|
-
|
|
1598
|
+
// Evidence only (#4519): the change set never makes a decision from it.
|
|
1599
|
+
const content = await store.readLatest(environment, lexiconName);
|
|
1428
1600
|
const observedThen = content ? (JSON.parse(content) as LifecycleSnapshot).resources : undefined;
|
|
1429
1601
|
|
|
1430
1602
|
const cs = buildChangeSet(environment, {
|
|
@@ -1745,17 +1917,20 @@ async function promptProdTeardown(environment: string): Promise<boolean> {
|
|
|
1745
1917
|
export async function runLifecycleLog(ctx: CommandContext): Promise<number> {
|
|
1746
1918
|
const environment = ctx.args.extraPositional;
|
|
1747
1919
|
|
|
1748
|
-
await
|
|
1920
|
+
const store = await resolveSnapshotStore();
|
|
1921
|
+
await store.fetch();
|
|
1749
1922
|
|
|
1750
|
-
const entries = await
|
|
1923
|
+
const entries = await store.list({ ...(environment ? { environment } : {}) });
|
|
1751
1924
|
if (entries.length === 0) {
|
|
1752
1925
|
console.error(formatError({ message: "No state snapshots found" }));
|
|
1753
1926
|
return 1;
|
|
1754
1927
|
}
|
|
1755
1928
|
|
|
1929
|
+
// A git store's version is a commit; s3's an object version, local's a time.
|
|
1930
|
+
const isCommit = (v: string) => /^[0-9a-f]{40}$/.test(v);
|
|
1756
1931
|
for (const entry of entries) {
|
|
1757
1932
|
const date = entry.date.split("T")[0];
|
|
1758
|
-
console.log(`${entry.
|
|
1933
|
+
console.log(`${isCommit(entry.version) ? entry.version.slice(0, 7) : entry.version} ${date} ${entry.key ?? entry.message}`);
|
|
1759
1934
|
}
|
|
1760
1935
|
|
|
1761
1936
|
return 0;
|
package/src/cli/handlers/misc.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { describeCommand, printDescribeResult } from "../commands/describe";
|
|
|
3
3
|
import { importCommand, importFromContent, importFromLive, importFromLiveStacks, printImportResult } from "../commands/import";
|
|
4
4
|
import { loadChantConfig } from "../../config";
|
|
5
5
|
import { resolve } from "path";
|
|
6
|
+
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import type { IndexImportSelection } from "../../lifecycle/index-import";
|
|
6
8
|
import { auditCommand, printAuditResult, type AuditFormat, type AuditTier, type AuditFailOn } from "../commands/audit";
|
|
7
9
|
import type { ReportTheme } from "../../audit/report-html";
|
|
8
10
|
import { AGENT_RUNTIMES, AGENT_SCOPES, type AgentRuntime, type AgentScope } from "../../agents/types";
|
|
@@ -248,6 +250,55 @@ export async function runDescribe(ctx: CommandContext): Promise<number> {
|
|
|
248
250
|
return result.success ? 0 : 1;
|
|
249
251
|
}
|
|
250
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The selection for `chant import --index` (#4524). `--type` and `--name`
|
|
255
|
+
* take comma-separated lists, `--tag key=value` repeats, `--select` is a JSON
|
|
256
|
+
* file of node ids (a list of ids, of `{ id }` or `{ node }` objects, or an
|
|
257
|
+
* object holding `nodes` or `results`) or a comma-separated list of ids, and
|
|
258
|
+
* `--all` takes every node.
|
|
259
|
+
*/
|
|
260
|
+
export function indexSelectionFromArgs(args: CommandContext["args"]): IndexImportSelection | Error {
|
|
261
|
+
const list = (v?: string) => (v ? v.split(",").map((s) => s.trim()).filter(Boolean) : undefined);
|
|
262
|
+
const selection: IndexImportSelection = {};
|
|
263
|
+
if (args.all) selection.all = true;
|
|
264
|
+
const types = list(args.selectType);
|
|
265
|
+
if (types) selection.types = types;
|
|
266
|
+
const names = list(args.selectName);
|
|
267
|
+
if (names) selection.names = names;
|
|
268
|
+
if (args.selectTags && args.selectTags.length > 0) {
|
|
269
|
+
const tags: Record<string, string> = {};
|
|
270
|
+
for (const t of args.selectTags) {
|
|
271
|
+
const eq = t.indexOf("=");
|
|
272
|
+
tags[t.slice(0, eq)] = t.slice(eq + 1);
|
|
273
|
+
}
|
|
274
|
+
selection.tags = tags;
|
|
275
|
+
}
|
|
276
|
+
if (args.selectAddress) {
|
|
277
|
+
const path = resolve(args.selectAddress);
|
|
278
|
+
if (existsSync(path)) {
|
|
279
|
+
let parsed: unknown;
|
|
280
|
+
try {
|
|
281
|
+
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
282
|
+
} catch (err) {
|
|
283
|
+
return new Error(`--select ${args.selectAddress} is not JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
284
|
+
}
|
|
285
|
+
const rows = Array.isArray(parsed)
|
|
286
|
+
? parsed
|
|
287
|
+
: parsed && typeof parsed === "object"
|
|
288
|
+
? ((parsed as { nodes?: unknown[]; results?: unknown[] }).nodes ?? (parsed as { results?: unknown[] }).results ?? [])
|
|
289
|
+
: [];
|
|
290
|
+
const ids = rows
|
|
291
|
+
.map((r) => (typeof r === "string" ? r : r && typeof r === "object" ? ((r as { id?: unknown }).id ?? (r as { node?: unknown }).node) : undefined))
|
|
292
|
+
.filter((x): x is string => typeof x === "string");
|
|
293
|
+
if (ids.length === 0) return new Error(`--select ${args.selectAddress} names no node ids`);
|
|
294
|
+
selection.nodes = ids;
|
|
295
|
+
} else {
|
|
296
|
+
selection.nodes = list(args.selectAddress);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return selection;
|
|
300
|
+
}
|
|
301
|
+
|
|
251
302
|
export async function runImport(ctx: CommandContext): Promise<number> {
|
|
252
303
|
const { args } = ctx;
|
|
253
304
|
|
|
@@ -330,6 +381,28 @@ export async function runImport(ctx: CommandContext): Promise<number> {
|
|
|
330
381
|
return result.success ? 0 : 1;
|
|
331
382
|
}
|
|
332
383
|
|
|
384
|
+
// `--index <ref>` (#4524): typed source for indexed resources; nothing is applied.
|
|
385
|
+
if (args.index) {
|
|
386
|
+
const { importFromIndex, summarizeIndexImport } = await import("../commands/import-index");
|
|
387
|
+
const selection = indexSelectionFromArgs(args);
|
|
388
|
+
if (selection instanceof Error) {
|
|
389
|
+
console.error(formatError({ message: selection.message }));
|
|
390
|
+
return 1;
|
|
391
|
+
}
|
|
392
|
+
const result = await importFromIndex({
|
|
393
|
+
index: args.index,
|
|
394
|
+
selection,
|
|
395
|
+
output: args.output,
|
|
396
|
+
force: args.force,
|
|
397
|
+
report: args.reportFile,
|
|
398
|
+
adoptOut: args.adoptOut,
|
|
399
|
+
src: args.src,
|
|
400
|
+
});
|
|
401
|
+
printImportResult(result);
|
|
402
|
+
if (result.report) console.error(summarizeIndexImport(result.report));
|
|
403
|
+
return result.success ? 0 : 1;
|
|
404
|
+
}
|
|
405
|
+
|
|
333
406
|
// `--from <env>` switches import from a template file to a live source.
|
|
334
407
|
if (args.migrateFrom) {
|
|
335
408
|
const selector: ResourceSelector | undefined =
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* The note lists the blocked set. Git, the change signal, the derivation and
|
|
6
6
|
* the gate ledger are fakes, as in `pr-waves.test.ts`; the planning, the
|
|
7
7
|
* coverage check and the apply are the real ones.
|
|
8
|
+
*
|
|
9
|
+
* Kept fast (#4502): the readers pr-plan and pr-apply run against the
|
|
10
|
+
* declaration at base (hooks, policy, security groups, ci.locks, new
|
|
11
|
+
* migrations) each start git processes in this checkout, so they read as a
|
|
12
|
+
* declaration that sets none of them. The pull request is planned once for
|
|
13
|
+
* the file, since every test starts from the same estate and so the same
|
|
14
|
+
* digest; each test approves that digest on its own ledger.
|
|
8
15
|
*/
|
|
9
16
|
|
|
10
17
|
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
@@ -46,6 +53,28 @@ vi.mock("../../lifecycle/git", async () => {
|
|
|
46
53
|
return { ...actual, pushLifecycleReport: async () => { throw new Error("pr-waves.test must not push chant/lifecycle"); } };
|
|
47
54
|
});
|
|
48
55
|
|
|
56
|
+
// The declaration at base sets no hooks, policy, security group or lock, and the change adds no migration (#4502).
|
|
57
|
+
vi.mock("../../components/pr-hooks", async () => {
|
|
58
|
+
const actual = await vi.importActual<typeof import("../../components/pr-hooks")>("../../components/pr-hooks");
|
|
59
|
+
return { ...actual, prLoopHooksAt: (_cwd: string, base: string) => ({ hooks: {}, base }) };
|
|
60
|
+
});
|
|
61
|
+
vi.mock("../../components/pr-policy", async () => {
|
|
62
|
+
const actual = await vi.importActual<typeof import("../../components/pr-policy")>("../../components/pr-policy");
|
|
63
|
+
return { ...actual, prLoopPolicyAt: (_cwd: string, base: string) => ({ base }) };
|
|
64
|
+
});
|
|
65
|
+
vi.mock("../../workspace/security", async () => {
|
|
66
|
+
const actual = await vi.importActual<typeof import("../../workspace/security")>("../../workspace/security");
|
|
67
|
+
return { ...actual, securityGroupsAt: () => new Set() };
|
|
68
|
+
});
|
|
69
|
+
vi.mock("../../workspace/ci-locks", async () => {
|
|
70
|
+
const actual = await vi.importActual<typeof import("../../workspace/ci-locks")>("../../workspace/ci-locks");
|
|
71
|
+
return { ...actual, ciLocksAt: () => null };
|
|
72
|
+
});
|
|
73
|
+
vi.mock("../../workspace/new-migrations", async () => {
|
|
74
|
+
const actual = await vi.importActual<typeof import("../../workspace/new-migrations")>("../../workspace/new-migrations");
|
|
75
|
+
return { ...actual, newMigrationFilesBetween: async () => [] };
|
|
76
|
+
});
|
|
77
|
+
|
|
49
78
|
vi.mock("./run", () => ({
|
|
50
79
|
GATED_EXIT_CODE: 3,
|
|
51
80
|
autoReleaseRun: (id: string) => ({ runId: id, runOrigin: { forge: "local" } }),
|
|
@@ -166,10 +195,16 @@ const resolution = (gate: string, planDigest: string, by = "github:alice") => ({
|
|
|
166
195
|
const report = async (): Promise<PrReport> => JSON.parse(await readFile(join(dir, "pr-apply.json"), "utf8")) as PrReport;
|
|
167
196
|
const note = async (): Promise<string> => readFile(join(dir, "pr-note.md"), "utf8");
|
|
168
197
|
|
|
198
|
+
/** The digest of pull request 12's plan, planned by the first test that asks: every test starts from the same estate (#4502). */
|
|
199
|
+
let plannedDigest: string | undefined;
|
|
200
|
+
|
|
169
201
|
/** Plan pull request 12, as its plan job does, and approve its digest as alice. */
|
|
170
202
|
async function planAndApprove(): Promise<string> {
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
if (plannedDigest === undefined) {
|
|
204
|
+
expect(await runComponentsPrPlan(ctx({ pr: 12 }))).toBe(0);
|
|
205
|
+
plannedDigest = (JSON.parse(await readFile(join(dir, "pr-plan.json"), "utf8")) as PrReport).digest;
|
|
206
|
+
}
|
|
207
|
+
const digest = plannedDigest;
|
|
173
208
|
gateLedger = memoryGateLedgerPort({ resolutions: [resolution("pr-apply", digest)] });
|
|
174
209
|
errors = [];
|
|
175
210
|
return digest;
|
package/src/cli/handlers/pr.ts
CHANGED
|
@@ -70,6 +70,7 @@ import { join, relative, resolve, sep } from "node:path";
|
|
|
70
70
|
import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
|
|
71
71
|
import { resolveCommit, resolveMergeBase } from "../../components/changed-files";
|
|
72
72
|
import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
|
|
73
|
+
import { findComponentGroups, groupFanOut } from "../../components/groups";
|
|
73
74
|
import {
|
|
74
75
|
applyPrSet,
|
|
75
76
|
approvalOf,
|
|
@@ -241,6 +242,7 @@ export async function prepare(ctx: CommandContext, stage: "plan" | "apply" | "re
|
|
|
241
242
|
const signal = await resolveChangedUnits(ctx, config, { base, stacksOnly: true });
|
|
242
243
|
if ("error" in signal) return fail(signal.error, signal.hint);
|
|
243
244
|
|
|
245
|
+
const registry = await fanOutRegistry(projectPath, config);
|
|
244
246
|
let derived;
|
|
245
247
|
try {
|
|
246
248
|
derived = await deriveFanOut({
|
|
@@ -249,6 +251,7 @@ export async function prepare(ctx: CommandContext, stage: "plan" | "apply" | "re
|
|
|
249
251
|
sandbox: args.sandbox,
|
|
250
252
|
buildParams: paramsResolution.provenance,
|
|
251
253
|
config,
|
|
254
|
+
registry,
|
|
252
255
|
});
|
|
253
256
|
} catch (err) {
|
|
254
257
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -288,9 +291,17 @@ export async function prepare(ctx: CommandContext, stage: "plan" | "apply" | "re
|
|
|
288
291
|
if (policy.note) console.error(formatInfo(policy.note));
|
|
289
292
|
|
|
290
293
|
const env = args.env ?? "local";
|
|
291
|
-
const registry = await fanOutRegistry(projectPath, config);
|
|
292
294
|
const routedAway = member ? await routing(ctx, stage, projectPath, member, base, forge) : undefined;
|
|
293
295
|
if (routedAway) console.error(formatInfo(routedAway));
|
|
296
|
+
// ws-107: the groups a capability plans and applies as one, placed in the waves every stage and wave job reads.
|
|
297
|
+
let plan = derived.plan;
|
|
298
|
+
if (!routedAway && plan.order.length > 0) {
|
|
299
|
+
try {
|
|
300
|
+
plan = groupFanOut(plan, derived.components, await findComponentGroups({ components: derived.components, plan, registry, env }));
|
|
301
|
+
} catch (err) {
|
|
302
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
294
305
|
return {
|
|
295
306
|
config,
|
|
296
307
|
env,
|
|
@@ -300,7 +311,7 @@ export async function prepare(ctx: CommandContext, stage: "plan" | "apply" | "re
|
|
|
300
311
|
gate: args.gate ?? PR_APPLY_GATE,
|
|
301
312
|
...(forge ? { forge } : {}),
|
|
302
313
|
components: derived.components,
|
|
303
|
-
plan: routedAway ? { ...derived.plan, order: [], waves: [], seeds: [], indeterminate: [] } :
|
|
314
|
+
plan: routedAway ? { ...derived.plan, order: [], waves: [], seeds: [], indeterminate: [] } : plan,
|
|
304
315
|
signal: derived.signal,
|
|
305
316
|
...(derived.sites ? { sites: derived.sites } : {}),
|
|
306
317
|
registry,
|
|
@@ -1648,6 +1659,7 @@ async function tryResume(p: Prepared, attempt: FanOutAttempt, file: string, op:
|
|
|
1648
1659
|
seededOutputs: p.seededOutputs,
|
|
1649
1660
|
record,
|
|
1650
1661
|
completed,
|
|
1662
|
+
applied: outputs,
|
|
1651
1663
|
});
|
|
1652
1664
|
if (!resumed.ok) return skip(`what is left is not what was approved. ${resumed.reasons.join("; ")}`);
|
|
1653
1665
|
console.error(formatInfo(`resume : ${completed.join(", ")} applied in an earlier attempt; applying ${resumed.plan.order.join(", ") || "nothing more"} under the approval of ${record.digest}`));
|