@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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `recordAutoReleasesForRun` hands the release record (#4020): the run
|
|
3
|
+
* and its origin, and for a component that passed a gate, who approved it and
|
|
4
|
+
* which resolution admitted it.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
|
|
7
|
+
|
|
8
|
+
const maybeRecordAutoReleaseMock = vi.fn();
|
|
9
|
+
vi.mock("../../components/auto-release", async () => {
|
|
10
|
+
const actual = await vi.importActual<typeof import("../../components/auto-release")>("../../components/auto-release");
|
|
11
|
+
return { ...actual, maybeRecordAutoRelease: (...args: unknown[]) => maybeRecordAutoReleaseMock(...args) };
|
|
12
|
+
});
|
|
13
|
+
vi.mock("../../components/manifest-persistence", async () => {
|
|
14
|
+
const actual = await vi.importActual<typeof import("../../components/manifest-persistence")>("../../components/manifest-persistence");
|
|
15
|
+
return { ...actual, maybePersistBuildManifest: async () => ({ persisted: false, reason: "no-manifest" }) };
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
import { autoReleaseRun, recordAutoReleasesForRun } from "./run";
|
|
19
|
+
import type { DriverComponentResult } from "../../components/driver";
|
|
20
|
+
|
|
21
|
+
const gatedResult = {
|
|
22
|
+
component: "api",
|
|
23
|
+
ok: true,
|
|
24
|
+
status: "ok",
|
|
25
|
+
records: [
|
|
26
|
+
{ component: "api", phase: "Deploy", kind: "gate:approve-prod", status: "ok", durationMs: 1, approval: { gate: "approve-prod", resolvedBy: "alice", timestamp: "2026-10-16T10:05:00.000Z" } },
|
|
27
|
+
{ component: "api", phase: "Deploy", kind: "apply", status: "ok", durationMs: 1 },
|
|
28
|
+
],
|
|
29
|
+
} as unknown as DriverComponentResult;
|
|
30
|
+
const plainResult = { component: "worker", ok: true, status: "ok", records: [] } as unknown as DriverComponentResult;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
maybeRecordAutoReleaseMock.mockReset().mockResolvedValue({ recorded: false, reason: "no-digest" });
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => vi.unstubAllEnvs());
|
|
36
|
+
|
|
37
|
+
describe("recordAutoReleasesForRun", () => {
|
|
38
|
+
test("a component that passed a gate records its approver and admission, one that did not records neither", async () => {
|
|
39
|
+
await recordAutoReleasesForRun([gatedResult, plainResult], "prod", "9001", false, { forge: "github", repo: "acme/app" });
|
|
40
|
+
const [gated, plain] = maybeRecordAutoReleaseMock.mock.calls.map((c) => c[0]);
|
|
41
|
+
expect(gated).toMatchObject({
|
|
42
|
+
component: "api", runId: "9001", runOrigin: { forge: "github", repo: "acme/app" },
|
|
43
|
+
approver: "alice", admission: { op: "api", gate: "approve-prod", resolvedAt: "2026-10-16T10:05:00.000Z" },
|
|
44
|
+
});
|
|
45
|
+
expect(plain).not.toHaveProperty("approver");
|
|
46
|
+
expect(plain).not.toHaveProperty("admission");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("a run under --release records the release digest on each component, one without it records none (#4043)", async () => {
|
|
50
|
+
const release = `jcs1-sha256:${"c".repeat(64)}`;
|
|
51
|
+
await recordAutoReleasesForRun([plainResult], "dev", "9001", false, { forge: "local" }, release);
|
|
52
|
+
expect(maybeRecordAutoReleaseMock.mock.calls[0][0]).toMatchObject({ releaseDigest: release });
|
|
53
|
+
maybeRecordAutoReleaseMock.mockClear();
|
|
54
|
+
await recordAutoReleasesForRun([plainResult], "dev", "9001", false, { forge: "local" });
|
|
55
|
+
expect(maybeRecordAutoReleaseMock.mock.calls[0][0]).not.toHaveProperty("releaseDigest");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("the origin defaults to local", async () => {
|
|
59
|
+
await recordAutoReleasesForRun([plainResult], "prod", "local-1", false);
|
|
60
|
+
expect(maybeRecordAutoReleaseMock.mock.calls[0][0]).toMatchObject({ runId: "local-1", runOrigin: { forge: "local" } });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("autoReleaseRun", () => {
|
|
65
|
+
test("in CI it names the CI run, so the release and the gate it passed name one run", () => {
|
|
66
|
+
vi.stubEnv("GITHUB_RUN_ID", "9001");
|
|
67
|
+
vi.stubEnv("GITHUB_REPOSITORY", "acme/app");
|
|
68
|
+
vi.stubEnv("GITHUB_SERVER_URL", "https://github.example");
|
|
69
|
+
expect(autoReleaseRun("local-1")).toEqual({
|
|
70
|
+
runId: "9001",
|
|
71
|
+
runOrigin: { forge: "github", repo: "acme/app", url: "https://github.example/acme/app/actions/runs/9001" },
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("outside CI it keeps the local id", () => {
|
|
76
|
+
vi.stubEnv("GITHUB_RUN_ID", "");
|
|
77
|
+
vi.stubEnv("CI_PIPELINE_ID", "");
|
|
78
|
+
expect(autoReleaseRun("local-1")).toEqual({ runId: "local-1", runOrigin: { forge: "local" } });
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** #4042: `chant run events <run> [--json] [--follow]`. */
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
8
|
+
import type { ParsedArgs } from "../registry";
|
|
9
|
+
import { runOpEvents } from "./run";
|
|
10
|
+
import { openRunEventStore } from "../../run-event-store";
|
|
11
|
+
import { openRunEventStream, runEventRunOf } from "../../run-event-stream";
|
|
12
|
+
|
|
13
|
+
function args(o: Partial<ParsedArgs>): ParsedArgs {
|
|
14
|
+
return { command: "run", path: ".", format: "", fix: false, watch: false, verbose: false, help: false, live: false, ...o };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let dir: string;
|
|
18
|
+
let cwd: string;
|
|
19
|
+
let out: string[];
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
cwd = process.cwd();
|
|
22
|
+
vi.stubEnv("CHANT_RUN_EVENTS_DIR", "");
|
|
23
|
+
dir = realpathSync(mkdtempSync(join(tmpdir(), "run-events-cmd-")));
|
|
24
|
+
execFileSync("git", ["init", "-q", "-b", "main"], { cwd: dir });
|
|
25
|
+
execFileSync("git", ["-c", "user.email=t@t", "-c", "user.name=t", "commit", "-q", "--allow-empty", "-m", "init"], { cwd: dir });
|
|
26
|
+
process.chdir(dir);
|
|
27
|
+
out = [];
|
|
28
|
+
vi.spyOn(process.stdout, "write").mockImplementation((s: string | Uint8Array) => (out.push(String(s)), true));
|
|
29
|
+
vi.spyOn(console, "log").mockImplementation((s: string) => void out.push(`${s}\n`));
|
|
30
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
31
|
+
});
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
vi.restoreAllMocks();
|
|
34
|
+
vi.unstubAllEnvs();
|
|
35
|
+
process.chdir(cwd);
|
|
36
|
+
rmSync(dir, { recursive: true, force: true });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
async function stream(runId: string, name = "deploy-api") {
|
|
40
|
+
const store = (await openRunEventStore(dir, runId))!;
|
|
41
|
+
return openRunEventStream(runEventRunOf({ kind: "op", name, runId }), store.write);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("chant run events", () => {
|
|
45
|
+
test("--json replays a settled run's lines and exits with its verdict", async () => {
|
|
46
|
+
const s = await stream("r-done");
|
|
47
|
+
s.emit({ type: "run-start", waves: null });
|
|
48
|
+
s.settle("failed", "boom");
|
|
49
|
+
const exit = await runOpEvents({ args: args({ extraPositional: "r-done", json: true }), plugins: [], serializers: [] });
|
|
50
|
+
expect(exit).toBe(1);
|
|
51
|
+
const events = out.join("").trim().split("\n").map((l) => JSON.parse(l));
|
|
52
|
+
expect(events.map((e) => e.type)).toEqual(["run-start", "run-settle"]);
|
|
53
|
+
expect(events[1]).toMatchObject({ status: "failed", error: "boom" });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("--json replays a run in progress up to now and exits 0", async () => {
|
|
57
|
+
const s = await stream("r-live");
|
|
58
|
+
s.emit({ type: "run-start", waves: null });
|
|
59
|
+
s.emit({ type: "phase-start", component: null, phase: "Build" });
|
|
60
|
+
const exit = await runOpEvents({ args: args({ extraPositional: "deploy-api", json: true }), plugins: [], serializers: [] });
|
|
61
|
+
expect(exit).toBe(0);
|
|
62
|
+
expect(out.join("").trim().split("\n").map((l) => JSON.parse(l).type)).toEqual(["run-start", "phase-start"]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("--follow prints each event of a run in progress, then the verdict", async () => {
|
|
66
|
+
const s = await stream("r-follow");
|
|
67
|
+
s.emit({ type: "run-start", waves: null });
|
|
68
|
+
const done = runOpEvents({ args: args({ extraPositional: "r-follow", json: true, follow: true }), plugins: [], serializers: [] });
|
|
69
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
70
|
+
expect(out.join("").trim().split("\n")).toHaveLength(1);
|
|
71
|
+
s.emit({ type: "phase-start", component: null, phase: "Build" });
|
|
72
|
+
s.emit({ type: "phase-settle", component: null, phase: "Build", status: "gated" });
|
|
73
|
+
s.settle("gated");
|
|
74
|
+
expect(await done).toBe(3);
|
|
75
|
+
expect(out.join("").trim().split("\n").map((l) => JSON.parse(l).type)).toEqual(["run-start", "phase-start", "phase-settle", "run-settle"]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("without --json each event is one line for a person", async () => {
|
|
79
|
+
const s = await stream("r-human");
|
|
80
|
+
s.emit({ type: "run-start", waves: null });
|
|
81
|
+
s.settle("ok");
|
|
82
|
+
expect(await runOpEvents({ args: args({ extraPositional: "r-human" }), plugins: [], serializers: [] })).toBe(0);
|
|
83
|
+
expect(out.join("")).toMatch(/run-start/);
|
|
84
|
+
expect(out.join("")).toMatch(/run-settle\s+ok/);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("a run with no kept events is refused by name; no run is refused", async () => {
|
|
88
|
+
expect(await runOpEvents({ args: args({ extraPositional: "nope" }), plugins: [], serializers: [] })).toBe(1);
|
|
89
|
+
expect(await runOpEvents({ args: args({}), plugins: [], serializers: [] })).toBe(1);
|
|
90
|
+
expect(await runOpEvents({ args: args({ extraPositional: "x", on: "fountain" }), plugins: [], serializers: [] })).toBe(1);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant run --components --release <label|digest>` (#4043): the run builds
|
|
3
|
+
* from the checked-out commit, so the release must be cut from it and have a
|
|
4
|
+
* target for the environment. Checked before anything deploys.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, test, expect, vi } from "vitest";
|
|
7
|
+
import { makeRelease } from "../../lifecycle/release-store";
|
|
8
|
+
|
|
9
|
+
const COMMIT = "a1b2c3d4".repeat(5);
|
|
10
|
+
const release = makeRelease({
|
|
11
|
+
member: null,
|
|
12
|
+
commit: COMMIT,
|
|
13
|
+
artifactDigests: [],
|
|
14
|
+
targets: [{ env: "dev", templates: [], params: [] }],
|
|
15
|
+
});
|
|
16
|
+
let head = COMMIT;
|
|
17
|
+
|
|
18
|
+
vi.mock("../../lifecycle/git", () => ({
|
|
19
|
+
getHeadCommit: async () => head,
|
|
20
|
+
fetchLifecycle: async () => true,
|
|
21
|
+
pushLifecycle: async () => false,
|
|
22
|
+
}));
|
|
23
|
+
vi.mock("../../lifecycle/release-store", async () => {
|
|
24
|
+
const actual = await vi.importActual<typeof import("../../lifecycle/release-store")>("../../lifecycle/release-store");
|
|
25
|
+
return {
|
|
26
|
+
...actual,
|
|
27
|
+
resolveRelease: async (ref: string) => (ref === "v1" || ref === release.releaseDigest ? { release, label: "v1" } : null),
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { resolveRunRelease } = await import("./run");
|
|
32
|
+
|
|
33
|
+
describe("resolveRunRelease", () => {
|
|
34
|
+
test("a release cut from HEAD with a target for the environment is the run's release, by label or digest", async () => {
|
|
35
|
+
head = COMMIT;
|
|
36
|
+
expect(await resolveRunRelease("v1", "dev", ".")).toMatchObject({ releaseDigest: release.releaseDigest, label: "v1" });
|
|
37
|
+
expect(await resolveRunRelease(release.releaseDigest, "dev", ".")).toMatchObject({ releaseDigest: release.releaseDigest });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("a release it can't find is refused", async () => {
|
|
41
|
+
expect(await resolveRunRelease("v9", "dev", ".")).toMatch(/no release is labelled or digested "v9"/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("a release cut from another commit is refused, and the message says why", async () => {
|
|
45
|
+
head = "f".repeat(40);
|
|
46
|
+
const why = await resolveRunRelease("v1", "dev", ".");
|
|
47
|
+
expect(why).toMatch(/was cut from a1b2c3d4a1b2 and this checkout is at ffffffffffff/);
|
|
48
|
+
expect(why).toMatch(/promote --release/);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("a release with no target for the environment is refused", async () => {
|
|
52
|
+
head = COMMIT;
|
|
53
|
+
expect(await resolveRunRelease("v1", "prod", ".")).toMatch(/has no target for "prod"/);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -98,6 +98,7 @@ vi.mock("../../lifecycle/run-ledger", async (importOriginal) => {
|
|
|
98
98
|
|
|
99
99
|
const { runOpList, runOpStatus, runOpLog, runOpSignalRenamed, runOpApprove, runOpCancel, runOp, runOpComponents } =
|
|
100
100
|
await import("./run");
|
|
101
|
+
const { checkRunEventLines } = await import("../../workspace/__fixtures__/run-event-check");
|
|
101
102
|
|
|
102
103
|
function makeArgs(overrides: Partial<ParsedArgs> = {}): ParsedArgs {
|
|
103
104
|
return {
|
|
@@ -1554,6 +1555,35 @@ describe("runOpComponents", () => {
|
|
|
1554
1555
|
vi.restoreAllMocks();
|
|
1555
1556
|
});
|
|
1556
1557
|
|
|
1558
|
+
test("--events-json streams the run-event stream as runComponents emits it, and ends one that never reached a component (#4041)", async () => {
|
|
1559
|
+
runComponentsMock.mockImplementation(
|
|
1560
|
+
async (_path: string, _selector: string, options: { onRunEvent?: (b: unknown) => void }) => {
|
|
1561
|
+
options.onRunEvent?.({ type: "run-start", waves: [["svc"]] });
|
|
1562
|
+
options.onRunEvent?.({ type: "run-settle", status: "ok", durationMs: null });
|
|
1563
|
+
return {
|
|
1564
|
+
success: true,
|
|
1565
|
+
selected: ["svc"],
|
|
1566
|
+
run: { order: ["svc"], waves: [["svc"]], results: [{ component: "svc", ok: true, status: "ok", records: [] }], ok: true, status: "ok" },
|
|
1567
|
+
};
|
|
1568
|
+
},
|
|
1569
|
+
);
|
|
1570
|
+
const stdoutWrite = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
1571
|
+
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
1572
|
+
|
|
1573
|
+
expect(await runOpComponents({ args: makeArgs({ path: "svc", eventsJson: true }), plugins: [], serializers: [] })).toBe(0);
|
|
1574
|
+
const events = checkRunEventLines(stdoutWrite.mock.calls.map((c) => String(c[0])));
|
|
1575
|
+
expect(events[0]).toMatchObject({ type: "run-start", kind: "component", name: "svc", waves: [["svc"]] });
|
|
1576
|
+
expect(events.at(-1)).toMatchObject({ type: "run-settle", status: "ok" });
|
|
1577
|
+
|
|
1578
|
+
stdoutWrite.mockClear();
|
|
1579
|
+
runComponentsMock.mockReset().mockResolvedValue({ success: false, selected: [], error: "no component named svc" });
|
|
1580
|
+
expect(await runOpComponents({ args: makeArgs({ path: "svc", eventsJson: true }), plugins: [], serializers: [] })).toBe(1);
|
|
1581
|
+
const failed = checkRunEventLines(stdoutWrite.mock.calls.map((c) => String(c[0])));
|
|
1582
|
+
expect(failed.map((e) => e.type)).toEqual(["run-start", "run-settle"]);
|
|
1583
|
+
expect(failed.at(-1)).toMatchObject({ status: "failed", error: "no component named svc" });
|
|
1584
|
+
vi.restoreAllMocks();
|
|
1585
|
+
});
|
|
1586
|
+
|
|
1557
1587
|
test("without --progress-json, runComponents receives onProgress: undefined and nothing streams", async () => {
|
|
1558
1588
|
runComponentsMock.mockResolvedValue({
|
|
1559
1589
|
success: true,
|
package/src/cli/handlers/run.ts
CHANGED
|
@@ -10,12 +10,12 @@ import { runOpLocally, findPolicyGateStep, OpRunFailure, type StepRecord } from
|
|
|
10
10
|
import { approveCommand, describeGateMismatch, gateIsSealed } from "../../op/gate";
|
|
11
11
|
import { summaryLedgerPrefix, writeGatedRunSummary, type GatedRunSummary } from "../../op/gate-summary";
|
|
12
12
|
import { createLocalOpRuntime } from "../../op/runtimes/local";
|
|
13
|
-
import type { OpRuntimeProvider, OpRunStatus } from "../../op/runtime";
|
|
13
|
+
import type { OpRuntimeProvider, OpRunRecord, OpRunStatus } from "../../op/runtime";
|
|
14
14
|
import { pointAnswerCommand, renderHuman, renderJson } from "../../op/local-output";
|
|
15
15
|
import { loadPlugins } from "../plugins";
|
|
16
16
|
import { recordGateApproval } from "./operator";
|
|
17
17
|
import { formatError, formatWarning, formatSuccess, formatBold, formatInfo } from "../format";
|
|
18
|
-
import {
|
|
18
|
+
import { parseParamFlags } from "../build-params-cli";
|
|
19
19
|
import type { CommandContext } from "../registry";
|
|
20
20
|
import { stewardBesideFor, stewardFormFor, stewardTurnLeaseName, DEFAULT_STEWARD_ENV, type StewardDeclaration } from "../../op/steward";
|
|
21
21
|
import { holdBesideLease } from "../../op/steward-beside";
|
|
@@ -26,11 +26,15 @@ import { LIFECYCLE_LOCAL_NOTE, isLifecycleLocalNote } from "../../lifecycle/loca
|
|
|
26
26
|
import { ledgerRecordingOff, noRecordEndNote, noRecordStartNote, resetNoRecordLedger, NO_RECORD_ENV } from "../../lifecycle/no-record";
|
|
27
27
|
import { renderDriverHuman, renderDriverJson } from "../../components/driver-output";
|
|
28
28
|
import { ndjsonProgressSink } from "../../components/run-progress";
|
|
29
|
+
import { findStoredRun, readRunEvents } from "../../run-event-store";
|
|
30
|
+
import type { RunEvent } from "../../run-event";
|
|
31
|
+
import { openCliRunEvents, refusesBothStreams, stdoutLine } from "../run-events";
|
|
29
32
|
import { maybeRecordAutoRelease } from "../../components/auto-release";
|
|
30
33
|
import { maybePersistBuildManifest } from "../../components/manifest-persistence";
|
|
31
34
|
import type { DriverComponentResult } from "../../components/driver";
|
|
32
|
-
import { isComponentList, type ComponentRunPlan } from "../../components/cli-support";
|
|
33
|
-
import type
|
|
35
|
+
import { isComponentList, type ComponentRunPlan, type RunComponentsResult } from "../../components/cli-support";
|
|
36
|
+
import { resolveCiRun, type ReleaseRecord, type RunOrigin } from "../../lifecycle/release-ledger";
|
|
37
|
+
import { gateAdmission, gateApprover } from "../../components/promote";
|
|
34
38
|
import { runOpGenerate } from "./run-generate";
|
|
35
39
|
|
|
36
40
|
/**
|
|
@@ -460,6 +464,91 @@ async function runOpLogOnRuntime(ctx: CommandContext, name: string): Promise<num
|
|
|
460
464
|
return 0;
|
|
461
465
|
}
|
|
462
466
|
|
|
467
|
+
// ── chant run events <run> ───────────────────────────────────────────────────
|
|
468
|
+
|
|
469
|
+
/** One event as a line for a person: its time, its type, where it is and how it ended. */
|
|
470
|
+
export function humanRunEventLine(e: RunEvent): string {
|
|
471
|
+
const x = e as unknown as Record<string, unknown>;
|
|
472
|
+
const where = [x.component, x.phase, x.step].filter((v): v is string => typeof v === "string").join("/");
|
|
473
|
+
const detail = [
|
|
474
|
+
where,
|
|
475
|
+
typeof x.status === "string" ? x.status : "",
|
|
476
|
+
// A blocked component (#4007) names what held it back.
|
|
477
|
+
typeof x.blockedBy === "string" ? `by ${x.blockedBy}` : "",
|
|
478
|
+
typeof x.error === "string" ? x.error : "",
|
|
479
|
+
].filter(Boolean).join(" ");
|
|
480
|
+
return `${String(x.at ?? "")} ${String(x.type).padEnd(16)}${detail}`.trimEnd();
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** The exit code a run's verdict maps to: `chant run`'s own (0 ok, 1 failed, 3 waiting on a person). */
|
|
484
|
+
function exitOfSettle(status: unknown): number {
|
|
485
|
+
return status === "ok" ? 0 : status === "gated" || status === "waiting" ? 3 : 1;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* `chant run events <run> [--json] [--follow]` (#4042): the events a run on
|
|
490
|
+
* this host kept, replayed. `<run>` is a run id, or the name of an Op or a
|
|
491
|
+
* component selection, for which the newest stored run stands. A settled run
|
|
492
|
+
* and a run in progress both replay what is in the file; `--follow` goes on
|
|
493
|
+
* from there until the run settles. `--json` prints the stored lines as they
|
|
494
|
+
* were written; without it each event is one line for a person.
|
|
495
|
+
*
|
|
496
|
+
* The exit code is the replayed run's verdict (0, 1, or 3 for a run waiting
|
|
497
|
+
* on a person). A replay of a run still going, and a follow cut short by
|
|
498
|
+
* Ctrl-C, exit 0.
|
|
499
|
+
*/
|
|
500
|
+
export async function runOpEvents(ctx: CommandContext): Promise<number> {
|
|
501
|
+
const ref = ctx.args.extraPositional;
|
|
502
|
+
if (!ref) {
|
|
503
|
+
console.error(formatError({ message: "A run id or an Op name is required: chant run events <run>" }));
|
|
504
|
+
return 1;
|
|
505
|
+
}
|
|
506
|
+
if (ctx.args.on !== undefined && ctx.args.on !== "local") {
|
|
507
|
+
console.error(formatError({
|
|
508
|
+
message: `run events reads the events kept on this host, so --on ${ctx.args.on} has none to read`,
|
|
509
|
+
hint: "A run hosted off this host is read once its in-flight state is off-host (#3990).",
|
|
510
|
+
}));
|
|
511
|
+
return 1;
|
|
512
|
+
}
|
|
513
|
+
const cwd = resolve(".");
|
|
514
|
+
let stored = await findStoredRun(cwd, ref);
|
|
515
|
+
if (!stored && ctx.args.follow) {
|
|
516
|
+
// The run may be starting: give it a moment to open its file.
|
|
517
|
+
const deadline = Date.now() + RUN_EVENTS_WAIT_MS;
|
|
518
|
+
while (!stored && Date.now() < deadline) {
|
|
519
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
520
|
+
stored = await findStoredRun(cwd, ref);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (!stored) {
|
|
524
|
+
console.error(formatError({
|
|
525
|
+
message: `No events are kept for "${ref}" on this host`,
|
|
526
|
+
hint: "A run keeps its events when it records to the ledger (not under --no-record), and a command other than `chant run <op>` keeps them under --events-json. Chant 0.124.28 and newer write them.",
|
|
527
|
+
}));
|
|
528
|
+
return 1;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const controller = new AbortController();
|
|
532
|
+
const onSigint = () => controller.abort();
|
|
533
|
+
process.on("SIGINT", onSigint);
|
|
534
|
+
try {
|
|
535
|
+
const settle = await readRunEvents(
|
|
536
|
+
stored.file,
|
|
537
|
+
(event, line) => {
|
|
538
|
+
if (ctx.args.json) process.stdout.write(line);
|
|
539
|
+
else console.log(humanRunEventLine(event));
|
|
540
|
+
},
|
|
541
|
+
{ follow: ctx.args.follow === true, signal: controller.signal },
|
|
542
|
+
);
|
|
543
|
+
return settle ? exitOfSettle((settle as unknown as { status?: unknown }).status) : 0;
|
|
544
|
+
} finally {
|
|
545
|
+
process.removeListener("SIGINT", onSigint);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** How long `--follow` waits for a run's file to appear. */
|
|
550
|
+
const RUN_EVENTS_WAIT_MS = 5000;
|
|
551
|
+
|
|
463
552
|
// ── chant run approve <op> <gate> ────────────────────────────────────────────
|
|
464
553
|
|
|
465
554
|
/**
|
|
@@ -778,6 +867,7 @@ export async function runOp(ctx: CommandContext): Promise<number> {
|
|
|
778
867
|
}));
|
|
779
868
|
return 1;
|
|
780
869
|
}
|
|
870
|
+
if (refusesBothStreams(ctx.args)) return 1;
|
|
781
871
|
if (ctx.args.components) return runOpComponents(ctx);
|
|
782
872
|
if (ctx.args.report) {
|
|
783
873
|
console.error(formatError({
|
|
@@ -791,6 +881,16 @@ export async function runOp(ctx: CommandContext): Promise<number> {
|
|
|
791
881
|
|
|
792
882
|
// ── Auto-release recording post-run (#597) ──────────────────────────────────
|
|
793
883
|
|
|
884
|
+
/**
|
|
885
|
+
* The run id and origin an auto-recorded release names (#4020): the CI run
|
|
886
|
+
* when the process is in CI, so the release and the gate it passed (which
|
|
887
|
+
* records the CI run id) name the same run, else `localId` with the `local`
|
|
888
|
+
* origin.
|
|
889
|
+
*/
|
|
890
|
+
export function autoReleaseRun(localId: string): { runId: string; runOrigin: RunOrigin } {
|
|
891
|
+
return resolveCiRun() ?? { runId: localId, runOrigin: { forge: "local" } };
|
|
892
|
+
}
|
|
893
|
+
|
|
794
894
|
/**
|
|
795
895
|
* After a successful `chant run --components` (local executor), auto-emit
|
|
796
896
|
* one release record per successfully deployed component that published a
|
|
@@ -831,6 +931,8 @@ export async function recordAutoReleasesForRun(
|
|
|
831
931
|
env: string,
|
|
832
932
|
runId: string,
|
|
833
933
|
disabled: boolean,
|
|
934
|
+
runOrigin: RunOrigin = { forge: "local" },
|
|
935
|
+
releaseDigest?: string,
|
|
834
936
|
): Promise<ReleaseRecord[]> {
|
|
835
937
|
const recorded: ReleaseRecord[] = [];
|
|
836
938
|
for (const componentResult of results) {
|
|
@@ -842,8 +944,13 @@ export async function recordAutoReleasesForRun(
|
|
|
842
944
|
success: true,
|
|
843
945
|
records: componentResult.records,
|
|
844
946
|
runId,
|
|
845
|
-
// A local-executor id resolves nowhere
|
|
846
|
-
runOrigin
|
|
947
|
+
// A local-executor id resolves nowhere, and says so in a field (#2045). A run in CI names the CI run.
|
|
948
|
+
runOrigin,
|
|
949
|
+
// #1035, #4020: who approved at the gate and which resolution admitted the deploy.
|
|
950
|
+
...(gateApprover(componentResult) ? { approver: gateApprover(componentResult) } : {}),
|
|
951
|
+
...(gateAdmission(componentResult) ? { admission: gateAdmission(componentResult) } : {}),
|
|
952
|
+
// #4043: the release the deploy was made under, when `--release` named one.
|
|
953
|
+
...(releaseDigest !== undefined ? { releaseDigest } : {}),
|
|
847
954
|
},
|
|
848
955
|
{ disabled },
|
|
849
956
|
);
|
|
@@ -953,6 +1060,44 @@ function refusesNoRecordOn(runtime: Pick<OpRuntimeProvider, "name">): boolean {
|
|
|
953
1060
|
return true;
|
|
954
1061
|
}
|
|
955
1062
|
|
|
1063
|
+
/**
|
|
1064
|
+
* Resolve the release `chant run --components --release` names (#4043), or the
|
|
1065
|
+
* reason it can't be used. The run builds from the checked-out commit, so the
|
|
1066
|
+
* release's commit must be HEAD, and the release needs a target for `env`.
|
|
1067
|
+
*/
|
|
1068
|
+
export async function resolveRunRelease(ref: string, env: string, cwd: string) {
|
|
1069
|
+
const { fetchLifecycle, getHeadCommit } = await import("../../lifecycle/git");
|
|
1070
|
+
const { resolveRelease } = await import("../../lifecycle/release-store");
|
|
1071
|
+
const { targetFor } = await import("../../components/release-promote");
|
|
1072
|
+
await fetchLifecycle({ cwd }).catch(() => false);
|
|
1073
|
+
const found = await resolveRelease(ref, { cwd });
|
|
1074
|
+
if (!found) return `no release is labelled or digested "${ref}" in this member`;
|
|
1075
|
+
const name = found.label ?? found.release.releaseDigest;
|
|
1076
|
+
const head = await getHeadCommit({ cwd });
|
|
1077
|
+
if (found.release.commit !== head) {
|
|
1078
|
+
return `release ${name} was cut from ${found.release.commit.slice(0, 12)} and this checkout is at ${head.slice(0, 12)}; run builds from the checkout, so check out the release's commit, or deploy it with \`chant components promote --release\``;
|
|
1079
|
+
}
|
|
1080
|
+
const target = targetFor(found.release, env);
|
|
1081
|
+
if ("error" in target) return target.error;
|
|
1082
|
+
return { releaseDigest: found.release.releaseDigest, label: found.label, release: found.release };
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/** A rebuilt image need not digest as the release's own did; say so, as promote does. Never fails the run. */
|
|
1086
|
+
async function warnOnArtifactMismatch(release: import("../../lifecycle/release-store").Release, recorded: readonly ReleaseRecord[]): Promise<void> {
|
|
1087
|
+
try {
|
|
1088
|
+
const { releaseArtifactMismatches } = await import("../../components/release-promote");
|
|
1089
|
+
const { readBuildManifest } = await import("../../lifecycle/build-ledger-store");
|
|
1090
|
+
const mismatches = await releaseArtifactMismatches(
|
|
1091
|
+
release,
|
|
1092
|
+
recorded.map((r) => ({ component: r.component, source: r })),
|
|
1093
|
+
(digest) => readBuildManifest(digest).catch(() => null),
|
|
1094
|
+
);
|
|
1095
|
+
for (const message of mismatches) console.error(formatWarning({ message }));
|
|
1096
|
+
} catch {
|
|
1097
|
+
// The record is written; a manifest that can't be read is not worth failing the run for.
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
956
1101
|
async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
957
1102
|
const selector = ctx.args.path;
|
|
958
1103
|
if (!selector || selector === ".") {
|
|
@@ -968,11 +1113,13 @@ async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
|
968
1113
|
|
|
969
1114
|
const projectPath = resolve(".");
|
|
970
1115
|
const { config } = await loadChantConfig(projectPath).catch(() => ({ config: {} as ChantConfig }));
|
|
971
|
-
|
|
1116
|
+
// #4024: with --env, a workspace member's flag records back their parameters.
|
|
1117
|
+
const { resolveFlaggedBuildParams } = await import("../../flag-params");
|
|
1118
|
+
const paramsResolution = await resolveFlaggedBuildParams(projectPath, config.buildParams, {
|
|
972
1119
|
cli: parseParamFlags(ctx.args.param),
|
|
973
1120
|
paramsFile: ctx.args.paramsFile,
|
|
974
1121
|
verbose: ctx.args.verbose,
|
|
975
|
-
});
|
|
1122
|
+
}, ctx.args.env);
|
|
976
1123
|
if (!paramsResolution.success) {
|
|
977
1124
|
for (const message of paramsResolution.errors) console.error(message);
|
|
978
1125
|
return 1;
|
|
@@ -990,6 +1137,20 @@ async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
|
990
1137
|
}
|
|
991
1138
|
|
|
992
1139
|
const env = ctx.args.env ?? "local";
|
|
1140
|
+
|
|
1141
|
+
// #4043: `--release <label|digest>` says this run deploys that release. The
|
|
1142
|
+
// run builds from the checked-out commit, so the release must have been cut
|
|
1143
|
+
// from it, and must have a target for the environment. Both are checked
|
|
1144
|
+
// before anything deploys; nothing is inferred when the flag is absent.
|
|
1145
|
+
let underRelease: { releaseDigest: string; label: string | null; release: import("../../lifecycle/release-store").Release } | undefined;
|
|
1146
|
+
if (ctx.args.release) {
|
|
1147
|
+
const refused = await resolveRunRelease(ctx.args.release, env, projectPath);
|
|
1148
|
+
if (typeof refused === "string") {
|
|
1149
|
+
console.error(formatError({ message: refused, hint: "List the releases with: chant release list" }));
|
|
1150
|
+
return 1;
|
|
1151
|
+
}
|
|
1152
|
+
underRelease = refused;
|
|
1153
|
+
}
|
|
993
1154
|
// Seed cross-component/cross-stack outputs from upstream jobs' dumped files
|
|
994
1155
|
// (`--seed-outputs`), so a single-component run resolves references to a
|
|
995
1156
|
// component that ran in an earlier CI job.
|
|
@@ -1011,6 +1172,10 @@ async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
|
1011
1172
|
// `undefined` and every `onProgress?.(...)` call in the driver is a no-op —
|
|
1012
1173
|
// behavior is byte-for-byte unchanged from before this flag existed.
|
|
1013
1174
|
const onProgress = ctx.args.progressJson ? ndjsonProgressSink() : undefined;
|
|
1175
|
+
// `--events-json` (#4041): the run-event stream instead. The run is named by
|
|
1176
|
+
// the id its release records carry, so the two join.
|
|
1177
|
+
const release = autoReleaseRun(`local-${Date.now()}`);
|
|
1178
|
+
const events = await openCliRunEvents(ctx.args, { kind: "component", name: selector, runId: release.runId, cwd: projectPath });
|
|
1014
1179
|
// A list (#3950) pulls in what its components depend on; say which ones and
|
|
1015
1180
|
// in what order before the first one runs. stderr, so --json and
|
|
1016
1181
|
// --progress-json keep stdout to themselves.
|
|
@@ -1020,14 +1185,25 @@ async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
|
1020
1185
|
if (plan.added.length > 0) console.error(formatInfo(`added as dependencies: ${plan.added.join(", ")}`));
|
|
1021
1186
|
}
|
|
1022
1187
|
: undefined;
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1188
|
+
let result: RunComponentsResult;
|
|
1189
|
+
try {
|
|
1190
|
+
result = await runtime.runComponents(projectPath, selector, {
|
|
1191
|
+
env: ctx.args.env,
|
|
1192
|
+
componentOutputs: seededOutputs,
|
|
1193
|
+
onProgress,
|
|
1194
|
+
...(events ? { onRunEvent: events.emit } : {}),
|
|
1195
|
+
sandbox: ctx.args.sandbox,
|
|
1196
|
+
buildParams: paramsResolution.provenance,
|
|
1197
|
+
...(onPlan ? { onPlan } : {}),
|
|
1198
|
+
});
|
|
1199
|
+
} catch (err) {
|
|
1200
|
+
events?.settle("failed", err instanceof Error ? err.message : String(err));
|
|
1201
|
+
throw err;
|
|
1202
|
+
}
|
|
1203
|
+
// A run that never reached its components (a bad selector, a cycle) still ends its stream.
|
|
1204
|
+
if (result.success) events?.settle("ok");
|
|
1205
|
+
else if (result.gated) events?.settle("gated");
|
|
1206
|
+
else events?.settle("failed", result.error);
|
|
1031
1207
|
|
|
1032
1208
|
// Dump the accumulated outputs for a downstream job to seed from. Written
|
|
1033
1209
|
// even on failure (partial outputs) so a resumed run still has what completed.
|
|
@@ -1094,7 +1270,8 @@ async function runComponentSelection(ctx: CommandContext): Promise<number> {
|
|
|
1094
1270
|
if (result.success && result.run) {
|
|
1095
1271
|
// #3955: a run that records nothing has no release to report either.
|
|
1096
1272
|
const disabled = resolveAutoReleaseDisabled(config, ctx.args.noReleaseRecord) || ledgerRecordingOff();
|
|
1097
|
-
const recorded = await recordAutoReleasesForRun(result.run.results, env,
|
|
1273
|
+
const recorded = await recordAutoReleasesForRun(result.run.results, env, release.runId, disabled, release.runOrigin, underRelease?.releaseDigest);
|
|
1274
|
+
if (underRelease) await warnOnArtifactMismatch(underRelease.release, recorded);
|
|
1098
1275
|
// `--digest-file` (#2602): the releases this run recorded, one
|
|
1099
1276
|
// `<component>=<digest>` line each, the form `chant components promote
|
|
1100
1277
|
// --digest` takes. A generated promote job reads it to promote exactly
|
|
@@ -1182,6 +1359,15 @@ async function runOpOnResolvedRuntime(ctx: CommandContext): Promise<number> {
|
|
|
1182
1359
|
return 1;
|
|
1183
1360
|
}
|
|
1184
1361
|
|
|
1362
|
+
// #4044: a runner key signs the run's record as it settles, so `ci tick`
|
|
1363
|
+
// can count the run. `--key` must be a runner key; the PEM in
|
|
1364
|
+
// CHANT_RUNNER_KEY that is not one leaves the run unsigned, with a warning.
|
|
1365
|
+
const signRecord = await runSignerFor(ctx);
|
|
1366
|
+
if (signRecord === null) {
|
|
1367
|
+
await stewardGate?.release?.();
|
|
1368
|
+
return 1;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1185
1371
|
// `--progress-json` streams one NDJSON StepRecord per settled step, fed by
|
|
1186
1372
|
// whatever the runtime reports through `progress`.
|
|
1187
1373
|
const progress = ctx.args.progressJson ? ndjsonProgressSink<StepRecord>() : undefined;
|
|
@@ -1217,6 +1403,10 @@ async function runOpOnResolvedRuntime(ctx: CommandContext): Promise<number> {
|
|
|
1217
1403
|
...(params ? { params } : {}),
|
|
1218
1404
|
...(ctx.args.profile !== undefined ? { profile: ctx.args.profile } : {}),
|
|
1219
1405
|
progress,
|
|
1406
|
+
// `--events-json` (#4041): the runtime writes the run's events itself,
|
|
1407
|
+
// since it is the one that knows the run's id and where it ran.
|
|
1408
|
+
...(ctx.args.eventsJson ? { runEvents: stdoutLine } : {}),
|
|
1409
|
+
...(signRecord ? { signRecord } : {}),
|
|
1220
1410
|
signal: controller.signal,
|
|
1221
1411
|
...(work ? { work } : {}),
|
|
1222
1412
|
});
|
|
@@ -1362,7 +1552,42 @@ async function resolveRunWork(
|
|
|
1362
1552
|
export function runOpUnknown(ctx: CommandContext): Promise<number> {
|
|
1363
1553
|
console.error(formatError({
|
|
1364
1554
|
message: `Unknown run subcommand: ${ctx.args.extraPositional ?? ctx.args.path}`,
|
|
1365
|
-
hint: "Available: chant run <name>, run list, run status, run approve, run cancel, run log",
|
|
1555
|
+
hint: "Available: chant run <name>, run list, run status, run approve, run cancel, run log, run events",
|
|
1366
1556
|
}));
|
|
1367
1557
|
return Promise.resolve(1);
|
|
1368
1558
|
}
|
|
1559
|
+
|
|
1560
|
+
/** The variable a runner key is read from, as PEM, as `chant ci tick` reads it (`RUNNER_KEY_ENV` in ../../workspace/ci-green.ts). */
|
|
1561
|
+
const RUNNER_KEY_ENV = "CHANT_RUNNER_KEY";
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* What signs the run's record (#4044): the runner key `--key` names, or the
|
|
1565
|
+
* PEM in `CHANT_RUNNER_KEY`, checked against `.chant/trust.json` at `HEAD`.
|
|
1566
|
+
* Undefined when neither is given. Null, after printing why, when `--key`
|
|
1567
|
+
* is not a runner key; an unusable `CHANT_RUNNER_KEY` only warns, since the
|
|
1568
|
+
* variable may be set for `ci tick` in a job that also runs Ops.
|
|
1569
|
+
*/
|
|
1570
|
+
async function runSignerFor(ctx: CommandContext): Promise<((record: OpRunRecord) => NonNullable<OpRunRecord["statement"]>) | undefined | null> {
|
|
1571
|
+
const fromFlag = ctx.args.key !== undefined;
|
|
1572
|
+
let pem: string | undefined;
|
|
1573
|
+
try {
|
|
1574
|
+
pem = fromFlag ? readFileSync(resolve(ctx.args.key!), "utf-8") : process.env[RUNNER_KEY_ENV] || undefined;
|
|
1575
|
+
} catch (err) {
|
|
1576
|
+
console.error(formatError({ message: `--key ${ctx.args.key}: ${err instanceof Error ? err.message : String(err)}` }));
|
|
1577
|
+
return null;
|
|
1578
|
+
}
|
|
1579
|
+
if (pem === undefined) return undefined;
|
|
1580
|
+
try {
|
|
1581
|
+
// Loaded only when a key is given, so a run without one loads no workspace code (level 0, #2525).
|
|
1582
|
+
const { opRunSigner } = await import("../../workspace/ci-green");
|
|
1583
|
+
return opRunSigner(process.cwd(), pem);
|
|
1584
|
+
} catch (err) {
|
|
1585
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1586
|
+
if (fromFlag) {
|
|
1587
|
+
console.error(formatError({ message: `the run would not be signed: ${message}` }));
|
|
1588
|
+
return null;
|
|
1589
|
+
}
|
|
1590
|
+
console.error(formatWarning({ message: `${RUNNER_KEY_ENV} is set, and the run will not be signed: ${message}` }));
|
|
1591
|
+
return undefined;
|
|
1592
|
+
}
|
|
1593
|
+
}
|