@intentius/chant 0.124.28 → 0.124.30
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/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 +8 -1
- package/dist/change-set-graph.d.ts.map +1 -1
- package/dist/change-set-graph.js +4 -2
- package/dist/change-set.d.ts +10 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +4 -3
- 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.map +1 -1
- package/dist/cli/commands/build.js +6 -3
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +45 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +18 -4
- package/dist/cli/handlers/fan-out.d.ts +9 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +67 -8
- 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 +11 -3
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +134 -26
- 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 +210 -33
- package/dist/cli/handlers/release.d.ts +62 -5
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +414 -28
- package/dist/cli/handlers/run.d.ts +11 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +67 -6
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +91 -10
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +73 -2
- package/dist/cli/registry.d.ts +32 -4
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/run-events.d.ts +3 -2
- package/dist/cli/run-events.d.ts.map +1 -1
- package/dist/cli/run-events.js +5 -3
- package/dist/components/auto-release.d.ts +2 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/auto-release.js +1 -0
- package/dist/components/capability.d.ts +9 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts +8 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +35 -0
- 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.map +1 -1
- package/dist/components/fan-out-run.js +50 -0
- 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 +49 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +38 -4
- package/dist/components/pr-run.d.ts +20 -2
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +26 -13
- package/dist/components/promote.d.ts +23 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +60 -2
- package/dist/components/release-compile.d.ts +9 -0
- package/dist/components/release-compile.d.ts.map +1 -1
- package/dist/components/release-compile.js +9 -3
- package/dist/components/release-gate.d.ts +11 -1
- package/dist/components/release-gate.d.ts.map +1 -1
- package/dist/components/release-gate.js +10 -4
- package/dist/components/wave-plan.d.ts +16 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +36 -2
- package/dist/config.d.ts +38 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -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/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 +2 -1
- package/dist/lifecycle/change-set-store.d.ts.map +1 -1
- package/dist/lifecycle/change-set-store.js +2 -1
- 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 +10 -1
- package/dist/lifecycle/gate-change-set.d.ts.map +1 -1
- package/dist/lifecycle/gate-change-set.js +35 -3
- package/dist/lifecycle/gate-ledger.d.ts +2 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- 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 +48 -1
- package/dist/lifecycle/release-cut.d.ts.map +1 -1
- package/dist/lifecycle/release-cut.js +116 -23
- 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 +8 -3
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.js +2 -0
- 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 +12 -2
- package/dist/lifecycle/release-store.d.ts.map +1 -1
- package/dist/lifecycle/release-store.js +4 -2
- 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 +1 -1
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +9 -0
- package/dist/op/activities/activity-contracts.d.ts +1 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +1 -0
- package/dist/op/activities/shell.d.ts +6 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/shell.js +1 -1
- package/dist/op/local-executor.d.ts +23 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +9 -3
- package/dist/op/runtime.d.ts +27 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/runtime.js +20 -0
- package/dist/plan-summary.d.ts.map +1 -1
- package/dist/plan-summary.js +8 -2
- package/dist/pr-forge.d.ts +23 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +44 -0
- package/dist/pr-loop.d.ts +17 -0
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +30 -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 +29 -2
- package/dist/run-event-store.d.ts.map +1 -1
- package/dist/run-event-store.js +50 -3
- package/dist/run-event-stream.d.ts +4 -3
- package/dist/run-event-stream.d.ts.map +1 -1
- package/dist/run-event-stream.js +7 -3
- package/dist/run-event.d.ts +34 -1
- package/dist/run-event.d.ts.map +1 -1
- package/dist/run-event.js +4 -0
- package/dist/wave-runtime.mjs +260 -229
- 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/change-set.schema.json +5 -1
- 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-forge.d.ts +2 -0
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green.d.ts +10 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +14 -5
- package/dist/workspace/ci-run.d.ts +222 -0
- package/dist/workspace/ci-run.d.ts.map +1 -0
- package/dist/workspace/ci-run.js +464 -0
- package/dist/workspace/ci-serve.d.ts +214 -0
- package/dist/workspace/ci-serve.d.ts.map +1 -0
- package/dist/workspace/ci-serve.js +412 -0
- package/dist/workspace/declaration.d.ts +16 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +26 -0
- package/dist/workspace/declaration.schema.json +64 -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/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 +30 -6
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +141 -21
- package/dist/workspace/intent.schema.json +702 -6
- 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/pr-report.schema.json +5 -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 +3 -0
- 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 +9 -0
- package/dist/workspace/releases.d.ts.map +1 -1
- package/dist/workspace/releases.js +9 -0
- package/dist/workspace/releases.schema.json +123 -1
- package/dist/workspace/run-event.schema.json +24 -6
- package/dist/workspace/status-gates.d.ts +8 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status-stewards.d.ts +2 -0
- package/dist/workspace/status-stewards.d.ts.map +1 -1
- package/dist/workspace/status-stewards.js +1 -0
- package/dist/workspace/status.d.ts +78 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +170 -3
- package/dist/workspace/status.schema.json +210 -2
- package/dist/workspace/wip.d.ts.map +1 -1
- package/dist/workspace/wip.js +11 -3
- package/package.json +1 -1
- package/src/build-params.test.ts +46 -0
- package/src/build-params.ts +55 -1
- package/src/change-set-graph.ts +10 -2
- package/src/change-set.ts +14 -3
- package/src/cli/build-params-cli.ts +22 -9
- package/src/cli/commands/build.ts +6 -3
- package/src/cli/handlers/approve-release.test.ts +5 -1
- package/src/cli/handlers/approve-revoked.test.ts +155 -0
- package/src/cli/handlers/approve.ts +47 -0
- package/src/cli/handlers/build.test.ts +30 -0
- package/src/cli/handlers/build.ts +20 -4
- package/src/cli/handlers/fan-out.test.ts +262 -1
- package/src/cli/handlers/fan-out.ts +72 -8
- 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/pr.test.ts +148 -1
- package/src/cli/handlers/pr.ts +144 -28
- package/src/cli/handlers/promote.test.ts +280 -2
- package/src/cli/handlers/promote.ts +210 -34
- package/src/cli/handlers/release-implicit.e2e.test.ts +12 -4
- 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 +146 -32
- package/src/cli/handlers/release.ts +415 -28
- package/src/cli/handlers/run-auto-release.test.ts +9 -0
- package/src/cli/handlers/run-release.test.ts +55 -0
- package/src/cli/handlers/run.ts +69 -5
- package/src/cli/main.test.ts +1 -0
- package/src/cli/main.ts +91 -10
- package/src/cli/parse-args.ts +54 -2
- package/src/cli/registry.ts +32 -4
- package/src/cli/run-events.ts +5 -2
- package/src/components/auto-release.test.ts +9 -0
- package/src/components/auto-release.ts +3 -0
- package/src/components/capability.ts +9 -0
- package/src/components/driver.test.ts +24 -0
- package/src/components/driver.ts +36 -0
- 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 +48 -0
- package/src/components/fan-out.ts +4 -0
- package/src/components/pr-pipeline.ts +67 -4
- package/src/components/pr-run.test.ts +127 -0
- package/src/components/pr-run.ts +32 -12
- package/src/components/promote.ts +68 -2
- package/src/components/release-compile.ts +17 -3
- package/src/components/release-gate.ts +18 -4
- package/src/components/wave-plan.ts +45 -2
- package/src/config.ts +8 -0
- package/src/flag-params.test.ts +144 -0
- package/src/flag-params.ts +134 -0
- package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
- package/src/lifecycle/change-set-store.ts +2 -1
- package/src/lifecycle/delivery-metrics.ts +263 -0
- package/src/lifecycle/deploy-outcome.ts +147 -0
- package/src/lifecycle/gate-change-set.ts +37 -6
- package/src/lifecycle/gate-ledger.ts +2 -2
- 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.test.ts +74 -2
- package/src/lifecycle/release-cut.ts +158 -22
- 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.ts +9 -3
- 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 +15 -4
- 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.ts +7 -1
- package/src/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/shell.ts +7 -1
- package/src/op/local-executor.ts +27 -4
- package/src/op/runtime.ts +42 -0
- package/src/plan-summary.test.ts +20 -0
- package/src/plan-summary.ts +8 -1
- package/src/pr-forge.test.ts +25 -0
- package/src/pr-forge.ts +62 -0
- package/src/pr-loop.test.ts +13 -1
- package/src/pr-loop.ts +41 -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.ts +63 -3
- package/src/run-event-stream.ts +8 -4
- package/src/run-event.ts +38 -1
- 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/change-set.schema.json +5 -1
- 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-forge.ts +2 -0
- package/src/workspace/ci-green.ts +20 -5
- package/src/workspace/ci-run.test.ts +416 -0
- package/src/workspace/ci-run.ts +571 -0
- package/src/workspace/ci-serve.test.ts +268 -0
- package/src/workspace/ci-serve.ts +521 -0
- package/src/workspace/declaration.schema.json +64 -0
- package/src/workspace/declaration.test.ts +28 -0
- package/src/workspace/declaration.ts +38 -0
- 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/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 +148 -25
- 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/pr-report.schema.json +5 -0
- package/src/workspace/read-contract.e2e.test.ts +2 -1
- package/src/workspace/reason-codes.test.ts +5 -0
- package/src/workspace/reason-codes.ts +3 -0
- 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 +123 -1
- package/src/workspace/releases.ts +11 -0
- package/src/workspace/run-event.schema.json +24 -6
- package/src/workspace/status-contract.test.ts +29 -0
- package/src/workspace/status-gates.ts +8 -0
- package/src/workspace/status-mixed.test.ts +152 -0
- package/src/workspace/status-revoked.test.ts +153 -0
- package/src/workspace/status-stewards.ts +3 -0
- package/src/workspace/status.schema.json +210 -2
- package/src/workspace/status.ts +254 -3
- package/src/workspace/wip.ts +11 -2
package/src/workspace/status.ts
CHANGED
|
@@ -39,7 +39,10 @@ import type { CommandContext } from "../cli/registry";
|
|
|
39
39
|
import { GATES_DIR } from "../lifecycle/gate-ledger";
|
|
40
40
|
import { readPathSha } from "../lifecycle/git";
|
|
41
41
|
import { latestPerComponent, readReleaseLedger, type ReleaseRecord } from "../lifecycle/release-ledger";
|
|
42
|
+
import { describeRevocation, revokedCommitsAt, revokedReleaseLookup, type ReleaseRevocation, type RevokedRelease } from "../lifecycle/release-revocation";
|
|
42
43
|
import { readReleasePlan, type ReleasePlan } from "../lifecycle/plan-ledger";
|
|
44
|
+
import { readDeployOutcomes, type DeployOutcome } from "../lifecycle/deploy-outcome";
|
|
45
|
+
import { mixedEnvironment, releaseRollbackLine, rollbackTarget, type MixedEnvironment, type ReleaseCheck } from "../lifecycle/mixed-environment";
|
|
43
46
|
import { listWorkLeases, type WorkLeaseState } from "../lifecycle/work-lease";
|
|
44
47
|
import { readCheckoutHead, worktreeChanges, type CheckoutHead } from "./records-checkout";
|
|
45
48
|
import { policyView, replicationState, type ReplicationState } from "./wip";
|
|
@@ -50,6 +53,9 @@ import { loadKindRegistry, resolveMemberFields, type MemberFields } from "./kind
|
|
|
50
53
|
import { factoryView, listingView, plantability, treeBytes, type FactoryView, type ListingView, type Plantable } from "./box-factory";
|
|
51
54
|
import { declaredRecordKinds, extensionsAt, readDeclaration, readerVersion, WorkspaceReadError, type Declaration, type ErrorLocation, type Member } from "./declaration";
|
|
52
55
|
import type { ReasonCode } from "./reason-codes";
|
|
56
|
+
import type { FlagDecision, FlagValue } from "./flags";
|
|
57
|
+
import type { OverlapChangeSetRef, OverlapReport } from "./overlap";
|
|
58
|
+
import type { WorkLink } from "./work";
|
|
53
59
|
import { readMemberPromotionOrder, type PromotionStep } from "./promotion-order";
|
|
54
60
|
import { gateAdmissionFrom, releaseRuleFrom } from "./identity";
|
|
55
61
|
import { checkReleaseSignature, type GateAdmissionRule, type ReleaseSignatureCheck } from "./identity-gate-rule";
|
|
@@ -126,6 +132,10 @@ export interface StatusRelease {
|
|
|
126
132
|
approver: string | null;
|
|
127
133
|
/** The gate resolution that admitted the release (#4020): the gate and when it was resolved. Null for an ungated release and for one recorded before chant 0.124.28. */
|
|
128
134
|
admission: { op: string; gate: string; resolvedAt: string } | null;
|
|
135
|
+
/** The release this deploy was made from (#4043): the `releaseDigest` of `_releases/<releaseDigest>.json`. Null for a deploy that named no release and for one recorded before chant 0.124.29. */
|
|
136
|
+
releaseDigest: string | null;
|
|
137
|
+
/** The label that release was cut with (#4043), or null when it has none, when no release is named, or when the cut can't be read. Chant 0.124.29 and newer write it. */
|
|
138
|
+
releaseLabel: string | null;
|
|
129
139
|
/** Read flags, such as `legacy-digest` (#2514). */
|
|
130
140
|
flags: string[];
|
|
131
141
|
/**
|
|
@@ -137,6 +147,25 @@ export interface StatusRelease {
|
|
|
137
147
|
* hasn't fetched yet.
|
|
138
148
|
*/
|
|
139
149
|
plan: ReleasePlan | null;
|
|
150
|
+
/**
|
|
151
|
+
* Set when the deploy names a release (`releaseDigest` on its record) that
|
|
152
|
+
* was cut from a revoked commit (#4033, ws-105): the revoked tag on that
|
|
153
|
+
* commit, the release and its label, and the line that rolls the component
|
|
154
|
+
* back. Absent otherwise, and from chant older than 0.124.29.
|
|
155
|
+
*/
|
|
156
|
+
revoked?: StatusRevokedRelease;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** A release an environment runs that was cut from a revoked commit (#4033). */
|
|
160
|
+
export interface StatusRevokedRelease extends RevokedRelease {
|
|
161
|
+
/**
|
|
162
|
+
* The command that rolls the environment back, run in the member's
|
|
163
|
+
* directory: `chant components rollback <env> --release <label|digest>`
|
|
164
|
+
* naming the newest release the environment ran before this one that is
|
|
165
|
+
* still kept and not revoked (#4035), or `chant components rollback <env>
|
|
166
|
+
* --component <component>` when there is none.
|
|
167
|
+
*/
|
|
168
|
+
rollback: string;
|
|
140
169
|
}
|
|
141
170
|
|
|
142
171
|
export interface StatusLedger {
|
|
@@ -154,6 +183,14 @@ export interface StatusEnvironment {
|
|
|
154
183
|
/** The latest release of each component in the ledger, sorted by component. */
|
|
155
184
|
releases: StatusRelease[];
|
|
156
185
|
reason: { code: StatusReasonCode; message: string } | null;
|
|
186
|
+
/**
|
|
187
|
+
* Set when the environment runs a mix (#4035): a promote, rollback or
|
|
188
|
+
* redeploy left a component failed or gated and nothing has been recorded
|
|
189
|
+
* for it since, or its components' latest records name more than one
|
|
190
|
+
* release. Each component with what it runs, and the lines that settle it.
|
|
191
|
+
* Absent otherwise, and from chant older than 0.124.29.
|
|
192
|
+
*/
|
|
193
|
+
mixed?: MixedEnvironment;
|
|
157
194
|
}
|
|
158
195
|
|
|
159
196
|
export type CompareState = "same" | "differs" | "only-env" | "only-compare";
|
|
@@ -207,6 +244,35 @@ export interface StatusMember {
|
|
|
207
244
|
* cuts could not be read. Added in contract 1 by chant 0.124.28.
|
|
208
245
|
*/
|
|
209
246
|
releaseCuts: StatusReleaseCut[] | null;
|
|
247
|
+
/**
|
|
248
|
+
* The member's feature flags (#4024): each record of a declared flag kind
|
|
249
|
+
* that names this member, with its value per environment and the work item
|
|
250
|
+
* it hides. Sorted by id. `[]` when none names it, null when the flag
|
|
251
|
+
* records could not be read. Called `featureFlags` because a release
|
|
252
|
+
* record's `flags` already means something else. Added in contract 1 by
|
|
253
|
+
* chant 0.124.29.
|
|
254
|
+
*/
|
|
255
|
+
featureFlags: StatusFeatureFlag[] | null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** One feature flag of a member (#4024), as `status --json` lists it. */
|
|
259
|
+
export interface StatusFeatureFlag {
|
|
260
|
+
/** The flag's name, its record's id. */
|
|
261
|
+
id: string;
|
|
262
|
+
/** The build parameter of the member the flag sets. */
|
|
263
|
+
param: string;
|
|
264
|
+
owner: string;
|
|
265
|
+
/** The value per environment, as the record writes it. An environment it leaves out builds with the parameter's default. */
|
|
266
|
+
values: Record<string, FlagValue>;
|
|
267
|
+
/** The work item the flag hides, with its state (null when no record has it), or null when the record names none. */
|
|
268
|
+
work: WorkLink | null;
|
|
269
|
+
/** Each decision the work item implements, with its state and whether it is confirmed. */
|
|
270
|
+
implements: FlagDecision[];
|
|
271
|
+
/** True when every decision the work item implements is confirmed: the flag is due for removal (check WSP118). */
|
|
272
|
+
stale: boolean;
|
|
273
|
+
/** The kind file and the record file, from the workspace root. */
|
|
274
|
+
kind: string;
|
|
275
|
+
path: string;
|
|
210
276
|
}
|
|
211
277
|
|
|
212
278
|
/** One cut of a member's release (#4031), as `status --json` lists it. */
|
|
@@ -328,6 +394,14 @@ export type StatusDocument =
|
|
|
328
394
|
acceptance: StatusAcceptance[];
|
|
329
395
|
/** How far each ref the box's replicate policy names is from its remote (#3172), read locally; null when no box declares one. */
|
|
330
396
|
replication: ReplicationState | null;
|
|
397
|
+
/**
|
|
398
|
+
* Overlap between in-flight work items (#4025): pairs of items whose
|
|
399
|
+
* linked commits touch the same files, or that both reach one entry of
|
|
400
|
+
* a change set a pending or approved gate binds. A report, never a
|
|
401
|
+
* lock. Null when no work kind is declared or the work records or
|
|
402
|
+
* history can't be read. Added in contract 1 by chant 0.124.29.
|
|
403
|
+
*/
|
|
404
|
+
overlap: OverlapReport | null;
|
|
331
405
|
summary: { members: number; released: number; unreadable: number; differing: number | null };
|
|
332
406
|
}
|
|
333
407
|
| {
|
|
@@ -346,6 +420,8 @@ export interface StatusQuery {
|
|
|
346
420
|
compareTo?: string;
|
|
347
421
|
/** Reads one ledger; the lifecycle reader unless a test swaps it. */
|
|
348
422
|
readLedger?: LedgerReader;
|
|
423
|
+
/** Reads the deploy outcomes beside one ledger (#4035), given the ledger's path; the lifecycle reader unless a test swaps it. */
|
|
424
|
+
readOutcomes?: OutcomeReader;
|
|
349
425
|
/** Reads one member's gate ledger directory; git unless a test swaps it. */
|
|
350
426
|
readGates?: GateLedgerReader;
|
|
351
427
|
/** The instant a gate's expiry is measured against; now by default. */
|
|
@@ -448,7 +524,27 @@ async function shipView(member: Member, cwd: string, read: LedgerReader): Promis
|
|
|
448
524
|
|
|
449
525
|
const defaultReader: LedgerReader = (path, cwd) => readReleaseLedger(path.slice(0, -"/releases.jsonl".length), { cwd });
|
|
450
526
|
|
|
451
|
-
|
|
527
|
+
/** Reads the deploy outcomes (#4035) in the directory of the ledger at `path`. */
|
|
528
|
+
type OutcomeReader = (path: string, cwd: string) => Promise<DeployOutcome[]>;
|
|
529
|
+
|
|
530
|
+
const defaultOutcomeReader: OutcomeReader = (path, cwd) => readDeployOutcomes(path.slice(0, -"/releases.jsonl".length), { cwd }).catch(() => []);
|
|
531
|
+
|
|
532
|
+
/** A release digest's revocation, for one member, or null (#4033). */
|
|
533
|
+
type RevokedOf = (releaseDigest: string) => Promise<RevokedRelease | null>;
|
|
534
|
+
|
|
535
|
+
/** The per-component rollback line, for a component an environment runs from a revoked release when no earlier release can be named (#4033). */
|
|
536
|
+
export function rollbackLine(env: string, component: string): string {
|
|
537
|
+
return `chant components rollback ${env} --component ${component}`;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function readEnvironment(
|
|
541
|
+
member: Member,
|
|
542
|
+
env: string,
|
|
543
|
+
cwd: string,
|
|
544
|
+
read: LedgerReader,
|
|
545
|
+
revokedOf: RevokedOf = async () => null,
|
|
546
|
+
readOutcomes: OutcomeReader = defaultOutcomeReader,
|
|
547
|
+
): Promise<StatusEnvironment> {
|
|
452
548
|
const ledger = await ledgerFor(member, env, cwd);
|
|
453
549
|
let records: ReleaseRecord[];
|
|
454
550
|
let malformed: number;
|
|
@@ -470,6 +566,37 @@ async function readEnvironment(member: Member, env: string, cwd: string, read: L
|
|
|
470
566
|
// member (see plan-ledger.ts's readReleasePlan doc).
|
|
471
567
|
const planPrefix = ledger.layout === "members" ? `${MEMBERS_DIR}/${member.name}/` : "";
|
|
472
568
|
const latest = [...latestPerComponent(records).values()].sort((a, b) => (a.component < b.component ? -1 : a.component > b.component ? 1 : 0));
|
|
569
|
+
// #4043: a release item names the label of the release it was deployed from.
|
|
570
|
+
const memberDir = resolve(cwd, member.dir);
|
|
571
|
+
let labels = new Map<string, string>();
|
|
572
|
+
let labelsRead = false;
|
|
573
|
+
const readLabels = async (): Promise<Map<string, string>> => {
|
|
574
|
+
if (labelsRead) return labels;
|
|
575
|
+
labelsRead = true;
|
|
576
|
+
try {
|
|
577
|
+
const { readCuts, labelsByDigest } = await import("../lifecycle/release-store");
|
|
578
|
+
labels = labelsByDigest((await readCuts({ cwd: memberDir })).cuts);
|
|
579
|
+
} catch {
|
|
580
|
+
// The label is a convenience; the digest is the join key.
|
|
581
|
+
}
|
|
582
|
+
return labels;
|
|
583
|
+
};
|
|
584
|
+
if (latest.some((r) => r.releaseDigest !== undefined)) await readLabels();
|
|
585
|
+
// #4035: whether a release a rollback could go back to is kept and not revoked.
|
|
586
|
+
const checks = new Map<string, Promise<ReleaseCheck>>();
|
|
587
|
+
const check = (digest: string): Promise<ReleaseCheck> => {
|
|
588
|
+
let found = checks.get(digest);
|
|
589
|
+
if (!found) {
|
|
590
|
+
found = (async () => {
|
|
591
|
+
const { readRelease } = await import("../lifecycle/release-store");
|
|
592
|
+
const kept = (await readRelease(digest, { cwd: memberDir }).catch(() => null)) !== null;
|
|
593
|
+
return { kept, revoked: kept && (await revokedOf(digest)) !== null };
|
|
594
|
+
})();
|
|
595
|
+
checks.set(digest, found);
|
|
596
|
+
}
|
|
597
|
+
return found;
|
|
598
|
+
};
|
|
599
|
+
const back = { records, check, label: async (digest: string) => (await readLabels()).get(digest) };
|
|
473
600
|
const releases: StatusRelease[] = await Promise.all(
|
|
474
601
|
latest.map(async (r) => ({
|
|
475
602
|
component: r.component,
|
|
@@ -481,10 +608,14 @@ async function readEnvironment(member: Member, env: string, cwd: string, read: L
|
|
|
481
608
|
actor: r.actor,
|
|
482
609
|
approver: r.approver ?? null,
|
|
483
610
|
admission: r.admission ? { op: r.admission.op, gate: r.admission.gate, resolvedAt: r.admission.resolvedAt } : null,
|
|
611
|
+
releaseDigest: r.releaseDigest ?? null,
|
|
612
|
+
releaseLabel: (r.releaseDigest !== undefined ? labels.get(r.releaseDigest) : undefined) ?? null,
|
|
484
613
|
flags: [...(r.flags ?? [])],
|
|
485
614
|
plan: await readReleasePlan(r.digest, { cwd, prefix: planPrefix }),
|
|
615
|
+
...(await revokedItem(r, env, revokedOf, back)),
|
|
486
616
|
})),
|
|
487
617
|
);
|
|
618
|
+
const mixed = await mixedEnvironment({ env, records, outcomes: await readOutcomes(ledger.path, cwd), label: back.label, check });
|
|
488
619
|
return {
|
|
489
620
|
env,
|
|
490
621
|
ledger: { ...ledger, shared: false },
|
|
@@ -493,9 +624,47 @@ async function readEnvironment(member: Member, env: string, cwd: string, read: L
|
|
|
493
624
|
malformed > 0
|
|
494
625
|
? { code: "ledger-malformed", message: `${ledger.path}: ${malformed} line${malformed === 1 ? " is" : "s are"} not a release record and ${malformed === 1 ? "was" : "were"} skipped` }
|
|
495
626
|
: null,
|
|
627
|
+
...(mixed ? { mixed } : {}),
|
|
496
628
|
};
|
|
497
629
|
}
|
|
498
630
|
|
|
631
|
+
/**
|
|
632
|
+
* `{ revoked }` when the record names a release cut from a revoked commit
|
|
633
|
+
* (#4033), else nothing. Its rollback line names the newest release the
|
|
634
|
+
* environment ran before this one that is kept and not revoked (#4035).
|
|
635
|
+
*/
|
|
636
|
+
async function revokedItem(
|
|
637
|
+
r: ReleaseRecord,
|
|
638
|
+
env: string,
|
|
639
|
+
revokedOf: RevokedOf,
|
|
640
|
+
back: { records: readonly ReleaseRecord[]; check: (digest: string) => Promise<ReleaseCheck>; label: (digest: string) => Promise<string | undefined> },
|
|
641
|
+
): Promise<{ revoked?: StatusRevokedRelease }> {
|
|
642
|
+
if (r.releaseDigest === undefined) return {};
|
|
643
|
+
const revoked = await revokedOf(r.releaseDigest);
|
|
644
|
+
if (!revoked) return {};
|
|
645
|
+
const target = await rollbackTarget({ records: back.records, exclude: new Set([r.releaseDigest]), before: r.timestamp, check: back.check });
|
|
646
|
+
const rollback = target ? releaseRollbackLine(env, target, await back.label(target)) : rollbackLine(env, r.component);
|
|
647
|
+
return { revoked: { ...revoked, rollback } };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* A release gate whose release was cut from a revoked commit is superseded
|
|
652
|
+
* (#4033): `chant approve` refuses it and the promote refuses the release, so
|
|
653
|
+
* neither an approval nor a pending fact will pass it. An expired gate stays
|
|
654
|
+
* expired. The gate carries the revocation.
|
|
655
|
+
*/
|
|
656
|
+
async function supersedeRevokedGates(gates: StatusGate[], revokedOf: RevokedOf): Promise<StatusGate[]> {
|
|
657
|
+
return Promise.all(
|
|
658
|
+
gates.map(async (g) => {
|
|
659
|
+
if (g.releaseDigest === undefined) return g;
|
|
660
|
+
const revoked = await revokedOf(g.releaseDigest);
|
|
661
|
+
if (!revoked) return g;
|
|
662
|
+
const { releaseDigest: _d, label: _l, ...revocation } = revoked;
|
|
663
|
+
return { ...g, state: g.state === "expired" ? g.state : "superseded", revoked: revocation };
|
|
664
|
+
}),
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
499
668
|
/** The digest two environments are compared on: the input side when there is one. */
|
|
500
669
|
const compareKey = (r: StatusRelease): string => r.inputDigest ?? r.digest;
|
|
501
670
|
|
|
@@ -545,10 +714,17 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
545
714
|
const ruleSource = scopeSource(found.dir);
|
|
546
715
|
const rules = (gate: string) => gateAdmissionFrom(ruleSource, gate);
|
|
547
716
|
const releaseRule = releaseRuleFrom(ruleSource).rule;
|
|
717
|
+
// #4033 (ws-105): revoked commits, read from local tags once and only when a release is met.
|
|
718
|
+
// Tags that can't be judged read as none revoked; workspace check reports the declaration.
|
|
719
|
+
let revokedCommits: Promise<ReadonlyMap<string, ReleaseRevocation>> | undefined;
|
|
720
|
+
const revoked = () => (revokedCommits ??= revokedCommitsAt(top, ruleSource.declaration?.ci?.green ?? null).catch(() => new Map()));
|
|
721
|
+
// #4024: the flag records, read once for every member. Unreadable records list as null.
|
|
722
|
+
const flags = await readStatusFlags(declaration, found.dir);
|
|
548
723
|
const members: StatusMember[] = [];
|
|
549
724
|
for (const m of declaration.members) {
|
|
725
|
+
const revokedOf = revokedReleaseLookup(resolve(found.dir, m.dir), revoked);
|
|
550
726
|
const environments: StatusEnvironment[] = [];
|
|
551
|
-
for (const env of envs) environments.push(await readEnvironment(m, env, found.dir, read));
|
|
727
|
+
for (const env of envs) environments.push(await readEnvironment(m, env, found.dir, read, revokedOf, query.readOutcomes));
|
|
552
728
|
const own = await hasMemberLedger(m, found.dir);
|
|
553
729
|
const gates = await readMemberGates(own ? `${MEMBERS_DIR}/${m.name}/${GATES_DIR}` : GATES_DIR, own ? "members" : "flat", commit, envs, found.dir, now, query.readGates, rules);
|
|
554
730
|
const stewards = await (query.readStewards ?? readMemberStewards)(resolve(found.dir, m.dir), query.env, now, m.kind, m.box);
|
|
@@ -565,7 +741,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
565
741
|
compare: query.compareTo === undefined ? null : compareEnvironments(environments[0], environments[environments.length - 1]),
|
|
566
742
|
readable: environments.every((e) => e.reason === null),
|
|
567
743
|
gateLedger: gates.ledger,
|
|
568
|
-
gates: gates.gates,
|
|
744
|
+
gates: await supersedeRevokedGates(gates.gates, revokedOf),
|
|
569
745
|
box:
|
|
570
746
|
m.box === null
|
|
571
747
|
? null
|
|
@@ -594,6 +770,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
594
770
|
stewardReasons: stewards.reasons,
|
|
595
771
|
promotionOrder: await (query.readPromotionOrder ?? readMemberPromotionOrder)(resolve(found.dir, m.dir)),
|
|
596
772
|
releaseCuts: await readReleaseCuts(resolve(found.dir, m.dir), releaseRule),
|
|
773
|
+
featureFlags: flags === null ? null : flags.filter((f) => f.member === m.name).map(({ member: _member, ...f }) => f),
|
|
597
774
|
...x(m.pointer),
|
|
598
775
|
});
|
|
599
776
|
}
|
|
@@ -606,6 +783,16 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
606
783
|
|
|
607
784
|
const leases = await readWorkspaceLeases(declaration.members, found.dir, new Date(now));
|
|
608
785
|
const acceptance = await readWorkspaceAcceptance(declaration, found.dir);
|
|
786
|
+
// #4025: the change sets still waiting to apply, the ones a pending or approved gate binds.
|
|
787
|
+
const pendingChangeSets: OverlapChangeSetRef[] = [];
|
|
788
|
+
for (const m of members) {
|
|
789
|
+
const own = m.gateLedger.layout === "members";
|
|
790
|
+
for (const g of m.gates) {
|
|
791
|
+
if (g.changeSet === undefined || (g.state !== "pending" && g.state !== "approved")) continue;
|
|
792
|
+
pendingChangeSets.push({ digest: g.changeSet, cwd: resolve(found.dir, m.dir), ledgerMember: own ? m.name : null, gitSha: g.gitSha ?? null });
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
const overlap = await readStatusOverlap(declaration, found.dir, top, pendingChangeSets);
|
|
609
796
|
|
|
610
797
|
return {
|
|
611
798
|
...head,
|
|
@@ -619,6 +806,7 @@ export async function workspaceStatus(query: StatusQuery): Promise<StatusDocumen
|
|
|
619
806
|
leases,
|
|
620
807
|
acceptance,
|
|
621
808
|
replication: replicationOf(declaration, top),
|
|
809
|
+
overlap,
|
|
622
810
|
summary: {
|
|
623
811
|
members: members.length,
|
|
624
812
|
released: members.filter((m) => m.environments[0].releases.length > 0).length,
|
|
@@ -680,6 +868,31 @@ async function readWorkspaceLeases(members: Member[], cwd: string, now: Date): P
|
|
|
680
868
|
return out;
|
|
681
869
|
}
|
|
682
870
|
|
|
871
|
+
/** Every flag of the declared flag kinds (#4024), read in the working tree, sorted by id; null when they can't be read. */
|
|
872
|
+
async function readStatusFlags(declaration: Declaration, root: string): Promise<Array<StatusFeatureFlag & { member: string }> | null> {
|
|
873
|
+
if (declaredRecordKinds(declaration).length === 0) return [];
|
|
874
|
+
try {
|
|
875
|
+
const { readWorkspaceFlags } = await import("./flags-read");
|
|
876
|
+
const { flags } = await readWorkspaceFlags(root);
|
|
877
|
+
return flags
|
|
878
|
+
.map((f) => ({ id: f.id, member: f.member, param: f.param, owner: f.owner, values: f.values, work: f.work, implements: f.implements, stale: f.stale, kind: f.kind, path: f.path }))
|
|
879
|
+
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
880
|
+
} catch {
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/** The overlap report (#4025); null when no work kind is declared or it can't be read. */
|
|
886
|
+
async function readStatusOverlap(declaration: Declaration, root: string, top: string, changeSets: OverlapChangeSetRef[]): Promise<OverlapReport | null> {
|
|
887
|
+
if (declaredRecordKinds(declaration).length === 0) return null;
|
|
888
|
+
try {
|
|
889
|
+
const { readOverlap } = await import("./overlap");
|
|
890
|
+
return await readOverlap({ declaration, root, top, changeSets });
|
|
891
|
+
} catch {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
683
896
|
/** The acceptance counts of every declared work kind with criteria (#2772), read in the working tree. */
|
|
684
897
|
async function readWorkspaceAcceptance(declaration: Declaration, root: string): Promise<StatusAcceptance[]> {
|
|
685
898
|
if (declaredRecordKinds(declaration).length === 0) return [];
|
|
@@ -765,6 +978,22 @@ export function formatStatus(doc: Extract<StatusDocument, { members: unknown }>)
|
|
|
765
978
|
for (const e of m.environments) {
|
|
766
979
|
if (e.reason) memberNotes.push(` ${e.reason.code}: ${e.reason.message}`);
|
|
767
980
|
else if (e.ledger.shared && e.releases.length > 0) memberNotes.push(` ${e.env} is read from the shared flat ledger ${e.ledger.path}`);
|
|
981
|
+
// #4033: a component running a release cut from a revoked commit, and the way back.
|
|
982
|
+
for (const r of e.releases) {
|
|
983
|
+
if (!r.revoked) continue;
|
|
984
|
+
const name = r.revoked.label ?? r.revoked.releaseDigest;
|
|
985
|
+
memberNotes.push(` ${e.env}: ${r.component} runs release ${name}, revoked by ${r.revoked.tag} (${describeRevocation(r.revoked)}); roll back: ${r.revoked.rollback}`);
|
|
986
|
+
}
|
|
987
|
+
// #4035: an environment running a mix, what each component runs, and the lines that settle it.
|
|
988
|
+
if (e.mixed) {
|
|
989
|
+
const what = e.mixed.components.map((c) => {
|
|
990
|
+
const runs = c.releaseDigest ? `release ${c.releaseLabel ?? c.releaseDigest.slice(0, 24)}` : c.digest ? "no release" : "nothing recorded";
|
|
991
|
+
return c.state === "settled" ? `${c.component} runs ${runs}` : `${c.component} ${c.state} (${c.attempt!.verb} ${c.attempt!.runId}), recorded ${runs}`;
|
|
992
|
+
});
|
|
993
|
+
memberNotes.push(` ${e.env} is mixed: ${what.join("; ")}`);
|
|
994
|
+
for (const line of e.mixed.redeploy) memberNotes.push(` redeploy: ${line}`);
|
|
995
|
+
if (e.mixed.rollback) memberNotes.push(` roll back: ${e.mixed.rollback}`);
|
|
996
|
+
}
|
|
768
997
|
}
|
|
769
998
|
if (memberNotes.length > 0) notes.set(rows.length - 1, memberNotes);
|
|
770
999
|
}
|
|
@@ -794,6 +1023,28 @@ export function formatStatus(doc: Extract<StatusDocument, { members: unknown }>)
|
|
|
794
1023
|
}
|
|
795
1024
|
lines.push(...table(rows));
|
|
796
1025
|
}
|
|
1026
|
+
const flagged = doc.members.filter((m) => (m.featureFlags ?? []).length > 0);
|
|
1027
|
+
if (flagged.length > 0) {
|
|
1028
|
+
lines.push("");
|
|
1029
|
+
const rows: string[][] = [["FLAG", "PARAM", doc.env.toUpperCase(), "WORK ITEM", ""]];
|
|
1030
|
+
for (const m of flagged) {
|
|
1031
|
+
for (const f of m.featureFlags!) {
|
|
1032
|
+
const value = f.values[doc.env];
|
|
1033
|
+
rows.push([`${m.name}/${f.id}`, f.param, value === undefined ? "default" : JSON.stringify(value), f.work ? `${f.work.id} (${f.work.state ?? "unknown"})` : "-", f.stale ? "due for removal" : ""]);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
lines.push(...table(rows));
|
|
1037
|
+
}
|
|
1038
|
+
// #4025: in-flight work items that changed the same thing.
|
|
1039
|
+
if (doc.overlap && doc.overlap.pairs.length > 0) {
|
|
1040
|
+
lines.push("");
|
|
1041
|
+
const rows: string[][] = [["OVERLAP", "FILES", "ADDRESSES"]];
|
|
1042
|
+
for (const p of doc.overlap.pairs) {
|
|
1043
|
+
const list = (xs: string[]) => (xs.length === 0 ? "-" : xs.length <= 2 ? xs.join(", ") : `${xs.slice(0, 2).join(", ")} and ${xs.length - 2} more`);
|
|
1044
|
+
rows.push([`${p.items[0]} and ${p.items[1]}`, list(p.files), list([...new Set(p.addresses.map((x) => x.node ?? x.address))])]);
|
|
1045
|
+
}
|
|
1046
|
+
lines.push(...table(rows));
|
|
1047
|
+
}
|
|
797
1048
|
const boxes = doc.members.filter((m) => m.box?.isolation);
|
|
798
1049
|
if (boxes.length > 0) {
|
|
799
1050
|
lines.push("");
|
package/src/workspace/wip.ts
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
import { spawnSync } from "node:child_process";
|
|
41
|
-
import { copyFileSync, existsSync, lstatSync, mkdtempSync, rmSync, unlinkSync } from "node:fs";
|
|
41
|
+
import { copyFileSync, existsSync, lstatSync, mkdtempSync, rmSync, statSync, unlinkSync, utimesSync } from "node:fs";
|
|
42
42
|
import { tmpdir } from "node:os";
|
|
43
43
|
import { join, resolve } from "node:path";
|
|
44
44
|
import { KEPT_REF_PREFIX } from "../lifecycle/work-lease";
|
|
@@ -348,7 +348,16 @@ function worktreeTree(top: string): string {
|
|
|
348
348
|
const index = join(dir, "index");
|
|
349
349
|
// Start from the checkout's index so git reuses its stat data; the original is never written.
|
|
350
350
|
const own = out(top, ["rev-parse", "--git-path", "index"]);
|
|
351
|
-
if (own && existsSync(resolve(top, own)))
|
|
351
|
+
if (own && existsSync(resolve(top, own))) {
|
|
352
|
+
const source = resolve(top, own);
|
|
353
|
+
copyFileSync(source, index);
|
|
354
|
+
// Keep the index's own timestamps on the copy. git treats an entry whose
|
|
355
|
+
// file is as new as the index as racily clean and reads its content; a
|
|
356
|
+
// copy stamped now would make a same-size edit made in the same second as
|
|
357
|
+
// the last index write look unchanged, and the snapshot would miss it.
|
|
358
|
+
const { atime, mtime } = statSync(source);
|
|
359
|
+
utimesSync(index, atime, mtime);
|
|
360
|
+
}
|
|
352
361
|
const env = { GIT_INDEX_FILE: index };
|
|
353
362
|
const add = git(top, ["add", "--all", "--", ":/"], { env });
|
|
354
363
|
if (!add.ok) throw new Error(`wip: git add into a temporary index failed: ${add.stderr.trim()}`);
|