@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
|
@@ -67,6 +67,14 @@
|
|
|
67
67
|
* says whether the approved change set covers what it planned, by the same
|
|
68
68
|
* test a resume uses ({@link planCoveredBy}). Covered, the wave applies under
|
|
69
69
|
* the pull request's approval; not covered, it needs its own.
|
|
70
|
+
*
|
|
71
|
+
* ## Groups
|
|
72
|
+
*
|
|
73
|
+
* A fan-out with `groups` (ws-107, `./groups.ts`) plans each group with one
|
|
74
|
+
* `planGroup` call at its wave and applies it with one `runGroup` call
|
|
75
|
+
* there. A member's read of another member of its group is computed by that
|
|
76
|
+
* apply: it is no `unknownInputs` entry and holds nothing back. Each member's
|
|
77
|
+
* digest binds the group's, so the one approval binds the composition.
|
|
70
78
|
*/
|
|
71
79
|
import { composeChangeSet, verifyChangeSetDigest } from "../change-set.js";
|
|
72
80
|
import { evaluateGate } from "../op/gate.js";
|
|
@@ -76,6 +84,7 @@ import { deployUnits } from "./deploy-units.js";
|
|
|
76
84
|
import { runFanOut } from "./fan-out-run.js";
|
|
77
85
|
import { remainingFanOut } from "./fan-out.js";
|
|
78
86
|
import { coveredRound } from "./covered-round.js";
|
|
87
|
+
import { groupsByComponent, narrowGroups, planComponentGroup, regroupRemaining } from "./groups.js";
|
|
79
88
|
import { capabilitySteps, planWaveComponent, readDeployedOutputs } from "./wave-plan.js";
|
|
80
89
|
/** The phase a pull request's planning is, in its run's events. */
|
|
81
90
|
export const PR_PLAN_PHASE = "plan";
|
|
@@ -113,13 +122,18 @@ export async function planPrSet(options) {
|
|
|
113
122
|
let failed = false;
|
|
114
123
|
const emit = options.onRunEvent;
|
|
115
124
|
emit?.({ type: "phase-start", component: null, phase: PR_PLAN_PHASE });
|
|
125
|
+
// ws-107: each group plans once, in its wave, with one call.
|
|
126
|
+
const groupOf = groupsByComponent(options.plan);
|
|
127
|
+
const groups = [];
|
|
116
128
|
for (const wave of options.plan.waves) {
|
|
117
129
|
// The dependencies' outputs first, each once. One the change plans is
|
|
118
130
|
// read from its plan, which an earlier wave made (#3999). Any other is
|
|
119
131
|
// read from the deployed estate (#4104). A dependency that cannot say
|
|
120
132
|
// leaves its references unresolved, which its dependent's plan reports
|
|
121
|
-
// if it needs them.
|
|
122
|
-
const deps = [
|
|
133
|
+
// if it needs them. A member of the dependent's own group plans with it.
|
|
134
|
+
const deps = [
|
|
135
|
+
...new Set(wave.flatMap((name) => (byName.get(name)?.dependsOn ?? []).filter((dep) => !groupOf.get(name)?.components.includes(dep)))),
|
|
136
|
+
].filter((dep) => !read.has(dep));
|
|
123
137
|
const fromEstate = [];
|
|
124
138
|
for (const dep of deps) {
|
|
125
139
|
read.add(dep);
|
|
@@ -134,26 +148,60 @@ export async function planPrSet(options) {
|
|
|
134
148
|
planned[dep] = Object.keys(known).sort();
|
|
135
149
|
}
|
|
136
150
|
Object.assign(deployed, await readDeployedOutputs(fromEstate, byName, options.registry, (dep) => deployContext(options, dep), outputs));
|
|
137
|
-
const
|
|
138
|
-
const at = { component: name, phase: PR_PLAN_PHASE, step: "plan" };
|
|
139
|
-
emit?.({ type: "step-start", ...at });
|
|
140
|
-
const start = Date.now();
|
|
141
|
-
const p = await planWaveComponent(byName.get(name), options.registry, deployContext(options, name), outputs);
|
|
151
|
+
const settle = (name, start, p) => {
|
|
142
152
|
emit?.({
|
|
143
153
|
type: "step-settle",
|
|
144
|
-
|
|
154
|
+
component: name,
|
|
155
|
+
phase: PR_PLAN_PHASE,
|
|
156
|
+
step: "plan",
|
|
145
157
|
status: "error" in p ? "failed" : "ok",
|
|
146
158
|
durationMs: Date.now() - start,
|
|
147
159
|
...("error" in p ? { error: p.error } : {}),
|
|
148
160
|
});
|
|
149
|
-
|
|
150
|
-
|
|
161
|
+
};
|
|
162
|
+
const groupsHere = [...new Set(wave.map((name) => groupOf.get(name)).filter((g) => g !== undefined))];
|
|
163
|
+
const results = (await Promise.all([
|
|
164
|
+
...wave
|
|
165
|
+
.filter((name) => !groupOf.has(name))
|
|
166
|
+
.map(async (name) => {
|
|
167
|
+
emit?.({ type: "step-start", component: name, phase: PR_PLAN_PHASE, step: "plan" });
|
|
168
|
+
const start = Date.now();
|
|
169
|
+
const p = await planWaveComponent(byName.get(name), options.registry, deployContext(options, name), outputs);
|
|
170
|
+
settle(name, start, p);
|
|
171
|
+
return [p];
|
|
172
|
+
}),
|
|
173
|
+
...groupsHere.map(async (group) => {
|
|
174
|
+
for (const name of group.components)
|
|
175
|
+
emit?.({ type: "step-start", component: name, phase: PR_PLAN_PHASE, step: "plan" });
|
|
176
|
+
const start = Date.now();
|
|
177
|
+
const g = await planComponentGroup({
|
|
178
|
+
group,
|
|
179
|
+
components: byName,
|
|
180
|
+
registry: options.registry,
|
|
181
|
+
env: options.env,
|
|
182
|
+
...(options.vars ? { vars: options.vars } : {}),
|
|
183
|
+
ctxOf: (name) => deployContext(options, name),
|
|
184
|
+
outputs,
|
|
185
|
+
});
|
|
186
|
+
for (const p of g.plans)
|
|
187
|
+
settle(p.component, start, p);
|
|
188
|
+
const error = g.plans.find((p) => "error" in p)?.error;
|
|
189
|
+
groups.push({ ...group, digest: g.digest ?? null, ...(error !== undefined ? { error } : {}), ...(g.run ? { run: g.run } : {}) });
|
|
190
|
+
return g.plans;
|
|
191
|
+
}),
|
|
192
|
+
])).flat();
|
|
193
|
+
/** What each member of a group planned to expose, for its group-mates' reads. */
|
|
194
|
+
const plannedHere = new Map(results.map((p) => [p.component, "error" in p ? undefined : p.outputs?.known]));
|
|
151
195
|
for (const p of results) {
|
|
152
196
|
const component = byName.get(p.component);
|
|
153
|
-
const
|
|
197
|
+
const group = groupOf.get(p.component);
|
|
198
|
+
const mates = group ? new Set(group.components) : undefined;
|
|
199
|
+
const unknown = unknownInputsOf(component, outputs, inChange, mates);
|
|
154
200
|
if (unknown.unknown.length > 0 || unknown.build.length > 0)
|
|
155
201
|
unknownOf.set(p.component, unknown);
|
|
156
|
-
|
|
202
|
+
// A read of a group-mate is known when that mate's plan knows it.
|
|
203
|
+
const readsView = group ? { ...outputs, ...Object.fromEntries(group.components.filter((c) => c !== p.component).map((c) => [c, { ...(plannedHere.get(c) ?? {}) }])) } : outputs;
|
|
204
|
+
const reads = readsOf(component, readsView);
|
|
157
205
|
if (reads.length > 0)
|
|
158
206
|
readsBy.set(p.component, reads);
|
|
159
207
|
if ("error" in p) {
|
|
@@ -195,12 +243,16 @@ export async function planPrSet(options) {
|
|
|
195
243
|
const sorted = (r) => Object.fromEntries(Object.entries(r).sort(([a], [b]) => a.localeCompare(b)));
|
|
196
244
|
const deployedOutputs = sorted(deployed);
|
|
197
245
|
const plannedOutputs = sorted(planned);
|
|
246
|
+
const at = new Map(options.plan.order.map((name, i) => [name, i]));
|
|
247
|
+
groups.sort((a, b) => (at.get(a.components[0]) ?? 0) - (at.get(b.components[0]) ?? 0));
|
|
198
248
|
return {
|
|
199
249
|
doc,
|
|
200
250
|
members,
|
|
201
251
|
plans,
|
|
202
252
|
outputs,
|
|
203
253
|
failed,
|
|
254
|
+
...(groups.length > 0 ? { groups } : {}),
|
|
255
|
+
...(options.plan.fallbacks?.length ? { fallbacks: options.plan.fallbacks } : {}),
|
|
204
256
|
...(Object.keys(shapes).length > 0 ? { shapes } : {}),
|
|
205
257
|
...(Object.keys(deployedOutputs).length > 0 ? { deployedOutputs } : {}),
|
|
206
258
|
...(Object.keys(plannedOutputs).length > 0 ? { plannedOutputs } : {}),
|
|
@@ -212,14 +264,17 @@ export async function planPrSet(options) {
|
|
|
212
264
|
* that upstream applies, each sorted. `build` are the published artifact
|
|
213
265
|
* identities a build in the change produces (`WiringReference.publish`):
|
|
214
266
|
* the build's provenance binds those, so they are never approved again.
|
|
215
|
-
* `unknown` are the rest.
|
|
267
|
+
* `unknown` are the rest. A reference to a member of `group`, the
|
|
268
|
+
* component's own group (ws-107), is neither: the group's apply computes it.
|
|
216
269
|
*/
|
|
217
|
-
function unknownInputsOf(component, outputs, inChange) {
|
|
270
|
+
function unknownInputsOf(component, outputs, inChange, group) {
|
|
218
271
|
const unknown = new Set();
|
|
219
272
|
const build = new Set();
|
|
220
273
|
for (const step of capabilitySteps(component.deploy)) {
|
|
221
274
|
const { kind: _kind, ...rest } = step;
|
|
222
275
|
for (const r of unresolvedWiringReferences(rest, outputs)) {
|
|
276
|
+
if (group?.has(r.source))
|
|
277
|
+
continue;
|
|
223
278
|
if (inChange.has(r.source))
|
|
224
279
|
(r.publish ? build : unknown).add(r.ref);
|
|
225
280
|
}
|
|
@@ -257,14 +312,16 @@ function readsOf(component, outputs) {
|
|
|
257
312
|
* stands (#3999): each reference its steps make that resolves to another
|
|
258
313
|
* value, said once. `undefined` when every one resolves as it did. A
|
|
259
314
|
* published artifact's identity from a build in `inChange` never holds a
|
|
260
|
-
* member back: the build's provenance binds it, not this approval.
|
|
315
|
+
* member back: the build's provenance binds it, not this approval. Nor
|
|
316
|
+
* does a reference to a member of `group`, the component's own group
|
|
317
|
+
* (ws-107), whose apply computes it.
|
|
261
318
|
*/
|
|
262
|
-
export function heldReason(component, read, now, inChange = new Set()) {
|
|
319
|
+
export function heldReason(component, read, now, inChange = new Set(), group = new Set()) {
|
|
263
320
|
const refs = new Set();
|
|
264
321
|
for (const step of capabilitySteps(component.deploy)) {
|
|
265
322
|
const { kind: _kind, ...rest } = step;
|
|
266
323
|
for (const r of movedWiringReferences(rest, read, now))
|
|
267
|
-
if (!(r.publish && inChange.has(r.source)))
|
|
324
|
+
if (!(r.publish && inChange.has(r.source)) && !group.has(r.source))
|
|
268
325
|
refs.add(r.ref);
|
|
269
326
|
}
|
|
270
327
|
if (refs.size === 0)
|
|
@@ -335,6 +392,10 @@ export function approversWhoAuthored(approvedBy, authors) {
|
|
|
335
392
|
function roundCover(options, fresh, plan, now, inChange, byName) {
|
|
336
393
|
if (options.approval?.status !== "approved")
|
|
337
394
|
return { covered: false, reason: "no approval of the first plan stands" };
|
|
395
|
+
// ws-107: a round's group is covered only when it has the approved group's members.
|
|
396
|
+
const moved = groupsMoved(options.set.groups ?? [], fresh.groups ?? [], plan.order);
|
|
397
|
+
if (moved)
|
|
398
|
+
return { covered: false, reason: moved };
|
|
338
399
|
// The values the round reads of a component it plans again are the ones
|
|
339
400
|
// that plan says it will expose: it has not applied yet, so the outputs
|
|
340
401
|
// standing say nothing of it. An output the first plan knew and the round's
|
|
@@ -358,15 +419,45 @@ function roundCover(options, fresh, plan, now, inChange, byName) {
|
|
|
358
419
|
}
|
|
359
420
|
changedKnown[name] = [...refs].sort();
|
|
360
421
|
}
|
|
422
|
+
// A member whose round plan still reads only outputs of components this
|
|
423
|
+
// round plans and has not applied (a chain of imports, #4466d) cannot apply
|
|
424
|
+
// in this round: it is held again once those apply, and its own round
|
|
425
|
+
// checks its coverage. Only the members this round can apply are checked.
|
|
426
|
+
const inRound = plan.order;
|
|
427
|
+
const fromRound = (ref) => inRound.some((c) => ref === c || ref.startsWith(`${c}.`));
|
|
428
|
+
const waits = (m) => (m.unknownInputs?.length ?? 0) > 0 && m.unknownInputs.every(fromRound);
|
|
361
429
|
const approved = { doc: options.set.doc, members: options.set.members, ...(options.set.shapes ? { shapes: options.set.shapes } : {}) };
|
|
362
430
|
return coveredRound({
|
|
363
431
|
approved,
|
|
364
432
|
approvedDigest: options.set.doc.digest,
|
|
365
|
-
fresh: { doc: fresh.doc, members: fresh.members, ...(fresh.shapes ? { shapes: fresh.shapes } : {}) },
|
|
433
|
+
fresh: { doc: fresh.doc, members: fresh.members.filter((m) => !waits(m)), ...(fresh.shapes ? { shapes: fresh.shapes } : {}) },
|
|
366
434
|
changedKnown,
|
|
367
435
|
attributes: (member) => memberAttributes(options.set.doc, fresh.doc, member, fresh.shapes?.[member] !== undefined),
|
|
368
436
|
});
|
|
369
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Why the groups `fresh` planned are not the `approved` ones over the
|
|
440
|
+
* components in `order` (ws-107), or `undefined` when each group the round
|
|
441
|
+
* plans has the members the approved group had.
|
|
442
|
+
*/
|
|
443
|
+
function groupsMoved(approved, fresh, order) {
|
|
444
|
+
const same = (a, b) => a.length === b.length && a.every((c) => b.includes(c));
|
|
445
|
+
const inRound = new Set(order);
|
|
446
|
+
for (const was of approved) {
|
|
447
|
+
const here = was.components.filter((c) => inRound.has(c));
|
|
448
|
+
if (here.length === 0)
|
|
449
|
+
continue;
|
|
450
|
+
const now = fresh.find((g) => g.components.includes(here[0]));
|
|
451
|
+
if (!now || !same(now.components, was.components)) {
|
|
452
|
+
return `the approved plan grouped ${was.components.join(", ")}, and the round ${now ? `groups ${now.components.join(", ")}` : `plans ${here.join(", ")} without that group`}`;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
for (const now of fresh) {
|
|
456
|
+
if (!approved.some((was) => same(was.components, now.components)))
|
|
457
|
+
return `the round groups ${now.components.join(", ")}, which the approved plan did not`;
|
|
458
|
+
}
|
|
459
|
+
return undefined;
|
|
460
|
+
}
|
|
370
461
|
/**
|
|
371
462
|
* The part of coverage that reads the change set's own attributes, shared by
|
|
372
463
|
* a round, a resume and a wave: a member whose planner describes no changes
|
|
@@ -397,6 +488,8 @@ function joinRuns(a, b) {
|
|
|
397
488
|
componentOutputs: b.componentOutputs,
|
|
398
489
|
...(gate ? { gate } : {}),
|
|
399
490
|
...(b.held ? { held: b.held } : {}),
|
|
491
|
+
...(a.notStarted || b.notStarted ? { notStarted: [...new Set([...(a.notStarted ?? []), ...(b.notStarted ?? [])])].sort() } : {}),
|
|
492
|
+
...(a.groupOutcomes || b.groupOutcomes ? { groupOutcomes: { ...(a.groupOutcomes ?? {}), ...(b.groupOutcomes ?? {}) } } : {}),
|
|
400
493
|
};
|
|
401
494
|
}
|
|
402
495
|
/**
|
|
@@ -419,18 +512,24 @@ export async function applyPrSet(options) {
|
|
|
419
512
|
...Object.fromEntries(Object.entries(options.set.outputs).filter(([name]) => !toApply.has(name))),
|
|
420
513
|
...(options.resumed?.outputs ?? {}),
|
|
421
514
|
};
|
|
422
|
-
const runRound = (plan,
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
515
|
+
const runRound = (plan, set, read, outputs) => {
|
|
516
|
+
// ws-107: each group runs the plan its group planned, and a read of a group-mate holds nothing back.
|
|
517
|
+
const groupOf = groupsByComponent(plan);
|
|
518
|
+
const groupRuns = Object.fromEntries((set.groups ?? []).filter((g) => g.run).map((g) => [g.components[0], g.run]));
|
|
519
|
+
return runFanOut(plan, options.components, options.registry, {
|
|
520
|
+
env: options.env,
|
|
521
|
+
...(options.vars ? { vars: options.vars } : {}),
|
|
522
|
+
plans: set.plans,
|
|
523
|
+
...(Object.keys(groupRuns).length > 0 ? { groupRuns } : {}),
|
|
524
|
+
...(options.targets ? { targets: options.targets } : {}),
|
|
525
|
+
componentOutputs: outputs,
|
|
526
|
+
hold: (name, now) => heldReason(byName.get(name), read, now, inChange, new Set(groupOf.get(name)?.components ?? [])),
|
|
527
|
+
...(options.onProgress ? { onProgress: options.onProgress } : {}),
|
|
528
|
+
...(options.onRunEvent ? { onRunEvent: options.onRunEvent } : {}),
|
|
529
|
+
...(options.onComponentSettled ? { onComponentSettled: options.onComponentSettled } : {}),
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
let run = await runRound(options.plan, options.set, options.set.outputs, { ...standing });
|
|
434
533
|
const rounds = [];
|
|
435
534
|
/** Per component, the round that applied it or holds it, and that round's set, after the first. */
|
|
436
535
|
const roundOf = new Map();
|
|
@@ -439,7 +538,8 @@ export async function applyPrSet(options) {
|
|
|
439
538
|
const round = rounds.length + 2;
|
|
440
539
|
const gate = prRoundGate(options.gate ?? PR_APPLY_GATE, round);
|
|
441
540
|
const heldNames = new Set(run.held.map((h) => h.component));
|
|
442
|
-
|
|
541
|
+
// A held group is planned again as the same group (ws-107).
|
|
542
|
+
const plan = narrowGroups(remainingFanOut(options.plan, options.components, { completed: options.plan.order.filter((name) => !heldNames.has(name)) }), options.components, options.plan.groups);
|
|
443
543
|
const set = await planPrSet({
|
|
444
544
|
components: options.components,
|
|
445
545
|
plan,
|
|
@@ -479,27 +579,35 @@ export async function applyPrSet(options) {
|
|
|
479
579
|
stopped = "waiting";
|
|
480
580
|
break;
|
|
481
581
|
}
|
|
482
|
-
const next = await runRound(plan, set
|
|
582
|
+
const next = await runRound(plan, set, set.outputs, run.componentOutputs);
|
|
483
583
|
record(next.status === "fail" ? "failed" : "applied", decision.approval, undefined, decision.covered);
|
|
484
584
|
run = joinRuns(run, next);
|
|
485
585
|
}
|
|
486
586
|
const completed = new Set(run.completed);
|
|
587
|
+
const notStarted = new Set(run.notStarted ?? []);
|
|
487
588
|
const held = new Map((run.held ?? []).map((h) => [h.component, h]));
|
|
488
589
|
const blocked = new Map(run.blocked.map((b) => [b.component, b.blockedBy]));
|
|
489
590
|
const errorOf = (component) => {
|
|
490
591
|
const result = [...run.results].reverse().find((r) => r.component === component);
|
|
491
592
|
if (result?.status === "gated")
|
|
492
593
|
return `stopped at its own gate ${result.gate?.gate ?? ""}`.trim();
|
|
493
|
-
return result?.records.find((r) => r.status === "fail")?.error;
|
|
594
|
+
return result?.records.find((r) => r.status === "fail" || (notStarted.has(component) && r.status === "skipped"))?.error;
|
|
494
595
|
};
|
|
495
596
|
const members = options.set.members.map((m) => {
|
|
496
597
|
if (priorCompleted.has(m.component))
|
|
497
598
|
return { ...m, status: "applied" };
|
|
498
599
|
const later = roundOf.get(m.component);
|
|
499
600
|
const fresh = later?.set.members.find((x) => x.member === m.member);
|
|
500
|
-
const
|
|
601
|
+
const planned = later && fresh ? { ...m, planDigest: fresh.planDigest, counts: fresh.counts, round: later.round } : m;
|
|
602
|
+
// #4446: how its part of a group's apply ended, as the capability said.
|
|
603
|
+
const groupOutcome = run.groupOutcomes?.[m.component];
|
|
604
|
+
const asPlanned = groupOutcome ? { ...planned, groupOutcome } : planned;
|
|
501
605
|
if (completed.has(m.component))
|
|
502
606
|
return { ...asPlanned, status: "applied" };
|
|
607
|
+
if (notStarted.has(m.component)) {
|
|
608
|
+
const error = errorOf(m.component);
|
|
609
|
+
return { ...asPlanned, status: "not-started", ...(error ? { error } : {}) };
|
|
610
|
+
}
|
|
503
611
|
const h = held.get(m.component);
|
|
504
612
|
if (h)
|
|
505
613
|
return { ...asPlanned, status: "waiting", held: h.heldBy ? `${h.heldBy} is held: ${h.reason}` : h.reason };
|
|
@@ -614,20 +722,42 @@ export function planCoveredBy(approved, fresh, member) {
|
|
|
614
722
|
* is `record.digest`, and the document gives that digest. The digest binds
|
|
615
723
|
* the entries, holes and side effects {@link planCoveredBy} reads (#3555),
|
|
616
724
|
* so a record cannot widen what a re-planned member may do.
|
|
725
|
+
*
|
|
726
|
+
* A group that failed part way (ws-107, "Resume"; #4446) leaves its
|
|
727
|
+
* `partial`, `failed` and `not-started` members; `applied` and `no-changes`
|
|
728
|
+
* ones are in `completed`. What is left of each approved group is grouped
|
|
729
|
+
* again ({@link regroupRemaining}), so it plans as a smaller group, or one
|
|
730
|
+
* by one when the rule or the capability says so. The smaller group's
|
|
731
|
+
* digest differs from the approved one, so coverage rests on entries and
|
|
732
|
+
* shapes, as for any resumed member.
|
|
617
733
|
*/
|
|
618
734
|
export async function resumePrSet(options) {
|
|
619
735
|
const { record } = options;
|
|
620
736
|
if (record.changeSet.digest !== record.digest || !verifyChangeSetDigest(record.changeSet)) {
|
|
621
737
|
return { ok: false, reasons: [`the record's change set is not the one its digest ${record.digest} names`] };
|
|
622
738
|
}
|
|
623
|
-
const plan =
|
|
739
|
+
const plan = await regroupRemaining({
|
|
740
|
+
components: options.components,
|
|
741
|
+
plan: remainingFanOut(options.plan, options.components, { completed: options.completed }),
|
|
742
|
+
registry: options.registry,
|
|
743
|
+
env: options.env,
|
|
744
|
+
...(options.vars ? { vars: options.vars } : {}),
|
|
745
|
+
groups: options.plan.groups,
|
|
746
|
+
...(options.plan.fallbacks ? { fallbacks: options.plan.fallbacks } : {}),
|
|
747
|
+
});
|
|
748
|
+
// The outputs of the applied members of a group with members left: the values the group's apply computed.
|
|
749
|
+
const left = new Set(plan.order);
|
|
750
|
+
const fromGroup = Object.fromEntries((options.plan.groups ?? [])
|
|
751
|
+
.filter((g) => g.components.some((c) => left.has(c)))
|
|
752
|
+
.flatMap((g) => g.components.filter((c) => !left.has(c) && options.applied?.[c] !== undefined))
|
|
753
|
+
.map((c) => [c, options.applied[c]]));
|
|
624
754
|
const fresh = await planPrSet({
|
|
625
755
|
components: options.components,
|
|
626
756
|
plan,
|
|
627
757
|
registry: options.registry,
|
|
628
758
|
env: options.env,
|
|
629
759
|
...(options.vars ? { vars: options.vars } : {}),
|
|
630
|
-
seededOutputs: { ...(options.seededOutputs ?? {}), ...options.record.planOutputs },
|
|
760
|
+
seededOutputs: { ...(options.seededOutputs ?? {}), ...options.record.planOutputs, ...fromGroup },
|
|
631
761
|
...(options.targets ? { targets: options.targets } : {}),
|
|
632
762
|
});
|
|
633
763
|
// #4422: decided as a round decides (`coveredRound`), by the same function a wave uses.
|
|
@@ -642,7 +772,9 @@ export async function resumePrSet(options) {
|
|
|
642
772
|
doc: options.record.changeSet,
|
|
643
773
|
members: options.record.members.map((m) => ({ ...m, status: "planned" })),
|
|
644
774
|
plans: fresh.plans,
|
|
645
|
-
outputs: options.record.planOutputs,
|
|
775
|
+
outputs: { ...options.record.planOutputs, ...fromGroup },
|
|
776
|
+
...(fresh.groups ? { groups: fresh.groups } : {}),
|
|
777
|
+
...(fresh.fallbacks ? { fallbacks: fresh.fallbacks } : {}),
|
|
646
778
|
failed: false,
|
|
647
779
|
},
|
|
648
780
|
};
|
|
@@ -661,7 +793,17 @@ export function prWavePlan(plan, components, wave, completed = []) {
|
|
|
661
793
|
const seeds = [
|
|
662
794
|
...new Set([...plan.seeds, ...order.flatMap((name) => (byName.get(name)?.dependsOn ?? []).filter((dep) => !inWave.has(dep)))]),
|
|
663
795
|
].sort();
|
|
664
|
-
|
|
796
|
+
// ws-107: a group sits in one wave, so what is left of it plans and applies as one there.
|
|
797
|
+
const groups = (plan.groups ?? []).map((g) => ({ ...g, components: g.components.filter((c) => inWave.has(c)) })).filter((g) => g.components.length > 1);
|
|
798
|
+
return {
|
|
799
|
+
order,
|
|
800
|
+
waves: order.length > 0 ? [order] : [],
|
|
801
|
+
skipped: [],
|
|
802
|
+
seeds,
|
|
803
|
+
indeterminate: plan.indeterminate,
|
|
804
|
+
digest: plan.digest,
|
|
805
|
+
...(groups.length > 0 ? { groups } : {}),
|
|
806
|
+
};
|
|
665
807
|
}
|
|
666
808
|
/**
|
|
667
809
|
* Why the approved change set does not cover a wave's new plan, one line per
|
|
@@ -713,9 +855,35 @@ export function waveNotCovered(approved, fresh, approvedMembers = [], shapes = {
|
|
|
713
855
|
})
|
|
714
856
|
.filter((r) => r !== undefined);
|
|
715
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
* The report's `groups` (#4446): each group the set planned, with the wave
|
|
860
|
+
* of `waves` its members sit in and the reads of group-mates its members'
|
|
861
|
+
* change-set parts name, which the group's apply computes.
|
|
862
|
+
*/
|
|
863
|
+
function reportGroups(set, waves) {
|
|
864
|
+
const componentOf = new Map(set.members.map((m) => [m.member, m.component]));
|
|
865
|
+
return (set.groups ?? []).map((g) => {
|
|
866
|
+
const wave = waves.findIndex((w) => g.components.some((c) => w.includes(c))) + 1;
|
|
867
|
+
const reads = set.doc.members
|
|
868
|
+
.filter((m) => g.components.includes(componentOf.get(m.member) ?? m.member))
|
|
869
|
+
.flatMap((m) => (m.group?.reads ?? []).map((ref) => ({ component: componentOf.get(m.member) ?? m.member, ref })))
|
|
870
|
+
.sort((a, b) => a.component.localeCompare(b.component) || a.ref.localeCompare(b.ref));
|
|
871
|
+
return {
|
|
872
|
+
capability: g.capability,
|
|
873
|
+
components: [...g.components],
|
|
874
|
+
wave: wave > 0 ? wave : 1,
|
|
875
|
+
digest: g.digest,
|
|
876
|
+
...(g.error !== undefined ? { error: g.error } : {}),
|
|
877
|
+
...(reads.length > 0 ? { reads } : {}),
|
|
878
|
+
};
|
|
879
|
+
});
|
|
880
|
+
}
|
|
716
881
|
/** The report a stage writes. */
|
|
717
882
|
export function prReport(input) {
|
|
718
883
|
const changed = new Set(input.signal.changed);
|
|
884
|
+
const groups = reportGroups(input.set, input.plan.waves);
|
|
885
|
+
const groupOf = new Map(groups.flatMap((g, i) => g.components.map((c) => [c, i])));
|
|
886
|
+
const members = (input.members ?? input.set.members).map((m) => (groupOf.has(m.component) ? { ...m, group: groupOf.get(m.component) } : m));
|
|
719
887
|
return {
|
|
720
888
|
$schema: PR_REPORT_SCHEMA_ID,
|
|
721
889
|
contract: PR_REPORT_CONTRACT,
|
|
@@ -746,7 +914,9 @@ export function prReport(input) {
|
|
|
746
914
|
indeterminate: input.plan.indeterminate,
|
|
747
915
|
waves: input.plan.waves,
|
|
748
916
|
},
|
|
749
|
-
|
|
917
|
+
...(groups.length > 0 ? { groups } : {}),
|
|
918
|
+
...(input.set.fallbacks?.length ? { fallbacks: input.set.fallbacks.map((f) => ({ ...f })) } : {}),
|
|
919
|
+
members,
|
|
750
920
|
changeSet: input.set.doc,
|
|
751
921
|
};
|
|
752
922
|
}
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
* A stage whose components declare no gate has nowhere to wait, so the
|
|
23
23
|
* promote stops there with nothing more deployed.
|
|
24
24
|
*
|
|
25
|
+
* - **Groups** (ws-107, #4465). With `grouped`, the waves are the grouped
|
|
26
|
+
* fan-out's, so each group sits in one wave and is checked, planned again
|
|
27
|
+
* and run as one: when any member's input moved, every member left of the
|
|
28
|
+
* group is planned again with it. Under `--wave-gate` no group forms
|
|
29
|
+
* (`formRunGroups`), so there is none here.
|
|
30
|
+
*
|
|
25
31
|
* A promote that stops at a round's or a wave's gate writes a resume record
|
|
26
32
|
* ({@link PromoteResume}): the components that applied and the outputs they
|
|
27
33
|
* left. The same promote run again with it skips what applied and carries on
|
|
@@ -31,6 +37,7 @@
|
|
|
31
37
|
import { type DriverComponent, type DriverRunResult, type ReleaseGateBinding } from "./driver.js";
|
|
32
38
|
import type { ChangeSetDocument } from "../change-set.js";
|
|
33
39
|
import type { ReleasePlan } from "./release-gate.js";
|
|
40
|
+
import type { FanOutPlan } from "./fan-out.js";
|
|
34
41
|
export declare const PROMOTE_RESUME_SCHEMA = "chant-promote-resume/v1";
|
|
35
42
|
/** What a promote that stopped at a round's or a wave's gate leaves for the next attempt. */
|
|
36
43
|
export interface PromoteResume {
|
|
@@ -80,6 +87,8 @@ export interface PromoteRoundsOptions {
|
|
|
80
87
|
replan: (only: ReadonlySet<string>, outputs: Record<string, Record<string, unknown>>) => Promise<ChangeSetDocument>;
|
|
81
88
|
/** Store a stage's plan and bind its gates (empty resolutions included). */
|
|
82
89
|
bind: (doc: ChangeSetDocument, gates: string[]) => Promise<ReleaseGateBinding>;
|
|
90
|
+
/** The grouped fan-out (#4465): its waves replace the ones `dependsOn` gives, and each group is checked as one. */
|
|
91
|
+
grouped?: FanOutPlan;
|
|
83
92
|
}
|
|
84
93
|
export interface PromoteRoundsResult {
|
|
85
94
|
run: DriverRunResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promote-rounds.d.ts","sourceRoot":"","sources":["../../src/components/promote-rounds.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"promote-rounds.d.ts","sourceRoot":"","sources":["../../src/components/promote-rounds.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
* A stage whose components declare no gate has nowhere to wait, so the
|
|
23
23
|
* promote stops there with nothing more deployed.
|
|
24
24
|
*
|
|
25
|
+
* - **Groups** (ws-107, #4465). With `grouped`, the waves are the grouped
|
|
26
|
+
* fan-out's, so each group sits in one wave and is checked, planned again
|
|
27
|
+
* and run as one: when any member's input moved, every member left of the
|
|
28
|
+
* group is planned again with it. Under `--wave-gate` no group forms
|
|
29
|
+
* (`formRunGroups`), so there is none here.
|
|
30
|
+
*
|
|
25
31
|
* A promote that stops at a round's or a wave's gate writes a resume record
|
|
26
32
|
* ({@link PromoteResume}): the components that applied and the outputs they
|
|
27
33
|
* left. The same promote run again with it skips what applied and carries on
|
|
@@ -34,6 +40,7 @@ import { waveNotCovered } from "./pr-run.js";
|
|
|
34
40
|
import { prRoundGate } from "../pr-loop.js";
|
|
35
41
|
import { waveGateName } from "../gated-waves.js";
|
|
36
42
|
import { capabilitySteps } from "./wave-plan.js";
|
|
43
|
+
import { groupsByComponent } from "./groups.js";
|
|
37
44
|
export const PROMOTE_RESUME_SCHEMA = "chant-promote-resume/v1";
|
|
38
45
|
function isGate(step) {
|
|
39
46
|
return step.kind === "gate";
|
|
@@ -107,7 +114,18 @@ function joinRuns(runs, outputs) {
|
|
|
107
114
|
*/
|
|
108
115
|
export async function runPromotionInRounds(options) {
|
|
109
116
|
const byName = new Map(options.components.map((c) => [c.name, c]));
|
|
110
|
-
const
|
|
117
|
+
const grouped = options.grouped?.groups?.length ? options.grouped : undefined;
|
|
118
|
+
const placed = new Set(grouped?.order ?? []);
|
|
119
|
+
// A grouped fan-out over what a resume left holds no wave for what applied earlier; that is skipped anyway.
|
|
120
|
+
const waves = grouped
|
|
121
|
+
? grouped.waves.map((w) => w.filter((name) => byName.has(name)))
|
|
122
|
+
: resolveComponentGraph(options.components.map((c) => ({ ...c, dependsOn: (c.dependsOn ?? []).filter((d) => byName.has(d)) }))).waves;
|
|
123
|
+
if (grouped) {
|
|
124
|
+
const missing = options.components.filter((c) => !placed.has(c.name) && !(options.completed ?? []).includes(c.name)).map((c) => c.name);
|
|
125
|
+
if (missing.length > 0)
|
|
126
|
+
throw new Error(`the grouped waves leave out ${missing.join(", ")}, which this promote runs`);
|
|
127
|
+
}
|
|
128
|
+
const groupOf = grouped ? groupsByComponent(grouped) : new Map();
|
|
111
129
|
const completed = [...(options.completed ?? [])];
|
|
112
130
|
const done = new Set(completed);
|
|
113
131
|
let outputs = { ...options.outputs };
|
|
@@ -119,9 +137,12 @@ export async function runPromotionInRounds(options) {
|
|
|
119
137
|
const pending = wave.filter((name) => !done.has(name));
|
|
120
138
|
if (pending.length === 0)
|
|
121
139
|
continue;
|
|
122
|
-
const
|
|
140
|
+
const moved = options.waveGate !== undefined && waveNumber > 1
|
|
123
141
|
? pending
|
|
124
142
|
: pending.filter((name) => movedInputs(byName.get(name), options.reads[name], outputs).length > 0);
|
|
143
|
+
// A group is planned again as one: a member whose input moved takes the rest of its group with it.
|
|
144
|
+
const withMates = new Set(moved.flatMap((name) => [name, ...(groupOf.get(name)?.components ?? [])]));
|
|
145
|
+
const check = pending.filter((name) => withMates.has(name));
|
|
125
146
|
const batches = [];
|
|
126
147
|
const rest = pending.filter((name) => !check.includes(name));
|
|
127
148
|
if (check.length > 0) {
|
|
@@ -41,6 +41,8 @@ import { type ReleaseRecord, type ReleaseRecordInput, type ReleaseAdmission, typ
|
|
|
41
41
|
import { CapabilityRegistry, type Capability } from "./capability.js";
|
|
42
42
|
import { type DriverComponent, type DriverComponentResult, type ReleaseGateBinding, type DriverRunResult } from "./driver.js";
|
|
43
43
|
import type { GateLedgerPort } from "../op/gate.js";
|
|
44
|
+
import type { GroupRun } from "./capability.js";
|
|
45
|
+
import type { FanOutPlan } from "./fan-out.js";
|
|
44
46
|
import type { Release } from "../lifecycle/release-store.js";
|
|
45
47
|
import type { RunProgressEvent } from "./run-progress.js";
|
|
46
48
|
import type { RunEventSink } from "../run-event-stream.js";
|
|
@@ -253,6 +255,21 @@ export interface RunPromotionOptions {
|
|
|
253
255
|
onProgress?: (event: RunProgressEvent) => void;
|
|
254
256
|
/** Where the run's events go (#4041, `--events-json`). */
|
|
255
257
|
onRunEvent?: RunEventSink;
|
|
258
|
+
/**
|
|
259
|
+
* The grouped fan-out (ws-107, #4465, `formRunGroups`): each of its groups
|
|
260
|
+
* applies as one, in the wave it places it in. Absent, or without
|
|
261
|
+
* `groups`: every component runs its own deploy, as before.
|
|
262
|
+
*/
|
|
263
|
+
grouped?: FanOutPlan;
|
|
264
|
+
/**
|
|
265
|
+
* The approved plan of each group, as the release gate's plan made it
|
|
266
|
+
* (`ReleasePlan.groups`). A group runs the one whose members are its own;
|
|
267
|
+
* the newest first. A group with none plans in its wave and applies only
|
|
268
|
+
* under `planGroupsAtWave`, and fails otherwise.
|
|
269
|
+
*/
|
|
270
|
+
groupRuns?: readonly GroupRun[];
|
|
271
|
+
/** A promote with no release gate to bind plans each group in its wave (#4465). */
|
|
272
|
+
planGroupsAtWave?: boolean;
|
|
256
273
|
}
|
|
257
274
|
/**
|
|
258
275
|
* Deploy the plan's components to `plan.to`, in dependency order. A
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promote.d.ts","sourceRoot":"","sources":["../../src/components/promote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,EAAqC,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACpK,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"promote.d.ts","sourceRoot":"","sources":["../../src/components/promote.ts"],"names":[],"mappings":"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"}
|