@intentius/chant 0.124.27 → 0.124.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/__golden__/wave-loop/fan-out-gated.json +8 -0
- package/dist/__golden__/wave-loop/fan-out-no-members.json +4 -0
- package/dist/__golden__/wave-loop/fan-out-only.json +6 -0
- package/dist/__golden__/wave-loop/op-by-apply-hold.json +2 -0
- package/dist/__golden__/wave-loop/op-cost-member.json +3 -0
- package/dist/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
- package/dist/__golden__/wave-loop/op-held-on.json +2 -0
- package/dist/__golden__/wave-loop/op-hooks-held.json +2 -0
- package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
- package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
- package/dist/__golden__/wave-loop/op-hooks-share.json +3 -0
- package/dist/__golden__/wave-loop/op-per-run.json +7 -0
- package/dist/__golden__/wave-loop/op-pr-review.json +7 -0
- package/dist/__golden__/wave-loop/op-sealed.json +3 -0
- package/dist/__golden__/wave-loop/op-spend.json +3 -0
- package/dist/__golden__/wave-loop/op-wave-commands.json +7 -0
- package/dist/__golden__/wave-loop/op-wide-waiting.json +4 -0
- package/dist/build-params.d.ts +34 -1
- package/dist/build-params.d.ts.map +1 -1
- package/dist/build-params.js +31 -1
- package/dist/change-set-graph.d.ts +63 -0
- package/dist/change-set-graph.d.ts.map +1 -0
- package/dist/change-set-graph.js +130 -0
- package/dist/change-set.d.ts +62 -3
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +36 -4
- package/dist/chant-version.d.ts +9 -0
- package/dist/chant-version.d.ts.map +1 -0
- package/dist/chant-version.js +16 -0
- package/dist/cli/build-params-cli.d.ts +7 -1
- package/dist/cli/build-params-cli.d.ts.map +1 -1
- package/dist/cli/build-params-cli.js +17 -8
- package/dist/cli/commands/build.d.ts +8 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +15 -11
- package/dist/cli/commands/check-lexicon-docs.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.js +30 -2
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.js +13 -2
- package/dist/cli/commands/init-lexicon/templates/docs.d.ts +4 -1
- package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/docs.js +6 -6
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.js +17 -8
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +64 -4
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +43 -4
- package/dist/cli/handlers/change-set.d.ts +10 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.js +51 -1
- package/dist/cli/handlers/fan-out.d.ts +10 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +54 -6
- package/dist/cli/handlers/lifecycle-gc.d.ts +19 -0
- package/dist/cli/handlers/lifecycle-gc.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-gc.js +143 -0
- package/dist/cli/handlers/pr.d.ts +16 -2
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +269 -37
- package/dist/cli/handlers/promote.d.ts +7 -0
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +440 -28
- package/dist/cli/handlers/release.d.ts +91 -0
- package/dist/cli/handlers/release.d.ts.map +1 -0
- package/dist/cli/handlers/release.js +589 -0
- package/dist/cli/handlers/run.d.ts +38 -2
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +234 -16
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +143 -17
- 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 +73 -5
- package/dist/cli/registry.d.ts +43 -5
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/run-events.d.ts +30 -0
- package/dist/cli/run-events.d.ts.map +1 -0
- package/dist/cli/run-events.js +49 -0
- package/dist/cli/version.d.ts +3 -5
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +3 -13
- package/dist/codegen/docs-in-site.d.ts +71 -0
- package/dist/codegen/docs-in-site.d.ts.map +1 -0
- package/dist/codegen/docs-in-site.js +177 -0
- package/dist/codegen/docs-types.d.ts +14 -1
- package/dist/codegen/docs-types.d.ts.map +1 -1
- package/dist/codegen/docs.d.ts +18 -1
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/docs.js +40 -7
- package/dist/codegen/rehype-base-url.mjs +15 -9
- package/dist/components/auto-release.d.ts +6 -1
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/auto-release.js +3 -0
- package/dist/components/capability.d.ts +9 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +6 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/cli-support.js +10 -9
- package/dist/components/driver.d.ts +50 -9
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +116 -54
- package/dist/components/fan-out-inputs.d.ts +69 -0
- package/dist/components/fan-out-inputs.d.ts.map +1 -0
- package/dist/components/fan-out-inputs.js +169 -0
- package/dist/components/fan-out-record.d.ts +13 -0
- package/dist/components/fan-out-record.d.ts.map +1 -1
- package/dist/components/fan-out-record.js +16 -0
- package/dist/components/fan-out-run.d.ts +7 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-run.js +85 -26
- package/dist/components/fan-out.d.ts +4 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/pr-pipeline.d.ts +25 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +22 -4
- package/dist/components/pr-run.d.ts +11 -0
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +20 -1
- package/dist/components/promote-order.d.ts +38 -0
- package/dist/components/promote-order.d.ts.map +1 -0
- package/dist/components/promote-order.js +62 -0
- package/dist/components/promote.d.ts +38 -2
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +77 -2
- package/dist/components/release-compile.d.ts +142 -0
- package/dist/components/release-compile.d.ts.map +1 -0
- package/dist/components/release-compile.js +382 -0
- package/dist/components/release-gate.d.ts +135 -0
- package/dist/components/release-gate.d.ts.map +1 -0
- package/dist/components/release-gate.js +288 -0
- package/dist/components/release-promote.d.ts +96 -0
- package/dist/components/release-promote.d.ts.map +1 -0
- package/dist/components/release-promote.js +204 -0
- package/dist/components/run-progress.d.ts +7 -0
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/wave-plan.d.ts +8 -1
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +11 -3
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/flag-params.d.ts +54 -0
- package/dist/flag-params.d.ts.map +1 -0
- package/dist/flag-params.js +130 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +120 -0
- package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -0
- package/dist/lifecycle/__fixtures__/publish-fakes.js +304 -0
- package/dist/lifecycle/change-set-store.d.ts +68 -0
- package/dist/lifecycle/change-set-store.d.ts.map +1 -0
- package/dist/lifecycle/change-set-store.js +97 -0
- package/dist/lifecycle/commit-sha.d.ts +13 -0
- package/dist/lifecycle/commit-sha.d.ts.map +1 -0
- package/dist/lifecycle/commit-sha.js +21 -0
- package/dist/lifecycle/delivery-metrics.d.ts +139 -0
- package/dist/lifecycle/delivery-metrics.d.ts.map +1 -0
- package/dist/lifecycle/delivery-metrics.js +145 -0
- package/dist/lifecycle/deploy-outcome.d.ts +81 -0
- package/dist/lifecycle/deploy-outcome.d.ts.map +1 -0
- package/dist/lifecycle/deploy-outcome.js +101 -0
- package/dist/lifecycle/gate-change-set.d.ts +78 -0
- package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
- package/dist/lifecycle/gate-change-set.js +138 -0
- package/dist/lifecycle/gate-ledger.d.ts +51 -4
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +18 -0
- package/dist/lifecycle/git.d.ts +30 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/git.js +31 -5
- 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/mixed-environment.d.ts +95 -0
- package/dist/lifecycle/mixed-environment.d.ts.map +1 -0
- package/dist/lifecycle/mixed-environment.js +154 -0
- package/dist/lifecycle/publish-attachments.d.ts +79 -0
- package/dist/lifecycle/publish-attachments.d.ts.map +1 -0
- package/dist/lifecycle/publish-attachments.js +179 -0
- package/dist/lifecycle/publish-credentials.d.ts +37 -0
- package/dist/lifecycle/publish-credentials.d.ts.map +1 -0
- package/dist/lifecycle/publish-credentials.js +69 -0
- package/dist/lifecycle/publish-declaration.d.ts +97 -0
- package/dist/lifecycle/publish-declaration.d.ts.map +1 -0
- package/dist/lifecycle/publish-declaration.js +83 -0
- package/dist/lifecycle/publish-forge.d.ts +53 -0
- package/dist/lifecycle/publish-forge.d.ts.map +1 -0
- package/dist/lifecycle/publish-forge.js +298 -0
- package/dist/lifecycle/publish-npm.d.ts +61 -0
- package/dist/lifecycle/publish-npm.d.ts.map +1 -0
- package/dist/lifecycle/publish-npm.js +242 -0
- package/dist/lifecycle/publish-oci.d.ts +64 -0
- package/dist/lifecycle/publish-oci.d.ts.map +1 -0
- package/dist/lifecycle/publish-oci.js +383 -0
- package/dist/lifecycle/publish-record.d.ts +66 -0
- package/dist/lifecycle/publish-record.d.ts.map +1 -0
- package/dist/lifecycle/publish-record.js +84 -0
- package/dist/lifecycle/publish-targets.d.ts +45 -0
- package/dist/lifecycle/publish-targets.d.ts.map +1 -0
- package/dist/lifecycle/publish-targets.js +85 -0
- package/dist/lifecycle/release-cut.d.ts +154 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -0
- package/dist/lifecycle/release-cut.js +366 -0
- package/dist/lifecycle/release-join.d.ts +95 -0
- package/dist/lifecycle/release-join.d.ts.map +1 -0
- package/dist/lifecycle/release-join.js +139 -0
- package/dist/lifecycle/release-ledger.d.ts +54 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.js +53 -20
- package/dist/lifecycle/release-publish.d.ts +312 -0
- package/dist/lifecycle/release-publish.d.ts.map +1 -0
- package/dist/lifecycle/release-publish.js +335 -0
- package/dist/lifecycle/release-revocation.d.ts +80 -0
- package/dist/lifecycle/release-revocation.d.ts.map +1 -0
- package/dist/lifecycle/release-revocation.js +123 -0
- package/dist/lifecycle/release-store.d.ts +200 -0
- package/dist/lifecycle/release-store.d.ts.map +1 -0
- package/dist/lifecycle/release-store.js +320 -0
- package/dist/lifecycle/release-verify.d.ts +61 -0
- package/dist/lifecycle/release-verify.d.ts.map +1 -0
- package/dist/lifecycle/release-verify.js +92 -0
- package/dist/lifecycle/release-workstation.d.ts +91 -0
- package/dist/lifecycle/release-workstation.d.ts.map +1 -0
- package/dist/lifecycle/release-workstation.js +180 -0
- package/dist/lifecycle/retention-policy.d.ts +45 -0
- package/dist/lifecycle/retention-policy.d.ts.map +1 -0
- package/dist/lifecycle/retention-policy.js +43 -0
- package/dist/lifecycle/retention.d.ts +185 -0
- package/dist/lifecycle/retention.d.ts.map +1 -0
- package/dist/lifecycle/retention.js +400 -0
- package/dist/lifecycle/run-ledger.d.ts +4 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +2 -0
- package/dist/op/activities/change-coverage.d.ts.map +1 -1
- package/dist/op/activities/change-coverage.js +4 -2
- package/dist/op/activities/source-release.d.ts.map +1 -1
- package/dist/op/activities/source-release.js +7 -3
- package/dist/op/activities/source-rollback.d.ts.map +1 -1
- package/dist/op/activities/source-rollback.js +7 -3
- package/dist/op/gate-name.d.ts +11 -2
- package/dist/op/gate-name.d.ts.map +1 -1
- package/dist/op/gate-name.js +12 -3
- package/dist/op/gate-run-locator.d.ts +22 -0
- package/dist/op/gate-run-locator.d.ts.map +1 -1
- package/dist/op/gate-run-locator.js +31 -0
- package/dist/op/gate.d.ts +27 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +57 -3
- package/dist/op/local-executor.d.ts +36 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +158 -52
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +4 -0
- package/dist/op/run-live.d.ts +2 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/run-live.js +1 -1
- package/dist/op/runtime.d.ts +46 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/runtimes/local.js +8 -0
- package/dist/plan-summary.d.ts.map +1 -1
- package/dist/plan-summary.js +8 -2
- package/dist/point-decision.d.ts +2 -0
- package/dist/point-decision.d.ts.map +1 -1
- package/dist/point-decision.js +9 -2
- package/dist/pr-loop.d.ts +7 -0
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +23 -4
- package/dist/pr-report-url.d.ts +82 -0
- package/dist/pr-report-url.d.ts.map +1 -0
- package/dist/pr-report-url.js +174 -0
- package/dist/provenance.d.ts +2 -2
- package/dist/provenance.d.ts.map +1 -1
- package/dist/run-event-store.d.ts +104 -0
- package/dist/run-event-store.d.ts.map +1 -0
- package/dist/run-event-store.js +251 -0
- package/dist/run-event-stream.d.ts +133 -0
- package/dist/run-event-stream.d.ts.map +1 -0
- package/dist/run-event-stream.js +242 -0
- package/dist/run-event.d.ts +285 -0
- package/dist/run-event.d.ts.map +1 -0
- package/dist/run-event.js +209 -0
- package/dist/wave-runtime.mjs +262 -226
- package/dist/workspace/__fixtures__/flag-workspace.d.ts +31 -0
- package/dist/workspace/__fixtures__/flag-workspace.d.ts.map +1 -0
- package/dist/workspace/__fixtures__/flag-workspace.js +114 -0
- package/dist/workspace/__fixtures__/run-event-check.d.ts +19 -0
- package/dist/workspace/__fixtures__/run-event-check.d.ts.map +1 -0
- package/dist/workspace/__fixtures__/run-event-check.js +59 -0
- package/dist/workspace/change-set-show.d.ts +56 -0
- package/dist/workspace/change-set-show.d.ts.map +1 -0
- package/dist/workspace/change-set-show.js +54 -0
- package/dist/workspace/change-set-show.schema.json +102 -0
- package/dist/workspace/change-set.schema.json +32 -1
- package/dist/workspace/changes-cli.d.ts.map +1 -1
- package/dist/workspace/changes-cli.js +10 -1
- package/dist/workspace/changes.d.ts +37 -0
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/changes.js +49 -2
- package/dist/workspace/changes.schema.json +135 -0
- package/dist/workspace/check.schema.json +4 -2
- package/dist/workspace/checks/records.d.ts +9 -1
- package/dist/workspace/checks/records.d.ts.map +1 -1
- package/dist/workspace/checks/records.js +35 -1
- package/dist/workspace/checks.d.ts +1 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +2 -1
- package/dist/workspace/ci-green-cli.d.ts +19 -4
- package/dist/workspace/ci-green-cli.d.ts.map +1 -1
- package/dist/workspace/ci-green-cli.js +75 -12
- package/dist/workspace/ci-green-forge.d.ts +20 -3
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green-forge.js +6 -4
- package/dist/workspace/ci-green-workflow.d.ts +11 -0
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +6 -0
- package/dist/workspace/ci-green.d.ts +281 -13
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +456 -38
- package/dist/workspace/ci-last-green.schema.json +32 -2
- package/dist/workspace/ci-list.schema.json +525 -0
- package/dist/workspace/commit-links.d.ts +85 -0
- package/dist/workspace/commit-links.d.ts.map +1 -0
- package/dist/workspace/commit-links.js +163 -0
- package/dist/workspace/declaration.d.ts +35 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +27 -1
- package/dist/workspace/declaration.schema.json +76 -0
- package/dist/workspace/declared-kinds.d.ts +16 -0
- package/dist/workspace/declared-kinds.d.ts.map +1 -1
- package/dist/workspace/declared-kinds.js +25 -0
- package/dist/workspace/delivery-metrics.d.ts +91 -0
- package/dist/workspace/delivery-metrics.d.ts.map +1 -0
- package/dist/workspace/delivery-metrics.js +217 -0
- package/dist/workspace/delivery-metrics.schema.json +519 -0
- package/dist/workspace/flags-read.d.ts +37 -0
- package/dist/workspace/flags-read.d.ts.map +1 -0
- package/dist/workspace/flags-read.js +103 -0
- package/dist/workspace/flags.d.ts +100 -0
- package/dist/workspace/flags.d.ts.map +1 -0
- package/dist/workspace/flags.js +98 -0
- package/dist/workspace/graph-cli.js +1 -1
- package/dist/workspace/identity-gate-rule.d.ts +37 -0
- package/dist/workspace/identity-gate-rule.d.ts.map +1 -1
- package/dist/workspace/identity-gate-rule.js +72 -7
- package/dist/workspace/identity.d.ts +12 -0
- package/dist/workspace/identity.d.ts.map +1 -1
- package/dist/workspace/identity.js +13 -1
- package/dist/workspace/intent-cli.d.ts +11 -2
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-cli.js +54 -5
- package/dist/workspace/intent-trace.d.ts +219 -0
- package/dist/workspace/intent-trace.d.ts.map +1 -0
- package/dist/workspace/intent-trace.js +314 -0
- package/dist/workspace/intent.d.ts +36 -7
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +192 -22
- package/dist/workspace/intent.schema.json +702 -6
- package/dist/workspace/ls.d.ts +4 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +2 -0
- package/dist/workspace/ls.schema.json +3 -1
- package/dist/workspace/member-pipeline.d.ts +6 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -1
- package/dist/workspace/member-pipeline.js +6 -0
- package/dist/workspace/overlap.d.ts +146 -0
- package/dist/workspace/overlap.d.ts.map +1 -0
- package/dist/workspace/overlap.js +276 -0
- package/dist/workspace/promotion-order.d.ts +41 -0
- package/dist/workspace/promotion-order.d.ts.map +1 -0
- package/dist/workspace/promotion-order.js +95 -0
- package/dist/workspace/reason-codes.d.ts +4 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +7 -1
- package/dist/workspace/records.d.ts +15 -2
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/records.js +32 -0
- package/dist/workspace/records.schema.json +21 -2
- package/dist/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
- package/dist/workspace/reference-kinds/flag/flag.schema.json +53 -0
- package/dist/workspace/releases.d.ts +81 -0
- package/dist/workspace/releases.d.ts.map +1 -0
- package/dist/workspace/releases.js +103 -0
- package/dist/workspace/releases.schema.json +513 -0
- package/dist/workspace/run-event.schema.json +295 -0
- package/dist/workspace/status-gates.d.ts +34 -1
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status-gates.js +31 -2
- package/dist/workspace/status-stewards.d.ts +4 -0
- package/dist/workspace/status-stewards.d.ts.map +1 -1
- package/dist/workspace/status-stewards.js +2 -0
- package/dist/workspace/status.d.ts +117 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +218 -4
- package/dist/workspace/status.schema.json +268 -2
- package/dist/workspace/trust/ci-tag-statement.d.ts +102 -0
- package/dist/workspace/trust/ci-tag-statement.d.ts.map +1 -0
- package/dist/workspace/trust/ci-tag-statement.js +123 -0
- package/dist/workspace/trust/op-run-statement.d.ts +91 -0
- package/dist/workspace/trust/op-run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/op-run-statement.js +143 -0
- package/dist/workspace/trust/rotation.d.ts +18 -2
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.js +65 -16
- package/dist/workspace/trust/seal.d.ts +11 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/seal.js +9 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
- package/dist/workspace/trust/ssh-commit.js +10 -10
- package/dist/workspace/wip.d.ts.map +1 -1
- package/dist/workspace/wip.js +11 -3
- package/package.json +1 -1
- package/src/__golden__/wave-loop/fan-out-gated.json +8 -0
- package/src/__golden__/wave-loop/fan-out-no-members.json +4 -0
- package/src/__golden__/wave-loop/fan-out-only.json +6 -0
- package/src/__golden__/wave-loop/op-by-apply-hold.json +2 -0
- package/src/__golden__/wave-loop/op-cost-member.json +3 -0
- package/src/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
- package/src/__golden__/wave-loop/op-held-on.json +2 -0
- package/src/__golden__/wave-loop/op-hooks-held.json +2 -0
- package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
- package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
- package/src/__golden__/wave-loop/op-hooks-share.json +3 -0
- package/src/__golden__/wave-loop/op-per-run.json +7 -0
- package/src/__golden__/wave-loop/op-pr-review.json +7 -0
- package/src/__golden__/wave-loop/op-sealed.json +3 -0
- package/src/__golden__/wave-loop/op-spend.json +3 -0
- package/src/__golden__/wave-loop/op-wave-commands.json +7 -0
- package/src/__golden__/wave-loop/op-wide-waiting.json +4 -0
- package/src/build-params.test.ts +46 -0
- package/src/build-params.ts +55 -1
- package/src/change-set-graph.test.ts +72 -0
- package/src/change-set-graph.ts +141 -0
- package/src/change-set.ts +87 -6
- package/src/chant-version.ts +16 -0
- package/src/cli/build-params-cli.ts +22 -9
- package/src/cli/commands/build.ts +25 -11
- package/src/cli/commands/check-lexicon-docs.test.ts +51 -0
- package/src/cli/commands/check-lexicon-docs.ts +39 -2
- package/src/cli/commands/check-lexicon.ts +14 -2
- package/src/cli/commands/init-lexicon/templates/docs.ts +7 -6
- package/src/cli/commands/init-lexicon.test.ts +25 -0
- package/src/cli/commands/init-lexicon.ts +18 -8
- package/src/cli/handlers/approve-release.test.ts +84 -0
- package/src/cli/handlers/approve-revoked.test.ts +155 -0
- package/src/cli/handlers/approve.ts +65 -2
- package/src/cli/handlers/build.test.ts +67 -0
- package/src/cli/handlers/build.ts +46 -4
- package/src/cli/handlers/change-set.ts +49 -1
- package/src/cli/handlers/fan-out.test.ts +228 -1
- package/src/cli/handlers/fan-out.ts +53 -6
- package/src/cli/handlers/intent-trace.e2e.test.ts +201 -0
- package/src/cli/handlers/lifecycle-gc.test.ts +126 -0
- package/src/cli/handlers/lifecycle-gc.ts +146 -0
- package/src/cli/handlers/operator.test.ts +37 -0
- package/src/cli/handlers/pr.test.ts +341 -0
- package/src/cli/handlers/pr.ts +292 -47
- package/src/cli/handlers/promote.test.ts +669 -7
- package/src/cli/handlers/promote.ts +464 -29
- package/src/cli/handlers/release-implicit.e2e.test.ts +161 -0
- package/src/cli/handlers/release-join.e2e.test.ts +185 -0
- package/src/cli/handlers/release-publish-targets.e2e.test.ts +295 -0
- package/src/cli/handlers/release-verify.e2e.test.ts +117 -0
- package/src/cli/handlers/release-workstation-ci.e2e.test.ts +135 -0
- package/src/cli/handlers/release.e2e.test.ts +199 -0
- package/src/cli/handlers/release.ts +593 -0
- package/src/cli/handlers/run-auto-release.test.ts +80 -0
- package/src/cli/handlers/run-events-cmd.test.ts +92 -0
- package/src/cli/handlers/run-release.test.ts +55 -0
- package/src/cli/handlers/run.test.ts +30 -0
- package/src/cli/handlers/run.ts +243 -18
- package/src/cli/main.test.ts +8 -0
- package/src/cli/main.ts +143 -17
- package/src/cli/mcp/never-over-mcp.test.ts +2 -0
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/cli/parse-args.ts +56 -5
- package/src/cli/registry.ts +43 -5
- package/src/cli/run-events.ts +57 -0
- package/src/cli/version.ts +3 -13
- package/src/codegen/docs-in-site.test.ts +166 -0
- package/src/codegen/docs-in-site.ts +182 -0
- package/src/codegen/docs-site/AgentPrompt.astro +26 -1
- package/src/codegen/docs-types.ts +14 -1
- package/src/codegen/docs.ts +60 -7
- package/src/codegen/rehype-base-url.d.mts +3 -1
- package/src/codegen/rehype-base-url.mjs +15 -9
- package/src/codegen/rehype-base-url.test.ts +34 -0
- package/src/components/auto-release.test.ts +30 -0
- package/src/components/auto-release.ts +9 -1
- package/src/components/capability.ts +9 -0
- package/src/components/cli-support.test.ts +82 -0
- package/src/components/cli-support.ts +16 -9
- package/src/components/driver.test.ts +24 -0
- package/src/components/driver.ts +165 -56
- package/src/components/fan-out-inputs.test.ts +85 -0
- package/src/components/fan-out-inputs.ts +192 -0
- package/src/components/fan-out-record.test.ts +10 -0
- package/src/components/fan-out-record.ts +19 -0
- package/src/components/fan-out-run.ts +104 -35
- package/src/components/fan-out.ts +4 -0
- package/src/components/pr-pipeline.ts +35 -4
- package/src/components/pr-run.ts +30 -1
- package/src/components/promote-order.test.ts +90 -0
- package/src/components/promote-order.ts +75 -0
- package/src/components/promote.test.ts +10 -1
- package/src/components/promote.ts +94 -3
- package/src/components/release-compile.test.ts +147 -0
- package/src/components/release-compile.ts +459 -0
- package/src/components/release-gate.test.ts +215 -0
- package/src/components/release-gate.ts +355 -0
- package/src/components/release-promote.test.ts +159 -0
- package/src/components/release-promote.ts +232 -0
- package/src/components/run-progress.ts +7 -0
- package/src/components/wave-plan.ts +16 -3
- package/src/config.ts +15 -1
- package/src/flag-params.test.ts +144 -0
- package/src/flag-params.ts +134 -0
- package/src/index.ts +2 -0
- package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
- package/src/lifecycle/change-set-store.test.ts +217 -0
- package/src/lifecycle/change-set-store.ts +113 -0
- package/src/lifecycle/commit-sha.ts +23 -0
- package/src/lifecycle/delivery-metrics.ts +263 -0
- package/src/lifecycle/deploy-outcome.ts +147 -0
- package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
- package/src/lifecycle/gate-change-set.ts +164 -0
- package/src/lifecycle/gate-ledger.test.ts +33 -0
- package/src/lifecycle/gate-ledger.ts +68 -3
- package/src/lifecycle/git.ts +61 -8
- package/src/lifecycle/index.ts +4 -0
- package/src/lifecycle/mixed-environment.test.ts +97 -0
- package/src/lifecycle/mixed-environment.ts +204 -0
- package/src/lifecycle/publish-attachments.ts +196 -0
- package/src/lifecycle/publish-credentials.ts +84 -0
- package/src/lifecycle/publish-declaration.ts +95 -0
- package/src/lifecycle/publish-forge.ts +325 -0
- package/src/lifecycle/publish-npm.ts +259 -0
- package/src/lifecycle/publish-oci.ts +396 -0
- package/src/lifecycle/publish-record.ts +113 -0
- package/src/lifecycle/publish-resume.test.ts +168 -0
- package/src/lifecycle/publish-targets.test.ts +494 -0
- package/src/lifecycle/publish-targets.ts +100 -0
- package/src/lifecycle/release-cut-signed.test.ts +180 -0
- package/src/lifecycle/release-cut.test.ts +483 -0
- package/src/lifecycle/release-cut.ts +503 -0
- package/src/lifecycle/release-flag.test.ts +112 -0
- package/src/lifecycle/release-join.test.ts +68 -0
- package/src/lifecycle/release-join.ts +182 -0
- package/src/lifecycle/release-ledger.test.ts +14 -0
- package/src/lifecycle/release-ledger.ts +85 -17
- package/src/lifecycle/release-publish.test.ts +225 -0
- package/src/lifecycle/release-publish.ts +568 -0
- package/src/lifecycle/release-revocation.ts +147 -0
- package/src/lifecycle/release-store.ts +434 -0
- package/src/lifecycle/release-verify.test.ts +110 -0
- package/src/lifecycle/release-verify.ts +120 -0
- package/src/lifecycle/release-workstation.test.ts +204 -0
- package/src/lifecycle/release-workstation.ts +216 -0
- package/src/lifecycle/retention-growth.e2e.test.ts +279 -0
- package/src/lifecycle/retention-policy.ts +63 -0
- package/src/lifecycle/retention.test.ts +363 -0
- package/src/lifecycle/retention.ts +508 -0
- package/src/lifecycle/run-ledger.test.ts +10 -0
- package/src/lifecycle/run-ledger.ts +6 -0
- package/src/op/activities/change-coverage.ts +4 -1
- package/src/op/activities/source-release.ts +8 -3
- package/src/op/activities/source-rollback.ts +8 -4
- package/src/op/commit-run-gate-deploy-join.test.ts +117 -0
- package/src/op/gate-name.ts +13 -3
- package/src/op/gate-release.test.ts +126 -0
- package/src/op/gate-run-locator.test.ts +110 -0
- package/src/op/gate-run-locator.ts +35 -0
- package/src/op/gate.ts +88 -6
- package/src/op/local-executor.ts +207 -52
- package/src/op/op-waves-run.ts +4 -0
- package/src/op/run-events.test.ts +166 -0
- package/src/op/run-live.ts +1 -1
- package/src/op/runtime.ts +39 -0
- package/src/op/runtimes/local.test.ts +16 -0
- package/src/op/runtimes/local.ts +9 -0
- package/src/plan-summary.test.ts +20 -0
- package/src/plan-summary.ts +8 -1
- package/src/point-decision.ts +12 -2
- package/src/pr-loop.ts +25 -4
- package/src/pr-report-url.test.ts +131 -0
- package/src/pr-report-url.ts +209 -0
- package/src/provenance.ts +2 -2
- package/src/run-event-store.test.ts +144 -0
- package/src/run-event-store.ts +273 -0
- package/src/run-event-stream.test.ts +175 -0
- package/src/run-event-stream.ts +309 -0
- package/src/run-event.test.ts +277 -0
- package/src/run-event.ts +471 -0
- package/src/wave-loop-golden.test.ts +9 -0
- package/src/workspace/__fixtures__/flag-workspace.ts +132 -0
- package/src/workspace/__fixtures__/older-records/change-set-984534ea9.json +100 -0
- package/src/workspace/__fixtures__/older-records/older-records.json +326 -0
- package/src/workspace/__fixtures__/run-event-check.ts +58 -0
- package/src/workspace/ancestry-index.test.ts +93 -0
- package/src/workspace/change-set-show.schema.json +102 -0
- package/src/workspace/change-set-show.ts +72 -0
- package/src/workspace/change-set.schema.json +32 -1
- package/src/workspace/changes-cli.ts +10 -1
- package/src/workspace/changes.schema.json +135 -0
- package/src/workspace/changes.test.ts +1 -1
- package/src/workspace/changes.ts +84 -2
- package/src/workspace/check.schema.json +4 -2
- package/src/workspace/checks/records.ts +35 -1
- package/src/workspace/checks.ts +2 -1
- package/src/workspace/ci-green-cli.ts +75 -13
- package/src/workspace/ci-green-forge.ts +24 -4
- package/src/workspace/ci-green-runs.test.ts +242 -0
- package/src/workspace/ci-green-signed.test.ts +302 -0
- package/src/workspace/ci-green-workflow.test.ts +16 -0
- package/src/workspace/ci-green-workflow.ts +12 -0
- package/src/workspace/ci-green.test.ts +131 -2
- package/src/workspace/ci-green.ts +635 -42
- package/src/workspace/ci-last-green.schema.json +32 -2
- package/src/workspace/ci-list.schema.json +525 -0
- package/src/workspace/commit-links.test.ts +279 -0
- package/src/workspace/commit-links.ts +183 -0
- package/src/workspace/declaration.schema.json +76 -0
- package/src/workspace/declaration.test.ts +28 -0
- package/src/workspace/declaration.ts +60 -2
- package/src/workspace/declared-kinds.ts +40 -1
- package/src/workspace/delivery-metrics.schema.json +519 -0
- package/src/workspace/delivery-metrics.test.ts +236 -0
- package/src/workspace/delivery-metrics.ts +286 -0
- package/src/workspace/flags-read.ts +121 -0
- package/src/workspace/flags.test.ts +141 -0
- package/src/workspace/flags.ts +157 -0
- package/src/workspace/graph-cli.ts +1 -1
- package/src/workspace/identity-gate-rule.ts +91 -7
- package/src/workspace/identity.ts +14 -1
- package/src/workspace/intent-cli.ts +46 -5
- package/src/workspace/intent-trace.test.ts +173 -0
- package/src/workspace/intent-trace.ts +484 -0
- package/src/workspace/intent.schema.json +702 -6
- package/src/workspace/intent.ts +196 -26
- package/src/workspace/ls.schema.json +3 -1
- package/src/workspace/ls.ts +6 -0
- package/src/workspace/member-pipeline.test.ts +17 -0
- package/src/workspace/member-pipeline.ts +9 -0
- package/src/workspace/older-records.test.ts +412 -0
- package/src/workspace/overlap.test.ts +165 -0
- package/src/workspace/overlap.ts +340 -0
- package/src/workspace/promotion-order.ts +97 -0
- package/src/workspace/read-contract.e2e.test.ts +5 -1
- package/src/workspace/reason-codes.test.ts +7 -1
- package/src/workspace/reason-codes.ts +7 -1
- package/src/workspace/record-assets.test.ts +2 -1
- package/src/workspace/records-contract.e2e.test.ts +2 -1
- package/src/workspace/records.schema.json +21 -2
- package/src/workspace/records.ts +36 -2
- package/src/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
- package/src/workspace/reference-kinds/flag/flag.schema.json +53 -0
- package/src/workspace/releases.schema.json +513 -0
- package/src/workspace/releases.test.ts +108 -0
- package/src/workspace/releases.ts +133 -0
- package/src/workspace/run-event.schema.json +295 -0
- package/src/workspace/status-contract.test.ts +81 -1
- package/src/workspace/status-gates.ts +64 -1
- package/src/workspace/status-mixed.test.ts +152 -0
- package/src/workspace/status-revoked.test.ts +153 -0
- package/src/workspace/status-stewards.ts +6 -0
- package/src/workspace/status.schema.json +268 -2
- package/src/workspace/status.ts +334 -4
- package/src/workspace/trust/ci-tag-statement.ts +151 -0
- package/src/workspace/trust/op-run-statement.ts +148 -0
- package/src/workspace/trust/rotation.ts +61 -14
- package/src/workspace/trust/seal.ts +10 -0
- package/src/workspace/trust/ssh-commit.ts +10 -9
- package/src/workspace/wip.ts +11 -2
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -14
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +0 -16
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +0 -8
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +0 -15
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +0 -10
|
@@ -52,6 +52,7 @@ import { gateName } from "../op/gate-name.js";
|
|
|
52
52
|
import { GateNotRecordableError } from "../lifecycle/no-record.js";
|
|
53
53
|
import { componentPlanDigest } from "./gate-plan.js";
|
|
54
54
|
import { isPromotedArtifact } from "./auto-release.js";
|
|
55
|
+
import { gateEventsOf, joinRunEventSinks, progressSinkOf } from "../run-event-stream.js";
|
|
55
56
|
function isGateStep(step) {
|
|
56
57
|
return step.kind === "gate";
|
|
57
58
|
}
|
|
@@ -185,6 +186,41 @@ export function resolveStepInput(input, phaseOutputs, componentOutputs) {
|
|
|
185
186
|
};
|
|
186
187
|
return walk(input);
|
|
187
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* The components (or stacks) whose outputs `input` reads through
|
|
191
|
+
* cross-component wiring, `stackOutput()` or `@<component>.publish.*`, and
|
|
192
|
+
* which have no value for it in `componentOutputs`, sorted and each once
|
|
193
|
+
* (#4084). {@link resolveStepInput} turns each such reference into
|
|
194
|
+
* `undefined`; a plan uses this to say whose outputs it is waiting on.
|
|
195
|
+
*/
|
|
196
|
+
export function unresolvedWiringSources(input, componentOutputs) {
|
|
197
|
+
const found = new Set();
|
|
198
|
+
const walk = (value) => {
|
|
199
|
+
if (typeof value === "string") {
|
|
200
|
+
if (PRIOR_STEP_REF.test(value))
|
|
201
|
+
return;
|
|
202
|
+
const ref = value.match(COMPONENT_ARTIFACT_REF);
|
|
203
|
+
if (ref && resolvePath(componentOutputs[ref[1]]?.publish, ref[2]) === undefined)
|
|
204
|
+
found.add(ref[1]);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (Array.isArray(value)) {
|
|
208
|
+
value.forEach(walk);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (value && typeof value === "object") {
|
|
212
|
+
if ("stackOutput" in value) {
|
|
213
|
+
const { stack, name } = value.stackOutput;
|
|
214
|
+
if (resolvePath(componentOutputs[stack], name) === undefined)
|
|
215
|
+
found.add(stack);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
Object.values(value).forEach(walk);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
walk(input);
|
|
222
|
+
return [...found].sort();
|
|
223
|
+
}
|
|
188
224
|
class StepFailure extends Error {
|
|
189
225
|
constructor(records, executed) {
|
|
190
226
|
super("step failed");
|
|
@@ -210,7 +246,7 @@ class GateStop extends Error {
|
|
|
210
246
|
this.name = "GateStop";
|
|
211
247
|
}
|
|
212
248
|
}
|
|
213
|
-
/** A result status as the
|
|
249
|
+
/** A result status as the event stream spells it — the only difference is `fail` vs `failed`, which the two vocabularies have always disagreed on. */
|
|
214
250
|
function progressStatus(status) {
|
|
215
251
|
return status === "fail" ? "failed" : status;
|
|
216
252
|
}
|
|
@@ -261,30 +297,44 @@ async function runCapabilityStep(step, phaseName, ctx, registry, phaseOutputs, c
|
|
|
261
297
|
* gate is a read of the ledger rather than work, and starting activities a
|
|
262
298
|
* pending gate is about to strand defeats the point of stopping at it.
|
|
263
299
|
*
|
|
264
|
-
* `
|
|
265
|
-
* step runs, a `step`
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
300
|
+
* `emit`, when supplied, gets the phase's run events (#4041): `phase-start`
|
|
301
|
+
* before any step runs, a `step-start` and a `step-settle` around each gate
|
|
302
|
+
* and each capability invocation, the gate's `gate-resolved` or
|
|
303
|
+
* `gate-waiting`, a `skipped` settle with `skip: "not-run"` for each step a
|
|
304
|
+
* failure or a gate stopped, and `phase-settle` once the phase settles. It
|
|
305
|
+
* is observation only, never consulted for control flow. Recursion into a
|
|
306
|
+
* nested fan-out phase passes the same sink through, so a nested phase's
|
|
307
|
+
* events use its own name. `--progress-json` reads the same events through
|
|
308
|
+
* `progressOfRunEvent` (../run-event-stream.ts), which keeps the older
|
|
309
|
+
* stream's shape.
|
|
272
310
|
*/
|
|
273
|
-
async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates,
|
|
311
|
+
async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit) {
|
|
312
|
+
/** Where a step of this phase sits, for its events. */
|
|
313
|
+
const stepAt = (entry, step) => ({
|
|
314
|
+
component: ctx.component,
|
|
315
|
+
phase: phaseDef.phase,
|
|
316
|
+
step,
|
|
317
|
+
index: phaseDef.steps.indexOf(entry),
|
|
318
|
+
});
|
|
274
319
|
/** Decide this phase's gates against the ledger, in authored order, before any of its work starts. Throws `GateStop` at the first one nobody has approved. */
|
|
275
320
|
const decideGates = async () => {
|
|
276
321
|
const gateRecords = [];
|
|
277
322
|
for (const gate of phaseDef.steps.filter(isGateStep)) {
|
|
278
323
|
const start = Date.now();
|
|
279
324
|
const base = { component: ctx.component, phase: phaseDef.phase, kind: `gate:${gateName(gate)}` };
|
|
325
|
+
const at = stepAt(gate, base.kind);
|
|
326
|
+
emit?.({ type: "step-start", ...at });
|
|
280
327
|
let check;
|
|
281
328
|
try {
|
|
282
329
|
check = await evaluateGate(gates.port, {
|
|
283
|
-
op: ctx.component,
|
|
330
|
+
op: gates.releaseGate?.op ?? ctx.component,
|
|
284
331
|
gate: gateName(gate),
|
|
285
332
|
// #2574: an approval counts only for this environment and this plan.
|
|
286
333
|
environment: ctx.env,
|
|
287
334
|
...(gates.planDigest !== undefined ? { planDigest: gates.planDigest } : {}),
|
|
335
|
+
// #4045: and under a release, only for that release.
|
|
336
|
+
...(gates.releaseGate ? { releaseDigest: gates.releaseGate.releaseDigest } : {}),
|
|
337
|
+
...(gates.releaseGate?.verifyEmpty ? { verifyEmpty: gates.releaseGate.verifyEmpty } : {}),
|
|
288
338
|
...(gate.description ? { description: gate.description } : {}),
|
|
289
339
|
...(gate.timeout ? { timeout: gate.timeout } : {}),
|
|
290
340
|
...(gates.now ? { now: gates.now } : {}),
|
|
@@ -296,11 +346,18 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
296
346
|
if (!(err instanceof GateNotRecordableError))
|
|
297
347
|
throw err;
|
|
298
348
|
gateRecords.push({ ...base, status: "fail", durationMs: Date.now() - start, error: err.message });
|
|
349
|
+
emit?.({ type: "step-settle", ...at, status: "failed", durationMs: Date.now() - start, error: err.message });
|
|
299
350
|
for (const skipped of phaseDef.steps.filter((s) => !isGateStep(s))) {
|
|
300
351
|
gateRecords.push(skippedRecord(skipped));
|
|
301
352
|
}
|
|
302
353
|
throw new StepFailure(gateRecords, []);
|
|
303
354
|
}
|
|
355
|
+
for (const body of gateEventsOf(check, { ...at, op: gates.releaseGate?.op ?? ctx.component, gate: gateName(gate) }, {
|
|
356
|
+
durationMs: Date.now() - start,
|
|
357
|
+
...(!check.satisfied && check.mismatch ? { message: "an approval stands for this gate, but for another environment or plan" } : {}),
|
|
358
|
+
})) {
|
|
359
|
+
emit?.(body);
|
|
360
|
+
}
|
|
304
361
|
if (!check.satisfied) {
|
|
305
362
|
gateRecords.push({ ...base, status: "skipped", durationMs: Date.now() - start });
|
|
306
363
|
for (const skipped of phaseDef.steps.filter((s) => !isGateStep(s))) {
|
|
@@ -317,6 +374,8 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
317
374
|
resolvedBy: check.resolution.resolvedBy,
|
|
318
375
|
timestamp: check.resolution.timestamp,
|
|
319
376
|
...(check.resolution.url ? { url: check.resolution.url } : {}),
|
|
377
|
+
...(gates.releaseGate ? { op: gates.releaseGate.op } : {}),
|
|
378
|
+
...(check.via === "empty" ? { empty: true } : {}),
|
|
320
379
|
},
|
|
321
380
|
});
|
|
322
381
|
}
|
|
@@ -326,7 +385,7 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
326
385
|
const runEntry = async (entry) => {
|
|
327
386
|
if (isPhaseStep(entry)) {
|
|
328
387
|
try {
|
|
329
|
-
const nested = await runPhase(entry, ctx, registry, phaseOutputs, componentOutputs, gates,
|
|
388
|
+
const nested = await runPhase(entry, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
|
|
330
389
|
return { ...nested, failed: false };
|
|
331
390
|
}
|
|
332
391
|
catch (err) {
|
|
@@ -348,14 +407,14 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
348
407
|
throw err;
|
|
349
408
|
}
|
|
350
409
|
}
|
|
351
|
-
|
|
410
|
+
const at = stepAt(entry, entry.kind);
|
|
411
|
+
emit?.({ type: "step-start", ...at });
|
|
352
412
|
const { record, resolvedInput, output } = await runCapabilityStep(entry, phaseDef.phase, ctx, registry, phaseOutputs, componentOutputs);
|
|
353
|
-
|
|
354
|
-
type: "step",
|
|
355
|
-
|
|
356
|
-
phase: phaseDef.phase,
|
|
357
|
-
step: entry.kind,
|
|
413
|
+
emit?.({
|
|
414
|
+
type: "step-settle",
|
|
415
|
+
...at,
|
|
358
416
|
status: record.status === "ok" ? "ok" : "failed",
|
|
417
|
+
durationMs: record.durationMs,
|
|
359
418
|
...(record.error !== undefined ? { error: record.error } : {}),
|
|
360
419
|
});
|
|
361
420
|
if (record.status === "ok") {
|
|
@@ -372,13 +431,12 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
372
431
|
failed: record.status === "fail",
|
|
373
432
|
};
|
|
374
433
|
};
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
phase:
|
|
378
|
-
|
|
379
|
-
status: "skipped",
|
|
380
|
-
|
|
381
|
-
});
|
|
434
|
+
/** A step a failure or a gate stopped before it started: recorded, and settled `skipped` with `skip: "not-run"`. */
|
|
435
|
+
const skippedRecord = (entry) => {
|
|
436
|
+
const kind = isPhaseStep(entry) ? entry.phase : entry.kind;
|
|
437
|
+
emit?.({ type: "step-settle", ...stepAt(entry, kind), status: "skipped", skip: "not-run", durationMs: null });
|
|
438
|
+
return { component: ctx.component, phase: phaseDef.phase, kind, status: "skipped", durationMs: 0 };
|
|
439
|
+
};
|
|
382
440
|
const runEntries = async () => {
|
|
383
441
|
const gateRecords = await decideGates();
|
|
384
442
|
if (phaseDef.parallel) {
|
|
@@ -412,18 +470,18 @@ async function runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs,
|
|
|
412
470
|
}
|
|
413
471
|
return { records, executed };
|
|
414
472
|
};
|
|
415
|
-
|
|
473
|
+
emit?.({ type: "phase-start", component: ctx.component, phase: phaseDef.phase });
|
|
416
474
|
try {
|
|
417
475
|
const result = await runEntries();
|
|
418
|
-
|
|
476
|
+
emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "ok" });
|
|
419
477
|
return result;
|
|
420
478
|
}
|
|
421
479
|
catch (err) {
|
|
422
480
|
if (err instanceof GateStop) {
|
|
423
|
-
|
|
481
|
+
emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "gated" });
|
|
424
482
|
}
|
|
425
483
|
else if (err instanceof StepFailure) {
|
|
426
|
-
|
|
484
|
+
emit?.({ type: "phase-settle", component: ctx.component, phase: phaseDef.phase, status: "failed" });
|
|
427
485
|
}
|
|
428
486
|
throw err;
|
|
429
487
|
}
|
|
@@ -492,16 +550,17 @@ async function rollbackExecuted(executed, ctx, registry) {
|
|
|
492
550
|
* any) are recorded into `componentOutputs` under its own name so downstream
|
|
493
551
|
* components can reference `@<name>.publish.*`.
|
|
494
552
|
*
|
|
495
|
-
* `onProgress
|
|
496
|
-
*
|
|
497
|
-
* `
|
|
498
|
-
* `
|
|
499
|
-
* unwind step-by-step compensation
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
553
|
+
* `onProgress` (the older `RunProgressEvent` stream) and `onRunEvent` (run
|
|
554
|
+
* events, #4041), when supplied, are forwarded to every `runPhase` call (both
|
|
555
|
+
* the forward `deploy` phases and, on failure, the component's own authored
|
|
556
|
+
* `rollback` phases), so a consumer sees the phase and step events of
|
|
557
|
+
* whichever phases actually ran. The saga unwind step-by-step compensation
|
|
558
|
+
* (`rollbackExecuted` below) stays silent: it isn't a `deploy` phase, and
|
|
559
|
+
* its record statuses (`rolled-back`/`rollback-opted-out`) are not step
|
|
560
|
+
* statuses either stream has.
|
|
503
561
|
*/
|
|
504
|
-
export async function runComponentDeploy(component, ctx, registry, componentOutputs, onProgress, gateContext = { port: gitGateLedgerPort() }) {
|
|
562
|
+
export async function runComponentDeploy(component, ctx, registry, componentOutputs, onProgress, gateContext = { port: gitGateLedgerPort() }, onRunEvent) {
|
|
563
|
+
const emit = joinRunEventSinks(onRunEvent, progressSinkOf(onProgress));
|
|
505
564
|
// Each component tracks its own release: a digest one component promoted never stamps another's deploy.
|
|
506
565
|
if (ctx.release)
|
|
507
566
|
ctx = { ...ctx, release: { ...ctx.release } };
|
|
@@ -515,18 +574,20 @@ export async function runComponentDeploy(component, ctx, registry, componentOutp
|
|
|
515
574
|
ctx.release.version = release;
|
|
516
575
|
const gates = {
|
|
517
576
|
...gateContext,
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
577
|
+
// #4045: a release gate binds the release's change set, not this composition.
|
|
578
|
+
planDigest: gateContext.releaseGate?.planDigest ??
|
|
579
|
+
componentPlanDigest({
|
|
580
|
+
environment: ctx.env,
|
|
581
|
+
component,
|
|
582
|
+
...(ctx.vars ? { vars: ctx.vars } : {}),
|
|
583
|
+
...(release !== undefined ? { release } : {}),
|
|
584
|
+
}),
|
|
524
585
|
};
|
|
525
586
|
const records = [];
|
|
526
587
|
const allExecuted = [];
|
|
527
588
|
try {
|
|
528
589
|
for (const phaseDef of component.deploy) {
|
|
529
|
-
const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates,
|
|
590
|
+
const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
|
|
530
591
|
records.push(...result.records);
|
|
531
592
|
allExecuted.push(...result.executed);
|
|
532
593
|
}
|
|
@@ -559,7 +620,7 @@ export async function runComponentDeploy(component, ctx, registry, componentOutp
|
|
|
559
620
|
records.push(...(await rollbackExecuted(allExecuted, ctx, registry)));
|
|
560
621
|
for (const phaseDef of [...(component.rollback ?? [])].reverse()) {
|
|
561
622
|
try {
|
|
562
|
-
const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates,
|
|
623
|
+
const result = await runPhase(phaseDef, ctx, registry, phaseOutputs, componentOutputs, gates, emit);
|
|
563
624
|
records.push(...result.records);
|
|
564
625
|
}
|
|
565
626
|
catch (compErr) {
|
|
@@ -688,29 +749,30 @@ export async function runInterpretDriver(components, registry, options) {
|
|
|
688
749
|
const { order, waves } = resolveComponentGraph(components);
|
|
689
750
|
const byName = new Map(components.map((c) => [c.name, c]));
|
|
690
751
|
const componentOutputs = { ...(options.componentOutputs ?? {}) };
|
|
691
|
-
const
|
|
752
|
+
const emit = joinRunEventSinks(options.onRunEvent, progressSinkOf(options.onProgress));
|
|
692
753
|
const gates = {
|
|
693
754
|
port: options.gates ?? gitGateLedgerPort(),
|
|
694
755
|
...(options.now ? { now: options.now } : {}),
|
|
695
756
|
...(options.releases ? { releases: options.releases } : {}),
|
|
757
|
+
...(options.releaseGate ? { releaseGate: options.releaseGate } : {}),
|
|
696
758
|
};
|
|
697
|
-
|
|
759
|
+
emit?.({ type: "run-start", waves });
|
|
698
760
|
const results = [];
|
|
699
761
|
let failedComponent;
|
|
700
762
|
let gated;
|
|
701
763
|
waveLoop: for (const [waveIndex, wave] of waves.entries()) {
|
|
702
764
|
const waveNum = waveIndex + 1;
|
|
703
|
-
|
|
765
|
+
emit?.({ type: "wave-start", wave: waveNum, components: wave });
|
|
704
766
|
const waveComponents = wave.map((name) => byName.get(name));
|
|
705
767
|
const waveResults = await Promise.all(waveComponents.map(async (component) => {
|
|
706
|
-
|
|
707
|
-
const result = await runComponentDeploy(component, deployContext(options, component.name), registry, componentOutputs,
|
|
708
|
-
|
|
768
|
+
emit?.({ type: "component-start", wave: waveNum, component: component.name });
|
|
769
|
+
const result = await runComponentDeploy(component, deployContext(options, component.name), registry, componentOutputs, undefined, gates, emit);
|
|
770
|
+
emit?.({ type: "component-settle", wave: waveNum, component: component.name, status: progressStatus(result.status) });
|
|
709
771
|
return result;
|
|
710
772
|
}));
|
|
711
773
|
results.push(...waveResults);
|
|
712
774
|
const stopped = waveResults.find((r) => r.status !== "ok");
|
|
713
|
-
|
|
775
|
+
emit?.({ type: "wave-settle", wave: waveNum, status: progressStatus(stopped?.status ?? "ok") });
|
|
714
776
|
if (stopped) {
|
|
715
777
|
// A failure in the same wave outranks a gate: something is actually
|
|
716
778
|
// broken, and reporting the run as "waiting on a human" would hide it.
|
|
@@ -724,7 +786,7 @@ export async function runInterpretDriver(components, registry, options) {
|
|
|
724
786
|
}
|
|
725
787
|
const status = failedComponent ? "fail" : gated ? "gated" : "ok";
|
|
726
788
|
const ok = status === "ok";
|
|
727
|
-
|
|
789
|
+
emit?.({ type: "run-settle", status: progressStatus(status), durationMs: null });
|
|
728
790
|
const result = {
|
|
729
791
|
order, waves, results, ok, status, failedComponent, componentOutputs,
|
|
730
792
|
...(gated
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each component of a fan-out would apply, as one digest per component
|
|
3
|
+
* (#4081), and which of an earlier attempt's progress still holds against it.
|
|
4
|
+
*
|
|
5
|
+
* A fan-out's plan digest identifies the derivation: who runs, in what order,
|
|
6
|
+
* off which edges. Two different changes that touch the same components in
|
|
7
|
+
* the same shape derive the same plan, so the plan digest alone cannot say
|
|
8
|
+
* whether "cluster-a already applied" is about the change in front of us.
|
|
9
|
+
* The attempt record therefore keeps, for each component it applied, the
|
|
10
|
+
* input digest computed here, and a resumed attempt carries a component as
|
|
11
|
+
* `already-applied` only when that digest is the one the component has now.
|
|
12
|
+
*
|
|
13
|
+
* ## What a component's input digest covers
|
|
14
|
+
*
|
|
15
|
+
* - The environment. Progress against `local` says nothing about `prod`.
|
|
16
|
+
* - The composition: every phase and step as authored, `rollback` included.
|
|
17
|
+
* A `stackOutput` reference is hashed as the reference, not its value.
|
|
18
|
+
* - The bytes of every file a step input names. A string input that resolves,
|
|
19
|
+
* relative to the project root, to a file or directory inside the root is
|
|
20
|
+
* read and hashed, so `template: "dist/cluster-a.template.json"` covers the
|
|
21
|
+
* built template and a rebuild that changes it changes the digest. A
|
|
22
|
+
* directory is hashed by its files, skipping `.git`, `node_modules` and
|
|
23
|
+
* `.chant`, the last because the attempt record itself lives there.
|
|
24
|
+
* - The input digests of the components it depends on. A parameter filled
|
|
25
|
+
* from an upstream output gets its value from that upstream's apply, so a
|
|
26
|
+
* change upstream changes the digest of everything downstream of it, the
|
|
27
|
+
* same reach the fan-out's own walk has.
|
|
28
|
+
*
|
|
29
|
+
* Nothing decided during the run goes in: no run id, no time, no output an
|
|
30
|
+
* apply produced.
|
|
31
|
+
*/
|
|
32
|
+
import type { DriverComponent } from "./driver.js";
|
|
33
|
+
export interface ComponentInputOptions {
|
|
34
|
+
/** The root step inputs' file paths are read relative to, the project the fan-out runs in. */
|
|
35
|
+
projectRoot: string;
|
|
36
|
+
/** The environment the fan-out applies to. */
|
|
37
|
+
env: string;
|
|
38
|
+
/** Environment config resolved ahead of the run, when the caller has any. */
|
|
39
|
+
vars?: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One input digest per component in `components`, keyed by name. Each folds
|
|
43
|
+
* in the digests of the components it depends on, so `components` should be
|
|
44
|
+
* the whole project: a dependency it does not contain is hashed by name only.
|
|
45
|
+
*/
|
|
46
|
+
export declare function componentInputDigests(components: DriverComponent[], options: ComponentInputOptions): Record<string, string>;
|
|
47
|
+
/** What of an earlier attempt's progress holds against the inputs the components have now. */
|
|
48
|
+
export interface CarriedProgress {
|
|
49
|
+
/** Components the attempt applied whose input is the same now. These stay `already-applied`. */
|
|
50
|
+
carried: string[];
|
|
51
|
+
/** Components the attempt applied whose input moved since. These run again. */
|
|
52
|
+
changed: string[];
|
|
53
|
+
/**
|
|
54
|
+
* True when the record has no input digests at all, as one written before
|
|
55
|
+
* #4081 has. Nothing carries from such a record, since nothing in it says
|
|
56
|
+
* what was applied.
|
|
57
|
+
*/
|
|
58
|
+
unrecorded: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Split an attempt's `completed` by whether each component's input is the
|
|
62
|
+
* same as now. A component the record holds no digest for counts as changed:
|
|
63
|
+
* a claim that it applied is only worth keeping for the input it applied.
|
|
64
|
+
*/
|
|
65
|
+
export declare function progressThatCarries(attempt: {
|
|
66
|
+
completed: string[];
|
|
67
|
+
inputs?: Record<string, string>;
|
|
68
|
+
}, now: Record<string, string>): CarriedProgress;
|
|
69
|
+
//# sourceMappingURL=fan-out-inputs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fan-out-inputs.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-inputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAyED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,EAAE,qBAAqB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+BxB;AAED,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC9B,gGAAgG;IAChG,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EACjE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,eAAe,CAUjB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each component of a fan-out would apply, as one digest per component
|
|
3
|
+
* (#4081), and which of an earlier attempt's progress still holds against it.
|
|
4
|
+
*
|
|
5
|
+
* A fan-out's plan digest identifies the derivation: who runs, in what order,
|
|
6
|
+
* off which edges. Two different changes that touch the same components in
|
|
7
|
+
* the same shape derive the same plan, so the plan digest alone cannot say
|
|
8
|
+
* whether "cluster-a already applied" is about the change in front of us.
|
|
9
|
+
* The attempt record therefore keeps, for each component it applied, the
|
|
10
|
+
* input digest computed here, and a resumed attempt carries a component as
|
|
11
|
+
* `already-applied` only when that digest is the one the component has now.
|
|
12
|
+
*
|
|
13
|
+
* ## What a component's input digest covers
|
|
14
|
+
*
|
|
15
|
+
* - The environment. Progress against `local` says nothing about `prod`.
|
|
16
|
+
* - The composition: every phase and step as authored, `rollback` included.
|
|
17
|
+
* A `stackOutput` reference is hashed as the reference, not its value.
|
|
18
|
+
* - The bytes of every file a step input names. A string input that resolves,
|
|
19
|
+
* relative to the project root, to a file or directory inside the root is
|
|
20
|
+
* read and hashed, so `template: "dist/cluster-a.template.json"` covers the
|
|
21
|
+
* built template and a rebuild that changes it changes the digest. A
|
|
22
|
+
* directory is hashed by its files, skipping `.git`, `node_modules` and
|
|
23
|
+
* `.chant`, the last because the attempt record itself lives there.
|
|
24
|
+
* - The input digests of the components it depends on. A parameter filled
|
|
25
|
+
* from an upstream output gets its value from that upstream's apply, so a
|
|
26
|
+
* change upstream changes the digest of everything downstream of it, the
|
|
27
|
+
* same reach the fan-out's own walk has.
|
|
28
|
+
*
|
|
29
|
+
* Nothing decided during the run goes in: no run id, no time, no output an
|
|
30
|
+
* apply produced.
|
|
31
|
+
*/
|
|
32
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
33
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
34
|
+
import { computePlanDigest } from "../lifecycle/plan-digest.js";
|
|
35
|
+
import { sha256Hex } from "../content-digest.js";
|
|
36
|
+
const SKIPPED_DIRS = new Set([".git", "node_modules", ".chant"]);
|
|
37
|
+
/** Inside `root`, and not `root` itself: a bare "." names the whole project, which is no one step's input. */
|
|
38
|
+
function insideRoot(root, path) {
|
|
39
|
+
const rel = relative(root, path);
|
|
40
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
41
|
+
}
|
|
42
|
+
/** Hash a file, or a directory by the relative path and bytes of each file under it. */
|
|
43
|
+
function hashPath(path) {
|
|
44
|
+
let stat;
|
|
45
|
+
try {
|
|
46
|
+
stat = statSync(path);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
if (stat.isFile())
|
|
52
|
+
return `sha256:${sha256Hex(readFileSync(path))}`;
|
|
53
|
+
if (!stat.isDirectory())
|
|
54
|
+
return undefined;
|
|
55
|
+
const files = {};
|
|
56
|
+
const walk = (dir) => {
|
|
57
|
+
for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
58
|
+
if (SKIPPED_DIRS.has(entry.name))
|
|
59
|
+
continue;
|
|
60
|
+
const full = join(dir, entry.name);
|
|
61
|
+
if (entry.isDirectory())
|
|
62
|
+
walk(full);
|
|
63
|
+
else if (entry.isFile())
|
|
64
|
+
files[relative(path, full).split(sep).join("/")] = sha256Hex(readFileSync(full));
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
walk(path);
|
|
68
|
+
return computePlanDigest("component-input-dir", files);
|
|
69
|
+
}
|
|
70
|
+
/** Every file or directory a component's steps name, keyed by the string the step wrote. */
|
|
71
|
+
function referencedFiles(component, root) {
|
|
72
|
+
const out = {};
|
|
73
|
+
const visit = (value) => {
|
|
74
|
+
if (typeof value === "string") {
|
|
75
|
+
if (value === "" || value.includes("\n") || value in out)
|
|
76
|
+
return;
|
|
77
|
+
const path = resolve(root, value);
|
|
78
|
+
if (!insideRoot(root, path) || !existsSync(path))
|
|
79
|
+
return;
|
|
80
|
+
const digest = hashPath(path);
|
|
81
|
+
if (digest !== undefined)
|
|
82
|
+
out[value] = digest;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(value))
|
|
86
|
+
value.forEach(visit);
|
|
87
|
+
else if (value && typeof value === "object")
|
|
88
|
+
Object.values(value).forEach(visit);
|
|
89
|
+
};
|
|
90
|
+
// Only a step's inputs name files. A phase name or a step's `kind` that
|
|
91
|
+
// happens to match a directory in the project is not one.
|
|
92
|
+
const visitPhases = (phases) => {
|
|
93
|
+
for (const phase of phases ?? []) {
|
|
94
|
+
for (const step of phase.steps) {
|
|
95
|
+
if (isPhase(step)) {
|
|
96
|
+
visitPhases([step]);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (step.kind === "gate")
|
|
100
|
+
continue;
|
|
101
|
+
const { kind: _kind, ...inputs } = step;
|
|
102
|
+
visit(inputs);
|
|
103
|
+
}
|
|
104
|
+
visitPhases(phase.onFailure);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
visitPhases(component.deploy);
|
|
108
|
+
visitPhases(component.rollback);
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function isPhase(step) {
|
|
112
|
+
return typeof step.phase === "string" && Array.isArray(step.steps);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* One input digest per component in `components`, keyed by name. Each folds
|
|
116
|
+
* in the digests of the components it depends on, so `components` should be
|
|
117
|
+
* the whole project: a dependency it does not contain is hashed by name only.
|
|
118
|
+
*/
|
|
119
|
+
export function componentInputDigests(components, options) {
|
|
120
|
+
const root = resolve(options.projectRoot);
|
|
121
|
+
const byName = new Map(components.map((c) => [c.name, c]));
|
|
122
|
+
const digests = new Map();
|
|
123
|
+
const visiting = new Set();
|
|
124
|
+
const digestOf = (name) => {
|
|
125
|
+
const known = digests.get(name);
|
|
126
|
+
if (known !== undefined)
|
|
127
|
+
return known;
|
|
128
|
+
const component = byName.get(name);
|
|
129
|
+
// An unknown dependency or a cycle is refused by the fan-out's derivation
|
|
130
|
+
// before this runs; here it only has to not loop.
|
|
131
|
+
if (!component || visiting.has(name))
|
|
132
|
+
return null;
|
|
133
|
+
visiting.add(name);
|
|
134
|
+
const upstream = [...(component.dependsOn ?? [])].sort().map((dep) => ({ component: dep, digest: digestOf(dep) }));
|
|
135
|
+
visiting.delete(name);
|
|
136
|
+
const digest = computePlanDigest("component-input", {
|
|
137
|
+
environment: options.env,
|
|
138
|
+
component: name,
|
|
139
|
+
deploy: component.deploy,
|
|
140
|
+
rollback: component.rollback ?? null,
|
|
141
|
+
vars: options.vars ?? null,
|
|
142
|
+
files: referencedFiles(component, root),
|
|
143
|
+
upstream,
|
|
144
|
+
});
|
|
145
|
+
digests.set(name, digest);
|
|
146
|
+
return digest;
|
|
147
|
+
};
|
|
148
|
+
for (const c of components)
|
|
149
|
+
digestOf(c.name);
|
|
150
|
+
return Object.fromEntries([...digests.entries()].sort(([a], [b]) => a.localeCompare(b)));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Split an attempt's `completed` by whether each component's input is the
|
|
154
|
+
* same as now. A component the record holds no digest for counts as changed:
|
|
155
|
+
* a claim that it applied is only worth keeping for the input it applied.
|
|
156
|
+
*/
|
|
157
|
+
export function progressThatCarries(attempt, now) {
|
|
158
|
+
const recorded = attempt.inputs;
|
|
159
|
+
const carried = [];
|
|
160
|
+
const changed = [];
|
|
161
|
+
for (const name of [...attempt.completed].sort()) {
|
|
162
|
+
const then = recorded?.[name];
|
|
163
|
+
if (then !== undefined && now[name] !== undefined && then === now[name])
|
|
164
|
+
carried.push(name);
|
|
165
|
+
else
|
|
166
|
+
changed.push(name);
|
|
167
|
+
}
|
|
168
|
+
return { carried, changed, unrecorded: recorded === undefined };
|
|
169
|
+
}
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
* `carried` holds what a step asked to keep for its member (#3459). It rides
|
|
26
26
|
* in the record rather than beside it because the record is the one file a
|
|
27
27
|
* per-wave CI job hands to the next.
|
|
28
|
+
*
|
|
29
|
+
* `inputs` holds, for each component in `completed`, the input digest it
|
|
30
|
+
* applied (#4081, ./fan-out-inputs.ts). The plan digest only identifies the
|
|
31
|
+
* derivation, and two different changes with the same shape derive the same
|
|
32
|
+
* one, so the digest alone would carry "cluster-a already applied" into a
|
|
33
|
+
* change that never applied it. A resumed attempt carries a component only
|
|
34
|
+
* when its input digest is the same now. A record written before #4081 has
|
|
35
|
+
* no `inputs`, and none of its progress carries.
|
|
28
36
|
*/
|
|
29
37
|
import { type WaveRecord } from "../wave-engine.js";
|
|
30
38
|
import type { ChangeSetDocument } from "../change-set.js";
|
|
@@ -64,6 +72,11 @@ export interface FanOutAttempt {
|
|
|
64
72
|
carried?: Record<string, unknown>;
|
|
65
73
|
/** A pull request's apply only (#3464). */
|
|
66
74
|
prApply?: PrApplyRecord;
|
|
75
|
+
/**
|
|
76
|
+
* The input digest each completed component applied (#4081), keyed by
|
|
77
|
+
* name. Absent on a record written before it, which then carries nothing.
|
|
78
|
+
*/
|
|
79
|
+
inputs?: Record<string, string>;
|
|
67
80
|
}
|
|
68
81
|
/** Read an attempt record, or `undefined` when there is none yet. Throws on a file that is not JSON. */
|
|
69
82
|
export declare function readFanOutAttempt(path: string): FanOutAttempt | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fan-out-record.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-record.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fan-out-record.d.ts","sourceRoot":"","sources":["../../src/components/fan-out-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oDAAoD;IACpD,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,qGAAqG;IACrG,SAAS,EAAE,iBAAiB,CAAC;IAC7B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,wCAAwC;IACxC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA+BD,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAwBzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAE7E"}
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
* `carried` holds what a step asked to keep for its member (#3459). It rides
|
|
26
26
|
* in the record rather than beside it because the record is the one file a
|
|
27
27
|
* per-wave CI job hands to the next.
|
|
28
|
+
*
|
|
29
|
+
* `inputs` holds, for each component in `completed`, the input digest it
|
|
30
|
+
* applied (#4081, ./fan-out-inputs.ts). The plan digest only identifies the
|
|
31
|
+
* derivation, and two different changes with the same shape derive the same
|
|
32
|
+
* one, so the digest alone would carry "cluster-a already applied" into a
|
|
33
|
+
* change that never applied it. A resumed attempt carries a component only
|
|
34
|
+
* when its input digest is the same now. A record written before #4081 has
|
|
35
|
+
* no `inputs`, and none of its progress carries.
|
|
28
36
|
*/
|
|
29
37
|
import { existsSync, readFileSync } from "node:fs";
|
|
30
38
|
import { readWaveRecords, writeWaveRecordFile } from "../wave-engine.js";
|
|
@@ -71,6 +79,13 @@ export function readFanOutAttempt(path) {
|
|
|
71
79
|
}
|
|
72
80
|
const waves = readWaveRecords(parsed.waves);
|
|
73
81
|
const prApply = readPrApplyRecord(parsed.prApply);
|
|
82
|
+
let inputs;
|
|
83
|
+
if (isRecord(parsed.inputs)) {
|
|
84
|
+
inputs = {};
|
|
85
|
+
for (const [name, value] of Object.entries(parsed.inputs))
|
|
86
|
+
if (typeof value === "string")
|
|
87
|
+
inputs[name] = value;
|
|
88
|
+
}
|
|
74
89
|
return {
|
|
75
90
|
digest: typeof parsed.digest === "string" ? parsed.digest : "",
|
|
76
91
|
completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n) => typeof n === "string") : [],
|
|
@@ -79,6 +94,7 @@ export function readFanOutAttempt(path) {
|
|
|
79
94
|
...(waves.length > 0 ? { waves } : {}),
|
|
80
95
|
...(isRecord(parsed.carried) && Object.keys(parsed.carried).length > 0 ? { carried: parsed.carried } : {}),
|
|
81
96
|
...(prApply ? { prApply } : {}),
|
|
97
|
+
...(inputs ? { inputs } : {}),
|
|
82
98
|
};
|
|
83
99
|
}
|
|
84
100
|
/**
|