@intentius/chant 0.124.27 → 0.124.28
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/change-set-graph.d.ts +56 -0
- package/dist/change-set-graph.d.ts.map +1 -0
- package/dist/change-set-graph.js +128 -0
- package/dist/change-set.d.ts +52 -3
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +35 -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/commands/build.d.ts +8 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +9 -8
- 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 +19 -4
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +28 -0
- 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 +1 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +14 -3
- package/dist/cli/handlers/pr.d.ts +8 -2
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +148 -24
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +256 -21
- package/dist/cli/handlers/release.d.ts +34 -0
- package/dist/cli/handlers/release.d.ts.map +1 -0
- package/dist/cli/handlers/release.js +203 -0
- package/dist/cli/handlers/run.d.ts +28 -2
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +170 -13
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +88 -13
- 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 +49 -3
- package/dist/cli/registry.d.ts +29 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/run-events.d.ts +29 -0
- package/dist/cli/run-events.d.ts.map +1 -0
- package/dist/cli/run-events.js +47 -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 +4 -1
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/auto-release.js +2 -0
- 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 +42 -9
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +81 -54
- 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 +35 -26
- 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 +15 -2
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +17 -0
- package/dist/components/release-compile.d.ts +133 -0
- package/dist/components/release-compile.d.ts.map +1 -0
- package/dist/components/release-compile.js +376 -0
- package/dist/components/release-gate.d.ts +125 -0
- package/dist/components/release-gate.d.ts.map +1 -0
- package/dist/components/release-gate.js +282 -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 +3 -1
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -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/change-set-store.d.ts +67 -0
- package/dist/lifecycle/change-set-store.d.ts.map +1 -0
- package/dist/lifecycle/change-set-store.js +96 -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/gate-change-set.d.ts +69 -0
- package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
- package/dist/lifecycle/gate-change-set.js +106 -0
- package/dist/lifecycle/gate-ledger.d.ts +49 -1
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +18 -0
- package/dist/lifecycle/release-cut.d.ts +107 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -0
- package/dist/lifecycle/release-cut.js +273 -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-store.d.ts +190 -0
- package/dist/lifecycle/release-store.d.ts.map +1 -0
- package/dist/lifecycle/release-store.js +318 -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/point-decision.d.ts +2 -0
- package/dist/point-decision.d.ts.map +1 -1
- package/dist/point-decision.js +9 -2
- package/dist/run-event-store.d.ts +77 -0
- package/dist/run-event-store.d.ts.map +1 -0
- package/dist/run-event-store.js +204 -0
- package/dist/run-event-stream.d.ts +132 -0
- package/dist/run-event-stream.d.ts.map +1 -0
- package/dist/run-event-stream.js +238 -0
- package/dist/run-event.d.ts +267 -0
- package/dist/run-event.d.ts.map +1 -0
- package/dist/run-event.js +207 -0
- package/dist/wave-runtime.mjs +204 -199
- 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 +28 -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/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 +273 -13
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +449 -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 +19 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +1 -1
- package/dist/workspace/declaration.schema.json +12 -0
- 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.d.ts +6 -1
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +51 -1
- 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/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 +2 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +4 -1
- package/dist/workspace/releases.d.ts +72 -0
- package/dist/workspace/releases.d.ts.map +1 -0
- package/dist/workspace/releases.js +94 -0
- package/dist/workspace/releases.schema.json +391 -0
- package/dist/workspace/run-event.schema.json +288 -0
- package/dist/workspace/status-gates.d.ts +26 -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 +39 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +48 -1
- package/dist/workspace/status.schema.json +70 -1
- 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/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/change-set-graph.test.ts +72 -0
- package/src/change-set-graph.ts +133 -0
- package/src/change-set.ts +76 -6
- package/src/chant-version.ts +16 -0
- package/src/cli/commands/build.ts +19 -8
- 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 +80 -0
- package/src/cli/handlers/approve.ts +18 -2
- package/src/cli/handlers/build.test.ts +52 -0
- package/src/cli/handlers/build.ts +29 -0
- package/src/cli/handlers/change-set.ts +49 -1
- package/src/cli/handlers/fan-out.test.ts +48 -0
- package/src/cli/handlers/fan-out.ts +15 -3
- package/src/cli/handlers/operator.test.ts +37 -0
- package/src/cli/handlers/pr.test.ts +194 -0
- package/src/cli/handlers/pr.ts +168 -34
- package/src/cli/handlers/promote.test.ts +389 -5
- package/src/cli/handlers/promote.ts +279 -20
- package/src/cli/handlers/release-implicit.e2e.test.ts +153 -0
- package/src/cli/handlers/release.e2e.test.ts +85 -0
- package/src/cli/handlers/release.ts +206 -0
- package/src/cli/handlers/run-auto-release.test.ts +71 -0
- package/src/cli/handlers/run-events-cmd.test.ts +92 -0
- package/src/cli/handlers/run.test.ts +30 -0
- package/src/cli/handlers/run.ts +176 -15
- package/src/cli/main.test.ts +7 -0
- package/src/cli/main.ts +88 -13
- 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 +37 -3
- package/src/cli/registry.ts +29 -3
- package/src/cli/run-events.ts +54 -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 +21 -0
- package/src/components/auto-release.ts +6 -1
- package/src/components/cli-support.test.ts +82 -0
- package/src/components/cli-support.ts +16 -9
- package/src/components/driver.ts +129 -56
- package/src/components/fan-out-run.ts +56 -35
- 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 +26 -1
- package/src/components/release-compile.test.ts +147 -0
- package/src/components/release-compile.ts +445 -0
- package/src/components/release-gate.test.ts +215 -0
- package/src/components/release-gate.ts +341 -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 +1 -1
- package/src/config.ts +7 -1
- package/src/index.ts +2 -0
- package/src/lifecycle/change-set-store.test.ts +217 -0
- package/src/lifecycle/change-set-store.ts +112 -0
- package/src/lifecycle/commit-sha.ts +23 -0
- package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
- package/src/lifecycle/gate-change-set.ts +133 -0
- package/src/lifecycle/gate-ledger.test.ts +33 -0
- package/src/lifecycle/gate-ledger.ts +66 -1
- package/src/lifecycle/release-cut-signed.test.ts +180 -0
- package/src/lifecycle/release-cut.test.ts +411 -0
- package/src/lifecycle/release-cut.ts +367 -0
- package/src/lifecycle/release-ledger.test.ts +14 -0
- package/src/lifecycle/release-ledger.ts +85 -17
- package/src/lifecycle/release-store.ts +423 -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/point-decision.ts +12 -2
- package/src/run-event-store.test.ts +144 -0
- package/src/run-event-store.ts +213 -0
- package/src/run-event-stream.test.ts +175 -0
- package/src/run-event-stream.ts +306 -0
- package/src/run-event.test.ts +277 -0
- package/src/run-event.ts +451 -0
- package/src/wave-loop-golden.test.ts +9 -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 +28 -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/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 +624 -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 +12 -0
- package/src/workspace/declaration.ts +22 -2
- package/src/workspace/identity-gate-rule.ts +91 -7
- package/src/workspace/identity.ts +14 -1
- package/src/workspace/intent.ts +48 -1
- 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/promotion-order.ts +97 -0
- package/src/workspace/read-contract.e2e.test.ts +4 -1
- package/src/workspace/reason-codes.test.ts +2 -1
- package/src/workspace/reason-codes.ts +4 -1
- package/src/workspace/releases.schema.json +391 -0
- package/src/workspace/releases.test.ts +108 -0
- package/src/workspace/releases.ts +122 -0
- package/src/workspace/run-event.schema.json +288 -0
- package/src/workspace/status-contract.test.ts +52 -1
- package/src/workspace/status-gates.ts +56 -1
- package/src/workspace/status-stewards.ts +6 -0
- package/src/workspace/status.schema.json +70 -1
- package/src/workspace/status.ts +80 -1
- 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/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,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cutting a release from a green commit (#4026, ws-104).
|
|
3
|
+
*
|
|
4
|
+
* The cut takes the checkout's `HEAD`, refuses it unless it carries a
|
|
5
|
+
* `ci/green/<sha>` tag and no `ci/revoked/<sha>` tag (ws-103, read from local
|
|
6
|
+
* tags), and refuses a working tree with uncommitted changes to tracked
|
|
7
|
+
* files, since the compile would then not be the commit's. It compiles every
|
|
8
|
+
* environment the member declares, in its promotion order (#4030), and
|
|
9
|
+
* refuses a component whose build steps differ between environments, since
|
|
10
|
+
* "built once" can't hold for it. It then builds each component's artifacts
|
|
11
|
+
* once, stores the release and appends the cut.
|
|
12
|
+
*
|
|
13
|
+
* An artifact whose source did not change since the earlier release cut
|
|
14
|
+
* from the nearest ancestor commit is not built again: the release carries that
|
|
15
|
+
* release's entry, so a config-only release keeps the same artifact digests.
|
|
16
|
+
* "Did not change" means git sees no change between the two commits in the
|
|
17
|
+
* component's own file, the member's `chant.config.ts` and the paths its
|
|
18
|
+
* build steps read.
|
|
19
|
+
*
|
|
20
|
+
* A project with no components (#4046) needs no special case here: its
|
|
21
|
+
* targets hold the files `chant build --env <env>` writes, each with
|
|
22
|
+
* `component: null`, and `artifactDigests` is empty.
|
|
23
|
+
*
|
|
24
|
+
* Compiling goes through a {@link TargetCompiler}, so a test hands the cut
|
|
25
|
+
* fixtures and the CLI hands it child processes.
|
|
26
|
+
*
|
|
27
|
+
* Who may cut (#4031): when the declaration at base names a `release` gate
|
|
28
|
+
* in `identity.gates`, a cut must be signed (`--sign`), its signature must
|
|
29
|
+
* verify for the actor against the signers at base, and when the gate names
|
|
30
|
+
* a class the actor must be in it. A cut signed without that gate is signed
|
|
31
|
+
* all the same, and readers report whether the signature verifies. With
|
|
32
|
+
* `ci.green.signedSince` declared, a green tag counts only with a valid
|
|
33
|
+
* statement (`../workspace/ci-green.ts`), so a hand-pushed tag cuts nothing.
|
|
34
|
+
*/
|
|
35
|
+
import { type Release, type ReleaseCut } from "./release-store.js";
|
|
36
|
+
import type { CompiledTarget, TargetCompiler } from "../components/release-compile.js";
|
|
37
|
+
/** The stable codes a cut refuses with. */
|
|
38
|
+
export type ReleaseCutCode = "not-a-git-repository" | "release-commit-not-green" | "release-commit-revoked" | "release-worktree-dirty" | "release-no-environments" | "release-no-components" | "release-build-inputs-differ" | "release-unsigned" | "release-signer-refused" | "declaration-invalid";
|
|
39
|
+
export declare class ReleaseCutError extends Error {
|
|
40
|
+
readonly code: ReleaseCutCode;
|
|
41
|
+
readonly fix?: string | undefined;
|
|
42
|
+
constructor(code: ReleaseCutCode, message: string, fix?: string | undefined);
|
|
43
|
+
}
|
|
44
|
+
export interface CutRequest {
|
|
45
|
+
/** The member's directory. */
|
|
46
|
+
cwd: string;
|
|
47
|
+
compiler: TargetCompiler;
|
|
48
|
+
/** The label, or null to cut without one. */
|
|
49
|
+
label: string | null;
|
|
50
|
+
actor: string;
|
|
51
|
+
/** The environments in promotion order. Read from the member's `chant.config.ts` when absent. */
|
|
52
|
+
environments?: readonly string[];
|
|
53
|
+
now?: () => Date;
|
|
54
|
+
/** The process environment the CI run is read from. */
|
|
55
|
+
env?: NodeJS.ProcessEnv;
|
|
56
|
+
/**
|
|
57
|
+
* Sign the cut (#4031): an ssh key file, or true for git's
|
|
58
|
+
* `user.signingkey`, as `chant approve --sign` takes it. The signature is
|
|
59
|
+
* over the release digest, the label, the actor and the time, and `actor`
|
|
60
|
+
* must be the principal the signers file lists the key for.
|
|
61
|
+
*/
|
|
62
|
+
sign?: string | true;
|
|
63
|
+
}
|
|
64
|
+
export interface CutResult {
|
|
65
|
+
release: Release;
|
|
66
|
+
/** The cut line written, or null when this digest was already cut. */
|
|
67
|
+
cut: ReleaseCut | null;
|
|
68
|
+
/** The release's label after the cut. */
|
|
69
|
+
label: string | null;
|
|
70
|
+
/** Whether the release file was written now, rather than already stored. */
|
|
71
|
+
stored: boolean;
|
|
72
|
+
/** The components whose artifacts were taken from an earlier release, and that release's digest. */
|
|
73
|
+
reused: Array<{
|
|
74
|
+
component: string;
|
|
75
|
+
from: string;
|
|
76
|
+
}>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Whether `sha` has a green tag and no revoked tag, read from local tags,
|
|
80
|
+
* and the tags on it that were ignored for want of a valid statement
|
|
81
|
+
* (#4031). The tags are judged by `green`, the declaration's `ci.green` at
|
|
82
|
+
* base, with the runner keys read at its branch's tip; with no `ci.green`,
|
|
83
|
+
* every tag counts.
|
|
84
|
+
*/
|
|
85
|
+
export declare function greenState(top: string, sha: string, green?: import("../workspace/declaration.js").CiGreen | null): Promise<{
|
|
86
|
+
state: "green" | "revoked" | "none";
|
|
87
|
+
ignored: Array<{
|
|
88
|
+
tag: string;
|
|
89
|
+
status: string;
|
|
90
|
+
reason: string;
|
|
91
|
+
}>;
|
|
92
|
+
}>;
|
|
93
|
+
/** Which components' build steps differ between environments, with the environments they appear in. */
|
|
94
|
+
export declare function differingBuildSteps(targets: readonly CompiledTarget[]): Array<{
|
|
95
|
+
component: string;
|
|
96
|
+
envs: string[];
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Cut a release of the member at `req.cwd` from its checkout's `HEAD`. Writes
|
|
100
|
+
* the release and the cut to the local `chant/lifecycle` branch and does not
|
|
101
|
+
* push. Throws {@link ReleaseCutError} before anything is written when the
|
|
102
|
+
* commit isn't green, the tree is dirty, or an environment can't be compiled
|
|
103
|
+
* to the same artifacts, and `ReleaseLabelError` (./release-store.ts) when the
|
|
104
|
+
* label is taken or the release already carries another one.
|
|
105
|
+
*/
|
|
106
|
+
export declare function cutRelease(req: CutRequest): Promise<CutResult>;
|
|
107
|
+
//# sourceMappingURL=release-cut.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-cut.d.ts","sourceRoot":"","sources":["../../src/lifecycle/release-cut.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAUH,OAAO,EAML,KAAK,OAAO,EAEZ,KAAK,UAAU,EAGhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpF,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GACtB,sBAAsB,GACtB,0BAA0B,GAC1B,wBAAwB,GACxB,wBAAwB,GACxB,yBAAyB,GACzB,uBAAuB,GACvB,6BAA6B,GAC7B,kBAAkB,GAClB,wBAAwB,GACxB,qBAAqB,CAAC;AAE1B,qBAAa,eAAgB,SAAQ,KAAK;IAEtC,QAAQ,CAAC,IAAI,EAAE,cAAc;IAE7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM;IAHvB,YACW,IAAI,EAAE,cAAc,EAC7B,OAAO,EAAE,MAAM,EACN,GAAG,CAAC,EAAE,MAAM,YAAA,EAItB;CACF;AAED,MAAM,WAAW,UAAU;IACzB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,cAAc,CAAC;IACzB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,iGAAiG;IACjG,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACvB,yCAAyC;IACzC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,oGAAoG;IACpG,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAcD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,OAAO,0BAA0B,EAAE,OAAO,GAAG,IAAW,GAC9D,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAkBnH;AAED,uGAAuG;AACvG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,GAAG,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAapH;AAiBD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA0KpE"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cutting a release from a green commit (#4026, ws-104).
|
|
3
|
+
*
|
|
4
|
+
* The cut takes the checkout's `HEAD`, refuses it unless it carries a
|
|
5
|
+
* `ci/green/<sha>` tag and no `ci/revoked/<sha>` tag (ws-103, read from local
|
|
6
|
+
* tags), and refuses a working tree with uncommitted changes to tracked
|
|
7
|
+
* files, since the compile would then not be the commit's. It compiles every
|
|
8
|
+
* environment the member declares, in its promotion order (#4030), and
|
|
9
|
+
* refuses a component whose build steps differ between environments, since
|
|
10
|
+
* "built once" can't hold for it. It then builds each component's artifacts
|
|
11
|
+
* once, stores the release and appends the cut.
|
|
12
|
+
*
|
|
13
|
+
* An artifact whose source did not change since the earlier release cut
|
|
14
|
+
* from the nearest ancestor commit is not built again: the release carries that
|
|
15
|
+
* release's entry, so a config-only release keeps the same artifact digests.
|
|
16
|
+
* "Did not change" means git sees no change between the two commits in the
|
|
17
|
+
* component's own file, the member's `chant.config.ts` and the paths its
|
|
18
|
+
* build steps read.
|
|
19
|
+
*
|
|
20
|
+
* A project with no components (#4046) needs no special case here: its
|
|
21
|
+
* targets hold the files `chant build --env <env>` writes, each with
|
|
22
|
+
* `component: null`, and `artifactDigests` is empty.
|
|
23
|
+
*
|
|
24
|
+
* Compiling goes through a {@link TargetCompiler}, so a test hands the cut
|
|
25
|
+
* fixtures and the CLI hands it child processes.
|
|
26
|
+
*
|
|
27
|
+
* Who may cut (#4031): when the declaration at base names a `release` gate
|
|
28
|
+
* in `identity.gates`, a cut must be signed (`--sign`), its signature must
|
|
29
|
+
* verify for the actor against the signers at base, and when the gate names
|
|
30
|
+
* a class the actor must be in it. A cut signed without that gate is signed
|
|
31
|
+
* all the same, and readers report whether the signature verifies. With
|
|
32
|
+
* `ci.green.signedSince` declared, a green tag counts only with a valid
|
|
33
|
+
* statement (`../workspace/ci-green.ts`), so a hand-pushed tag cuts nothing.
|
|
34
|
+
*/
|
|
35
|
+
import { execFileSync } from "node:child_process";
|
|
36
|
+
import { realpathSync } from "node:fs";
|
|
37
|
+
import { relative, resolve } from "node:path";
|
|
38
|
+
import { canonicalJson } from "../effect-receipt.js";
|
|
39
|
+
import { contentDigest } from "../content-digest.js";
|
|
40
|
+
import { getHeadCommit } from "./git.js";
|
|
41
|
+
import { resolveMemberLedger } from "./member-ledger.js";
|
|
42
|
+
import { resolveCiRun } from "./release-ledger.js";
|
|
43
|
+
import { appendCut, makeRelease, persistRelease, readAllReleases, readCuts, } from "./release-store.js";
|
|
44
|
+
export class ReleaseCutError extends Error {
|
|
45
|
+
constructor(code, message, fix) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.fix = fix;
|
|
49
|
+
this.name = "ReleaseCutError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function git(top, args) {
|
|
53
|
+
return execFileSync("git", args, { cwd: top, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
54
|
+
}
|
|
55
|
+
function tryGit(top, args) {
|
|
56
|
+
try {
|
|
57
|
+
return git(top, args);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Whether `sha` has a green tag and no revoked tag, read from local tags,
|
|
65
|
+
* and the tags on it that were ignored for want of a valid statement
|
|
66
|
+
* (#4031). The tags are judged by `green`, the declaration's `ci.green` at
|
|
67
|
+
* base, with the runner keys read at its branch's tip; with no `ci.green`,
|
|
68
|
+
* every tag counts.
|
|
69
|
+
*/
|
|
70
|
+
export async function greenState(top, sha, green = null) {
|
|
71
|
+
const { readCiTags } = await import("../workspace/ci-green.js");
|
|
72
|
+
const base = green
|
|
73
|
+
? (tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${green.branch}^{commit}`]) ??
|
|
74
|
+
tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/heads/${green.branch}^{commit}`]) ??
|
|
75
|
+
tryGit(top, ["rev-parse", "HEAD"]))
|
|
76
|
+
: null;
|
|
77
|
+
let tags;
|
|
78
|
+
try {
|
|
79
|
+
tags = readCiTags(top, green, base);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const { WorkspaceReadError } = await import("../workspace/declaration.js");
|
|
83
|
+
if (err instanceof WorkspaceReadError)
|
|
84
|
+
throw new ReleaseCutError("declaration-invalid", err.message);
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
const ignored = tags.ignored.get(sha) ?? [];
|
|
88
|
+
if (tags.revoked.has(sha))
|
|
89
|
+
return { state: "revoked", ignored };
|
|
90
|
+
return { state: tags.green.has(sha) ? "green" : "none", ignored };
|
|
91
|
+
}
|
|
92
|
+
/** Which components' build steps differ between environments, with the environments they appear in. */
|
|
93
|
+
export function differingBuildSteps(targets) {
|
|
94
|
+
const byComponent = new Map();
|
|
95
|
+
for (const t of targets) {
|
|
96
|
+
for (const [component, steps] of Object.entries(t.buildSteps)) {
|
|
97
|
+
if (!byComponent.has(component))
|
|
98
|
+
byComponent.set(component, new Map());
|
|
99
|
+
byComponent.get(component).set(t.env, canonicalJson(steps));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const [component, perEnv] of byComponent) {
|
|
104
|
+
if (new Set(perEnv.values()).size > 1)
|
|
105
|
+
out.push({ component, envs: [...perEnv.keys()] });
|
|
106
|
+
}
|
|
107
|
+
return out.sort((a, b) => (a.component < b.component ? -1 : 1));
|
|
108
|
+
}
|
|
109
|
+
/** The earlier release of this member cut from the nearest ancestor of `commit`. */
|
|
110
|
+
async function previousRelease(top, commit, cwd) {
|
|
111
|
+
const { releases } = await readAllReleases({ cwd });
|
|
112
|
+
const { cuts } = await readCuts({ cwd });
|
|
113
|
+
const cutAt = new Map();
|
|
114
|
+
for (const c of cuts)
|
|
115
|
+
if (!cutAt.has(c.releaseDigest) || c.timestamp > cutAt.get(c.releaseDigest))
|
|
116
|
+
cutAt.set(c.releaseDigest, c.timestamp);
|
|
117
|
+
const candidates = releases
|
|
118
|
+
.filter((r) => cutAt.has(r.releaseDigest) && r.commit !== commit)
|
|
119
|
+
.filter((r) => tryGit(top, ["merge-base", "--is-ancestor", r.commit, commit]) !== null)
|
|
120
|
+
.map((r) => ({ r, depth: Number(tryGit(top, ["rev-list", "--count", r.commit]) ?? 0), at: cutAt.get(r.releaseDigest) }))
|
|
121
|
+
// The nearest ancestor first, then the newest cut of it.
|
|
122
|
+
.sort((a, b) => b.depth - a.depth || (b.at < a.at ? -1 : b.at > a.at ? 1 : 0));
|
|
123
|
+
return candidates[0]?.r;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Cut a release of the member at `req.cwd` from its checkout's `HEAD`. Writes
|
|
127
|
+
* the release and the cut to the local `chant/lifecycle` branch and does not
|
|
128
|
+
* push. Throws {@link ReleaseCutError} before anything is written when the
|
|
129
|
+
* commit isn't green, the tree is dirty, or an environment can't be compiled
|
|
130
|
+
* to the same artifacts, and `ReleaseLabelError` (./release-store.ts) when the
|
|
131
|
+
* label is taken or the release already carries another one.
|
|
132
|
+
*/
|
|
133
|
+
export async function cutRelease(req) {
|
|
134
|
+
const cwd = resolve(req.cwd);
|
|
135
|
+
const top = tryGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
136
|
+
if (!top)
|
|
137
|
+
throw new ReleaseCutError("not-a-git-repository", "a release is cut from a commit, and this directory is not in a git repository");
|
|
138
|
+
const commit = await getHeadCommit({ cwd });
|
|
139
|
+
// #4031: the declaration at base says whether tags need a statement and who may cut.
|
|
140
|
+
const { scopeSource } = await import("../workspace/write-scope.js");
|
|
141
|
+
const { releaseRuleFrom } = await import("../workspace/identity.js");
|
|
142
|
+
const source = scopeSource(cwd);
|
|
143
|
+
const { state, ignored } = await greenState(top, commit, source.declaration?.ci?.green ?? null);
|
|
144
|
+
if (state !== "green") {
|
|
145
|
+
const why = ignored.length > 0 ? `; ignored: ${ignored.map((t) => `${t.tag} (${t.status}): ${t.reason}`).join("; ")}` : "";
|
|
146
|
+
throw new ReleaseCutError(state === "revoked" ? "release-commit-revoked" : "release-commit-not-green", state === "revoked"
|
|
147
|
+
? `commit ${commit.slice(0, 12)} has a ci/revoked tag: it went red after it was green, so no release is cut from it`
|
|
148
|
+
: ignored.some((t) => t.tag.startsWith("ci/green/"))
|
|
149
|
+
? `commit ${commit.slice(0, 12)} has no ci/green tag that counts, so no release is cut from it${why}`
|
|
150
|
+
: `commit ${commit.slice(0, 12)} has no ci/green tag, so no release is cut from it`, "Check out a green commit (`chant ci last-green` names the newest) after fetching the tags: git fetch origin --tags");
|
|
151
|
+
}
|
|
152
|
+
// Who may cut is the declaration's identity.gates.release, read at base.
|
|
153
|
+
const releaseRule = releaseRuleFrom(source);
|
|
154
|
+
if (releaseRule.requirement && req.sign === undefined) {
|
|
155
|
+
throw new ReleaseCutError("release-unsigned", `chant.workspace.json at base names a release gate in identity.gates${releaseRule.requirement.class !== null ? `, from the class ${releaseRule.requirement.class}` : ""}, and this cut is not signed`, `chant release cut <label> --actor <principal> --sign [<key file>], with a key ${releaseRule.rule.signers.signersPath} at base lists for that principal.`);
|
|
156
|
+
}
|
|
157
|
+
const dirty = tryGit(top, ["status", "--porcelain", "--untracked-files=no"]);
|
|
158
|
+
if (dirty) {
|
|
159
|
+
throw new ReleaseCutError("release-worktree-dirty", `the working tree has uncommitted changes to tracked files, so a compile here would not be commit ${commit.slice(0, 12)}'s`, "Commit or stash them, or cut from a clean checkout of the commit.");
|
|
160
|
+
}
|
|
161
|
+
let envs = req.environments;
|
|
162
|
+
if (!envs) {
|
|
163
|
+
const { readMemberPromotionOrder } = await import("../workspace/promotion-order.js");
|
|
164
|
+
envs = ((await readMemberPromotionOrder(cwd)) ?? []).map((s) => s.name);
|
|
165
|
+
}
|
|
166
|
+
if (envs.length === 0) {
|
|
167
|
+
throw new ReleaseCutError("release-no-environments", "this member's chant.config.ts declares no environments, so there is nothing to compile a release for", "Declare them in promotion order: environments: [\"dev\", \"staging\", \"prod\"]");
|
|
168
|
+
}
|
|
169
|
+
const compiled = [];
|
|
170
|
+
for (const env of envs)
|
|
171
|
+
compiled.push(await req.compiler.compile(env));
|
|
172
|
+
// A project with no components compiles to its build output (#4046), so only a target with neither is empty.
|
|
173
|
+
if (compiled.every((t) => t.components.length === 0 && t.templates.length === 0)) {
|
|
174
|
+
throw new ReleaseCutError("release-no-components", "no component is enabled in any environment and nothing was compiled, so there is nothing to release", "Enable a component under one environment's parameters, or remove the component files so the project's build output is released.");
|
|
175
|
+
}
|
|
176
|
+
const differing = differingBuildSteps(compiled);
|
|
177
|
+
if (differing.length > 0) {
|
|
178
|
+
throw new ReleaseCutError("release-build-inputs-differ", `the build steps of ${differing.map((d) => `"${d.component}"`).join(", ")} differ between environments (${[...new Set(differing.flatMap((d) => d.envs))].join(", ")}), ` +
|
|
179
|
+
"so their artifacts can't be built once for every environment", "Make the build steps read no environment-specific value; pass the value to a deploy step instead.");
|
|
180
|
+
}
|
|
181
|
+
// Which environment each component's artifacts are built in: the first one it is enabled in.
|
|
182
|
+
const firstEnv = new Map();
|
|
183
|
+
for (const t of compiled)
|
|
184
|
+
for (const c of t.components)
|
|
185
|
+
if (!firstEnv.has(c) && (t.buildSteps[c]?.length ?? 0) > 0)
|
|
186
|
+
firstEnv.set(c, t);
|
|
187
|
+
// git names paths from its top with symlinks resolved (/private/var on macOS).
|
|
188
|
+
const realCwd = realpathSync(cwd);
|
|
189
|
+
const previous = firstEnv.size > 0 ? await previousRelease(top, commit, cwd) : undefined;
|
|
190
|
+
const reused = [];
|
|
191
|
+
const artifacts = [];
|
|
192
|
+
const toBuild = new Map();
|
|
193
|
+
for (const [component, target] of firstEnv) {
|
|
194
|
+
const prior = previous?.artifactDigests.filter((a) => a.component === component) ?? [];
|
|
195
|
+
if (previous && prior.length > 0) {
|
|
196
|
+
const paths = [target.componentFiles[component], "chant.config.ts", ...(target.buildInputs[component] ?? [])]
|
|
197
|
+
.filter((p) => typeof p === "string")
|
|
198
|
+
.map((p) => relative(top, resolve(realCwd, p)))
|
|
199
|
+
.filter((p) => p !== "" && !p.startsWith(".."));
|
|
200
|
+
// With no path to compare, the source can't be shown unchanged, so it is built.
|
|
201
|
+
const changed = paths.length === 0 ? null : tryGit(top, ["diff", "--name-only", previous.commit, commit, "--", ...paths]);
|
|
202
|
+
if (changed === "") {
|
|
203
|
+
artifacts.push(...prior);
|
|
204
|
+
reused.push({ component, from: previous.releaseDigest });
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
toBuild.set(target.env, [...(toBuild.get(target.env) ?? []), component]);
|
|
209
|
+
}
|
|
210
|
+
for (const env of envs) {
|
|
211
|
+
const names = toBuild.get(env);
|
|
212
|
+
if (names)
|
|
213
|
+
artifacts.push(...(await req.compiler.buildArtifacts(env, names)));
|
|
214
|
+
}
|
|
215
|
+
const templates = [];
|
|
216
|
+
const targets = compiled.map((t) => ({
|
|
217
|
+
env: t.env,
|
|
218
|
+
params: t.params,
|
|
219
|
+
templates: t.templates.map((tpl) => {
|
|
220
|
+
const digest = contentDigest(tpl.content);
|
|
221
|
+
templates.push({ digest, content: tpl.content });
|
|
222
|
+
return { component: tpl.component, path: tpl.path, digest };
|
|
223
|
+
}),
|
|
224
|
+
}));
|
|
225
|
+
const ledger = await resolveMemberLedger(cwd);
|
|
226
|
+
const release = makeRelease({ member: ledger.members.length > 0 ? ledger.members.join("/") : null, commit, artifactDigests: artifacts, targets });
|
|
227
|
+
const timestamp = (req.now ?? (() => new Date()))().toISOString();
|
|
228
|
+
const signed = { releaseDigest: release.releaseDigest, label: req.label, actor: req.actor, timestamp };
|
|
229
|
+
let signature = null;
|
|
230
|
+
if (req.sign !== undefined) {
|
|
231
|
+
const { resolveSigningKey, sealReleaseCut, SealError } = await import("../workspace/trust/seal.js");
|
|
232
|
+
try {
|
|
233
|
+
const key = resolveSigningKey(req.sign, cwd);
|
|
234
|
+
try {
|
|
235
|
+
signature = sealReleaseCut(key.file, signed).signature;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
key.cleanup();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
if (!(err instanceof SealError))
|
|
243
|
+
throw err;
|
|
244
|
+
throw new ReleaseCutError("release-signer-refused", `no release was cut: ${err.message}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (releaseRule.requirement) {
|
|
248
|
+
const { admitReleaseCut } = await import("../workspace/identity-gate-rule.js");
|
|
249
|
+
const why = admitReleaseCut(releaseRule.rule, { ...signed, signature });
|
|
250
|
+
if (why !== null) {
|
|
251
|
+
throw new ReleaseCutError("release-signer-refused", `no release was cut: ${why}`, `identity.gates.release in chant.workspace.json at base counts only a cut signed by a key ${releaseRule.rule.signers.signersPath} lists for the actor` +
|
|
252
|
+
(releaseRule.requirement.class !== null ? `, who holds the role of the class ${releaseRule.requirement.class}` : "") +
|
|
253
|
+
". Pass --actor <principal> naming that signer.");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const stored = await persistRelease(release, templates, { cwd });
|
|
257
|
+
const ci = resolveCiRun(req.env ?? process.env);
|
|
258
|
+
const outcome = await appendCut({
|
|
259
|
+
releaseDigest: release.releaseDigest,
|
|
260
|
+
label: req.label,
|
|
261
|
+
actor: req.actor,
|
|
262
|
+
timestamp,
|
|
263
|
+
runOrigin: ci?.runOrigin ?? null,
|
|
264
|
+
signature,
|
|
265
|
+
}, { cwd });
|
|
266
|
+
return {
|
|
267
|
+
release,
|
|
268
|
+
cut: outcome.appended ? outcome.cut : null,
|
|
269
|
+
label: outcome.appended ? outcome.cut.label : outcome.label,
|
|
270
|
+
stored: stored.written,
|
|
271
|
+
reused,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { type LegacyDigestFlag } from "./legacy-digest.js";
|
|
31
31
|
import { type LedgerLocation } from "./git.js";
|
|
32
|
+
import type { GateResolutionRecord } from "./gate-ledger.js";
|
|
32
33
|
export { validateReleaseRecord, parseReleaseLedger, releaseLedgerLines, readReleaseRecords, listReleaseEnvironmentsOn } from "./release-read.js";
|
|
33
34
|
export type { LedgerReadPort } from "./ledger-port.js";
|
|
34
35
|
/**
|
|
@@ -49,6 +50,35 @@ export interface RunOrigin {
|
|
|
49
50
|
/** Resolved link to the run, when the environment provided enough to build one. */
|
|
50
51
|
url?: string;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The gate resolution that admitted a deploy (#4020): the gate's address in the
|
|
55
|
+
* gate ledger (`_gates/<op>.jsonl`, `op` and `gate`) and when the resolution
|
|
56
|
+
* was recorded. With `approver` on the same record it names the line a reader
|
|
57
|
+
* opens to see what was approved. Chant 0.124.28 and newer write it.
|
|
58
|
+
*/
|
|
59
|
+
export interface ReleaseAdmission {
|
|
60
|
+
/** The op, or for a component gate the component, whose gate ledger holds the resolution. */
|
|
61
|
+
op: string;
|
|
62
|
+
/** The gate's name. */
|
|
63
|
+
gate: string;
|
|
64
|
+
/** ISO-8601 time the resolution was recorded (`GateResolutionRecord.timestamp`). When several approvals counted, the newest one. */
|
|
65
|
+
resolvedAt: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The approver and admission a release records for the resolutions of its gate
|
|
69
|
+
* (#4020): those of `gate` on `op` bound to `planDigest`. The approver is the
|
|
70
|
+
* distinct `resolvedBy` names, comma joined, as `approver` has always been
|
|
71
|
+
* written by the release activities; `resolvedAt` is the newest one's time.
|
|
72
|
+
* Undefined when no resolution is bound to the plan.
|
|
73
|
+
*/
|
|
74
|
+
export declare function admissionOf(resolutions: readonly GateResolutionRecord[], at: {
|
|
75
|
+
op: string;
|
|
76
|
+
gate: string;
|
|
77
|
+
planDigest?: string;
|
|
78
|
+
}): {
|
|
79
|
+
approver: string;
|
|
80
|
+
admission: ReleaseAdmission;
|
|
81
|
+
} | undefined;
|
|
52
82
|
/**
|
|
53
83
|
* Points at one earlier release record (#2530, #2531, #2604). A record has no id of its own,
|
|
54
84
|
* so it is named by the environment whose ledger holds it plus the run id and
|
|
@@ -118,6 +148,13 @@ export interface ReleaseRecord {
|
|
|
118
148
|
* the one who triggered the deploy (separation of duties).
|
|
119
149
|
*/
|
|
120
150
|
approver?: string;
|
|
151
|
+
/**
|
|
152
|
+
* The gate resolution that admitted this deploy (#4020), for a gated change:
|
|
153
|
+
* which gate (`op` and `gate`) and when it was resolved. The approver is
|
|
154
|
+
* `approver`. Optional and omitted for an ungated change and for a record
|
|
155
|
+
* written before 0.124.28, whose gate cannot be recovered from the record.
|
|
156
|
+
*/
|
|
157
|
+
admission?: ReleaseAdmission;
|
|
121
158
|
/** Optional: the archive's own manifest digest (../components/verbs/build-archive.ts's `manifestDigest`), when the caller has it — lets a reader recover full build contents/provenance, not just the promoted image digest. */
|
|
122
159
|
manifestDigest?: string;
|
|
123
160
|
/**
|
|
@@ -167,6 +204,13 @@ export interface ReleaseRecord {
|
|
|
167
204
|
* partway. Absent on every other record.
|
|
168
205
|
*/
|
|
169
206
|
redeploys?: ReleaseRef;
|
|
207
|
+
/**
|
|
208
|
+
* Optional: the release this deploy came from (#4026, ws-104), the
|
|
209
|
+
* `releaseDigest` of `_releases/<releaseDigest>.json`. Written by
|
|
210
|
+
* `chant components promote --release` since 0.124.28. Absent on every
|
|
211
|
+
* deploy that was not made from a release.
|
|
212
|
+
*/
|
|
213
|
+
releaseDigest?: string;
|
|
170
214
|
}
|
|
171
215
|
/** Thrown by `appendReleaseRecord` when the record is missing a required field — a release record can never be recorded partially, since it is never editable afterward. */
|
|
172
216
|
export declare class InvalidReleaseRecordError extends Error {
|
|
@@ -200,6 +244,16 @@ export declare function resolveRunId(explicit?: string, env?: NodeJS.ProcessEnv)
|
|
|
200
244
|
runId: string;
|
|
201
245
|
runOrigin?: RunOrigin;
|
|
202
246
|
};
|
|
247
|
+
/**
|
|
248
|
+
* The CI run the environment names, with the origin that locates it, or
|
|
249
|
+
* undefined outside CI (#4020). `resolveRunId` takes its CI branches from
|
|
250
|
+
* here, and an Op run record takes its `runOrigin` from here, so a run and the
|
|
251
|
+
* deploy it made name the run the same way.
|
|
252
|
+
*/
|
|
253
|
+
export declare function resolveCiRun(env?: NodeJS.ProcessEnv): {
|
|
254
|
+
runId: string;
|
|
255
|
+
runOrigin: RunOrigin;
|
|
256
|
+
} | undefined;
|
|
203
257
|
/**
|
|
204
258
|
* Append one immutable release record to the `<env>` ledger on the
|
|
205
259
|
* `chant/lifecycle` orphan branch. Throws `InvalidReleaseRecordError` before
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/release-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/F,OAAO,EAAwG,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"release-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/release-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,22 @@ import { appendReleaseRecordLine, readReleaseLedgerLines, listLedgerEnvironments
|
|
|
33
33
|
import { parseReleaseLedger, validateReleaseRecord } from "./release-read.js";
|
|
34
34
|
// The pure readers live apart, so a bundle can import them without git (#3865).
|
|
35
35
|
export { validateReleaseRecord, parseReleaseLedger, releaseLedgerLines, readReleaseRecords, listReleaseEnvironmentsOn } from "./release-read.js";
|
|
36
|
+
/**
|
|
37
|
+
* The approver and admission a release records for the resolutions of its gate
|
|
38
|
+
* (#4020): those of `gate` on `op` bound to `planDigest`. The approver is the
|
|
39
|
+
* distinct `resolvedBy` names, comma joined, as `approver` has always been
|
|
40
|
+
* written by the release activities; `resolvedAt` is the newest one's time.
|
|
41
|
+
* Undefined when no resolution is bound to the plan.
|
|
42
|
+
*/
|
|
43
|
+
export function admissionOf(resolutions, at) {
|
|
44
|
+
const bound = resolutions.filter((r) => r.gate === at.gate && r.planDigest === at.planDigest);
|
|
45
|
+
if (bound.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
return {
|
|
48
|
+
approver: [...new Set(bound.map((r) => r.resolvedBy))].join(", "),
|
|
49
|
+
admission: { op: at.op, gate: at.gate, resolvedAt: bound.map((r) => r.timestamp).sort().at(-1) },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
36
52
|
/** Thrown by `appendReleaseRecord` when the record is missing a required field — a release record can never be recorded partially, since it is never editable afterward. */
|
|
37
53
|
export class InvalidReleaseRecordError extends Error {
|
|
38
54
|
constructor(missing) {
|
|
@@ -63,31 +79,48 @@ export class InvalidReleaseRecordError extends Error {
|
|
|
63
79
|
* remove.
|
|
64
80
|
*/
|
|
65
81
|
export function resolveRunId(explicit, env = process.env) {
|
|
66
|
-
const
|
|
67
|
-
forge: "github",
|
|
68
|
-
...(env.GITHUB_REPOSITORY ? { repo: env.GITHUB_REPOSITORY } : {}),
|
|
69
|
-
...(env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY
|
|
70
|
-
? { url: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${id}` }
|
|
71
|
-
: {}),
|
|
72
|
-
});
|
|
73
|
-
const gitlabOrigin = () => ({
|
|
74
|
-
forge: "gitlab",
|
|
75
|
-
...(env.CI_PROJECT_PATH ? { repo: env.CI_PROJECT_PATH } : {}),
|
|
76
|
-
...(env.CI_PIPELINE_URL ? { url: env.CI_PIPELINE_URL } : {}),
|
|
77
|
-
});
|
|
82
|
+
const ci = resolveCiRun(env);
|
|
78
83
|
if (explicit) {
|
|
79
|
-
if (
|
|
80
|
-
return
|
|
81
|
-
if (env.CI_PIPELINE_ID && explicit === env.CI_PIPELINE_ID)
|
|
82
|
-
return { runId: explicit, runOrigin: gitlabOrigin() };
|
|
84
|
+
if (ci && explicit === ci.runId)
|
|
85
|
+
return ci;
|
|
83
86
|
return { runId: explicit };
|
|
84
87
|
}
|
|
85
|
-
if (
|
|
86
|
-
return
|
|
87
|
-
if (env.CI_PIPELINE_ID)
|
|
88
|
-
return { runId: env.CI_PIPELINE_ID, runOrigin: gitlabOrigin() };
|
|
88
|
+
if (ci)
|
|
89
|
+
return ci;
|
|
89
90
|
return { runId: `local-${Date.now()}`, runOrigin: { forge: "local" } };
|
|
90
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* The CI run the environment names, with the origin that locates it, or
|
|
94
|
+
* undefined outside CI (#4020). `resolveRunId` takes its CI branches from
|
|
95
|
+
* here, and an Op run record takes its `runOrigin` from here, so a run and the
|
|
96
|
+
* deploy it made name the run the same way.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveCiRun(env = process.env) {
|
|
99
|
+
if (env.GITHUB_RUN_ID) {
|
|
100
|
+
const id = env.GITHUB_RUN_ID;
|
|
101
|
+
return {
|
|
102
|
+
runId: id,
|
|
103
|
+
runOrigin: {
|
|
104
|
+
forge: "github",
|
|
105
|
+
...(env.GITHUB_REPOSITORY ? { repo: env.GITHUB_REPOSITORY } : {}),
|
|
106
|
+
...(env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY
|
|
107
|
+
? { url: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${id}` }
|
|
108
|
+
: {}),
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (env.CI_PIPELINE_ID) {
|
|
113
|
+
return {
|
|
114
|
+
runId: env.CI_PIPELINE_ID,
|
|
115
|
+
runOrigin: {
|
|
116
|
+
forge: "gitlab",
|
|
117
|
+
...(env.CI_PROJECT_PATH ? { repo: env.CI_PROJECT_PATH } : {}),
|
|
118
|
+
...(env.CI_PIPELINE_URL ? { url: env.CI_PIPELINE_URL } : {}),
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
91
124
|
/**
|
|
92
125
|
* Append one immutable release record to the `<env>` ledger on the
|
|
93
126
|
* `chant/lifecycle` orphan branch. Throws `InvalidReleaseRecordError` before
|