@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
|
@@ -7,6 +7,22 @@ import { generateComponentsPipeline } from "../../components/cli-support";
|
|
|
7
7
|
import { loadChantConfigUpward, type ChantConfig } from "../../config";
|
|
8
8
|
import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
|
|
9
9
|
import { findWorkspaceRoot } from "../../project-root";
|
|
10
|
+
import { resolvePromotionSource } from "../../components/promote-order";
|
|
11
|
+
import type { PrLoopPipelineOptions } from "../../components/pr-pipeline";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The `prLoop` generator option from `--pr-loop`'s flags (#3183): the gate
|
|
15
|
+
* and the branch, and with `--events-json` and `--report-url` (#4007) the
|
|
16
|
+
* flags the generated jobs pass to pr-plan and pr-apply.
|
|
17
|
+
*/
|
|
18
|
+
function prLoopOption(args: CommandContext["args"]): PrLoopPipelineOptions {
|
|
19
|
+
return {
|
|
20
|
+
...(args.gate ? { gate: args.gate } : {}),
|
|
21
|
+
...(args.branch ? { branch: args.branch } : {}),
|
|
22
|
+
...(args.eventsJson ? { events: true } : {}),
|
|
23
|
+
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
10
26
|
|
|
11
27
|
/**
|
|
12
28
|
* `chant build --components --generate <lexicon>` — generate mode (#563,
|
|
@@ -45,6 +61,24 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
45
61
|
return 1;
|
|
46
62
|
}
|
|
47
63
|
|
|
64
|
+
// #4030: the generated promote job runs `promote --from <env> --to <promote-to>`,
|
|
65
|
+
// which the member's declared promotion order refuses when it skips a step.
|
|
66
|
+
// Refuse here, with the same code, rather than write a job that fails.
|
|
67
|
+
if (args.promoteTo) {
|
|
68
|
+
// Loaded here, not at the top: a build without --promote-to loads no workspace module (#2526).
|
|
69
|
+
const { promotionOrder } = await import("../../workspace/promotion-order");
|
|
70
|
+
const resolved = resolvePromotionSource({
|
|
71
|
+
order: promotionOrder(config.environments),
|
|
72
|
+
to: args.promoteTo,
|
|
73
|
+
from: args.env ?? "production",
|
|
74
|
+
...(args.allowSkip ? { allowSkip: true } : {}),
|
|
75
|
+
});
|
|
76
|
+
if ("error" in resolved) {
|
|
77
|
+
console.error(formatError({ message: `${resolved.error.message} [${resolved.error.code}]`, hint: resolved.error.fix }));
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
48
82
|
// A project inside a workspace member gets that member's pipeline (#2542):
|
|
49
83
|
// path-filtered, run in the member's directory, written to a file named
|
|
50
84
|
// after the member and recorded as the member's generated file. The
|
|
@@ -62,11 +96,14 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
62
96
|
lexicon,
|
|
63
97
|
env: args.env,
|
|
64
98
|
promoteTo: args.promoteTo,
|
|
99
|
+
...(args.allowSkip ? { allowSkip: true } : {}),
|
|
65
100
|
output: args.output,
|
|
66
101
|
params: args.param,
|
|
67
102
|
paramsFile: args.paramsFile,
|
|
68
103
|
...(args.waveGate ? { waveGate: { gate: args.waveGate, ...(args.canary?.length ? { canary: args.canary } : {}), ...(args.base ? { base: args.base } : {}) } } : {}),
|
|
69
|
-
...(args.prLoop ? { prLoop:
|
|
104
|
+
...(args.prLoop ? { prLoop: prLoopOption(args) } : {}),
|
|
105
|
+
...(args.image ? { image: args.image } : {}),
|
|
106
|
+
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
70
107
|
});
|
|
71
108
|
} catch (err) {
|
|
72
109
|
console.error(formatError({ message: memberPipeline.describeError(err) }));
|
|
@@ -84,15 +121,20 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
|
|
|
84
121
|
{
|
|
85
122
|
env: args.env,
|
|
86
123
|
...(args.promoteTo ? { promoteTo: args.promoteTo } : {}),
|
|
124
|
+
// #4030: the job passes --allow-skip through, so it is not refused again at deploy time.
|
|
125
|
+
...(args.promoteTo && args.allowSkip
|
|
126
|
+
? { promoteCommand: ["chant", "components", "promote", "--from", args.env ?? "production", "--to", args.promoteTo, "--allow-skip"] }
|
|
127
|
+
: {}),
|
|
87
128
|
...(plan ? { member: plan.member } : {}),
|
|
88
129
|
// #3049: one job per wave of a gated-wave fan-out instead of one per component.
|
|
89
130
|
...(args.waveGate
|
|
90
131
|
? { gatedWaves: { gate: args.waveGate, ...(args.canary?.length ? { canary: args.canary } : {}), ...(args.base ? { base: args.base } : {}) } }
|
|
91
132
|
: {}),
|
|
92
133
|
// #3183: a plan job per pull request and an apply job per merge.
|
|
93
|
-
...(args.prLoop
|
|
94
|
-
|
|
95
|
-
|
|
134
|
+
...(args.prLoop ? { prLoop: prLoopOption(args) } : {}),
|
|
135
|
+
// #4002: the job image and the lines that install what it lacks, chant itself included.
|
|
136
|
+
...(args.image ? { image: args.image } : {}),
|
|
137
|
+
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
96
138
|
},
|
|
97
139
|
args.sandbox,
|
|
98
140
|
paramsResolution.provenance,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
2
3
|
import { CHANGE_SET_CONTRACT, CHANGE_SET_SCHEMA_ID, type ChangeSetDocument } from "../../change-set";
|
|
3
4
|
import { GITHUB_COMMENT_LIMIT, groupChangeSet, renderPlanSummaryMarkdown, renderPlanSummaryText } from "../../plan-summary";
|
|
4
|
-
import { formatError } from "../format";
|
|
5
|
+
import { formatError, formatWarning } from "../format";
|
|
5
6
|
import type { CommandContext } from "../registry";
|
|
6
7
|
|
|
7
8
|
const USAGE = "chant change-set summary <change-set.json> [--format text|json|markdown] [--limit <chars>]";
|
|
9
|
+
const SHOW_USAGE = "chant change-set show <digest> [--member <name>] [--json]";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* `chant change-set summary <file>` (#3188): the grouped plan summary of a
|
|
@@ -42,3 +44,49 @@ export async function runChangeSetSummary(ctx: CommandContext): Promise<number>
|
|
|
42
44
|
else process.stdout.write(renderPlanSummaryText(summary));
|
|
43
45
|
return 0;
|
|
44
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* `chant change-set show <digest>` (#4022): the change-set document a gate
|
|
50
|
+
* bound, stored on `chant/lifecycle` under its digest, with each entry's
|
|
51
|
+
* graph node. `--json` prints the read contract's `change-set-show`
|
|
52
|
+
* document (`../../workspace/change-set-show.ts`); without it, the grouped
|
|
53
|
+
* summary and each entry with its node. `--member` reads a workspace
|
|
54
|
+
* member's ledger from anywhere in the checkout. Exit 1 when nothing is
|
|
55
|
+
* stored under the digest.
|
|
56
|
+
*/
|
|
57
|
+
export async function runChangeSetShow(ctx: CommandContext): Promise<number> {
|
|
58
|
+
const { args } = ctx;
|
|
59
|
+
const digest = args.extraPositional;
|
|
60
|
+
const { changeSetShowDocument, CHANGE_SET_DIGEST_PATTERN } = await import("../../workspace/change-set-show");
|
|
61
|
+
if (!digest || !CHANGE_SET_DIGEST_PATTERN.test(digest)) {
|
|
62
|
+
console.error(formatError({ message: digest ? `${digest} is not a change-set digest` : "change-set show needs the digest a gate binds", hint: SHOW_USAGE }));
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if ((args.members?.length ?? 0) > 1) {
|
|
66
|
+
console.error(formatError({ message: `change-set show reads one member, not ${args.members!.join(", ")}`, hint: SHOW_USAGE }));
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
const member = args.members?.[0]?.split("/").filter(Boolean);
|
|
70
|
+
const doc = await changeSetShowDocument({ cwd: resolve("."), digest, ...(member ? { member } : {}) });
|
|
71
|
+
if (args.json) {
|
|
72
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
73
|
+
return "error" in doc || doc.changeSet === null ? 1 : 0;
|
|
74
|
+
}
|
|
75
|
+
if ("error" in doc) {
|
|
76
|
+
console.error(formatError({ message: doc.error.message, hint: SHOW_USAGE }));
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
if (doc.reason) console.error(formatWarning({ message: doc.reason.message }));
|
|
80
|
+
if (doc.changeSet === null) {
|
|
81
|
+
if (!doc.reason) console.error(formatError({ message: `no change set is stored under ${digest}${doc.member ? ` for member ${doc.member}` : ""}`, hint: "A pull-request or release gate stores the change set it binds; a component gate binds a lifecycle plan and stores none." }));
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
process.stdout.write(renderPlanSummaryText(groupChangeSet(doc.changeSet)));
|
|
85
|
+
const graph = doc.changeSet.graph;
|
|
86
|
+
console.log(graph ? `\nNodes from the graph of ${graph.member ?? "this project"}${graph.at ? ` at ${graph.at.slice(0, 12)}` : ""}:` : "\nNo graph was read, so no entry has a node.");
|
|
87
|
+
for (const e of doc.changeSet.entries) {
|
|
88
|
+
if (e.action === "no-op" || e.action === "read") continue;
|
|
89
|
+
console.log(` ${e.action.padEnd(8)} ${e.member} ${e.address}${e.deposed ? ` (deposed ${e.deposed})` : ""} ${e.node ?? "(no node)"}`);
|
|
90
|
+
}
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
@@ -52,6 +52,7 @@ const sealedGates = new Set<string>();
|
|
|
52
52
|
const { CapabilityRegistry } = await import("../../components/capability");
|
|
53
53
|
const { memoryGateLedgerPort } = await import("../../op/gate");
|
|
54
54
|
const { runComponentsFanOut } = await import("./fan-out");
|
|
55
|
+
const { checkRunEventLines } = await import("../../workspace/__fixtures__/run-event-check");
|
|
55
56
|
|
|
56
57
|
let gateLedger = memoryGateLedgerPort();
|
|
57
58
|
|
|
@@ -232,7 +233,8 @@ describe("proof: a plan-only invocation prints the derivation and dispatches not
|
|
|
232
233
|
|
|
233
234
|
ran = [];
|
|
234
235
|
stderrLines = [];
|
|
235
|
-
|
|
236
|
+
// The same environment: progress is bound to it (#4081).
|
|
237
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume, dryRun: true }))).toBe(0);
|
|
236
238
|
|
|
237
239
|
expect(ran).toEqual([]);
|
|
238
240
|
const out = stderr();
|
|
@@ -622,3 +624,228 @@ describe("gated waves (#3049): one gate per wave, bound to the wave's set digest
|
|
|
622
624
|
expect(stderr()).toContain("--wave runs one wave");
|
|
623
625
|
});
|
|
624
626
|
});
|
|
627
|
+
|
|
628
|
+
describe("--events-json (#4041)", () => {
|
|
629
|
+
const lines = () => stdoutLines.filter((l) => l.startsWith('{"$schema"'));
|
|
630
|
+
|
|
631
|
+
test("a fan-out over the set: the gate is a gate phase settled gated, and nothing after it starts", async () => {
|
|
632
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", eventsJson: true }))).toBe(3);
|
|
633
|
+
const events = checkRunEventLines(lines());
|
|
634
|
+
expect(events[0]).toMatchObject({ type: "run-start", kind: "component", waves: [["net"], ["cluster-a", "cluster-b"], ["app-one", "app-three", "app-two"]] });
|
|
635
|
+
expect(events.map((e) => e.type)).toEqual(["run-start", "phase-start", "step-start", "gate-waiting", "step-settle", "phase-settle", "run-settle"]);
|
|
636
|
+
expect(events.find((e) => e.type === "gate-waiting")).toMatchObject({ component: null, phase: "gate", step: "gate:release", op: "fan-out", gate: "release" });
|
|
637
|
+
expect(events.at(-1)).toMatchObject({ status: "gated" });
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test("approved, the gate resolves and every wave and component follows, each step started before it settles", async () => {
|
|
641
|
+
await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release" }));
|
|
642
|
+
const pending = gateLedger.appended[0];
|
|
643
|
+
gateLedger = memoryGateLedgerPort({
|
|
644
|
+
pending: [pending],
|
|
645
|
+
resolutions: [{
|
|
646
|
+
version: 1, kind: "resolution", op: "fan-out", gate: "release", resolvedBy: "operator",
|
|
647
|
+
timestamp: new Date(Date.parse(pending.timestamp) + 1000).toISOString(), planDigest: pending.planDigest,
|
|
648
|
+
}],
|
|
649
|
+
});
|
|
650
|
+
stdoutLines = [];
|
|
651
|
+
failing = ["cluster-b"];
|
|
652
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", eventsJson: true }))).toBe(1);
|
|
653
|
+
const events = checkRunEventLines(lines());
|
|
654
|
+
expect(events.find((e) => e.type === "gate-resolved")).toMatchObject({ gate: "release", resolvedBy: "operator" });
|
|
655
|
+
expect(events.filter((e) => e.type === "wave-start").map((e) => (e as { wave: number }).wave)).toEqual([1, 2, 3]);
|
|
656
|
+
expect(events.find((e) => e.type === "component-settle" && e.component === "cluster-b")).toMatchObject({ status: "failed" });
|
|
657
|
+
expect(events.at(-1)).toMatchObject({ type: "run-settle", status: "failed" });
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
test("a component behind a failure settles blocked, naming it, after the failing wave and before the next starts (#4007)", async () => {
|
|
661
|
+
failing = ["cluster-a"];
|
|
662
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", eventsJson: true }))).toBe(1);
|
|
663
|
+
const events = checkRunEventLines(lines());
|
|
664
|
+
const blocked = events.filter((e) => e.type === "component-settle" && e.status === "blocked");
|
|
665
|
+
expect(blocked.map((e) => ({ wave: (e as { wave: number }).wave, component: (e as { component: string }).component, blockedBy: (e as { blockedBy?: string }).blockedBy }))).toEqual([
|
|
666
|
+
{ wave: 3, component: "app-one", blockedBy: "cluster-a" },
|
|
667
|
+
{ wave: 3, component: "app-two", blockedBy: "cluster-a" },
|
|
668
|
+
]);
|
|
669
|
+
const wave2Settle = events.findIndex((e) => e.type === "wave-settle" && e.wave === 2);
|
|
670
|
+
const wave3Start = events.findIndex((e) => e.type === "wave-start" && e.wave === 3);
|
|
671
|
+
expect(events.indexOf(blocked[0]!)).toBeGreaterThan(wave2Settle);
|
|
672
|
+
expect(events.indexOf(blocked[1]!)).toBeLessThan(wave3Start);
|
|
673
|
+
// A blocked component never starts.
|
|
674
|
+
expect(events.some((e) => e.type === "component-start" && e.component === "app-one")).toBe(false);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test("a resumed fan-out settles what the earlier attempt applied as already-applied, in the derivation's waves (#4007)", async () => {
|
|
678
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-"));
|
|
679
|
+
try {
|
|
680
|
+
const resume = join(dir, "attempt.json");
|
|
681
|
+
failing = ["cluster-a"];
|
|
682
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(1);
|
|
683
|
+
failing = [];
|
|
684
|
+
stdoutLines = [];
|
|
685
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume, eventsJson: true }))).toBe(0);
|
|
686
|
+
const events = checkRunEventLines(lines());
|
|
687
|
+
const firstWave = events.findIndex((e) => e.type === "wave-start");
|
|
688
|
+
const applied = events.filter((e) => e.type === "component-settle" && e.status === "already-applied");
|
|
689
|
+
expect(applied.map((e) => [(e as { component: string }).component, (e as { wave: number }).wave])).toEqual([["app-three", 3], ["cluster-b", 2], ["net", 1]]);
|
|
690
|
+
for (const e of applied) expect(events.indexOf(e)).toBeLessThan(firstWave);
|
|
691
|
+
// --progress-json never printed them, and still does not.
|
|
692
|
+
stdoutLines = [];
|
|
693
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume, progressJson: true }))).toBe(0);
|
|
694
|
+
expect(stdoutLines.filter((l) => l.startsWith('{"type"')).map((l) => JSON.parse(l).type)).toEqual(["run-start", "run-done"]);
|
|
695
|
+
} finally {
|
|
696
|
+
await rm(dir, { recursive: true, force: true });
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
test("--progress-json on a set the gate stops now prints run-start and run-done gated (a level-0 change)", async () => {
|
|
701
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", progressJson: true }))).toBe(3);
|
|
702
|
+
const progress = stdoutLines.filter((l) => l.startsWith('{"type"')).map((l) => JSON.parse(l));
|
|
703
|
+
expect(progress).toEqual([
|
|
704
|
+
{ type: "run-start", waves: [["net"], ["cluster-a", "cluster-b"], ["app-one", "app-three", "app-two"]] },
|
|
705
|
+
{ type: "run-done", status: "gated" },
|
|
706
|
+
]);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
test("beside --progress-json it is refused", async () => {
|
|
710
|
+
expect(await runComponentsFanOut(ctx({ base: "main", eventsJson: true, progressJson: true }))).toBe(1);
|
|
711
|
+
expect(stderr()).toContain("--events-json and --progress-json both stream to stdout");
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
describe("progress carries only for an unchanged input (#4081)", () => {
|
|
716
|
+
/** The estate with each component deploying a built template from `templates/`, read relative to the project. */
|
|
717
|
+
const templated = ESTATE.map((c) => ({
|
|
718
|
+
...c,
|
|
719
|
+
deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy", stack: `${c.name}-stack`, template: `templates/${c.name}.json` }] }],
|
|
720
|
+
}));
|
|
721
|
+
let dir: string;
|
|
722
|
+
const writeTemplate = (name: string, body: unknown) =>
|
|
723
|
+
writeFile(join(dir, "templates", `${name}.json`), JSON.stringify(body));
|
|
724
|
+
|
|
725
|
+
beforeEach(async () => {
|
|
726
|
+
dir = await mkdtemp(join(tmpdir(), "fan-out-inputs-"));
|
|
727
|
+
const { mkdir } = await import("node:fs/promises");
|
|
728
|
+
await mkdir(join(dir, "templates"));
|
|
729
|
+
for (const c of templated) await writeTemplate(c.name, { Resources: { [c.name]: { Type: "AWS::SNS::Topic" } } });
|
|
730
|
+
// The project is the temp directory, so the templates are read from there and nothing touches the checkout.
|
|
731
|
+
vi.spyOn(process, "cwd").mockReturnValue(dir);
|
|
732
|
+
discoverComponentsMock.mockResolvedValue({
|
|
733
|
+
components: new Map(templated.map((c) => [c.name, { component: c, exportName: c.name, filePath: `${c.name}.component.ts` }])),
|
|
734
|
+
sourceFiles: [],
|
|
735
|
+
errors: [],
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
afterEach(async () => {
|
|
739
|
+
await rm(dir, { recursive: true, force: true });
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
test("same shape, changed content: a stale record does not skip the components whose input moved", async () => {
|
|
743
|
+
const resume = join(dir, "attempt.json");
|
|
744
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
745
|
+
const first = JSON.parse(await readFile(resume, "utf8"));
|
|
746
|
+
expect(first.completed).toEqual(["app-one", "app-three", "app-two", "cluster-a", "cluster-b", "net"]);
|
|
747
|
+
expect(Object.keys(first.inputs).sort()).toEqual(first.completed);
|
|
748
|
+
const digest = /plan: (jcs1-sha256:[0-9a-f]{64})/.exec(stderr())?.[1];
|
|
749
|
+
|
|
750
|
+
// The next change: net's topic gets a display name and cluster-a a queue.
|
|
751
|
+
// Same components, same edges, so the same plan digest.
|
|
752
|
+
await writeTemplate("net", { Resources: { net: { Type: "AWS::SNS::Topic", Properties: { DisplayName: "estate" } } } });
|
|
753
|
+
await writeTemplate("cluster-a", { Resources: { "cluster-a": { Type: "AWS::SNS::Topic" }, events: { Type: "AWS::SQS::Queue" } } });
|
|
754
|
+
ran = [];
|
|
755
|
+
stderrLines = [];
|
|
756
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
757
|
+
|
|
758
|
+
expect([...ran].sort()).toEqual(["app-one", "app-three", "app-two", "cluster-a", "cluster-b", "net"]);
|
|
759
|
+
const out = stderr();
|
|
760
|
+
expect(out).toContain(`plan: ${digest}`);
|
|
761
|
+
expect(out).toContain("net: changed since the earlier attempt, so it runs again");
|
|
762
|
+
expect(out).toContain("cluster-a: changed since the earlier attempt, so it runs again");
|
|
763
|
+
// Downstream of net, so its parameters read a changed upstream.
|
|
764
|
+
expect(out).toContain("app-three: changed since the earlier attempt, so it runs again");
|
|
765
|
+
expect(out).not.toMatch(/already-applied/);
|
|
766
|
+
expect(out).toContain("fan-out completed: 6 applied, 0 failed, 0 blocked");
|
|
767
|
+
const second = JSON.parse(await readFile(resume, "utf8"));
|
|
768
|
+
expect(second.inputs.net).not.toBe(first.inputs.net);
|
|
769
|
+
expect(second.inputs["cluster-b"]).not.toBe(first.inputs["cluster-b"]);
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
test("a change below the root reruns only its own subtree", async () => {
|
|
773
|
+
const resume = join(dir, "attempt.json");
|
|
774
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
775
|
+
await writeTemplate("cluster-a", { Resources: { "cluster-a": { Type: "AWS::SNS::Topic" }, events: { Type: "AWS::SQS::Queue" } } });
|
|
776
|
+
ran = [];
|
|
777
|
+
stderrLines = [];
|
|
778
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
779
|
+
expect(ran).toEqual(["cluster-a", "app-one", "app-two"]);
|
|
780
|
+
expect(stderr()).toMatch(/cluster-b +already-applied/);
|
|
781
|
+
expect(stderr()).not.toContain("net: changed");
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
test("the README's fail-then-fix: the fix reruns the failed subtree and the rest stay already-applied", async () => {
|
|
785
|
+
const resume = join(dir, "attempt.json");
|
|
786
|
+
failing = ["cluster-a"];
|
|
787
|
+
await writeTemplate("cluster-a", { Resources: { events: { Type: "AWS::SQS::Queue", Properties: { FifoQueue: true, QueueName: "events" } } } });
|
|
788
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(1);
|
|
789
|
+
const digest = /plan: (jcs1-sha256:[0-9a-f]{64})/.exec(stderr())?.[1];
|
|
790
|
+
|
|
791
|
+
// The fix changes cluster-a's template, which never applied.
|
|
792
|
+
failing = [];
|
|
793
|
+
await writeTemplate("cluster-a", { Resources: { events: { Type: "AWS::SQS::Queue", Properties: { FifoQueue: true, QueueName: "events.fifo" } } } });
|
|
794
|
+
ran = [];
|
|
795
|
+
stderrLines = [];
|
|
796
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
797
|
+
expect(ran).toEqual(["cluster-a", "app-one", "app-two"]);
|
|
798
|
+
const out = stderr();
|
|
799
|
+
expect(out).toContain(`plan: ${digest}`);
|
|
800
|
+
expect(out).not.toContain("changed since the earlier attempt");
|
|
801
|
+
for (const name of ["net", "cluster-b", "app-three"]) expect(out).toMatch(new RegExp(`${name} +already-applied`));
|
|
802
|
+
expect(out).toContain("fan-out completed: 3 applied, 0 failed, 0 blocked");
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
test("the fix keeps the approval: approval binds the derivation, progress binds the inputs", async () => {
|
|
806
|
+
const resume = join(dir, "attempt.json");
|
|
807
|
+
failing = ["cluster-a"];
|
|
808
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", resume }))).toBe(3);
|
|
809
|
+
const pending = gateLedger.appended[0]!;
|
|
810
|
+
gateLedger = memoryGateLedgerPort({
|
|
811
|
+
pending: [pending],
|
|
812
|
+
resolutions: [
|
|
813
|
+
{
|
|
814
|
+
version: 1,
|
|
815
|
+
kind: "resolution",
|
|
816
|
+
op: "fan-out",
|
|
817
|
+
gate: "release",
|
|
818
|
+
resolvedBy: "operator",
|
|
819
|
+
timestamp: new Date(Date.parse(pending.timestamp) + 1000).toISOString(),
|
|
820
|
+
planDigest: pending.planDigest,
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
});
|
|
824
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", resume }))).toBe(1);
|
|
825
|
+
|
|
826
|
+
failing = [];
|
|
827
|
+
await writeTemplate("cluster-a", { Resources: { fixed: { Type: "AWS::SQS::Queue" } } });
|
|
828
|
+
ran = [];
|
|
829
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release", resume }))).toBe(0);
|
|
830
|
+
expect(ran).toEqual(["cluster-a", "app-one", "app-two"]);
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
test("the input digest is per environment: progress against one does not carry into another", async () => {
|
|
834
|
+
const resume = join(dir, "attempt.json");
|
|
835
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
836
|
+
ran = [];
|
|
837
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "prod", resume }))).toBe(0);
|
|
838
|
+
expect(ran).toHaveLength(6);
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
test("a record without input digests carries nothing, and says so", async () => {
|
|
842
|
+
const resume = join(dir, "attempt.json");
|
|
843
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", dryRun: true }))).toBe(0);
|
|
844
|
+
const digest = /plan: (jcs1-sha256:[0-9a-f]{64})/.exec(stderr())![1]!;
|
|
845
|
+
await writeFile(resume, JSON.stringify({ digest, completed: ["net", "cluster-b"], failed: [], outputs: {} }));
|
|
846
|
+
stderrLines = [];
|
|
847
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
848
|
+
expect(ran).toHaveLength(6);
|
|
849
|
+
expect(stderr()).toContain("does not record what each component applied, so none of its progress carries");
|
|
850
|
+
});
|
|
851
|
+
});
|
|
@@ -34,6 +34,15 @@
|
|
|
34
34
|
* the plan before the gate is decided, and the digest is carried rather than
|
|
35
35
|
* recomputed, so the approval still stands.
|
|
36
36
|
*
|
|
37
|
+
* The approval and the progress are bound to different things (#4081). The
|
|
38
|
+
* approval is bound to the plan digest, the derivation: who runs, in what
|
|
39
|
+
* order, off which edges. The progress is bound to each component's input
|
|
40
|
+
* digest (../../components/fan-out-inputs.ts): a component the earlier
|
|
41
|
+
* attempt applied stays `already-applied` only while what it would apply is
|
|
42
|
+
* the same, and one whose template, step inputs or upstream moved runs again
|
|
43
|
+
* with a line saying so. The fix after a failure keeps the approval, and a
|
|
44
|
+
* different change of the same shape does not inherit the progress.
|
|
45
|
+
*
|
|
37
46
|
* `--wave-gate <name>` (#3049) swaps the one gate for one per wave: the same
|
|
38
47
|
* repeated command stops at each wave's gate in turn, each planned after the
|
|
39
48
|
* wave before it applied, and `chant approve fan-out <name>-wave-<n>` answers
|
|
@@ -49,9 +58,11 @@ import { changedFilesBetween, lexiconChangedUnits } from "../../components/chang
|
|
|
49
58
|
import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
|
|
50
59
|
import { EarlierWaveNotAppliedError, runFanOut } from "../../components/fan-out-run";
|
|
51
60
|
import { readFanOutAttempt, writeFanOutAttempt, type FanOutAttempt } from "../../components/fan-out-record";
|
|
61
|
+
import { componentInputDigests, progressThatCarries } from "../../components/fan-out-inputs";
|
|
52
62
|
import { describeChangedWave, withWaveRecord, type WaveRecord } from "../../gated-waves";
|
|
53
63
|
import { renderFanOutHuman, renderFanOutJson, renderFanOutPlan } from "../../components/fan-out-output";
|
|
54
64
|
import { ndjsonProgressSink } from "../../components/run-progress";
|
|
65
|
+
import { openCliRunEvents, refusesBothStreams } from "../run-events";
|
|
55
66
|
import { summaryLedgerPrefix, writeGatedRunSummary } from "../../op/gate-summary";
|
|
56
67
|
import { approveCommand, gateIsSealed } from "../../op/gate";
|
|
57
68
|
import { getHeadCommit } from "../../lifecycle/git";
|
|
@@ -60,7 +71,7 @@ import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
|
|
|
60
71
|
import { formatError, formatInfo, formatWarning } from "../format";
|
|
61
72
|
import { FAN_OUT_GATE_OP } from "../../op/gate-name";
|
|
62
73
|
import { resolveBuildRoot } from "./lifecycle";
|
|
63
|
-
import { GATED_EXIT_CODE, recordAutoReleasesForRun } from "./run";
|
|
74
|
+
import { GATED_EXIT_CODE, autoReleaseRun, recordAutoReleasesForRun } from "./run";
|
|
64
75
|
import type { CommandContext } from "../registry";
|
|
65
76
|
|
|
66
77
|
/**
|
|
@@ -172,10 +183,11 @@ export async function resolveChangedUnits(
|
|
|
172
183
|
* chant components fan-out --base <ref> | --from-affected <file>
|
|
173
184
|
* [--head <ref>] [--include-dependents] [--env <env>] [--gate <name>]
|
|
174
185
|
* [--dry-run] [--json] [--resume <file>] [--seed-outputs <file>]
|
|
175
|
-
* [--dump-outputs <file>] [--progress-json]
|
|
186
|
+
* [--dump-outputs <file>] [--progress-json | --events-json]
|
|
176
187
|
*/
|
|
177
188
|
export async function runComponentsFanOut(ctx: CommandContext): Promise<number> {
|
|
178
189
|
const { args } = ctx;
|
|
190
|
+
if (refusesBothStreams(args)) return 1;
|
|
179
191
|
const projectPath = resolve(".");
|
|
180
192
|
const { config } = await loadChantConfig(projectPath).catch(() => ({ config: {} as ChantConfig }));
|
|
181
193
|
|
|
@@ -251,7 +263,12 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
251
263
|
// real run happens inside `runFanOut`, before the gate is decided, so an
|
|
252
264
|
// approval survives the resume rather than being re-asked for.
|
|
253
265
|
const resumePath = args.resume ? resolve(args.resume) : undefined;
|
|
266
|
+
// What each component would apply now (#4081). The record keeps it for
|
|
267
|
+
// every component that applies, and a later attempt carries progress only
|
|
268
|
+
// where it is unchanged.
|
|
269
|
+
const inputsNow = resumePath ? componentInputDigests(derived.components, { projectRoot: projectPath, env: args.env ?? "local" }) : {};
|
|
254
270
|
let priorCompleted: string[] = [];
|
|
271
|
+
let priorInputs: Record<string, string> = {};
|
|
255
272
|
let priorOutputs: Record<string, Record<string, unknown>> = {};
|
|
256
273
|
let priorWaves: WaveRecord[] = [];
|
|
257
274
|
let priorCarried: Record<string, unknown> = {};
|
|
@@ -275,11 +292,28 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
275
292
|
// as progress would block their subtrees again on the very run that
|
|
276
293
|
// exists to retry them — the operator repeated the command precisely
|
|
277
294
|
// because the thing that failed is now expected to work.
|
|
278
|
-
|
|
295
|
+
//
|
|
296
|
+
// And only the part of `completed` whose input is the same now (#4081).
|
|
297
|
+
// The plan digest identifies the derivation, which a different change
|
|
298
|
+
// of the same shape shares; the input digest says what was applied.
|
|
299
|
+
const split = progressThatCarries(attempt, inputsNow);
|
|
300
|
+
if (split.unrecorded && split.changed.length > 0) {
|
|
301
|
+
console.error(formatWarning({
|
|
302
|
+
message: `--resume: "${args.resume}" does not record what each component applied, so none of its progress carries`,
|
|
303
|
+
hint: "It was written before chant recorded component inputs. Everything selected will run.",
|
|
304
|
+
}));
|
|
305
|
+
} else {
|
|
306
|
+
for (const name of split.changed) {
|
|
307
|
+
console.error(formatInfo(`${name}: changed since the earlier attempt, so it runs again`));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const carried = new Set(split.carried);
|
|
311
|
+
priorCompleted = split.carried;
|
|
312
|
+
priorInputs = Object.fromEntries(split.carried.map((name) => [name, inputsNow[name]!]));
|
|
279
313
|
priorOutputs = Object.fromEntries(
|
|
280
|
-
Object.entries(attempt.outputs).filter(([name]) =>
|
|
314
|
+
Object.entries(attempt.outputs).filter(([name]) => carried.has(name)),
|
|
281
315
|
);
|
|
282
|
-
progress = { completed:
|
|
316
|
+
progress = { completed: split.carried };
|
|
283
317
|
priorWaves = attempt.waves ?? [];
|
|
284
318
|
// What steps kept per member (#3459), such as a choudoufu root's wave
|
|
285
319
|
// resume file. Each step decides whether what it kept still applies.
|
|
@@ -317,6 +351,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
317
351
|
// runner, ctrl-c) then still knows that the first two applied, and the
|
|
318
352
|
// repeated command picks up from there instead of redoing them.
|
|
319
353
|
const completedSoFar = new Set(priorCompleted);
|
|
354
|
+
const inputsSoFar: Record<string, string> = { ...priorInputs };
|
|
320
355
|
const failedSoFar: string[] = [];
|
|
321
356
|
const outputsSoFar = { ...priorOutputs };
|
|
322
357
|
let wavesSoFar = priorWaves;
|
|
@@ -328,12 +363,18 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
328
363
|
completed: [...completedSoFar].sort(),
|
|
329
364
|
failed: [...failedSoFar].sort(),
|
|
330
365
|
outputs: outputsSoFar,
|
|
366
|
+
inputs: Object.fromEntries(Object.entries(inputsSoFar).sort(([a], [b]) => a.localeCompare(b))),
|
|
331
367
|
...(wavesSoFar.length > 0 ? { waves: wavesSoFar } : {}),
|
|
332
368
|
...(Object.keys(carriedSoFar).length > 0 ? { carried: carriedSoFar } : {}),
|
|
333
369
|
};
|
|
334
370
|
writeFanOutAttempt(resumePath, attempt);
|
|
335
371
|
};
|
|
336
372
|
|
|
373
|
+
// The run id the release records carry, chosen before the run so that
|
|
374
|
+
// `--events-json` (#4041) names the run by it too.
|
|
375
|
+
const release = autoReleaseRun(`fan-out-${Date.now()}`);
|
|
376
|
+
const events = await openCliRunEvents(args, { kind: "component", name: `fan-out ${derived.plan.order.join(",")}`, runId: release.runId, cwd: projectPath });
|
|
377
|
+
|
|
337
378
|
let result;
|
|
338
379
|
try {
|
|
339
380
|
result = await runFanOut(derived.plan, derived.components, registry, {
|
|
@@ -364,11 +405,13 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
364
405
|
}
|
|
365
406
|
: {}),
|
|
366
407
|
...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
|
|
408
|
+
...(events ? { onRunEvent: events.emit } : {}),
|
|
367
409
|
...(resumePath
|
|
368
410
|
? {
|
|
369
411
|
onComponentSettled: (settled, outputs) => {
|
|
370
412
|
if (settled.status === "ok") {
|
|
371
413
|
completedSoFar.add(settled.component);
|
|
414
|
+
if (inputsNow[settled.component] !== undefined) inputsSoFar[settled.component] = inputsNow[settled.component]!;
|
|
372
415
|
if (outputs) outputsSoFar[settled.component] = outputs;
|
|
373
416
|
} else if (settled.status === "fail") {
|
|
374
417
|
failedSoFar.push(settled.component);
|
|
@@ -379,6 +422,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
379
422
|
: {}),
|
|
380
423
|
});
|
|
381
424
|
} catch (err) {
|
|
425
|
+
events?.settle("failed", err instanceof Error ? err.message : String(err));
|
|
382
426
|
// `--wave <n>` reached before an earlier wave applied: nothing ran.
|
|
383
427
|
if (err instanceof EarlierWaveNotAppliedError) {
|
|
384
428
|
console.error(formatError({ message: err.message }));
|
|
@@ -386,6 +430,8 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
386
430
|
}
|
|
387
431
|
throw err;
|
|
388
432
|
}
|
|
433
|
+
// The fan-out settles the stream; this only ends one it left open.
|
|
434
|
+
events?.settle(result.status === "fail" ? "failed" : result.status);
|
|
389
435
|
|
|
390
436
|
if (args.dumpOutputs) {
|
|
391
437
|
const dumpPath = resolve(args.dumpOutputs);
|
|
@@ -420,8 +466,9 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
420
466
|
await recordAutoReleasesForRun(
|
|
421
467
|
result.results,
|
|
422
468
|
args.env ?? "local",
|
|
423
|
-
|
|
469
|
+
release.runId,
|
|
424
470
|
resolveAutoReleaseDisabled(config, args.noReleaseRecord),
|
|
471
|
+
release.runOrigin,
|
|
425
472
|
);
|
|
426
473
|
}
|
|
427
474
|
|