@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,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each component of a fan-out would apply, as one digest per component
|
|
3
|
+
* (#4081), and which of an earlier attempt's progress still holds against it.
|
|
4
|
+
*
|
|
5
|
+
* A fan-out's plan digest identifies the derivation: who runs, in what order,
|
|
6
|
+
* off which edges. Two different changes that touch the same components in
|
|
7
|
+
* the same shape derive the same plan, so the plan digest alone cannot say
|
|
8
|
+
* whether "cluster-a already applied" is about the change in front of us.
|
|
9
|
+
* The attempt record therefore keeps, for each component it applied, the
|
|
10
|
+
* input digest computed here, and a resumed attempt carries a component as
|
|
11
|
+
* `already-applied` only when that digest is the one the component has now.
|
|
12
|
+
*
|
|
13
|
+
* ## What a component's input digest covers
|
|
14
|
+
*
|
|
15
|
+
* - The environment. Progress against `local` says nothing about `prod`.
|
|
16
|
+
* - The composition: every phase and step as authored, `rollback` included.
|
|
17
|
+
* A `stackOutput` reference is hashed as the reference, not its value.
|
|
18
|
+
* - The bytes of every file a step input names. A string input that resolves,
|
|
19
|
+
* relative to the project root, to a file or directory inside the root is
|
|
20
|
+
* read and hashed, so `template: "dist/cluster-a.template.json"` covers the
|
|
21
|
+
* built template and a rebuild that changes it changes the digest. A
|
|
22
|
+
* directory is hashed by its files, skipping `.git`, `node_modules` and
|
|
23
|
+
* `.chant`, the last because the attempt record itself lives there.
|
|
24
|
+
* - The input digests of the components it depends on. A parameter filled
|
|
25
|
+
* from an upstream output gets its value from that upstream's apply, so a
|
|
26
|
+
* change upstream changes the digest of everything downstream of it, the
|
|
27
|
+
* same reach the fan-out's own walk has.
|
|
28
|
+
*
|
|
29
|
+
* Nothing decided during the run goes in: no run id, no time, no output an
|
|
30
|
+
* apply produced.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
34
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
35
|
+
import { computePlanDigest } from "../lifecycle/plan-digest";
|
|
36
|
+
import { sha256Hex } from "../content-digest";
|
|
37
|
+
import type { DriverComponent, DriverPhase } from "./driver";
|
|
38
|
+
|
|
39
|
+
export interface ComponentInputOptions {
|
|
40
|
+
/** The root step inputs' file paths are read relative to, the project the fan-out runs in. */
|
|
41
|
+
projectRoot: string;
|
|
42
|
+
/** The environment the fan-out applies to. */
|
|
43
|
+
env: string;
|
|
44
|
+
/** Environment config resolved ahead of the run, when the caller has any. */
|
|
45
|
+
vars?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const SKIPPED_DIRS = new Set([".git", "node_modules", ".chant"]);
|
|
49
|
+
|
|
50
|
+
/** Inside `root`, and not `root` itself: a bare "." names the whole project, which is no one step's input. */
|
|
51
|
+
function insideRoot(root: string, path: string): boolean {
|
|
52
|
+
const rel = relative(root, path);
|
|
53
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Hash a file, or a directory by the relative path and bytes of each file under it. */
|
|
57
|
+
function hashPath(path: string): string | undefined {
|
|
58
|
+
let stat;
|
|
59
|
+
try {
|
|
60
|
+
stat = statSync(path);
|
|
61
|
+
} catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (stat.isFile()) return `sha256:${sha256Hex(readFileSync(path))}`;
|
|
65
|
+
if (!stat.isDirectory()) return undefined;
|
|
66
|
+
const files: Record<string, string> = {};
|
|
67
|
+
const walk = (dir: string): void => {
|
|
68
|
+
for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
69
|
+
if (SKIPPED_DIRS.has(entry.name)) continue;
|
|
70
|
+
const full = join(dir, entry.name);
|
|
71
|
+
if (entry.isDirectory()) walk(full);
|
|
72
|
+
else if (entry.isFile()) files[relative(path, full).split(sep).join("/")] = sha256Hex(readFileSync(full));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
walk(path);
|
|
76
|
+
return computePlanDigest("component-input-dir", files);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Every file or directory a component's steps name, keyed by the string the step wrote. */
|
|
80
|
+
function referencedFiles(component: DriverComponent, root: string): Record<string, string> {
|
|
81
|
+
const out: Record<string, string> = {};
|
|
82
|
+
const visit = (value: unknown): void => {
|
|
83
|
+
if (typeof value === "string") {
|
|
84
|
+
if (value === "" || value.includes("\n") || value in out) return;
|
|
85
|
+
const path = resolve(root, value);
|
|
86
|
+
if (!insideRoot(root, path) || !existsSync(path)) return;
|
|
87
|
+
const digest = hashPath(path);
|
|
88
|
+
if (digest !== undefined) out[value] = digest;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(value)) value.forEach(visit);
|
|
92
|
+
else if (value && typeof value === "object") Object.values(value).forEach(visit);
|
|
93
|
+
};
|
|
94
|
+
// Only a step's inputs name files. A phase name or a step's `kind` that
|
|
95
|
+
// happens to match a directory in the project is not one.
|
|
96
|
+
const visitPhases = (phases: DriverPhase[] | undefined): void => {
|
|
97
|
+
for (const phase of phases ?? []) {
|
|
98
|
+
for (const step of phase.steps) {
|
|
99
|
+
if (isPhase(step)) {
|
|
100
|
+
visitPhases([step]);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (step.kind === "gate") continue;
|
|
104
|
+
const { kind: _kind, ...inputs } = step;
|
|
105
|
+
visit(inputs);
|
|
106
|
+
}
|
|
107
|
+
visitPhases(phase.onFailure);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
visitPhases(component.deploy);
|
|
111
|
+
visitPhases(component.rollback);
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isPhase(step: DriverPhase["steps"][number]): step is DriverPhase {
|
|
116
|
+
return typeof (step as { phase?: unknown }).phase === "string" && Array.isArray((step as DriverPhase).steps);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* One input digest per component in `components`, keyed by name. Each folds
|
|
121
|
+
* in the digests of the components it depends on, so `components` should be
|
|
122
|
+
* the whole project: a dependency it does not contain is hashed by name only.
|
|
123
|
+
*/
|
|
124
|
+
export function componentInputDigests(
|
|
125
|
+
components: DriverComponent[],
|
|
126
|
+
options: ComponentInputOptions,
|
|
127
|
+
): Record<string, string> {
|
|
128
|
+
const root = resolve(options.projectRoot);
|
|
129
|
+
const byName = new Map(components.map((c) => [c.name, c]));
|
|
130
|
+
const digests = new Map<string, string>();
|
|
131
|
+
const visiting = new Set<string>();
|
|
132
|
+
|
|
133
|
+
const digestOf = (name: string): string | null => {
|
|
134
|
+
const known = digests.get(name);
|
|
135
|
+
if (known !== undefined) return known;
|
|
136
|
+
const component = byName.get(name);
|
|
137
|
+
// An unknown dependency or a cycle is refused by the fan-out's derivation
|
|
138
|
+
// before this runs; here it only has to not loop.
|
|
139
|
+
if (!component || visiting.has(name)) return null;
|
|
140
|
+
visiting.add(name);
|
|
141
|
+
const upstream = [...(component.dependsOn ?? [])].sort().map((dep) => ({ component: dep, digest: digestOf(dep) }));
|
|
142
|
+
visiting.delete(name);
|
|
143
|
+
const digest = computePlanDigest("component-input", {
|
|
144
|
+
environment: options.env,
|
|
145
|
+
component: name,
|
|
146
|
+
deploy: component.deploy,
|
|
147
|
+
rollback: component.rollback ?? null,
|
|
148
|
+
vars: options.vars ?? null,
|
|
149
|
+
files: referencedFiles(component, root),
|
|
150
|
+
upstream,
|
|
151
|
+
});
|
|
152
|
+
digests.set(name, digest);
|
|
153
|
+
return digest;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
for (const c of components) digestOf(c.name);
|
|
157
|
+
return Object.fromEntries([...digests.entries()].sort(([a], [b]) => a.localeCompare(b)));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** What of an earlier attempt's progress holds against the inputs the components have now. */
|
|
161
|
+
export interface CarriedProgress {
|
|
162
|
+
/** Components the attempt applied whose input is the same now. These stay `already-applied`. */
|
|
163
|
+
carried: string[];
|
|
164
|
+
/** Components the attempt applied whose input moved since. These run again. */
|
|
165
|
+
changed: string[];
|
|
166
|
+
/**
|
|
167
|
+
* True when the record has no input digests at all, as one written before
|
|
168
|
+
* #4081 has. Nothing carries from such a record, since nothing in it says
|
|
169
|
+
* what was applied.
|
|
170
|
+
*/
|
|
171
|
+
unrecorded: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Split an attempt's `completed` by whether each component's input is the
|
|
176
|
+
* same as now. A component the record holds no digest for counts as changed:
|
|
177
|
+
* a claim that it applied is only worth keeping for the input it applied.
|
|
178
|
+
*/
|
|
179
|
+
export function progressThatCarries(
|
|
180
|
+
attempt: { completed: string[]; inputs?: Record<string, string> },
|
|
181
|
+
now: Record<string, string>,
|
|
182
|
+
): CarriedProgress {
|
|
183
|
+
const recorded = attempt.inputs;
|
|
184
|
+
const carried: string[] = [];
|
|
185
|
+
const changed: string[] = [];
|
|
186
|
+
for (const name of [...attempt.completed].sort()) {
|
|
187
|
+
const then = recorded?.[name];
|
|
188
|
+
if (then !== undefined && now[name] !== undefined && then === now[name]) carried.push(name);
|
|
189
|
+
else changed.push(name);
|
|
190
|
+
}
|
|
191
|
+
return { carried, changed, unrecorded: recorded === undefined };
|
|
192
|
+
}
|
|
@@ -70,3 +70,13 @@ describe("prApply (#3464)", () => {
|
|
|
70
70
|
for (const name of ["a.json", "b.json", "c.json"]) expect(readFanOutAttempt(join(dir, name))?.prApply).toBeUndefined();
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
|
+
|
|
74
|
+
describe("inputs (#4081)", () => {
|
|
75
|
+
test("round-trips, and a record without them reads as none", () => {
|
|
76
|
+
const dir = mkdtempSync(join(tmpdir(), "fan-out-record-"));
|
|
77
|
+
writeFanOutAttempt(join(dir, "a.json"), { digest: "d", completed: ["net"], failed: [], outputs: {}, inputs: { net: "jcs1-sha256:x" } });
|
|
78
|
+
expect(readFanOutAttempt(join(dir, "a.json"))?.inputs).toEqual({ net: "jcs1-sha256:x" });
|
|
79
|
+
writeFileSync(join(dir, "b.json"), JSON.stringify({ digest: "d", completed: ["net"], failed: [], outputs: {} }));
|
|
80
|
+
expect(readFanOutAttempt(join(dir, "b.json"))?.inputs).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
* `carried` holds what a step asked to keep for its member (#3459). It rides
|
|
26
26
|
* in the record rather than beside it because the record is the one file a
|
|
27
27
|
* per-wave CI job hands to the next.
|
|
28
|
+
*
|
|
29
|
+
* `inputs` holds, for each component in `completed`, the input digest it
|
|
30
|
+
* applied (#4081, ./fan-out-inputs.ts). The plan digest only identifies the
|
|
31
|
+
* derivation, and two different changes with the same shape derive the same
|
|
32
|
+
* one, so the digest alone would carry "cluster-a already applied" into a
|
|
33
|
+
* change that never applied it. A resumed attempt carries a component only
|
|
34
|
+
* when its input digest is the same now. A record written before #4081 has
|
|
35
|
+
* no `inputs`, and none of its progress carries.
|
|
28
36
|
*/
|
|
29
37
|
|
|
30
38
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -68,6 +76,11 @@ export interface FanOutAttempt {
|
|
|
68
76
|
carried?: Record<string, unknown>;
|
|
69
77
|
/** A pull request's apply only (#3464). */
|
|
70
78
|
prApply?: PrApplyRecord;
|
|
79
|
+
/**
|
|
80
|
+
* The input digest each completed component applied (#4081), keyed by
|
|
81
|
+
* name. Absent on a record written before it, which then carries nothing.
|
|
82
|
+
*/
|
|
83
|
+
inputs?: Record<string, string>;
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
@@ -109,6 +122,11 @@ export function readFanOutAttempt(path: string): FanOutAttempt | undefined {
|
|
|
109
122
|
}
|
|
110
123
|
const waves = readWaveRecords(parsed.waves);
|
|
111
124
|
const prApply = readPrApplyRecord(parsed.prApply);
|
|
125
|
+
let inputs: Record<string, string> | undefined;
|
|
126
|
+
if (isRecord(parsed.inputs)) {
|
|
127
|
+
inputs = {};
|
|
128
|
+
for (const [name, value] of Object.entries(parsed.inputs)) if (typeof value === "string") inputs[name] = value;
|
|
129
|
+
}
|
|
112
130
|
return {
|
|
113
131
|
digest: typeof parsed.digest === "string" ? parsed.digest : "",
|
|
114
132
|
completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n): n is string => typeof n === "string") : [],
|
|
@@ -117,6 +135,7 @@ export function readFanOutAttempt(path: string): FanOutAttempt | undefined {
|
|
|
117
135
|
...(waves.length > 0 ? { waves } : {}),
|
|
118
136
|
...(isRecord(parsed.carried) && Object.keys(parsed.carried).length > 0 ? { carried: parsed.carried } : {}),
|
|
119
137
|
...(prApply ? { prApply } : {}),
|
|
138
|
+
...(inputs ? { inputs } : {}),
|
|
120
139
|
};
|
|
121
140
|
}
|
|
122
141
|
|
|
@@ -49,12 +49,58 @@ import type { ReleaseIdentity } from "../telemetry-attribution";
|
|
|
49
49
|
import { downstreamWithin, remainingFanOut, type FanOutPlan, type FanOutProgress, type FanOutSkip } from "./fan-out";
|
|
50
50
|
import { evaluateGate, gitGateLedgerPort, type GateCheck, type GateLedgerPort } from "../op/gate";
|
|
51
51
|
import type { RunProgressEvent } from "./run-progress";
|
|
52
|
+
import { emitGateStep, joinRunEventSinks, progressSinkOf, type RunEventSink } from "../run-event-stream";
|
|
52
53
|
import type { CapabilityRegistry } from "./capability";
|
|
53
54
|
import type { PendingGateRecord } from "../lifecycle/gate-ledger";
|
|
54
55
|
import type { DeployContext } from "./capability";
|
|
55
56
|
import { planWaveComponent, type WaveComponentPlan } from "./wave-plan";
|
|
56
57
|
import { decideWaveGate, runWaveLoop, waveGateName, waveSetDigest, type WaveMember, type WaveRecord } from "../wave-engine";
|
|
57
58
|
|
|
59
|
+
/** The sink a fan-out emits to: run events, and the older stream through them. */
|
|
60
|
+
function fanOutSink(options: FanOutRunOptions): RunEventSink | undefined {
|
|
61
|
+
return joinRunEventSinks(options.onRunEvent, progressSinkOf(options.onProgress));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The 1-based wave of each component in `waves`. */
|
|
65
|
+
function waveNumbers(waves: string[][]): Map<string, number> {
|
|
66
|
+
const out = new Map<string, number>();
|
|
67
|
+
waves.forEach((wave, i) => wave.forEach((name) => out.set(name, i + 1)));
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The settles of components a fan-out does not start (#4007): `blocked`
|
|
73
|
+
* when a dependency failed or stopped at a gate, `already-applied` when an
|
|
74
|
+
* earlier attempt applied it. Each is said once, with no `component-start`
|
|
75
|
+
* before it, so a reader of the stream sees every component of the plan.
|
|
76
|
+
*/
|
|
77
|
+
function skipSettles(emit: RunEventSink | undefined, waveOf: Map<string, number>) {
|
|
78
|
+
const said = new Set<string>();
|
|
79
|
+
const say = (component: string, wave: number | undefined, body: { status: "blocked"; blockedBy: string } | { status: "already-applied" }): void => {
|
|
80
|
+
if (!emit || wave === undefined || said.has(component)) return;
|
|
81
|
+
said.add(component);
|
|
82
|
+
emit({ type: "component-settle", wave, component, ...body });
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
/** Each component in `blockedBy` not yet said, in wave order then by name. */
|
|
86
|
+
blocked(blockedBy: Map<string, string>): void {
|
|
87
|
+
const order = [...blockedBy.keys()].sort((a, b) => (waveOf.get(a) ?? 0) - (waveOf.get(b) ?? 0) || a.localeCompare(b));
|
|
88
|
+
for (const component of order) say(component, waveOf.get(component), { status: "blocked", blockedBy: blockedBy.get(component)! });
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* What an earlier attempt left (`remainingFanOut`'s skips): the components
|
|
92
|
+
* it applied, and the ones its failures blocked. Their wave is the one
|
|
93
|
+
* they have in the derivation, `derived`, which a resumed run re-layers.
|
|
94
|
+
*/
|
|
95
|
+
carried(skipped: FanOutSkip[], derived: Map<string, number>): void {
|
|
96
|
+
for (const skip of skipped) {
|
|
97
|
+
if (skip.reason === "already-applied") say(skip.component, derived.get(skip.component), { status: "already-applied" });
|
|
98
|
+
else if (skip.reason === "blocked" && skip.blockedBy) say(skip.component, derived.get(skip.component), { status: "blocked", blockedBy: skip.blockedBy });
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
58
104
|
/**
|
|
59
105
|
* One gate per wave (#3049), each bound to its wave's set digest. The other
|
|
60
106
|
* mode beside {@link FanOutGate}: that one approves the whole set once, this
|
|
@@ -115,6 +161,12 @@ export interface FanOutRunOptions {
|
|
|
115
161
|
/** Outputs of components this run is not running: the ones the plan lists in `seeds`. */
|
|
116
162
|
componentOutputs?: Record<string, Record<string, unknown>>;
|
|
117
163
|
onProgress?: (event: RunProgressEvent) => void;
|
|
164
|
+
/**
|
|
165
|
+
* Where the run's events go (#4041, `--events-json`). A gate over the set
|
|
166
|
+
* or over a wave is a `gate:<name>` step of a `gate` phase with no
|
|
167
|
+
* component, settled before the components it lets through start.
|
|
168
|
+
*/
|
|
169
|
+
onRunEvent?: RunEventSink;
|
|
118
170
|
gates?: GateLedgerPort;
|
|
119
171
|
now?: string;
|
|
120
172
|
/** One approval over the ordered set, bound to `plan.digest`. */
|
|
@@ -206,18 +258,27 @@ export async function runFanOut(
|
|
|
206
258
|
return runGatedWaves(plan, active, components, registry, options, options.waveGate, gates, componentOutputs);
|
|
207
259
|
}
|
|
208
260
|
|
|
261
|
+
const emit = fanOutSink(options);
|
|
262
|
+
emit?.({ type: "run-start", waves: active.waves });
|
|
263
|
+
const skips = skipSettles(emit, waveNumbers(active.waves));
|
|
264
|
+
skips.carried(active.skipped, waveNumbers(plan.waves));
|
|
265
|
+
|
|
209
266
|
if (options.gate) {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
267
|
+
const gate = options.gate;
|
|
268
|
+
const check = await emitGateStep(emit, gate, () =>
|
|
269
|
+
evaluateGate(gates.port, {
|
|
270
|
+
op: gate.op,
|
|
271
|
+
gate: gate.gate,
|
|
272
|
+
planDigest: active.digest,
|
|
273
|
+
...(gate.description ? { description: gate.description } : {}),
|
|
274
|
+
...(gate.timeout ? { timeout: gate.timeout } : {}),
|
|
275
|
+
...(options.now ? { now: options.now } : {}),
|
|
276
|
+
}),
|
|
277
|
+
);
|
|
218
278
|
if (!check.satisfied) {
|
|
219
279
|
// Nothing ran, so nothing is half-applied and there is nothing to
|
|
220
280
|
// compensate. A gate is a fact, not a failure.
|
|
281
|
+
emit?.({ type: "run-settle", status: "gated", durationMs: null });
|
|
221
282
|
return {
|
|
222
283
|
plan: active,
|
|
223
284
|
status: "gated",
|
|
@@ -246,29 +307,28 @@ export async function runFanOut(
|
|
|
246
307
|
}
|
|
247
308
|
};
|
|
248
309
|
|
|
249
|
-
options.onProgress?.({ type: "run-start", waves: active.waves });
|
|
250
|
-
|
|
251
310
|
for (const [waveIndex, wave] of active.waves.entries()) {
|
|
252
311
|
const waveNum = waveIndex + 1;
|
|
253
312
|
// A component whose upstream failed in an earlier wave is not dispatched.
|
|
254
313
|
const runnable = wave.filter((name) => inPlan.has(name) && !blockedBy.has(name));
|
|
255
314
|
if (runnable.length === 0) continue;
|
|
256
315
|
|
|
257
|
-
|
|
316
|
+
emit?.({ type: "wave-start", wave: waveNum, components: runnable });
|
|
258
317
|
const waveResults = await Promise.all(
|
|
259
318
|
runnable.map(async (name) => {
|
|
260
|
-
|
|
319
|
+
emit?.({ type: "component-start", wave: waveNum, component: name });
|
|
261
320
|
const planned = options.plans?.[name];
|
|
262
321
|
const result = await runComponentDeploy(
|
|
263
322
|
byName.get(name)!,
|
|
264
323
|
{ ...fanOutContext(options, name), ...(planned && Object.keys(planned).length > 0 ? { plans: planned } : {}) },
|
|
265
324
|
registry,
|
|
266
325
|
componentOutputs,
|
|
267
|
-
|
|
326
|
+
undefined,
|
|
268
327
|
gates,
|
|
328
|
+
emit,
|
|
269
329
|
);
|
|
270
|
-
|
|
271
|
-
type: "component-
|
|
330
|
+
emit?.({
|
|
331
|
+
type: "component-settle",
|
|
272
332
|
wave: waveNum,
|
|
273
333
|
component: name,
|
|
274
334
|
status: result.status === "fail" ? "failed" : result.status,
|
|
@@ -297,11 +357,13 @@ export async function runFanOut(
|
|
|
297
357
|
}
|
|
298
358
|
|
|
299
359
|
const waveFailed = waveResults.some((r) => r.status === "fail");
|
|
300
|
-
|
|
301
|
-
type: "wave-
|
|
360
|
+
emit?.({
|
|
361
|
+
type: "wave-settle",
|
|
302
362
|
wave: waveNum,
|
|
303
363
|
status: waveFailed ? "failed" : waveResults.some((r) => r.status === "gated") ? "gated" : "ok",
|
|
304
364
|
});
|
|
365
|
+
// What this wave's failures and gates hold back settles now, before the next wave starts.
|
|
366
|
+
skips.blocked(blockedBy);
|
|
305
367
|
}
|
|
306
368
|
|
|
307
369
|
const blocked: FanOutSkip[] = [...blockedBy.entries()]
|
|
@@ -311,7 +373,7 @@ export async function runFanOut(
|
|
|
311
373
|
// A failure outranks a gate: something is actually broken, and reporting the
|
|
312
374
|
// run as "waiting on a human" would hide it. Same precedence the driver uses.
|
|
313
375
|
const status: FanOutRunResult["status"] = failed.length > 0 ? "fail" : gatedFact ? "gated" : "ok";
|
|
314
|
-
|
|
376
|
+
emit?.({ type: "run-settle", status: status === "fail" ? "failed" : status, durationMs: null });
|
|
315
377
|
|
|
316
378
|
return {
|
|
317
379
|
plan: active,
|
|
@@ -391,7 +453,10 @@ async function runGatedWaves(
|
|
|
391
453
|
}
|
|
392
454
|
};
|
|
393
455
|
|
|
394
|
-
|
|
456
|
+
const emit = fanOutSink(options);
|
|
457
|
+
emit?.({ type: "run-start", waves: plan.waves });
|
|
458
|
+
const skips = skipSettles(emit, waveNumbers(plan.waves));
|
|
459
|
+
skips.carried(active.skipped, waveNumbers(plan.waves));
|
|
395
460
|
|
|
396
461
|
/** What planning one wave gave. */
|
|
397
462
|
interface Planned {
|
|
@@ -459,6 +524,7 @@ async function runGatedWaves(
|
|
|
459
524
|
results.push(planFailure(f.component, f.error ?? "plan failed"));
|
|
460
525
|
markBlocked(f.component);
|
|
461
526
|
}
|
|
527
|
+
skips.blocked(blockedBy);
|
|
462
528
|
|
|
463
529
|
const toRun = runnable.filter((name) => plansFor.has(name));
|
|
464
530
|
const record: WaveRecord = {
|
|
@@ -477,14 +543,16 @@ async function runGatedWaves(
|
|
|
477
543
|
return { end: "next" };
|
|
478
544
|
}
|
|
479
545
|
|
|
480
|
-
const check = await
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
546
|
+
const check = await emitGateStep(emit, { op: waveGate.op, gate: gateName }, () =>
|
|
547
|
+
decideWaveGate(gates.port, {
|
|
548
|
+
op: waveGate.op,
|
|
549
|
+
gate: gateName,
|
|
550
|
+
digest,
|
|
551
|
+
description: waveGate.description ?? `wave ${waveNum} of ${plan.waves.length}: ${toRun.join(", ")}`,
|
|
552
|
+
...(waveGate.timeout ? { timeout: waveGate.timeout } : {}),
|
|
553
|
+
...(options.now ? { now: options.now } : {}),
|
|
554
|
+
}),
|
|
555
|
+
);
|
|
488
556
|
if (!check.satisfied) {
|
|
489
557
|
// Nothing in this wave ran, and no later wave is planned: its plan
|
|
490
558
|
// would read outputs this wave has not written.
|
|
@@ -502,15 +570,15 @@ async function runGatedWaves(
|
|
|
502
570
|
},
|
|
503
571
|
|
|
504
572
|
async apply({ k: waveNum }, { contexts, plansFor, waveFailures }, { check, record, toRun }) {
|
|
505
|
-
|
|
573
|
+
emit?.({ type: "wave-start", wave: waveNum, components: toRun });
|
|
506
574
|
const waveResults = await Promise.all(
|
|
507
575
|
toRun.map(async (name) => {
|
|
508
|
-
|
|
576
|
+
emit?.({ type: "component-start", wave: waveNum, component: name });
|
|
509
577
|
const plans = plansFor.get(name)!;
|
|
510
578
|
const ctx = { ...contexts.get(name)!, ...(Object.keys(plans).length > 0 ? { plans } : {}) };
|
|
511
|
-
const result = await runComponentDeploy(byName.get(name)!, ctx, registry, componentOutputs,
|
|
512
|
-
|
|
513
|
-
type: "component-
|
|
579
|
+
const result = await runComponentDeploy(byName.get(name)!, ctx, registry, componentOutputs, undefined, gates, emit);
|
|
580
|
+
emit?.({
|
|
581
|
+
type: "component-settle",
|
|
514
582
|
wave: waveNum,
|
|
515
583
|
component: name,
|
|
516
584
|
status: result.status === "fail" ? "failed" : result.status,
|
|
@@ -543,11 +611,12 @@ async function runGatedWaves(
|
|
|
543
611
|
};
|
|
544
612
|
waves.push(settled);
|
|
545
613
|
options.onWaveSettled?.(settled);
|
|
546
|
-
|
|
547
|
-
type: "wave-
|
|
614
|
+
emit?.({
|
|
615
|
+
type: "wave-settle",
|
|
548
616
|
wave: waveNum,
|
|
549
617
|
status: waveFailures.length > 0 ? "failed" : waveResults.some((r) => r.status === "gated") ? "gated" : "ok",
|
|
550
618
|
});
|
|
619
|
+
skips.blocked(blockedBy);
|
|
551
620
|
return "next";
|
|
552
621
|
},
|
|
553
622
|
});
|
|
@@ -557,7 +626,7 @@ async function runGatedWaves(
|
|
|
557
626
|
.map(([component, by]) => ({ component, reason: "blocked" as const, blockedBy: by }));
|
|
558
627
|
|
|
559
628
|
const status: FanOutRunResult["status"] = failed.length > 0 ? "fail" : gatedFact ? "gated" : "ok";
|
|
560
|
-
|
|
629
|
+
emit?.({ type: "run-settle", status: status === "fail" ? "failed" : status, durationMs: null });
|
|
561
630
|
|
|
562
631
|
return {
|
|
563
632
|
// The derivation's waves, not the narrowed re-layering: their numbers name the gates.
|
|
@@ -89,6 +89,10 @@ export interface FanOutRequest {
|
|
|
89
89
|
* {@link FanOutPlan.digest} so an approval is bound to *what* would be
|
|
90
90
|
* applied and not only to who would run. Absent, the digest still identifies
|
|
91
91
|
* the derivation — the selection, the order and the edges it came from.
|
|
92
|
+
*
|
|
93
|
+
* `chant components fan-out` does not pass it: its approval stays bound to
|
|
94
|
+
* the derivation, and it binds a resumed attempt's progress to each
|
|
95
|
+
* component's input instead (./fan-out-inputs.ts, #4081).
|
|
92
96
|
*/
|
|
93
97
|
inputDigests?: Record<string, string>;
|
|
94
98
|
/**
|
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
* squash merges and rebase merges alike, and every job measures from the
|
|
30
30
|
* merge base of that commit and its own head (`resolveMergeBase`).
|
|
31
31
|
*
|
|
32
|
+
* With `events` (#4007) both commands pass `--events-json`, so the job log
|
|
33
|
+
* carries the run-event stream, and keep a copy of it under the report
|
|
34
|
+
* directory through `CHANT_RUN_EVENTS_DIR`, so the report artifact carries
|
|
35
|
+
* it too. With `reportUrl` both pass `--report-url`, which copies the report,
|
|
36
|
+
* the change set and the events where a reader outside CI can fetch them;
|
|
37
|
+
* the job's own environment brings the credentials an `s3://` URL needs.
|
|
38
|
+
*
|
|
32
39
|
* In a workspace member (#3465) both commands run in the member's directory
|
|
33
40
|
* and pass `--member <name>`, so the member's gate (`pr-<number>-<member>`),
|
|
34
41
|
* note and statuses stay apart from every other member's on the same pull
|
|
@@ -68,6 +75,13 @@ export function prLoopSetup(image: string): string[] {
|
|
|
68
75
|
return image === PR_LOOP_IMAGE ? PR_LOOP_SETUP : [];
|
|
69
76
|
}
|
|
70
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Where the jobs keep their run-event files with `events` (#4007), as
|
|
80
|
+
* `CHANT_RUN_EVENTS_DIR`: inside the report directory, so the report
|
|
81
|
+
* artifact carries them.
|
|
82
|
+
*/
|
|
83
|
+
export const PR_LOOP_EVENTS_DIR = `${PR_LOOP_REPORT_DIR}/run-events`;
|
|
84
|
+
|
|
71
85
|
/** The `prLoop` generator option (`ComponentPipelineOptions.prLoop`). */
|
|
72
86
|
export interface PrLoopPipelineOptions {
|
|
73
87
|
/** The gate the apply waits on. Default `pr-apply`. */
|
|
@@ -79,6 +93,18 @@ export interface PrLoopPipelineOptions {
|
|
|
79
93
|
branch?: string;
|
|
80
94
|
/** Count an approval only from someone who approved the pull request on the forge. Default true. */
|
|
81
95
|
requireReview?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Stream each job's run events (#4007): `--events-json` on both commands,
|
|
98
|
+
* and `CHANT_RUN_EVENTS_DIR` set to {@link PR_LOOP_EVENTS_DIR}. Default false.
|
|
99
|
+
*/
|
|
100
|
+
events?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Copy each job's report, change set and events to this `s3://` or
|
|
103
|
+
* `file://` URL (#4007, `--report-url`), under `<pr>/<commit>/`. It is
|
|
104
|
+
* passed in double quotes, so it may name a variable the job expands,
|
|
105
|
+
* such as `$CHANT_REPORT_URL`.
|
|
106
|
+
*/
|
|
107
|
+
reportUrl?: string;
|
|
82
108
|
/**
|
|
83
109
|
* Which GitHub-shaped forge the workflow is for. Set by the forgejo
|
|
84
110
|
* generator, which reuses the github one; a caller never needs to.
|
|
@@ -112,16 +138,21 @@ export function prLoopJobs(forge: ForgeKind, env: string, options: PrLoopPipelin
|
|
|
112
138
|
const common = [
|
|
113
139
|
"--env", env, "--gate", gate, "--output", PR_LOOP_REPORT_DIR, "--forge", forge,
|
|
114
140
|
...(member ? ["--member", member] : []),
|
|
141
|
+
...(options.events ? ["--events-json"] : []),
|
|
142
|
+
...(options.reportUrl ? ["--report-url", JSON.stringify(options.reportUrl)] : []),
|
|
115
143
|
];
|
|
116
144
|
const github = forge !== "gitlab";
|
|
117
|
-
const
|
|
145
|
+
const jobEnv: Record<string, string> = {
|
|
146
|
+
...(github ? { GITHUB_TOKEN: GITHUB_JOB_TOKEN } : {}),
|
|
147
|
+
...(options.events ? { CHANT_RUN_EVENTS_DIR: PR_LOOP_EVENTS_DIR } : {}),
|
|
148
|
+
};
|
|
118
149
|
return [
|
|
119
150
|
{
|
|
120
151
|
jobName: "plan",
|
|
121
152
|
command: ["chant", "components", "pr-plan", "--base", '"$BASE_SHA"', "--pr", '"$PR_NUMBER"', ...common].join(" "),
|
|
122
153
|
env: github
|
|
123
|
-
? { BASE_SHA: "${{ github.event.pull_request.base.sha }}", PR_NUMBER: "${{ github.event.pull_request.number }}", ...
|
|
124
|
-
: { BASE_SHA: "$CI_MERGE_REQUEST_DIFF_BASE_SHA", PR_NUMBER: "$CI_MERGE_REQUEST_IID" },
|
|
154
|
+
? { BASE_SHA: "${{ github.event.pull_request.base.sha }}", PR_NUMBER: "${{ github.event.pull_request.number }}", ...jobEnv }
|
|
155
|
+
: { BASE_SHA: "$CI_MERGE_REQUEST_DIFF_BASE_SHA", PR_NUMBER: "$CI_MERGE_REQUEST_IID", ...jobEnv },
|
|
125
156
|
},
|
|
126
157
|
{
|
|
127
158
|
jobName: "apply",
|
|
@@ -130,7 +161,7 @@ export function prLoopJobs(forge: ForgeKind, env: string, options: PrLoopPipelin
|
|
|
130
161
|
...(options.requireReview === false ? [] : ["--require-review"]),
|
|
131
162
|
"--resume", PR_APPLY_RECORD,
|
|
132
163
|
].join(" "),
|
|
133
|
-
env: github ? { BASE_SHA: "${{ github.event.before }}", ...
|
|
164
|
+
env: github ? { BASE_SHA: "${{ github.event.before }}", ...jobEnv } : { BASE_SHA: "$CI_COMMIT_BEFORE_SHA", ...jobEnv },
|
|
134
165
|
...(github ? {} : { setup: [gitlabBaseFallback(options.branch)] }),
|
|
135
166
|
},
|
|
136
167
|
];
|