@intentius/chant 0.124.28 → 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/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 +15 -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 +40 -3
- 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 +61 -10
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +24 -2
- package/dist/cli/registry.d.ts +15 -3
- 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 +25 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +22 -4
- 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 +5 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +10 -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-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/plan-summary.d.ts.map +1 -1
- package/dist/plan-summary.js +8 -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 +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 +2 -1
- package/dist/run-event-stream.d.ts.map +1 -1
- package/dist/run-event-stream.js +5 -1
- package/dist/run-event.d.ts +19 -1
- package/dist/run-event.d.ts.map +1 -1
- package/dist/run-event.js +2 -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.d.ts +8 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +10 -3
- 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/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 +10 -3
- package/dist/workspace/status-gates.d.ts +8 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- 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 +198 -1
- 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 +15 -0
- package/src/cli/handlers/build.ts +17 -4
- package/src/cli/handlers/fan-out.test.ts +180 -1
- package/src/cli/handlers/fan-out.ts +38 -3
- 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 +139 -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 +61 -10
- package/src/cli/parse-args.ts +19 -2
- package/src/cli/registry.ts +15 -3
- 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 +35 -4
- 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 +15 -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-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/plan-summary.test.ts +20 -0
- package/src/plan-summary.ts +8 -1
- 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.ts +63 -3
- package/src/run-event-stream.ts +4 -1
- package/src/run-event.ts +21 -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.ts +14 -3
- 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/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 +10 -3
- 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.schema.json +198 -1
- package/src/workspace/status.ts +254 -3
- package/src/workspace/wip.ts +11 -2
|
@@ -28,7 +28,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
28
28
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
29
29
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
30
30
|
import { loadChantConfig, type ChantConfig } from "../config";
|
|
31
|
-
import {
|
|
31
|
+
import { resolveFlaggedBuildParams } from "../flag-params";
|
|
32
32
|
import { discoverComponents } from "./discover";
|
|
33
33
|
import { withoutDisabled } from "./cli-support";
|
|
34
34
|
import { applyConfigDefaults } from "./config-defaults";
|
|
@@ -72,6 +72,13 @@ export interface CompiledTarget {
|
|
|
72
72
|
components: string[];
|
|
73
73
|
/** Each component's build-time steps, as declared for this environment, in composition order. */
|
|
74
74
|
buildSteps: Record<string, unknown[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Each component's publish steps (`PUBLISH_STEP_KINDS`), as declared for
|
|
77
|
+
* this environment, in composition order (#4027). The cut's dry run shows
|
|
78
|
+
* them as what each environment's deploy publishes. Absent from a compiler
|
|
79
|
+
* that does not report them.
|
|
80
|
+
*/
|
|
81
|
+
publishSteps?: Record<string, unknown[]>;
|
|
75
82
|
/** For each component, the files its build steps read, relative to the member's directory. Used to tell whether an artifact's source changed. */
|
|
76
83
|
buildInputs: Record<string, string[]>;
|
|
77
84
|
/** For each component, the file that declares it, relative to the member's directory. */
|
|
@@ -132,6 +139,11 @@ export function buildStepsOf(component: DriverComponent): DriverStep[] {
|
|
|
132
139
|
return stepsOf(component.deploy).map((s) => s.step).filter((s) => BUILD_STEP_KINDS.includes(s.kind));
|
|
133
140
|
}
|
|
134
141
|
|
|
142
|
+
/** A component's publish steps ({@link PUBLISH_STEP_KINDS}), each as declared, in composition order. */
|
|
143
|
+
export function publishStepsOf(component: DriverComponent): DriverStep[] {
|
|
144
|
+
return stepsOf(component.deploy).map((s) => s.step).filter((s) => PUBLISH_STEP_KINDS.includes(s.kind));
|
|
145
|
+
}
|
|
146
|
+
|
|
135
147
|
/** The literal paths a component's archive steps read: `docker-build`'s `context` and `dockerfile`, `zip-package`'s `source`, `jvm-build`'s `path`. */
|
|
136
148
|
export function buildInputPaths(component: DriverComponent): string[] {
|
|
137
149
|
const out: string[] = [];
|
|
@@ -201,10 +213,11 @@ async function loadComponents(
|
|
|
201
213
|
env: string,
|
|
202
214
|
): Promise<{ config: ChantConfig; params: ReleaseParam[]; declared: number; components: Array<{ component: DriverComponent; file: string }> }> {
|
|
203
215
|
const { config } = await loadChantConfig(inputs.projectDir).catch(() => ({ config: {} as ChantConfig }));
|
|
204
|
-
|
|
216
|
+
// #4024: a workspace member's flag records back their parameters, so a flag's value is a param with source flag:<name>.
|
|
217
|
+
const resolved = await resolveFlaggedBuildParams(inputs.projectDir, config.buildParams, {
|
|
205
218
|
...(inputs.params ? { cli: inputs.params } : {}),
|
|
206
219
|
...(inputs.paramsFile ? { paramsFile: inputs.paramsFile.replaceAll("{env}", env) } : {}),
|
|
207
|
-
});
|
|
220
|
+
}, env);
|
|
208
221
|
if (!resolved.success) throw new ReleaseCompileError(`build parameters for "${env}" did not resolve:\n${resolved.errors.join("\n")}`);
|
|
209
222
|
const discovered = await discoverComponents(inputs.projectDir, { buildParams: resolved.provenance });
|
|
210
223
|
if (discovered.errors.length > 0) throw new ReleaseCompileError(discovered.errors.map((e) => e.message).join("\n"));
|
|
@@ -267,6 +280,7 @@ export async function compileEnvironment(inputs: CompileInputs, env: string): Pr
|
|
|
267
280
|
params,
|
|
268
281
|
components: components.map((c) => c.component.name),
|
|
269
282
|
buildSteps: Object.fromEntries(components.map(({ component }) => [component.name, buildStepsOf(component)])),
|
|
283
|
+
publishSteps: Object.fromEntries(components.map(({ component }) => [component.name, publishStepsOf(component)])),
|
|
270
284
|
buildInputs: Object.fromEntries(components.map(({ component }) => [component.name, buildInputPaths(component)])),
|
|
271
285
|
componentFiles: Object.fromEntries(components.map(({ component, file }) => [component.name, rel(file)])),
|
|
272
286
|
templates,
|
|
@@ -47,14 +47,16 @@
|
|
|
47
47
|
* environment has no deploy of the component). When they are all equal the
|
|
48
48
|
* member has no entries. When the environment's deploy names no release, or
|
|
49
49
|
* the release it names can't be read, the member has a hole: nothing says
|
|
50
|
-
* what the environment runs, so the change can't be shown empty.
|
|
50
|
+
* what the environment runs, so the change can't be shown empty. So does a
|
|
51
|
+
* component a promote, rollback or redeploy left failed or gated with nothing
|
|
52
|
+
* recorded since (#4035): its record names what ran before that run.
|
|
51
53
|
*/
|
|
52
54
|
|
|
53
55
|
import type { CapabilityRegistry } from "./capability";
|
|
54
56
|
import { deployContext, resolveComponentGraph, resolveStepInput, type DriverComponent, type DriverGate, type DriverPhase, type DriverStep } from "./driver";
|
|
55
57
|
import { componentPlanDigest } from "./gate-plan";
|
|
56
58
|
import { gateName, RELEASE_GATE_OP } from "../op/gate-name";
|
|
57
|
-
import { capabilitySteps, readComponentOutputs } from "./wave-plan";
|
|
59
|
+
import { capabilitySteps, planContext, readComponentOutputs } from "./wave-plan";
|
|
58
60
|
import {
|
|
59
61
|
composeChangeSet,
|
|
60
62
|
isEmptyChangeSet,
|
|
@@ -111,6 +113,12 @@ export interface ReleaseChangeSetInput {
|
|
|
111
113
|
registry: CapabilityRegistry;
|
|
112
114
|
/** Per component, what `env` runs now. A component missing here has never been deployed to it. */
|
|
113
115
|
current: ReadonlyMap<string, CurrentDeploy>;
|
|
116
|
+
/**
|
|
117
|
+
* Components a promote, rollback or redeploy left failed or gated in `env`
|
|
118
|
+
* with nothing recorded since (#4035), each with why. What they run is not
|
|
119
|
+
* known, so each is a hole whatever its ledger record says.
|
|
120
|
+
*/
|
|
121
|
+
unsettled?: ReadonlyMap<string, string>;
|
|
114
122
|
/** Outputs supplied by the caller (`--seed-outputs`). */
|
|
115
123
|
seededOutputs?: Record<string, Record<string, unknown>>;
|
|
116
124
|
/** The chant version to record in the document. */
|
|
@@ -151,6 +159,8 @@ export function chantComponentPart(input: {
|
|
|
151
159
|
env: string;
|
|
152
160
|
digest: string;
|
|
153
161
|
current: CurrentDeploy | undefined;
|
|
162
|
+
/** Why the component is unsettled in `env` (#4035), when it is. */
|
|
163
|
+
unsettled?: string;
|
|
154
164
|
}): ChangeSetPart {
|
|
155
165
|
const { component, release, env, digest, current } = input;
|
|
156
166
|
const name = component.name;
|
|
@@ -184,6 +194,10 @@ export function chantComponentPart(input: {
|
|
|
184
194
|
},
|
|
185
195
|
],
|
|
186
196
|
});
|
|
197
|
+
if (input.unsettled !== undefined) {
|
|
198
|
+
member.holes.push({ address: name, type: RELEASE_COMPONENT_ENTRY_TYPE, reason: input.unsettled });
|
|
199
|
+
return { member, entries: [] };
|
|
200
|
+
}
|
|
187
201
|
if (!current) {
|
|
188
202
|
return entry("create", [
|
|
189
203
|
{ path: "artifact", after: digest },
|
|
@@ -238,7 +252,7 @@ export async function planReleaseChangeSet(input: ReleaseChangeSetInput): Promis
|
|
|
238
252
|
const digest = input.digests.get(name) ?? "";
|
|
239
253
|
const plannable = capabilitySteps(component.deploy).filter((s) => registry.has(s.kind) && registry.resolve(s.kind).plan !== undefined);
|
|
240
254
|
if (plannable.length === 0) {
|
|
241
|
-
parts.push(chantComponentPart({ component, release, env, digest, current: input.current.get(name) }));
|
|
255
|
+
parts.push(chantComponentPart({ component, release, env, digest, current: input.current.get(name), unsettled: input.unsettled?.get(name) }));
|
|
242
256
|
continue;
|
|
243
257
|
}
|
|
244
258
|
const ctx = deployContext({ env }, name);
|
|
@@ -251,7 +265,7 @@ export async function planReleaseChangeSet(input: ReleaseChangeSetInput): Promis
|
|
|
251
265
|
}
|
|
252
266
|
for (const step of plannable) {
|
|
253
267
|
const { kind, ...rest } = step;
|
|
254
|
-
const planned = await registry.resolve(kind).plan!(ctx, resolveStepInput(rest, {}, outputs) as never);
|
|
268
|
+
const planned = await registry.resolve(kind).plan!(planContext(ctx, rest, outputs), resolveStepInput(rest, {}, outputs) as never);
|
|
255
269
|
parts.push(
|
|
256
270
|
planned.changeSet ?? {
|
|
257
271
|
member: {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `@<component>.publish.*`) resolves.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { resolveStepInput, type DriverComponent, type DriverPhase, type DriverStep } from "./driver";
|
|
22
|
+
import { resolveStepInput, unresolvedWiringSources, type DriverComponent, type DriverPhase, type DriverStep } from "./driver";
|
|
23
23
|
import { componentPlanDigest } from "./gate-plan";
|
|
24
24
|
import type { CapabilityRegistry, DeployContext } from "./capability";
|
|
25
25
|
import type { WaveMember } from "../gated-waves";
|
|
@@ -60,6 +60,19 @@ export function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[] {
|
|
|
60
60
|
return out;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* The context a step is planned with: `ctx`, plus the components whose
|
|
65
|
+
* outputs the step reads and could not read yet (`unresolvedInputs`, #4084).
|
|
66
|
+
*/
|
|
67
|
+
export function planContext(
|
|
68
|
+
ctx: DeployContext,
|
|
69
|
+
stepInput: Record<string, unknown>,
|
|
70
|
+
componentOutputs: Record<string, Record<string, unknown>>,
|
|
71
|
+
): DeployContext {
|
|
72
|
+
const unresolved = unresolvedWiringSources(stepInput, componentOutputs);
|
|
73
|
+
return unresolved.length > 0 ? { ...ctx, unresolvedInputs: unresolved } : ctx;
|
|
74
|
+
}
|
|
75
|
+
|
|
63
76
|
/** Plan one component against the outputs earlier waves produced. Never throws: a failure comes back as `error`. */
|
|
64
77
|
export async function planWaveComponent(
|
|
65
78
|
component: DriverComponent,
|
|
@@ -76,7 +89,7 @@ export async function planWaveComponent(
|
|
|
76
89
|
if (!capability.plan) continue;
|
|
77
90
|
const { kind: _kind, ...rest } = step;
|
|
78
91
|
const input = resolveStepInput(rest, {}, componentOutputs);
|
|
79
|
-
const planned = await capability.plan(ctx, input as never);
|
|
92
|
+
const planned = await capability.plan(planContext(ctx, rest, componentOutputs), input as never);
|
|
80
93
|
const member = { member: planned.member, planDigest: planned.planDigest };
|
|
81
94
|
members.push(member);
|
|
82
95
|
parts.push(planned.changeSet ?? emptyPart(member));
|
package/src/config.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { findProjectConfig } from "./project-root";
|
|
|
12
12
|
import { evaluateProjectConfig } from "./config-sandbox";
|
|
13
13
|
import { lexiconNames, pathLexiconRoot, registerLexiconDeclarations, type LexiconDeclaration } from "./lexicon-module";
|
|
14
14
|
import { decideConfigSchema, type DecideConfig } from "./op/decide-config";
|
|
15
|
+
import { PublishDeclarationSchema, type PublishDeclaration } from "./lifecycle/publish-declaration";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* One project-declared environment (chant #1166). Historically always a bare
|
|
@@ -169,6 +170,7 @@ export const ChantConfigSchema = z.object({
|
|
|
169
170
|
).optional(),
|
|
170
171
|
release: z.object({
|
|
171
172
|
autoRecord: z.boolean().optional(),
|
|
173
|
+
publish: z.array(PublishDeclarationSchema).optional(),
|
|
172
174
|
}).optional(),
|
|
173
175
|
// Strict: a misspelt key here would leave Ops on the local runtime with
|
|
174
176
|
// nothing said (#2523).
|
|
@@ -382,6 +384,12 @@ export interface ChantConfig {
|
|
|
382
384
|
release?: {
|
|
383
385
|
/** Set false to disable auto-emitting a release record after a successful component deploy project-wide. The `--no-release-record` CLI flag overrides this per-invocation. */
|
|
384
386
|
autoRecord?: boolean;
|
|
387
|
+
/**
|
|
388
|
+
* Where `chant release publish` publishes a cut release (#4047): npm
|
|
389
|
+
* packages, an image in an OCI registry, release assets on a forge. Run in
|
|
390
|
+
* the order given. See ./lifecycle/publish-declaration.ts.
|
|
391
|
+
*/
|
|
392
|
+
publish?: PublishDeclaration[];
|
|
385
393
|
};
|
|
386
394
|
|
|
387
395
|
/** Defaults for `chant run` and its subcommands (#2523). */
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time parameters from workspace flags (#4024): what a build for an
|
|
3
|
+
* environment resolves in a member with flags, and the precedence rule that a
|
|
4
|
+
* flag-backed parameter can't be overridden where the environment has a gate.
|
|
5
|
+
* On the fixture in `workspace/__fixtures__/flag-workspace.ts`, where member
|
|
6
|
+
* `shop`'s component declares a gate and member `blog`'s does not.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { writeFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
|
|
12
|
+
import { buildCommand } from "./cli/commands/build";
|
|
13
|
+
import type { Serializer } from "./serializer";
|
|
14
|
+
import type { BuildParamsConfig } from "./build-params";
|
|
15
|
+
import { loadBuildParamFlags, resolveFlaggedBuildParams } from "./flag-params";
|
|
16
|
+
import { cleanScratch, scratchDir } from "./workspace/__fixtures__/contract-repo";
|
|
17
|
+
import { flagWorkspace } from "./workspace/__fixtures__/flag-workspace";
|
|
18
|
+
|
|
19
|
+
const SHOP: BuildParamsConfig = { newCheckout: { type: "boolean", default: false }, tier: { type: "string", default: "small" } };
|
|
20
|
+
const BLOG: BuildParamsConfig = { banner: { type: "boolean", default: false } };
|
|
21
|
+
|
|
22
|
+
let root: string;
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
root = flagWorkspace();
|
|
25
|
+
});
|
|
26
|
+
afterAll(cleanScratch);
|
|
27
|
+
|
|
28
|
+
const quiet = { echo: false } as const;
|
|
29
|
+
|
|
30
|
+
describe("loadBuildParamFlags", () => {
|
|
31
|
+
test("outside a workspace, and without an environment, there are no flags", async () => {
|
|
32
|
+
const plain = scratchDir("chant-flags-plain-");
|
|
33
|
+
expect(await loadBuildParamFlags(plain, "prod")).toEqual({ flags: undefined, errors: [] });
|
|
34
|
+
expect(await loadBuildParamFlags(join(root, "shop"), undefined)).toEqual({ flags: undefined, errors: [] });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("in a member, each flag-backed parameter with the flag's value for the environment", async () => {
|
|
38
|
+
expect(await loadBuildParamFlags(join(root, "shop"), "dev")).toEqual({
|
|
39
|
+
flags: { env: "dev", byParam: { newCheckout: { flag: "new-checkout", value: true } } },
|
|
40
|
+
errors: [],
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("a flag kind that can't be read stops the build rather than building without its flags", async () => {
|
|
45
|
+
const dir = flagWorkspace({ "flags/flag.schema.json": "{ not json" });
|
|
46
|
+
const loaded = await loadBuildParamFlags(join(dir, "shop"), "prod");
|
|
47
|
+
expect(loaded.flags).toBeUndefined();
|
|
48
|
+
expect(loaded.errors[0]).toMatch(/the workspace's flag records can't be read/);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("resolveFlaggedBuildParams", () => {
|
|
53
|
+
test("records the flag as the parameter's source, per environment", async () => {
|
|
54
|
+
const prod = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "prod");
|
|
55
|
+
expect(prod).toEqual({
|
|
56
|
+
success: true,
|
|
57
|
+
errors: [],
|
|
58
|
+
provenance: [
|
|
59
|
+
{ name: "newCheckout", value: false, source: "flag:new-checkout" },
|
|
60
|
+
{ name: "tier", value: "small", source: "default" },
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
const dev = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "dev");
|
|
64
|
+
expect(dev.provenance[0]).toEqual({ name: "newCheckout", value: true, source: "flag:new-checkout" });
|
|
65
|
+
// staging: the record gives no value, so the declared default applies.
|
|
66
|
+
expect((await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "staging")).provenance[0]).toEqual({ name: "newCheckout", value: false, source: "default" });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("--param can't override a flag in an environment with a gate: the build refuses", async () => {
|
|
70
|
+
const refused = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, cli: { newCheckout: "true" } }, "prod");
|
|
71
|
+
expect(refused.success).toBe(false);
|
|
72
|
+
expect(refused.provenance).toEqual([]);
|
|
73
|
+
expect(refused.errors).toHaveLength(1);
|
|
74
|
+
expect(refused.errors[0]).toMatch(/build parameter "newCheckout" is backed by the flag "new-checkout", and "prod" has a gate, so --param can't set it/);
|
|
75
|
+
expect(refused.errors[0]).toMatch(/gates: prod-release/);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("--params-file can't either, and a parameter no flag backs still can", async () => {
|
|
79
|
+
const file = join(scratchDir("chant-flags-file-"), "params.json");
|
|
80
|
+
writeFileSync(file, JSON.stringify({ newCheckout: true }));
|
|
81
|
+
const refused = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, paramsFile: file }, "prod");
|
|
82
|
+
expect(refused.success).toBe(false);
|
|
83
|
+
expect(refused.errors[0]).toMatch(/so --params-file can't set it/);
|
|
84
|
+
const tier = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, cli: { tier: "large" } }, "prod");
|
|
85
|
+
expect(tier.success).toBe(true);
|
|
86
|
+
expect(tier.provenance).toContainEqual({ name: "tier", value: "large", source: "cli" });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("where no component declares a gate, --param still overrides the flag", async () => {
|
|
90
|
+
const r = await resolveFlaggedBuildParams(join(root, "blog"), BLOG, { ...quiet, cli: { banner: "false" } }, "prod");
|
|
91
|
+
expect(r.success).toBe(true);
|
|
92
|
+
expect(r.provenance).toEqual([{ name: "banner", value: false, source: "cli" }]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("components that can't be read refuse an override, since the gate can't be ruled out", async () => {
|
|
96
|
+
const dir = flagWorkspace({ "shop/broken.component.ts": "export const = ;\n" });
|
|
97
|
+
const r = await resolveFlaggedBuildParams(join(dir, "shop"), SHOP, { ...quiet, cli: { newCheckout: "true" } }, "prod");
|
|
98
|
+
expect(r.success).toBe(false);
|
|
99
|
+
expect(r.errors[0]).toMatch(/whether "prod" has a gate can't be told/);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("chant build --env in a member with flags", () => {
|
|
104
|
+
const runtime = join(import.meta.dirname, "runtime");
|
|
105
|
+
const paramsModule = join(import.meta.dirname, "params");
|
|
106
|
+
const serializer: Serializer = {
|
|
107
|
+
name: "aws",
|
|
108
|
+
rulePrefix: "TEST",
|
|
109
|
+
serialize: (entities) => JSON.stringify([...entities.values()].map((e) => (e as unknown as { props: unknown }).props)),
|
|
110
|
+
};
|
|
111
|
+
const shopFiles = {
|
|
112
|
+
"shop/chant.config.ts": `export default { environments: ["dev", "staging", "prod"], buildParams: { newCheckout: { type: "boolean", default: false } } };\n`,
|
|
113
|
+
"shop/main.ts":
|
|
114
|
+
`import { createResource } from ${JSON.stringify(runtime)};\n` +
|
|
115
|
+
`import { params } from ${JSON.stringify(paramsModule)};\n` +
|
|
116
|
+
`const Bucket = createResource("Test::Bucket", "aws", { arn: "Arn" });\n` +
|
|
117
|
+
`export const bucket = new Bucket({ checkout: params.newCheckout ? "new" : "old" });\n`,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
test("records the flag on BuildResult.buildParams and builds with its value", async () => {
|
|
121
|
+
const dir = flagWorkspace(shopFiles);
|
|
122
|
+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
123
|
+
try {
|
|
124
|
+
const result = await buildCommand({ path: join(dir, "shop"), format: "json", serializers: [serializer], env: "dev" });
|
|
125
|
+
expect(result.errors).toEqual([]);
|
|
126
|
+
expect(result.buildParams).toEqual([{ name: "newCheckout", value: true, source: "flag:new-checkout" }]);
|
|
127
|
+
expect(spy.mock.calls.map((c) => String(c[0])).some((l) => l.includes("1 build parameter resolved (1 from flags)"))).toBe(true);
|
|
128
|
+
} finally {
|
|
129
|
+
spy.mockRestore();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("refuses --param for a flag-backed parameter in an environment with a gate", async () => {
|
|
134
|
+
const dir = flagWorkspace(shopFiles);
|
|
135
|
+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
136
|
+
try {
|
|
137
|
+
const result = await buildCommand({ path: join(dir, "shop"), format: "json", serializers: [serializer], env: "prod", params: { newCheckout: "true" } });
|
|
138
|
+
expect(result.success).toBe(false);
|
|
139
|
+
expect(result.errors.join("\n")).toMatch(/"newCheckout" is backed by the flag "new-checkout", and "prod" has a gate, so --param can't set it/);
|
|
140
|
+
} finally {
|
|
141
|
+
spy.mockRestore();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time parameters from workspace flags (#4024, decided in #4016).
|
|
3
|
+
*
|
|
4
|
+
* A member of a workspace may have flag records: records of a kind with a
|
|
5
|
+
* `flag` block, each naming the member, one of its declared build
|
|
6
|
+
* parameters and a value per environment (`workspace/flags.ts`). A build
|
|
7
|
+
* for an environment (`chant build --env <env>`, `chant run --components
|
|
8
|
+
* --env <env>`, and each environment a release cut compiles) reads them, and
|
|
9
|
+
* a flag-backed parameter takes the flag's value for that environment,
|
|
10
|
+
* recorded as `source: "flag:<name>"` on `BuildResult.buildParams` and on the
|
|
11
|
+
* release target's `params`.
|
|
12
|
+
*
|
|
13
|
+
* The precedence rule: where the environment has a gate, `--param`,
|
|
14
|
+
* `--params-file` and the parameter's env var can't set a flag-backed
|
|
15
|
+
* parameter, and the build refuses. An environment has a gate when a
|
|
16
|
+
* component enabled in it declares a gate step, the same test `components
|
|
17
|
+
* promote --release` uses to bind a release gate. The test runs only when one
|
|
18
|
+
* of those sources did set a flag-backed parameter, since it imports the
|
|
19
|
+
* member's components; a project with no components has no gate.
|
|
20
|
+
*
|
|
21
|
+
* Level 0 pays one upward `existsSync` walk here and nothing more. Workspace
|
|
22
|
+
* code is imported only once a declaration is found (#2525 rule 5, pinned by
|
|
23
|
+
* #2526's goldens).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { findWorkspaceRoot } from "./project-root";
|
|
27
|
+
import { flagGateRefusal, type BuildParamFlags, type BuildParamsConfig } from "./build-params";
|
|
28
|
+
import type { BuildParamProvenance } from "./provenance";
|
|
29
|
+
import { echoBuildParams, resolveCliBuildParams, type CliBuildParamsArgs, type CliBuildParamsResolution } from "./cli/build-params-cli";
|
|
30
|
+
import { formatError } from "./cli/format";
|
|
31
|
+
|
|
32
|
+
/** The flags backing parameters of the member at `projectDir` in `env`, or why they can't be read. `flags` is undefined outside a workspace, without an environment, or when no flag names the member. */
|
|
33
|
+
export async function loadBuildParamFlags(projectDir: string, env: string | undefined): Promise<{ flags: BuildParamFlags | undefined; errors: string[] }> {
|
|
34
|
+
if (!env) return { flags: undefined, errors: [] };
|
|
35
|
+
const found = findWorkspaceRoot(projectDir);
|
|
36
|
+
if (!found) return { flags: undefined, errors: [] };
|
|
37
|
+
const { memberFlagBindings } = await import("./workspace/flags-read");
|
|
38
|
+
try {
|
|
39
|
+
const bindings = await memberFlagBindings(found.dir, projectDir, env);
|
|
40
|
+
if (!bindings) return { flags: undefined, errors: [] };
|
|
41
|
+
if (bindings.errors.length > 0) return { flags: undefined, errors: bindings.errors };
|
|
42
|
+
if (Object.keys(bindings.byParam).length === 0) return { flags: undefined, errors: [] };
|
|
43
|
+
return { flags: { env, byParam: bindings.byParam }, errors: [] };
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const { WorkspaceReadError } = await import("./workspace/declaration");
|
|
46
|
+
const { RecordReadError } = await import("./workspace/records");
|
|
47
|
+
if (err instanceof WorkspaceReadError || err instanceof RecordReadError) {
|
|
48
|
+
return { flags: undefined, errors: [`the workspace's flag records can't be read, so this build can't tell which parameters they set: ${err.message}`] };
|
|
49
|
+
}
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The parameters a flag backs that `--param`, `--params-file` or an env var set instead. */
|
|
55
|
+
export function overriddenFlagParams(provenance: readonly BuildParamProvenance[], flags: BuildParamFlags | undefined): BuildParamProvenance[] {
|
|
56
|
+
if (!flags) return [];
|
|
57
|
+
return provenance.filter((p) => flags.byParam[p.name] !== undefined && (p.source === "cli" || p.source === "params-file" || p.source === "env"));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The gates the member's components declare in the environment the process
|
|
62
|
+
* builds for (`CHANT_ENV`), with the parameters as resolved, or why the
|
|
63
|
+
* components can't be read. Only components enabled under those parameters
|
|
64
|
+
* count.
|
|
65
|
+
*/
|
|
66
|
+
export async function environmentGates(projectDir: string, provenance: BuildParamProvenance[]): Promise<{ gates: string[] } | { error: string }> {
|
|
67
|
+
const { discoverComponents } = await import("./components/discover");
|
|
68
|
+
const { withoutDisabled } = await import("./components/cli-support");
|
|
69
|
+
const { gateNamesOf } = await import("./components/release-gate");
|
|
70
|
+
try {
|
|
71
|
+
const discovered = await discoverComponents(projectDir, { buildParams: provenance });
|
|
72
|
+
if (discovered.errors.length > 0) return { error: discovered.errors.map((e) => e.message).join("; ") };
|
|
73
|
+
const all = [...discovered.components.values()].map((d) => d.component);
|
|
74
|
+
const plain = all.map((c) => ({ name: c.name, dependsOn: c.dependsOn, deploy: c.deploy as never }));
|
|
75
|
+
return { gates: gateNamesOf(withoutDisabled(all, plain)) };
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the build parameters of the project at `projectDir` for `env`,
|
|
83
|
+
* with the workspace's flags, as `resolveCliBuildParams` does without them.
|
|
84
|
+
* Refuses when a flag record can't be read, and when `--param`,
|
|
85
|
+
* `--params-file` or an env var sets a flag-backed parameter in an
|
|
86
|
+
* environment with a gate. Prints the summary line only on success.
|
|
87
|
+
*/
|
|
88
|
+
export async function resolveFlaggedBuildParams(
|
|
89
|
+
projectDir: string,
|
|
90
|
+
buildParamsConfig: BuildParamsConfig | undefined,
|
|
91
|
+
args: CliBuildParamsArgs,
|
|
92
|
+
env: string | undefined,
|
|
93
|
+
): Promise<CliBuildParamsResolution> {
|
|
94
|
+
const loaded = await loadBuildParamFlags(projectDir, env);
|
|
95
|
+
if (loaded.errors.length > 0) {
|
|
96
|
+
return { success: false, provenance: [], errors: loaded.errors.map((message) => formatError({ message })) };
|
|
97
|
+
}
|
|
98
|
+
const { flags } = loaded;
|
|
99
|
+
const resolution = resolveCliBuildParams(buildParamsConfig, { ...args, ...(flags ? { flags } : {}), echo: false });
|
|
100
|
+
if (!resolution.success || !flags) {
|
|
101
|
+
if (resolution.success && args.echo !== false) echoBuildParams(resolution.provenance, args.verbose);
|
|
102
|
+
return resolution;
|
|
103
|
+
}
|
|
104
|
+
const overridden = overriddenFlagParams(resolution.provenance, flags);
|
|
105
|
+
if (overridden.length > 0) {
|
|
106
|
+
const found = await environmentGates(projectDir, resolution.provenance);
|
|
107
|
+
if ("error" in found) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
provenance: [],
|
|
111
|
+
errors: [
|
|
112
|
+
formatError({
|
|
113
|
+
message:
|
|
114
|
+
`${overridden.map((p) => `"${p.name}"`).join(", ")} ${overridden.length === 1 ? "is" : "are"} backed by a flag and set by ${[...new Set(overridden.map((p) => p.source))].join(", ")}, ` +
|
|
115
|
+
`and whether "${flags.env}" has a gate can't be told, because its components can't be read: ${found.error}`,
|
|
116
|
+
}),
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (found.gates.length > 0) {
|
|
121
|
+
const around = (p: BuildParamProvenance): string =>
|
|
122
|
+
p.source === "cli" ? "--param" : p.source === "params-file" ? "--params-file" : `the env var ${buildParamsConfig?.[p.name]?.env ?? "(unknown)"}`;
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
provenance: [],
|
|
126
|
+
errors: overridden.map((p) =>
|
|
127
|
+
formatError({ message: `${flagGateRefusal(p.name, flags.byParam[p.name].flag, flags.env, around(p))} (gates: ${found.gates.join(", ")})` }),
|
|
128
|
+
),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (args.echo !== false) echoBuildParams(resolution.provenance, args.verbose);
|
|
133
|
+
return resolution;
|
|
134
|
+
}
|