@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,589 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant release` (#4026, ws-104): the release is what graduates.
|
|
3
|
+
*
|
|
4
|
+
* release cut [<label>] [--yes] [--build <command>] [--param k=v]... [--params-file <file>] [--src <dir>] [-o <file>] [--lexicon <name>] [--actor <name>] [--sign [<key file>]] [--json]
|
|
5
|
+
* a dry run of a cut of this member from the checkout's HEAD, which must be
|
|
6
|
+
* clean, on trunk and pushed, and green (#4027); `--yes` cuts, records,
|
|
7
|
+
* and tags the commit `release/<label>` locally;
|
|
8
|
+
* --sign signs the cut with the actor's ssh key (#4031); `--src`, `-o` and
|
|
9
|
+
* `--lexicon` shape the build of a project with no components (#4046)
|
|
10
|
+
* release publish <label|digest> [--yes] [--allow-unsigned] [--require-provenance] [--json]
|
|
11
|
+
* publish a cut release (#4027) to the targets release.publish declares
|
|
12
|
+
* (#4047): a dry run unless --yes; refuses a revoked one, one with no
|
|
13
|
+
* signature that verifies against .chant/allowed_signers unless
|
|
14
|
+
* --allow-unsigned (#4049), and with a target a checkout that is not
|
|
15
|
+
* the release's commit; warns with no OIDC provenance, and refuses
|
|
16
|
+
* under --require-provenance; attaches SBOMs and provenance (#4049)
|
|
17
|
+
* release verify <label|digest> [--json]
|
|
18
|
+
* check the release's signature offline against .chant/allowed_signers
|
|
19
|
+
* at the release's commit (#4049)
|
|
20
|
+
* release list [--json]
|
|
21
|
+
* every release of this member with its targets, its cuts and where it runs;
|
|
22
|
+
* `--json` prints the read contract's `releases` document
|
|
23
|
+
* release export <label|digest> --env <env> [-o <dir>] [--json]
|
|
24
|
+
* write the files the release recorded for <env>, checked against their digests (#4046)
|
|
25
|
+
* release compile --env <env> [--build <command>] [--artifacts --component <a,b>] --json
|
|
26
|
+
* internal: what the cut runs in a child process per environment
|
|
27
|
+
*
|
|
28
|
+
* The workstation checks, the actor and the tag are in
|
|
29
|
+
* ../../lifecycle/release-workstation.ts, and the publish contract in
|
|
30
|
+
* ../../lifecycle/release-publish.ts. A declaration whose `identity.gates`
|
|
31
|
+
* names a `release` gate requires a signed cut by an actor in its class (#4031).
|
|
32
|
+
*/
|
|
33
|
+
import { execFileSync } from "node:child_process";
|
|
34
|
+
import { existsSync } from "node:fs";
|
|
35
|
+
import { resolve } from "node:path";
|
|
36
|
+
import { formatBold, formatError, formatSuccess, formatWarning } from "../format.js";
|
|
37
|
+
import { parseParamFlags } from "../build-params-cli.js";
|
|
38
|
+
const USAGE = "chant release cut [<label>] [--yes] [--build <command>] [--param <k=v>] [--params-file <file>] [--src <dir>] [-o <file>] [--lexicon <name>] [--actor <name>] [--sign [<key file>]] [--json] | release publish <label|digest> [--yes] [--allow-unsigned] [--require-provenance] [--json] | release verify <label|digest> [--json] | release list [--json] | release export <label|digest> --env <env> [-o <dir>] [--json]";
|
|
39
|
+
/** The build inputs `release cut` and `release compile` share. */
|
|
40
|
+
function compileInputs(ctx, params) {
|
|
41
|
+
const { args } = ctx;
|
|
42
|
+
return {
|
|
43
|
+
projectDir: resolve("."),
|
|
44
|
+
...(args.buildCommand ? { buildCommand: args.buildCommand } : {}),
|
|
45
|
+
...(params ? { params } : {}),
|
|
46
|
+
...(args.paramsFile ? { paramsFile: args.paramsFile } : {}),
|
|
47
|
+
...(args.src ? { src: args.src } : {}),
|
|
48
|
+
...(args.output ? { output: args.output } : {}),
|
|
49
|
+
...(args.lexicon ? { lexicon: args.lexicon } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** What to run after a cut (#4027): publish from CI, or push the tag so CI publishes, or deploy the first environment. */
|
|
53
|
+
export function nextCommands(req) {
|
|
54
|
+
const publish = `chant release publish ${req.ref}`;
|
|
55
|
+
const deploy = req.firstEnv === null
|
|
56
|
+
? null
|
|
57
|
+
: req.noComponents
|
|
58
|
+
? `chant release export ${req.ref} --env ${req.firstEnv}`
|
|
59
|
+
: `chant components promote --release ${req.ref} --to ${req.firstEnv}`;
|
|
60
|
+
if (req.inCi)
|
|
61
|
+
return [publish, ...(deploy ? [deploy] : [])];
|
|
62
|
+
return [...(req.tag ? [`git push origin ${req.tag}`] : []), publish, ...(deploy ? [deploy] : [])];
|
|
63
|
+
}
|
|
64
|
+
/** The command line that ran, without `--json`, with `--yes` added: what a dry run says to run next. */
|
|
65
|
+
export function sameWithYes(argv) {
|
|
66
|
+
const quote = (a) => (/^[\w@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`);
|
|
67
|
+
return ["chant", ...argv.filter((a) => a !== "--json" && a !== "--yes"), "--yes"].map(quote).join(" ");
|
|
68
|
+
}
|
|
69
|
+
function describeActorSource(source) {
|
|
70
|
+
switch (source) {
|
|
71
|
+
case "flag":
|
|
72
|
+
return "--actor";
|
|
73
|
+
case "signer":
|
|
74
|
+
return "the signers file at base, for the signing key";
|
|
75
|
+
case "ci":
|
|
76
|
+
return "the CI's actor";
|
|
77
|
+
case "git":
|
|
78
|
+
return "git user.email";
|
|
79
|
+
case "user":
|
|
80
|
+
return "$USER";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* `release cut [<label>]` (#4026, #4027). A dry run unless `--yes`: it
|
|
85
|
+
* refuses a dirty tree, a commit that is not on trunk and pushed, and one
|
|
86
|
+
* that is not green, compiles every environment, and prints what the cut
|
|
87
|
+
* would record, build and tag, and what publishes where. With `--yes` it
|
|
88
|
+
* cuts, signs with `--sign`, records the cut with its actor and run id,
|
|
89
|
+
* tags the commit locally and prints the next command.
|
|
90
|
+
*/
|
|
91
|
+
export async function runReleaseCut(ctx) {
|
|
92
|
+
const { args } = ctx;
|
|
93
|
+
const positional = args.extraPositional;
|
|
94
|
+
if (positional && args.label && positional !== args.label) {
|
|
95
|
+
console.error(formatError({ message: `the label is given twice, as "${positional}" and --label "${args.label}"`, hint: USAGE }));
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
const label = positional ?? args.label ?? null;
|
|
99
|
+
const dryRun = args.yes !== true;
|
|
100
|
+
const cwd = resolve(".");
|
|
101
|
+
const { spawnTargetCompiler, ReleaseCompileError } = await import("../../components/release-compile.js");
|
|
102
|
+
const { cutRelease, planRelease, ReleaseCutError } = await import("../../lifecycle/release-cut.js");
|
|
103
|
+
const { ReleaseLabelError } = await import("../../lifecycle/release-store.js");
|
|
104
|
+
const { pushLifecycleReport, getHeadCommit } = await import("../../lifecycle/git.js");
|
|
105
|
+
const { resolveCiRun } = await import("../../lifecycle/release-ledger.js");
|
|
106
|
+
const ws = await import("../../lifecycle/release-workstation.js");
|
|
107
|
+
const { detectProvenance, releasePublishTargets } = await import("../../lifecycle/release-publish.js");
|
|
108
|
+
const fail = (code, message, fix) => {
|
|
109
|
+
console.error(formatError({ message: `${message} [${code}]`, ...(fix ? { hint: fix } : {}) }));
|
|
110
|
+
return 1;
|
|
111
|
+
};
|
|
112
|
+
try {
|
|
113
|
+
// The workstation checks come first, in the order #4027 lists them; the
|
|
114
|
+
// green check and the rest are the cut's own.
|
|
115
|
+
const top = (() => {
|
|
116
|
+
try {
|
|
117
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
})();
|
|
123
|
+
let commit = null;
|
|
124
|
+
let trunk = null;
|
|
125
|
+
let signers = [];
|
|
126
|
+
let member = null;
|
|
127
|
+
if (top) {
|
|
128
|
+
commit = await getHeadCommit({ cwd });
|
|
129
|
+
ws.checkCleanTree(top, commit);
|
|
130
|
+
const { scopeSource } = await import("../../workspace/write-scope.js");
|
|
131
|
+
const { releaseRuleFrom } = await import("../../workspace/identity.js");
|
|
132
|
+
const source = scopeSource(cwd);
|
|
133
|
+
trunk = ws.resolveTrunk(top, source.declaration?.ci?.green?.branch ?? null);
|
|
134
|
+
ws.checkOnTrunk(top, commit, trunk);
|
|
135
|
+
signers = releaseRuleFrom(source).rule.signers.signers;
|
|
136
|
+
const { resolveMemberLedger } = await import("../../lifecycle/member-ledger.js");
|
|
137
|
+
const ledger = await resolveMemberLedger(cwd);
|
|
138
|
+
member = ledger.members.length > 0 ? ledger.members.join("/") : null;
|
|
139
|
+
}
|
|
140
|
+
// The signing key is resolved now, so a dry run shows a key that can't be read.
|
|
141
|
+
let publicKey = null;
|
|
142
|
+
if (args.sign !== undefined) {
|
|
143
|
+
const { resolveSigningKey, SealError } = await import("../../workspace/trust/seal.js");
|
|
144
|
+
try {
|
|
145
|
+
const key = resolveSigningKey(args.sign, cwd);
|
|
146
|
+
try {
|
|
147
|
+
if (!existsSync(key.file))
|
|
148
|
+
return fail("release-signer-refused", `no release was cut: the signing key ${key.file} does not exist`);
|
|
149
|
+
publicKey = ws.publicKeyOf(key.file);
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
key.cleanup();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (!(err instanceof SealError))
|
|
157
|
+
throw err;
|
|
158
|
+
return fail("release-signer-refused", `no release was cut: ${err.message}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const who = ws.resolveCutActor({ cwd, ...(args.actor ? { explicit: args.actor } : {}), publicKey, signers });
|
|
162
|
+
if (!who) {
|
|
163
|
+
console.error(formatError({ message: "Could not resolve --actor", hint: "Pass --actor explicitly, or set git's user.email, GITHUB_ACTOR, GITLAB_USER_LOGIN or USER." }));
|
|
164
|
+
return 1;
|
|
165
|
+
}
|
|
166
|
+
const actor = who.actor;
|
|
167
|
+
const tag = label !== null && commit !== null && top ? { name: ws.releaseTagName(member, label), state: ws.checkReleaseTag(top, ws.releaseTagName(member, label), commit) } : null;
|
|
168
|
+
const ci = resolveCiRun(process.env);
|
|
169
|
+
const params = parseParamFlags(args.param);
|
|
170
|
+
const compiler = spawnTargetCompiler(compileInputs(ctx, params));
|
|
171
|
+
const request = { cwd, compiler, label, actor, ...(args.sign !== undefined ? { sign: args.sign } : {}) };
|
|
172
|
+
if (dryRun) {
|
|
173
|
+
const plan = await planRelease(request);
|
|
174
|
+
// Under the release gate, a key the signers file at base lists for someone else is refused now, not after the build.
|
|
175
|
+
if (plan.signatureRequired && publicKey !== null && !signers.some((s) => s.key === publicKey && s.principal.trim().toLowerCase() === actor.trim().toLowerCase())) {
|
|
176
|
+
return fail("release-signer-refused", `no release would be cut: the signing key is not listed for ${actor} in the signers file at base, and identity.gates.release counts only a cut its signer signs`, "Pass --actor <principal> naming the key's signer, or sign with that principal's key.");
|
|
177
|
+
}
|
|
178
|
+
const ref = plan.label ?? plan.alreadyCut ?? plan.releaseDigest;
|
|
179
|
+
const provenance = detectProvenance();
|
|
180
|
+
// The targets release publish would run, as the config here declares them; their files are read at publish.
|
|
181
|
+
const publishTargets = await releasePublishTargets(cwd).then((ts) => ts.map((t) => `${t.name} to ${t.destination}`), (err) => (err instanceof Error ? err : new Error(String(err))));
|
|
182
|
+
const deployRef = plan.label ?? "<label|digest>";
|
|
183
|
+
const doc = {
|
|
184
|
+
dryRun: true,
|
|
185
|
+
...plan,
|
|
186
|
+
actor,
|
|
187
|
+
actorSource: who.source,
|
|
188
|
+
run: ci ? { runId: ci.runId, runOrigin: ci.runOrigin } : { runId: null, runOrigin: { forge: "local" } },
|
|
189
|
+
trunk,
|
|
190
|
+
sign: args.sign !== undefined ? { key: publicKey !== null ? publicKey.split(" ")[0] : null, readable: publicKey !== null } : null,
|
|
191
|
+
tag: tag ? { name: tag.name, exists: tag.state === "present" } : null,
|
|
192
|
+
publish: { targets: Array.isArray(publishTargets) ? publishTargets : [], provenance },
|
|
193
|
+
next: [sameWithYes(process.argv.slice(2))],
|
|
194
|
+
};
|
|
195
|
+
if (args.json) {
|
|
196
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
const name = plan.label ? formatBold(plan.label) : "an unlabelled release";
|
|
200
|
+
console.log(`Dry run: cut ${name} from commit ${plan.commit.slice(0, 12)}${trunk ? ` (on ${trunk.remote}/${trunk.branch}, green)` : ""}`);
|
|
201
|
+
if (plan.alreadyCut)
|
|
202
|
+
console.log(` already cut as ${plan.alreadyCut}: the cut would record nothing new`);
|
|
203
|
+
console.log(` actor ${actor} (from ${describeActorSource(who.source)})`);
|
|
204
|
+
console.log(` run ${ci ? `${ci.runId} (${ci.runOrigin.forge})` : "minted on this machine at the cut (local)"}`);
|
|
205
|
+
console.log(` ${args.sign !== undefined ? `signed with ${publicKey ? publicKey.split(" ")[0] : "a key whose public half can't be read until it signs"}` : "not signed"}` +
|
|
206
|
+
(plan.signatureRequired ? "; identity.gates.release requires a signed cut" : ""));
|
|
207
|
+
console.log(` tag ${tag ? `${tag.name}${tag.state === "present" ? " (exists)" : ""}, made here and not pushed` : "none, since the release has no label"}`);
|
|
208
|
+
for (const t of plan.targets) {
|
|
209
|
+
console.log(` ${t.env}: ${t.templates.length} template(s)${t.params.length > 0 ? `, ${t.params.map((p) => `${p.name}=${p.value}`).join(" ")}` : ""}`);
|
|
210
|
+
}
|
|
211
|
+
for (const b of plan.build)
|
|
212
|
+
console.log(` ${b.component}: artifacts built in ${b.env}`);
|
|
213
|
+
for (const r of plan.reused)
|
|
214
|
+
console.log(` ${r.component}: artifacts unchanged, carried from ${r.from}`);
|
|
215
|
+
console.log(` digest ${plan.releaseDigest ?? "decided when the artifacts are built"}`);
|
|
216
|
+
console.log("What will be published where:");
|
|
217
|
+
if (plan.publishSteps.length === 0)
|
|
218
|
+
console.log(" no component declares a publish step");
|
|
219
|
+
for (const p of plan.publishSteps) {
|
|
220
|
+
console.log(` ${p.component}: ${p.kind}${p.to ? ` to ${p.to}` : ""} in ${p.envs.join(", ")}, by that environment's deploy (chant components promote --release ${deployRef})`);
|
|
221
|
+
}
|
|
222
|
+
const publishCmd = `chant release publish ${ref ?? "<label|digest>"}`;
|
|
223
|
+
if (!Array.isArray(publishTargets))
|
|
224
|
+
console.log(` ${publishCmd}: the publish targets can't be read: ${publishTargets.message}`);
|
|
225
|
+
else if (publishTargets.length === 0)
|
|
226
|
+
console.log(` ${publishCmd}: nothing, since this member declares no publish target (release.publish in chant.config.ts)`);
|
|
227
|
+
else
|
|
228
|
+
for (const t of publishTargets)
|
|
229
|
+
console.log(` ${publishCmd}: ${t}`);
|
|
230
|
+
if (!provenance.oidc)
|
|
231
|
+
console.log(` a publish from here would carry no OIDC provenance: ${provenance.reason}`);
|
|
232
|
+
console.error(`Dry run: nothing was cut, signed or tagged. Run again with --yes to cut: ${doc.next[0]}`);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
const result = await cutRelease(request);
|
|
236
|
+
const push = await pushLifecycleReport({ cwd }).catch(() => ({ pushed: false, pushWarning: undefined }));
|
|
237
|
+
// The tag names the release's label, which a re-cut with no label reads from the earlier cut.
|
|
238
|
+
let tagged = null;
|
|
239
|
+
let tagWarning;
|
|
240
|
+
if (result.label !== null && top) {
|
|
241
|
+
const name = ws.releaseTagName(member, result.label);
|
|
242
|
+
try {
|
|
243
|
+
const state = ws.checkReleaseTag(top, name, result.release.commit);
|
|
244
|
+
if (state === "absent")
|
|
245
|
+
ws.createReleaseTag(top, name, result.release.commit, { releaseDigest: result.release.releaseDigest, label: result.label, member });
|
|
246
|
+
tagged = { name, created: state === "absent" };
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
tagWarning = `the release was cut, and the commit was not tagged: ${err instanceof Error ? err.message : String(err)}`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const firstEnv = result.release.targets[0]?.env ?? null;
|
|
253
|
+
const next = nextCommands({
|
|
254
|
+
ref: result.label ?? result.release.releaseDigest,
|
|
255
|
+
tag: tagged?.name ?? null,
|
|
256
|
+
inCi: ci !== undefined,
|
|
257
|
+
firstEnv,
|
|
258
|
+
noComponents: result.release.targets.every((t) => t.templates.every((tpl) => tpl.component === null)) && result.release.artifactDigests.length === 0,
|
|
259
|
+
});
|
|
260
|
+
if (args.json) {
|
|
261
|
+
console.log(JSON.stringify({ dryRun: false, release: result.release, label: result.label, cut: result.cut, stored: result.stored, reused: result.reused, actor, actorSource: who.source, tag: tagged, next }, null, 2));
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
const name = result.label ? formatBold(result.label) : "unlabelled release";
|
|
265
|
+
if (result.cut)
|
|
266
|
+
console.error(formatSuccess(`Cut ${name}: ${result.release.releaseDigest}`));
|
|
267
|
+
else
|
|
268
|
+
console.error(formatSuccess(`Already cut${result.label ? ` as ${formatBold(result.label)}` : ""}: ${result.release.releaseDigest}`));
|
|
269
|
+
console.error(` commit ${result.release.commit}`);
|
|
270
|
+
if (result.cut)
|
|
271
|
+
console.error(` ${result.cut.signature ? `signed by ${result.cut.actor}` : `not signed; actor ${result.cut.actor}`}, run ${result.cut.runId}`);
|
|
272
|
+
console.error(` artifacts ${result.release.artifactDigests.length}, targets ${result.release.targets.map((t) => `${t.env} (${t.templates.length} template${t.templates.length === 1 ? "" : "s"})`).join(", ")}`);
|
|
273
|
+
for (const r of result.reused)
|
|
274
|
+
console.error(` ${r.component}: artifacts unchanged, carried from ${r.from}`);
|
|
275
|
+
if (tagged)
|
|
276
|
+
console.error(` tag ${tagged.name}${tagged.created ? "" : " (already there)"}, not pushed`);
|
|
277
|
+
console.error(`Next: ${next[0]}`);
|
|
278
|
+
for (const n of next.slice(1))
|
|
279
|
+
console.error(` or: ${n}`);
|
|
280
|
+
console.log(result.release.releaseDigest);
|
|
281
|
+
}
|
|
282
|
+
if (push.pushWarning)
|
|
283
|
+
console.error(formatWarning({ message: push.pushWarning }));
|
|
284
|
+
if (tagWarning)
|
|
285
|
+
console.error(formatWarning({ message: tagWarning }));
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
if (err instanceof ws.WorkstationCheckError || err instanceof ReleaseCutError) {
|
|
290
|
+
return fail(err.code, err.message, err.fix);
|
|
291
|
+
}
|
|
292
|
+
if (err instanceof ReleaseLabelError)
|
|
293
|
+
return fail(err.code, err.message);
|
|
294
|
+
if (err instanceof ReleaseCompileError) {
|
|
295
|
+
console.error(formatError({ message: `no release was cut: ${err.message}` }));
|
|
296
|
+
return 1;
|
|
297
|
+
}
|
|
298
|
+
throw err;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* `release publish <label|digest> [--yes]` (#4027, #4047): publish a cut
|
|
303
|
+
* release to the targets the member declares under `release.publish` in
|
|
304
|
+
* its `chant.config.ts`. It refuses a release no cut names, one cut from a
|
|
305
|
+
* revoked commit, one with no signature that verifies against the signers
|
|
306
|
+
* file at base unless `--allow-unsigned` (#4049; never under
|
|
307
|
+
* identity.gates.release), and, when there is a target, a checkout that is
|
|
308
|
+
* not the release's commit with a clean tree. It warns before publishing
|
|
309
|
+
* when the run has no OIDC token, so what it publishes carries no
|
|
310
|
+
* provenance, and refuses under `--require-provenance`. Each target attaches
|
|
311
|
+
* an SBOM and the release's provenance statement (#4049). Every
|
|
312
|
+
* target is planned (its files read and checked, its credentials found)
|
|
313
|
+
* before any publishes. Without `--yes` it is a dry run that prints the plan
|
|
314
|
+
* and uploads nothing. With `--yes` it stages every target, then reveals them
|
|
315
|
+
* (#4048, `runPublish`), recording each step in `_releases/publishes.jsonl`,
|
|
316
|
+
* so running it again after a failure resumes. Every line is redacted.
|
|
317
|
+
*/
|
|
318
|
+
export async function runReleasePublish(ctx) {
|
|
319
|
+
const { args } = ctx;
|
|
320
|
+
const ref = args.extraPositional;
|
|
321
|
+
if (!ref) {
|
|
322
|
+
console.error(formatError({ message: "release publish needs a release", hint: USAGE }));
|
|
323
|
+
return 1;
|
|
324
|
+
}
|
|
325
|
+
const dryRun = args.yes !== true;
|
|
326
|
+
const cwd = resolve(".");
|
|
327
|
+
const fail = (code, message, fix) => {
|
|
328
|
+
console.error(formatError({ message: `${message} [${code}]`, ...(fix ? { hint: fix } : {}) }));
|
|
329
|
+
return 1;
|
|
330
|
+
};
|
|
331
|
+
const { fetchLifecycle } = await import("../../lifecycle/git.js");
|
|
332
|
+
const { preparePublish, publishContext, runPublish, PublishTargetError, PublishRunError } = await import("../../lifecycle/release-publish.js");
|
|
333
|
+
const { publishProgress, progressOf, readPublishRecords } = await import("../../lifecycle/publish-record.js");
|
|
334
|
+
await fetchLifecycle({ cwd }).catch(() => false);
|
|
335
|
+
const prepared = await preparePublish({ cwd, ref, allowUnsigned: args.allowUnsigned === true, requireProvenance: args.requireProvenance === true });
|
|
336
|
+
if ("refusal" in prepared)
|
|
337
|
+
return fail(prepared.refusal.code, prepared.refusal.message, prepared.refusal.fix);
|
|
338
|
+
const { release, label, signature, provenance, warning, signatureWarning, targets, redactor } = prepared;
|
|
339
|
+
const name = label ?? release.releaseDigest;
|
|
340
|
+
const deploySteps = release.targets.map((t) => t.env);
|
|
341
|
+
const say = (line) => console.error(redactor.redact(line));
|
|
342
|
+
const failed = (code, message, fix) => fail(code, redactor.redact(message), fix);
|
|
343
|
+
const errorOf = (err) => err instanceof PublishTargetError ? { code: err.code, message: err.message, ...(err.fix ? { fix: err.fix } : {}) } : { code: "publish-failed", message: err instanceof Error ? err.message : String(err) };
|
|
344
|
+
if (!args.json) {
|
|
345
|
+
say(`${dryRun ? "Dry run: publish" : "Publishing"} ${formatBold(name)} (${release.releaseDigest}) from commit ${release.commit.slice(0, 12)}`);
|
|
346
|
+
say(` ${signature.status === "verified" ? `signed by ${signature.actor}` : signature.status === "unsigned" ? "not signed" : `signature unverified: ${signature.reason}`}`);
|
|
347
|
+
}
|
|
348
|
+
// The warnings go to stderr with --json too, before any target runs.
|
|
349
|
+
if (signatureWarning)
|
|
350
|
+
console.error(formatWarning({ message: signatureWarning }));
|
|
351
|
+
if (warning)
|
|
352
|
+
console.error(formatWarning({ message: warning }));
|
|
353
|
+
const pctx = publishContext(prepared, { cwd, log: (line) => (args.json ? undefined : console.error(` ${line}`)) });
|
|
354
|
+
// Every target is planned before any publishes, so a missing file or credential stops the publish with nothing sent.
|
|
355
|
+
const progress = publishProgress(await readPublishRecords(release.releaseDigest, { cwd }).catch(() => []));
|
|
356
|
+
const planned = [];
|
|
357
|
+
for (const target of targets) {
|
|
358
|
+
try {
|
|
359
|
+
planned.push({ kind: target.kind, name: target.name, destination: target.destination, progress: progressOf(progress, target), items: await target.plan(pctx) });
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
const e = errorOf(err);
|
|
363
|
+
return failed(e.code, `nothing was published: ${target.name}: ${e.message}`, e.fix);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const promoteHint = () => {
|
|
367
|
+
if (deploySteps.length === 0)
|
|
368
|
+
return null;
|
|
369
|
+
const noComponents = release.artifactDigests.length === 0 && release.targets.every((t) => t.templates.every((tpl) => tpl.component === null));
|
|
370
|
+
return noComponents
|
|
371
|
+
? ` Each environment deploys the files the release recorded: chant release export ${name} --env ${deploySteps[0]}`
|
|
372
|
+
: ` A component's publish steps run in each environment's deploy of the release: chant components promote --release ${name} --to ${deploySteps[0]}`;
|
|
373
|
+
};
|
|
374
|
+
const base = { releaseDigest: release.releaseDigest, label, commit: release.commit, signature, provenance, warnings: [signatureWarning, warning].filter((w) => w !== null) };
|
|
375
|
+
if (dryRun) {
|
|
376
|
+
const next = [sameWithYes(process.argv.slice(2))];
|
|
377
|
+
if (args.json) {
|
|
378
|
+
console.log(redactor.redact(JSON.stringify({ dryRun: true, ...base, targets: planned, published: [], environments: deploySteps, next }, null, 2)));
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
381
|
+
const out = (line) => console.log(redactor.redact(line));
|
|
382
|
+
out("What would be published where:");
|
|
383
|
+
if (planned.length === 0)
|
|
384
|
+
out(" nothing: this member declares no publish target (release.publish in chant.config.ts)");
|
|
385
|
+
for (const p of planned) {
|
|
386
|
+
const earlier = p.progress === "revealed" ? " (published by an earlier run; skipped)" : p.progress === "staged" ? " (staged by an earlier run; only revealed)" : "";
|
|
387
|
+
out(` ${p.name}${provenance.oidc && p.kind === "npm" ? ", with --provenance" : ""}${earlier}:`);
|
|
388
|
+
for (const i of p.items)
|
|
389
|
+
out(` ${describeItem(i)}`);
|
|
390
|
+
}
|
|
391
|
+
say(`Dry run: nothing was published. Run again with --yes to publish: ${next[0]}`);
|
|
392
|
+
const hint = planned.length === 0 ? promoteHint() : null;
|
|
393
|
+
if (hint)
|
|
394
|
+
say(hint);
|
|
395
|
+
return 0;
|
|
396
|
+
}
|
|
397
|
+
if (targets.length > 0 && !args.json)
|
|
398
|
+
say(" every target stages first, and none is visible until all have staged");
|
|
399
|
+
let run;
|
|
400
|
+
try {
|
|
401
|
+
run = await runPublish({ cwd, release, label, targets, ctx: pctx, say: (line) => (args.json ? undefined : say(line)) });
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
if (err instanceof PublishRunError) {
|
|
405
|
+
const again = sameWithYes(process.argv.slice(2));
|
|
406
|
+
const where = err.step === "stage"
|
|
407
|
+
? `nothing is visible yet${err.staged.length > 0 ? `; staged: ${err.staged.join(", ")}` : ""}`
|
|
408
|
+
: `revealed: ${err.revealed.length > 0 ? err.revealed.join(", ") : "none"}; staged and not yet revealed: ${err.staged.filter((t) => !err.revealed.includes(t)).join(", ")}`;
|
|
409
|
+
return failed(err.code, `${err.message}; ${where}`, `${err.fix ? `${err.fix} ` : ""}Run the same command again to resume; what went out is not published again: ${again}`);
|
|
410
|
+
}
|
|
411
|
+
const e = errorOf(err);
|
|
412
|
+
return failed(e.code, e.message, e.fix);
|
|
413
|
+
}
|
|
414
|
+
const { published } = run;
|
|
415
|
+
if (run.recordWarning && targets.length > 0)
|
|
416
|
+
console.error(formatWarning({ message: redactor.redact(`${run.recordWarning}. A resume asks the registries what is already there.`) }));
|
|
417
|
+
if (args.json) {
|
|
418
|
+
console.log(redactor.redact(JSON.stringify({ dryRun: false, ...base, targets: planned, published, resumed: run.resumed, environments: deploySteps }, null, 2)));
|
|
419
|
+
return 0;
|
|
420
|
+
}
|
|
421
|
+
if (targets.length === 0) {
|
|
422
|
+
say("Nothing was published: this member declares no publish target (release.publish in chant.config.ts).");
|
|
423
|
+
const hint = promoteHint();
|
|
424
|
+
if (hint)
|
|
425
|
+
say(hint);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
for (const p of published)
|
|
429
|
+
for (const i of p.items)
|
|
430
|
+
say(` ${i.present ? "already there" : "published"}: ${describeItem(i)}`);
|
|
431
|
+
console.error(formatSuccess(`Published ${name} to ${published.length} target(s)`));
|
|
432
|
+
}
|
|
433
|
+
return 0;
|
|
434
|
+
}
|
|
435
|
+
/** One item a target publishes, for a line: what, where, and the SBOM or attachment it is (#4049). */
|
|
436
|
+
function describeItem(i) {
|
|
437
|
+
const what = i.attachment === "sbom" ? `${i.name} (SBOM)` : i.attachment === "provenance" ? `${i.name} (provenance)` : i.name;
|
|
438
|
+
return `${what} to ${i.destination}${i.sbom ? `, carrying ${i.sbom}` : ""}`;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* `release verify <label|digest> [--json]` (#4049): check, offline, that the
|
|
442
|
+
* release was signed by a key `.chant/allowed_signers` lists at the release's
|
|
443
|
+
* commit, and that its file is the digest of what it holds. Exits 0 when it
|
|
444
|
+
* verifies and 1 when it does not or can't be checked.
|
|
445
|
+
*/
|
|
446
|
+
export async function runReleaseVerify(ctx) {
|
|
447
|
+
const { args } = ctx;
|
|
448
|
+
const ref = args.extraPositional;
|
|
449
|
+
if (!ref) {
|
|
450
|
+
console.error(formatError({ message: "release verify needs a release", hint: USAGE }));
|
|
451
|
+
return 1;
|
|
452
|
+
}
|
|
453
|
+
const { verifyRelease, verificationCode } = await import("../../lifecycle/release-verify.js");
|
|
454
|
+
const result = await verifyRelease({ cwd: resolve("."), ref });
|
|
455
|
+
if ("error" in result) {
|
|
456
|
+
if (args.json)
|
|
457
|
+
console.log(JSON.stringify({ ref, error: result.error }, null, 2));
|
|
458
|
+
else
|
|
459
|
+
console.error(formatError({ message: `${result.error.message} [${result.error.code}]`, ...(result.error.fix ? { hint: result.error.fix } : {}) }));
|
|
460
|
+
return 1;
|
|
461
|
+
}
|
|
462
|
+
const code = verificationCode(result);
|
|
463
|
+
if (args.json) {
|
|
464
|
+
console.log(JSON.stringify({ ...result, ...(code ? { error: { code, message: result.reason } } : {}) }, null, 2));
|
|
465
|
+
return code ? 1 : 0;
|
|
466
|
+
}
|
|
467
|
+
const name = result.label ? `${formatBold(result.label)} (${result.releaseDigest})` : result.releaseDigest;
|
|
468
|
+
for (const c of result.cuts) {
|
|
469
|
+
console.log(` cut by ${c.actor} at ${c.timestamp}: ${c.signatureCheck.status}${c.signatureCheck.key ? ` (${c.signatureCheck.key})` : ""}`);
|
|
470
|
+
}
|
|
471
|
+
if (code) {
|
|
472
|
+
console.error(formatError({
|
|
473
|
+
message: `${name} does not verify: ${result.reason} [${code}]`,
|
|
474
|
+
hint: code === "release-digest-mismatch" ? "Do not publish or deploy it; cut the release again." : `Cut it again signed with a key ${result.signers.path} lists: chant release cut ${result.label ?? "<label>"} --sign --yes`,
|
|
475
|
+
}));
|
|
476
|
+
return 1;
|
|
477
|
+
}
|
|
478
|
+
console.error(formatSuccess(`Verified ${name}: ${result.reason}`));
|
|
479
|
+
return 0;
|
|
480
|
+
}
|
|
481
|
+
export async function runReleaseList(ctx) {
|
|
482
|
+
const { releasesDocument } = await import("../../workspace/releases.js");
|
|
483
|
+
const doc = await releasesDocument({ cwd: resolve(".") });
|
|
484
|
+
if (ctx.args.json) {
|
|
485
|
+
console.log(JSON.stringify(doc, null, 2));
|
|
486
|
+
return "error" in doc ? 1 : 0;
|
|
487
|
+
}
|
|
488
|
+
if ("error" in doc) {
|
|
489
|
+
console.error(formatError({ message: doc.error.message, hint: USAGE }));
|
|
490
|
+
return 1;
|
|
491
|
+
}
|
|
492
|
+
if (doc.reason)
|
|
493
|
+
console.error(formatWarning({ message: doc.reason.message }));
|
|
494
|
+
if (doc.releases.length === 0) {
|
|
495
|
+
console.error("No releases. Cut one from a green commit: chant release cut <label>");
|
|
496
|
+
return 0;
|
|
497
|
+
}
|
|
498
|
+
for (const r of doc.releases) {
|
|
499
|
+
const where = r.environments.map((e) => e.env).join(", ") || "not deployed from the release";
|
|
500
|
+
// #4031: the newest cut's signature, as the policy at base judges it.
|
|
501
|
+
const newest = r.cuts.at(-1);
|
|
502
|
+
const signature = newest ? (newest.signatureCheck.status === "verified" ? `signed by ${newest.actor}` : newest.signatureCheck.status) : "-";
|
|
503
|
+
// #4033: a release cut from a revoked commit says so at the end of its line, and why on stderr.
|
|
504
|
+
console.log(`${(r.label ?? "-").padEnd(16)} ${r.releaseDigest} ${r.commit.slice(0, 12)} ${signature} ${where}${r.revoked ? " revoked" : ""}`);
|
|
505
|
+
if (newest?.signatureCheck.status === "unverified")
|
|
506
|
+
console.error(` ${r.label ?? r.releaseDigest}: ${newest.signatureCheck.reason}`);
|
|
507
|
+
if (r.revoked) {
|
|
508
|
+
const { describeRevocation } = await import("../../lifecycle/release-revocation.js");
|
|
509
|
+
console.error(` ${r.label ?? r.releaseDigest}: revoked by ${r.revoked.tag}, ${describeRevocation(r.revoked)}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* `release export <label|digest> --env <env> [-o <dir>]` (#4046): write each
|
|
516
|
+
* file the release's target for <env> records, at the path it was compiled to,
|
|
517
|
+
* under <dir> (the member's directory by default), after checking each one's
|
|
518
|
+
* bytes against its digest. This is how a project with no components deploys
|
|
519
|
+
* a release: its own deploy reads these files instead of building again.
|
|
520
|
+
*/
|
|
521
|
+
export async function runReleaseExport(ctx) {
|
|
522
|
+
const { args } = ctx;
|
|
523
|
+
const ref = args.extraPositional;
|
|
524
|
+
if (!ref || !args.env) {
|
|
525
|
+
console.error(formatError({ message: "release export needs a release and an environment", hint: USAGE }));
|
|
526
|
+
return 1;
|
|
527
|
+
}
|
|
528
|
+
const { fetchLifecycle } = await import("../../lifecycle/git.js");
|
|
529
|
+
const { resolveRelease, readReleaseTemplate } = await import("../../lifecycle/release-store.js");
|
|
530
|
+
const { targetFor, targetFiles, writePinnedTemplates } = await import("../../components/release-promote.js");
|
|
531
|
+
await fetchLifecycle().catch(() => false);
|
|
532
|
+
const found = await resolveRelease(ref);
|
|
533
|
+
if (!found) {
|
|
534
|
+
console.error(formatError({ message: `no release is labelled or digested "${ref}" in this member`, hint: "List them with: chant release list" }));
|
|
535
|
+
return 1;
|
|
536
|
+
}
|
|
537
|
+
const target = targetFor(found.release, args.env);
|
|
538
|
+
if ("error" in target) {
|
|
539
|
+
console.error(formatError({ message: target.error }));
|
|
540
|
+
return 1;
|
|
541
|
+
}
|
|
542
|
+
const read = await targetFiles(found.release, target.target, (digest) => readReleaseTemplate(digest));
|
|
543
|
+
if ("errors" in read) {
|
|
544
|
+
for (const e of read.errors)
|
|
545
|
+
console.error(formatError({ message: e }));
|
|
546
|
+
return 1;
|
|
547
|
+
}
|
|
548
|
+
const dir = resolve(args.output ?? ".");
|
|
549
|
+
writePinnedTemplates(dir, read.files);
|
|
550
|
+
if (args.json) {
|
|
551
|
+
console.log(JSON.stringify({ releaseDigest: found.release.releaseDigest, label: found.label, env: args.env, dir, templates: target.target.templates, params: target.target.params }, null, 2));
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
console.error(formatSuccess(`Wrote ${read.files.length} file(s) of ${found.label ? formatBold(found.label) : found.release.releaseDigest} for "${args.env}"`));
|
|
555
|
+
for (const f of read.files)
|
|
556
|
+
console.log(f.path);
|
|
557
|
+
}
|
|
558
|
+
return 0;
|
|
559
|
+
}
|
|
560
|
+
/** Internal: compile one environment, or build artifacts, in this process, and print the JSON the cut reads. */
|
|
561
|
+
export async function runReleaseCompile(ctx) {
|
|
562
|
+
const { args } = ctx;
|
|
563
|
+
const env = args.env;
|
|
564
|
+
if (!env) {
|
|
565
|
+
console.error(formatError({ message: "release compile needs --env <env>" }));
|
|
566
|
+
return 1;
|
|
567
|
+
}
|
|
568
|
+
const { compileEnvironment, buildReleaseArtifacts } = await import("../../components/release-compile.js");
|
|
569
|
+
const params = parseParamFlags(args.param);
|
|
570
|
+
const inputs = compileInputs(ctx, params);
|
|
571
|
+
try {
|
|
572
|
+
if (args.artifacts) {
|
|
573
|
+
const names = (args.component ?? "").split(",").map((n) => n.trim()).filter(Boolean);
|
|
574
|
+
console.log(JSON.stringify({ artifacts: await buildReleaseArtifacts(inputs, env, names) }));
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
console.log(JSON.stringify(await compileEnvironment(inputs, env)));
|
|
578
|
+
}
|
|
579
|
+
return 0;
|
|
580
|
+
}
|
|
581
|
+
catch (err) {
|
|
582
|
+
console.error(formatError({ message: err instanceof Error ? err.message : String(err) }));
|
|
583
|
+
return 1;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
export async function runReleaseUnknown(ctx) {
|
|
587
|
+
console.error(formatError({ message: `Unknown release subcommand: ${ctx.args.path}`, hint: USAGE }));
|
|
588
|
+
return 1;
|
|
589
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type OpConfig } from "../../op/types.js";
|
|
2
2
|
import { type StepRecord } from "../../op/local-executor.js";
|
|
3
3
|
import type { CommandContext } from "../registry.js";
|
|
4
|
+
import type { RunEvent } from "../../run-event.js";
|
|
4
5
|
import type { DriverComponentResult } from "../../components/driver.js";
|
|
5
|
-
import type
|
|
6
|
+
import { type ReleaseRecord, type RunOrigin } from "../../lifecycle/release-ledger.js";
|
|
6
7
|
/**
|
|
7
8
|
* The exit code a run that stopped at an unapproved gate uses (#2119).
|
|
8
9
|
* Deliberately not 1: a gate is a standing fact waiting on a human, and a CI
|
|
@@ -26,6 +27,21 @@ export declare function completedRunExitCode(opName: string, config: Pick<OpConf
|
|
|
26
27
|
export declare function runOpList(ctx: CommandContext): Promise<number>;
|
|
27
28
|
export declare function runOpStatus(ctx: CommandContext): Promise<number>;
|
|
28
29
|
export declare function runOpLog(ctx: CommandContext): Promise<number>;
|
|
30
|
+
/** One event as a line for a person: its time, its type, where it is and how it ended. */
|
|
31
|
+
export declare function humanRunEventLine(e: RunEvent): string;
|
|
32
|
+
/**
|
|
33
|
+
* `chant run events <run> [--json] [--follow]` (#4042): the events a run on
|
|
34
|
+
* this host kept, replayed. `<run>` is a run id, or the name of an Op or a
|
|
35
|
+
* component selection, for which the newest stored run stands. A settled run
|
|
36
|
+
* and a run in progress both replay what is in the file; `--follow` goes on
|
|
37
|
+
* from there until the run settles. `--json` prints the stored lines as they
|
|
38
|
+
* were written; without it each event is one line for a person.
|
|
39
|
+
*
|
|
40
|
+
* The exit code is the replayed run's verdict (0, 1, or 3 for a run waiting
|
|
41
|
+
* on a person). A replay of a run still going, and a follow cut short by
|
|
42
|
+
* Ctrl-C, exit 0.
|
|
43
|
+
*/
|
|
44
|
+
export declare function runOpEvents(ctx: CommandContext): Promise<number>;
|
|
29
45
|
/**
|
|
30
46
|
* `chant run approve <op> <gate> [--approver] [--url] [--note]` (#2121) — the
|
|
31
47
|
* rename of `chant run signal`, and a different act.
|
|
@@ -48,6 +64,16 @@ export declare function runOpSignalRenamed(ctx: CommandContext): Promise<number>
|
|
|
48
64
|
/** `chant run cancel <name>` — asks the resolved runtime (#2121) to stop the Op's active run. */
|
|
49
65
|
export declare function runOpCancel(ctx: CommandContext): Promise<number>;
|
|
50
66
|
export declare function runOp(ctx: CommandContext): Promise<number>;
|
|
67
|
+
/**
|
|
68
|
+
* The run id and origin an auto-recorded release names (#4020): the CI run
|
|
69
|
+
* when the process is in CI, so the release and the gate it passed (which
|
|
70
|
+
* records the CI run id) name the same run, else `localId` with the `local`
|
|
71
|
+
* origin.
|
|
72
|
+
*/
|
|
73
|
+
export declare function autoReleaseRun(localId: string): {
|
|
74
|
+
runId: string;
|
|
75
|
+
runOrigin: RunOrigin;
|
|
76
|
+
};
|
|
51
77
|
/**
|
|
52
78
|
* After a successful `chant run --components` (local executor), auto-emit
|
|
53
79
|
* one release record per successfully deployed component that published a
|
|
@@ -83,7 +109,7 @@ export declare function runOp(ctx: CommandContext): Promise<number>;
|
|
|
83
109
|
*
|
|
84
110
|
* Returns the records it wrote, for `--digest-file` (#2602).
|
|
85
111
|
*/
|
|
86
|
-
export declare function recordAutoReleasesForRun(results: DriverComponentResult[], env: string, runId: string, disabled: boolean): Promise<ReleaseRecord[]>;
|
|
112
|
+
export declare function recordAutoReleasesForRun(results: DriverComponentResult[], env: string, runId: string, disabled: boolean, runOrigin?: RunOrigin, releaseDigest?: string): Promise<ReleaseRecord[]>;
|
|
87
113
|
/**
|
|
88
114
|
* `chant run --components <name|all|a,b,c> [--env <env>]` (#585) — the
|
|
89
115
|
* interpret driver's CLI entrypoint, and since #2116 the only component run
|
|
@@ -120,6 +146,16 @@ export declare function recordAutoReleasesForRun(results: DriverComponentResult[
|
|
|
120
146
|
* rather than loaded a second time.
|
|
121
147
|
*/
|
|
122
148
|
export declare function runOpComponents(ctx: CommandContext): Promise<number>;
|
|
149
|
+
/**
|
|
150
|
+
* Resolve the release `chant run --components --release` names (#4043), or the
|
|
151
|
+
* reason it can't be used. The run builds from the checked-out commit, so the
|
|
152
|
+
* release's commit must be HEAD, and the release needs a target for `env`.
|
|
153
|
+
*/
|
|
154
|
+
export declare function resolveRunRelease(ref: string, env: string, cwd: string): Promise<string | {
|
|
155
|
+
releaseDigest: string;
|
|
156
|
+
label: string | null;
|
|
157
|
+
release: import("../../lifecycle/release-store.js").Release;
|
|
158
|
+
}>;
|
|
123
159
|
/**
|
|
124
160
|
* `chant run <name>` on the resolved runtime (#2121) — the built-in `local`
|
|
125
161
|
* provider by default, a lexicon's `opRuntime` under `--on <name>`.
|