@intentius/chant 0.124.31 → 0.124.32

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.
Files changed (321) hide show
  1. package/bin/chant +7 -2
  2. package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
  3. package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
  4. package/dist/cli/commands/check-lexicon-plugin.js +10 -7
  5. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  6. package/dist/cli/commands/check-lexicon.js +18 -12
  7. package/dist/cli/commands/import.d.ts +10 -0
  8. package/dist/cli/commands/import.d.ts.map +1 -1
  9. package/dist/cli/commands/import.js +37 -0
  10. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  11. package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
  12. package/dist/cli/commands/onboard.d.ts.map +1 -1
  13. package/dist/cli/commands/onboard.js +8 -4
  14. package/dist/cli/commands/update.d.ts.map +1 -1
  15. package/dist/cli/commands/update.js +2 -1
  16. package/dist/cli/dependencies.d.ts +18 -0
  17. package/dist/cli/dependencies.d.ts.map +1 -0
  18. package/dist/cli/dependencies.js +120 -0
  19. package/dist/cli/handlers/build.d.ts.map +1 -1
  20. package/dist/cli/handlers/build.js +23 -4
  21. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  22. package/dist/cli/handlers/fan-out.js +12 -4
  23. package/dist/cli/handlers/graph.d.ts.map +1 -1
  24. package/dist/cli/handlers/graph.js +16 -6
  25. package/dist/cli/handlers/lint.d.ts.map +1 -1
  26. package/dist/cli/handlers/lint.js +6 -0
  27. package/dist/cli/handlers/operator.d.ts +2 -2
  28. package/dist/cli/handlers/operator.js +3 -3
  29. package/dist/cli/handlers/pr.d.ts +14 -0
  30. package/dist/cli/handlers/pr.d.ts.map +1 -1
  31. package/dist/cli/handlers/pr.js +488 -32
  32. package/dist/cli/handlers/promote.d.ts.map +1 -1
  33. package/dist/cli/handlers/promote.js +3 -1
  34. package/dist/cli/handlers/run.d.ts +13 -1
  35. package/dist/cli/handlers/run.d.ts.map +1 -1
  36. package/dist/cli/handlers/run.js +38 -15
  37. package/dist/cli/main.d.ts.map +1 -1
  38. package/dist/cli/main.js +44 -16
  39. package/dist/cli/parse-args.d.ts.map +1 -1
  40. package/dist/cli/parse-args.js +15 -0
  41. package/dist/cli/registry.d.ts +13 -4
  42. package/dist/cli/registry.d.ts.map +1 -1
  43. package/dist/cli/registry.js +6 -2
  44. package/dist/codegen/generate-post-synth-barrel.js +2 -2
  45. package/dist/codegen/lexicon-regen.d.ts +4 -0
  46. package/dist/codegen/lexicon-regen.d.ts.map +1 -1
  47. package/dist/codegen/lexicon-regen.js +1 -1
  48. package/dist/codegen/pinned-upgrade.js +2 -2
  49. package/dist/components/capability.d.ts +44 -3
  50. package/dist/components/capability.d.ts.map +1 -1
  51. package/dist/components/capability.js +21 -0
  52. package/dist/components/changed-files.d.ts +7 -1
  53. package/dist/components/changed-files.d.ts.map +1 -1
  54. package/dist/components/changed-files.js +9 -1
  55. package/dist/components/driver.d.ts +38 -0
  56. package/dist/components/driver.d.ts.map +1 -1
  57. package/dist/components/driver.js +47 -6
  58. package/dist/components/fan-out-record.d.ts +6 -1
  59. package/dist/components/fan-out-record.d.ts.map +1 -1
  60. package/dist/components/fan-out-record.js +24 -0
  61. package/dist/components/fan-out-run.d.ts +20 -0
  62. package/dist/components/fan-out-run.d.ts.map +1 -1
  63. package/dist/components/fan-out-run.js +21 -1
  64. package/dist/components/pr-pipeline.d.ts +65 -2
  65. package/dist/components/pr-pipeline.d.ts.map +1 -1
  66. package/dist/components/pr-pipeline.js +107 -15
  67. package/dist/components/pr-run.d.ts +127 -29
  68. package/dist/components/pr-run.d.ts.map +1 -1
  69. package/dist/components/pr-run.js +290 -70
  70. package/dist/components/wave-plan.d.ts +5 -2
  71. package/dist/components/wave-plan.d.ts.map +1 -1
  72. package/dist/components/wave-plan.js +12 -1
  73. package/dist/discovery/fold-import.d.ts.map +1 -1
  74. package/dist/discovery/fold-import.js +16 -6
  75. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  76. package/dist/discovery/sandbox/bundle.js +6 -0
  77. package/dist/discovery/specifier-resolve.d.ts.map +1 -1
  78. package/dist/discovery/specifier-resolve.js +8 -2
  79. package/dist/fold/fold.d.ts.map +1 -1
  80. package/dist/fold/fold.js +68 -1
  81. package/dist/fold/subset.d.ts +37 -0
  82. package/dist/fold/subset.d.ts.map +1 -1
  83. package/dist/fold/subset.js +88 -0
  84. package/dist/lexicon-module.d.ts +10 -0
  85. package/dist/lexicon-module.d.ts.map +1 -1
  86. package/dist/lexicon-module.js +53 -8
  87. package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
  88. package/dist/lexicon-plugin-helpers.js +6 -4
  89. package/dist/lexicon.d.ts +2 -0
  90. package/dist/lexicon.d.ts.map +1 -1
  91. package/dist/lifecycle/affected.d.ts.map +1 -1
  92. package/dist/lifecycle/affected.js +7 -1
  93. package/dist/lifecycle/release-ledger.d.ts +21 -0
  94. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  95. package/dist/lifecycle/release-ledger.js +24 -0
  96. package/dist/lifecycle/work-dir.d.ts +45 -0
  97. package/dist/lifecycle/work-dir.d.ts.map +1 -0
  98. package/dist/lifecycle/work-dir.js +78 -0
  99. package/dist/lint/discover.d.ts +17 -9
  100. package/dist/lint/discover.d.ts.map +1 -1
  101. package/dist/lint/discover.js +62 -54
  102. package/dist/module-source.d.ts +57 -0
  103. package/dist/module-source.d.ts.map +1 -0
  104. package/dist/module-source.js +104 -0
  105. package/dist/op/activities/factory.js +1 -1
  106. package/dist/op/discover.d.ts.map +1 -1
  107. package/dist/op/discover.js +13 -3
  108. package/dist/op/gate.d.ts.map +1 -1
  109. package/dist/op/gate.js +3 -0
  110. package/dist/op/op-waves-run.d.ts.map +1 -1
  111. package/dist/op/op-waves-run.js +20 -5
  112. package/dist/op/operator.d.ts +2 -2
  113. package/dist/op/operator.js +2 -2
  114. package/dist/op/steward.d.ts +6 -4
  115. package/dist/op/steward.d.ts.map +1 -1
  116. package/dist/op/steward.js +5 -3
  117. package/dist/op/work-lease-run.d.ts +20 -7
  118. package/dist/op/work-lease-run.d.ts.map +1 -1
  119. package/dist/op/work-lease-run.js +56 -12
  120. package/dist/pr-forge.d.ts +10 -0
  121. package/dist/pr-forge.d.ts.map +1 -1
  122. package/dist/pr-forge.js +39 -0
  123. package/dist/pr-loop.d.ts +141 -4
  124. package/dist/pr-loop.d.ts.map +1 -1
  125. package/dist/pr-loop.js +122 -6
  126. package/dist/pr-report-url.d.ts +2 -2
  127. package/dist/pr-report-url.d.ts.map +1 -1
  128. package/dist/pr-report-url.js +5 -5
  129. package/dist/ts-loader.d.ts +38 -4
  130. package/dist/ts-loader.d.ts.map +1 -1
  131. package/dist/ts-loader.js +190 -16
  132. package/dist/wave-runtime.mjs +208 -208
  133. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
  134. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
  135. package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
  136. package/dist/workspace/chant-migrations.d.ts.map +1 -1
  137. package/dist/workspace/chant-migrations.js +2 -0
  138. package/dist/workspace/checks/boxes.d.ts +6 -6
  139. package/dist/workspace/checks/boxes.js +9 -9
  140. package/dist/workspace/ci-green-forge.d.ts +6 -4
  141. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  142. package/dist/workspace/ci-green.d.ts +28 -12
  143. package/dist/workspace/ci-green.d.ts.map +1 -1
  144. package/dist/workspace/ci-green.js +49 -21
  145. package/dist/workspace/ci-list.schema.json +12 -6
  146. package/dist/workspace/ci-report-url.d.ts +18 -0
  147. package/dist/workspace/ci-report-url.d.ts.map +1 -0
  148. package/dist/workspace/ci-report-url.js +33 -0
  149. package/dist/workspace/ci-run-index.d.ts +12 -0
  150. package/dist/workspace/ci-run-index.d.ts.map +1 -1
  151. package/dist/workspace/ci-run-index.js +6 -4
  152. package/dist/workspace/ci-run-index.schema.json +5 -3
  153. package/dist/workspace/ci-run.d.ts +75 -2
  154. package/dist/workspace/ci-run.d.ts.map +1 -1
  155. package/dist/workspace/ci-run.js +195 -53
  156. package/dist/workspace/ci-runner-key.d.ts +16 -3
  157. package/dist/workspace/ci-runner-key.d.ts.map +1 -1
  158. package/dist/workspace/ci-runner-key.js +30 -10
  159. package/dist/workspace/ci-serve.d.ts +54 -4
  160. package/dist/workspace/ci-serve.d.ts.map +1 -1
  161. package/dist/workspace/ci-serve.js +175 -26
  162. package/dist/workspace/declaration.d.ts +8 -0
  163. package/dist/workspace/declaration.d.ts.map +1 -1
  164. package/dist/workspace/declaration.js +11 -2
  165. package/dist/workspace/declaration.schema.json +7 -2
  166. package/dist/workspace/export.d.ts +1 -1
  167. package/dist/workspace/export.d.ts.map +1 -1
  168. package/dist/workspace/export.js +7 -3
  169. package/dist/workspace/ls.d.ts +6 -1
  170. package/dist/workspace/ls.d.ts.map +1 -1
  171. package/dist/workspace/ls.js +1 -0
  172. package/dist/workspace/ls.schema.json +7 -1
  173. package/dist/workspace/pin-integrity.d.ts.map +1 -1
  174. package/dist/workspace/pin-integrity.js +3 -2
  175. package/dist/workspace/pr-report.schema.json +74 -7
  176. package/dist/workspace/reason-codes.d.ts +1 -1
  177. package/dist/workspace/reason-codes.d.ts.map +1 -1
  178. package/dist/workspace/reason-codes.js +2 -2
  179. package/dist/workspace/run-event.schema.json +3 -1
  180. package/dist/workspace/status.schema.json +3 -1
  181. package/dist/workspace/write-scope.d.ts +9 -0
  182. package/dist/workspace/write-scope.d.ts.map +1 -1
  183. package/dist/workspace/write-scope.js +11 -1
  184. package/package.json +1 -1
  185. package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
  186. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
  187. package/src/cli/commands/audit.test.ts +2 -2
  188. package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
  189. package/src/cli/commands/check-lexicon-plugin.ts +11 -8
  190. package/src/cli/commands/check-lexicon.test.ts +1 -1
  191. package/src/cli/commands/check-lexicon.ts +16 -11
  192. package/src/cli/commands/import.ts +40 -0
  193. package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
  194. package/src/cli/commands/init-lexicon.test.ts +8 -5
  195. package/src/cli/commands/onboard.test.ts +45 -0
  196. package/src/cli/commands/onboard.ts +8 -4
  197. package/src/cli/commands/update.test.ts +6 -0
  198. package/src/cli/commands/update.ts +4 -1
  199. package/src/cli/compiled-cli.e2e.test.ts +76 -11
  200. package/src/cli/dependencies.e2e.test.ts +101 -0
  201. package/src/cli/dependencies.test.ts +93 -0
  202. package/src/cli/dependencies.ts +122 -0
  203. package/src/cli/handlers/build.test.ts +69 -0
  204. package/src/cli/handlers/build.ts +20 -4
  205. package/src/cli/handlers/fan-out.test.ts +73 -0
  206. package/src/cli/handlers/fan-out.ts +11 -4
  207. package/src/cli/handlers/graph.test.ts +76 -0
  208. package/src/cli/handlers/graph.ts +19 -12
  209. package/src/cli/handlers/lint.test.ts +42 -0
  210. package/src/cli/handlers/lint.ts +6 -0
  211. package/src/cli/handlers/operator.ts +3 -3
  212. package/src/cli/handlers/pr-waves.test.ts +449 -0
  213. package/src/cli/handlers/pr.test.ts +134 -0
  214. package/src/cli/handlers/pr.ts +523 -31
  215. package/src/cli/handlers/promote.test.ts +26 -1
  216. package/src/cli/handlers/promote.ts +3 -2
  217. package/src/cli/handlers/run-components-exit.test.ts +99 -0
  218. package/src/cli/handlers/run-signer.test.ts +79 -0
  219. package/src/cli/handlers/run.ts +34 -16
  220. package/src/cli/main.test.ts +18 -0
  221. package/src/cli/main.ts +43 -16
  222. package/src/cli/parse-args.ts +12 -0
  223. package/src/cli/registry.ts +19 -6
  224. package/src/codegen/generate-post-synth-barrel.ts +2 -2
  225. package/src/codegen/lexicon-regen.ts +1 -1
  226. package/src/codegen/pinned-upgrade.ts +2 -2
  227. package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
  228. package/src/components/capability.ts +51 -3
  229. package/src/components/changed-files.test.ts +16 -1
  230. package/src/components/changed-files.ts +9 -1
  231. package/src/components/driver.test.ts +36 -1
  232. package/src/components/driver.ts +76 -4
  233. package/src/components/fan-out-record.ts +29 -1
  234. package/src/components/fan-out-run.test.ts +35 -0
  235. package/src/components/fan-out-run.ts +40 -1
  236. package/src/components/pr-pipeline.test.ts +100 -0
  237. package/src/components/pr-pipeline.ts +132 -17
  238. package/src/components/pr-run.test.ts +323 -18
  239. package/src/components/pr-run.ts +354 -75
  240. package/src/components/wave-plan.ts +16 -4
  241. package/src/discovery/fold-host-method.test.ts +87 -0
  242. package/src/discovery/fold-import.ts +15 -5
  243. package/src/discovery/fold-package-composite.test.ts +27 -0
  244. package/src/discovery/fold-specifiers.test.ts +8 -0
  245. package/src/discovery/sandbox/bundle.ts +6 -0
  246. package/src/discovery/specifier-resolve.ts +8 -2
  247. package/src/fold/fold.test.ts +72 -0
  248. package/src/fold/fold.ts +71 -0
  249. package/src/fold/subset.test.ts +31 -0
  250. package/src/fold/subset.ts +99 -0
  251. package/src/lexicon-dist.e2e.test.ts +254 -0
  252. package/src/lexicon-module.test.ts +47 -0
  253. package/src/lexicon-module.ts +49 -7
  254. package/src/lexicon-plugin-helpers.ts +6 -4
  255. package/src/lexicon.ts +2 -0
  256. package/src/lifecycle/affected.test.ts +7 -0
  257. package/src/lifecycle/affected.ts +6 -1
  258. package/src/lifecycle/release-ledger.ts +34 -0
  259. package/src/lifecycle/work-dir.test.ts +77 -0
  260. package/src/lifecycle/work-dir.ts +82 -0
  261. package/src/lint/discover.test.ts +46 -2
  262. package/src/lint/discover.ts +55 -49
  263. package/src/module-source.test.ts +85 -0
  264. package/src/module-source.ts +112 -0
  265. package/src/op/activities/factory.ts +1 -1
  266. package/src/op/discover-root.test.ts +31 -2
  267. package/src/op/discover.ts +14 -4
  268. package/src/op/gate.test.ts +30 -0
  269. package/src/op/gate.ts +3 -0
  270. package/src/op/op-waves-run.ts +20 -5
  271. package/src/op/op-waves.test.ts +49 -0
  272. package/src/op/operator.ts +2 -2
  273. package/src/op/steward.ts +6 -4
  274. package/src/op/work-lease-run.test.ts +88 -2
  275. package/src/op/work-lease-run.ts +52 -12
  276. package/src/pr-forge-bundle.test.ts +2 -2
  277. package/src/pr-forge.test.ts +42 -0
  278. package/src/pr-forge.ts +40 -0
  279. package/src/pr-loop-bundle.test.ts +2 -1
  280. package/src/pr-loop.test.ts +117 -1
  281. package/src/pr-loop.ts +252 -10
  282. package/src/pr-report-url.ts +5 -5
  283. package/src/terraform/__fixtures__/advise.test.ts +21 -2
  284. package/src/ts-loader.test.ts +89 -1
  285. package/src/ts-loader.ts +180 -13
  286. package/src/workspace/changes.test.ts +1 -1
  287. package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
  288. package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
  289. package/src/workspace/chant-migrations.e2e.test.ts +5 -0
  290. package/src/workspace/chant-migrations.ts +2 -0
  291. package/src/workspace/checks/boxes.ts +9 -9
  292. package/src/workspace/ci-green-forge.ts +6 -4
  293. package/src/workspace/ci-green-runs.test.ts +53 -11
  294. package/src/workspace/ci-green.test.ts +1 -1
  295. package/src/workspace/ci-green.ts +50 -22
  296. package/src/workspace/ci-list.schema.json +12 -6
  297. package/src/workspace/ci-report-url.test.ts +220 -0
  298. package/src/workspace/ci-report-url.ts +33 -0
  299. package/src/workspace/ci-run-index.schema.json +5 -3
  300. package/src/workspace/ci-run-index.test.ts +42 -3
  301. package/src/workspace/ci-run-index.ts +18 -4
  302. package/src/workspace/ci-run.test.ts +185 -7
  303. package/src/workspace/ci-run.ts +224 -54
  304. package/src/workspace/ci-runner-key.test.ts +55 -17
  305. package/src/workspace/ci-runner-key.ts +36 -11
  306. package/src/workspace/ci-serve.test.ts +150 -6
  307. package/src/workspace/ci-serve.ts +169 -25
  308. package/src/workspace/declaration.schema.json +7 -2
  309. package/src/workspace/declaration.test.ts +23 -0
  310. package/src/workspace/declaration.ts +19 -3
  311. package/src/workspace/export.ts +6 -3
  312. package/src/workspace/ls.schema.json +7 -1
  313. package/src/workspace/ls.ts +7 -2
  314. package/src/workspace/pin-integrity.test.ts +5 -0
  315. package/src/workspace/pin-integrity.ts +3 -2
  316. package/src/workspace/pr-report.schema.json +74 -7
  317. package/src/workspace/reason-codes.ts +2 -2
  318. package/src/workspace/run-event.schema.json +3 -1
  319. package/src/workspace/status.schema.json +3 -1
  320. package/src/workspace/write-scope.test.ts +29 -1
  321. package/src/workspace/write-scope.ts +12 -1
@@ -42,6 +42,25 @@
42
42
  * build is `chant build --env <env>`, or `buildCommand` when the templates
43
43
  * come from several builds (`npm run build`).
44
44
  *
45
+ * With `waveGate` (#4003) the apply runs a wave at a time: `pr-apply
46
+ * --wave-gate <gate>`, each wave planned after the one before it applied. A
47
+ * generator writes one apply job per wave of the component graph
48
+ * (`prLoopWaveJobs`), job `apply-wave-<k>` passing `--wave <k>` and needing
49
+ * the job before it, and the attempt record carries the approved set from
50
+ * one job to the next. A wave whose plan the approved change set covers
51
+ * applies under the pull request's approval; one whose plan moved stops at
52
+ * `<gate>-wave-<k>` (exit 3), and re-running its job after the approval
53
+ * carries on. `chant ci serve` runs the one apply job, which runs the waves
54
+ * in order until one stops.
55
+ *
56
+ * Each generated job runs its command through `chant ci run plan|apply
57
+ * --in-place` (#4156, `PrLoopJob.run`), so a forge job writes the same run
58
+ * record the chant runner does: Op `pr-plan` or `pr-apply`, signed with
59
+ * the runner key a forge secret puts in `CHANT_RUNNER_KEY`, and naming the
60
+ * forge's run as its `runOrigin`. `ci run` runs `command` in the job's own
61
+ * checkout with the job's environment, less the key. The plan passes
62
+ * `--no-push`, so it still writes nothing to the remote `chant/lifecycle`.
63
+ *
45
64
  * In a workspace member (#3465) both commands run in the member's directory
46
65
  * and pass `--member <name>`, so the member's gate (`pr-<number>-<member>`),
47
66
  * note and statuses stay apart from every other member's on the same pull
@@ -52,6 +71,13 @@
52
71
  import type { ForgeKind } from "../pr-forge";
53
72
  import { PR_APPLY_GATE } from "../pr-loop";
54
73
  import { CI_IMAGE, GITHUB_JOB_TOKEN } from "../ci-jobs";
74
+ import { EMPTY_TREE_SHA } from "./changed-files";
75
+ import { layerWaves } from "../gated-waves";
76
+ import type { DriverComponent } from "./driver";
77
+ import type { GatedWavePipelineOptions } from "./gated-wave-pipeline";
78
+
79
+ /** The variable `chant ci run` reads its runner key from (`RUNNER_KEY_ENV` in ../workspace/ci-green.ts). */
80
+ const RUNNER_KEY_ENV = "CHANT_RUNNER_KEY";
55
81
 
56
82
  /** Where both jobs write their reports, kept as a CI artifact. */
57
83
  export const PR_LOOP_REPORT_DIR = ".chant/pr";
@@ -125,6 +151,12 @@ export interface PrLoopPipelineOptions {
125
151
  * `npm run build`. Setting it turns `build` on.
126
152
  */
127
153
  buildCommand?: string;
154
+ /**
155
+ * A gate per wave on merge (#4003): the apply runs `pr-apply --wave-gate
156
+ * <waveGate>`, a wave at a time, and a generator writes one apply job per
157
+ * wave. Set from `--wave-gate` beside `--pr-loop` ({@link prLoopWithWaves}).
158
+ */
159
+ waveGate?: string;
128
160
  /**
129
161
  * Which GitHub-shaped forge the workflow is for. Set by the forgejo
130
162
  * generator, which reuses the github one; a caller never needs to.
@@ -148,6 +180,17 @@ export interface PrLoopJob {
148
180
  setup?: string[];
149
181
  /** With `build` (#4088): the build line and the lint line, run in this order before the command. */
150
182
  build?: string[];
183
+ /** With `waveGate` (#4003): the wave a generated apply job runs, 1-based. */
184
+ wave?: number;
185
+ /**
186
+ * What the generated job runs in place of `command` (#4156): `chant ci run
187
+ * <job> --in-place` with the same environment, gate, forge, events and
188
+ * report URL, which runs `command` and records the run. `env` is the
189
+ * job's `env` and, on GitHub and Forgejo, `CHANT_RUNNER_KEY` from the
190
+ * repository secret of that name. GitLab hands its CI/CD variables to a
191
+ * job itself.
192
+ */
193
+ run: { command: string; env: Record<string, string> };
151
194
  }
152
195
 
153
196
  /** The lines `build` (#4088) runs before a job's command: the build, then the lint. Empty without the option. */
@@ -176,29 +219,82 @@ export function prLoopJobs(forge: ForgeKind, env: string, options: PrLoopPipelin
176
219
  ...(github ? { GITHUB_TOKEN: GITHUB_JOB_TOKEN } : {}),
177
220
  ...(options.events ? { CHANT_RUN_EVENTS_DIR: PR_LOOP_EVENTS_DIR } : {}),
178
221
  };
222
+ // #4156: the flags `chant ci run` rebuilds `command` from. It finds the member from the directory it runs in.
223
+ const ciRun = (job: "plan" | "apply"): string[] => [
224
+ "chant", "ci", "run", job, "--in-place", ...(job === "plan" ? ["--no-push"] : []),
225
+ "--base", '"$BASE_SHA"', ...(job === "plan" ? ["--pr", '"$PR_NUMBER"'] : []),
226
+ "--env", env, "--gate", gate, "--forge", forge,
227
+ ...(options.waveGate ? ["--wave-gate", options.waveGate] : []),
228
+ ...(job === "apply" && options.branch ? ["--branch", JSON.stringify(options.branch)] : []),
229
+ ...(job === "apply" && options.requireReview === false ? ["--no-require-review"] : []),
230
+ ...(options.events ? ["--events-json"] : []),
231
+ ...(options.reportUrl ? ["--report-url", JSON.stringify(options.reportUrl)] : []),
232
+ ];
233
+ const runEnv = (env: Record<string, string>): Record<string, string> => (github ? { ...env, [RUNNER_KEY_ENV]: `\${{ secrets.${RUNNER_KEY_ENV} }}` } : env);
234
+ const planEnv = github
235
+ ? { BASE_SHA: "${{ github.event.pull_request.base.sha }}", PR_NUMBER: "${{ github.event.pull_request.number }}", ...jobEnv }
236
+ : { BASE_SHA: "$CI_MERGE_REQUEST_DIFF_BASE_SHA", PR_NUMBER: "$CI_MERGE_REQUEST_IID", ...jobEnv };
237
+ const applyEnv = github ? { BASE_SHA: "${{ github.event.before }}", ...jobEnv } : { BASE_SHA: "$CI_COMMIT_BEFORE_SHA", ...jobEnv };
179
238
  return [
180
239
  {
181
240
  jobName: "plan",
182
- command: ["chant", "components", "pr-plan", "--base", '"$BASE_SHA"', "--pr", '"$PR_NUMBER"', ...common].join(" "),
183
- env: github
184
- ? { BASE_SHA: "${{ github.event.pull_request.base.sha }}", PR_NUMBER: "${{ github.event.pull_request.number }}", ...jobEnv }
185
- : { BASE_SHA: "$CI_MERGE_REQUEST_DIFF_BASE_SHA", PR_NUMBER: "$CI_MERGE_REQUEST_IID", ...jobEnv },
241
+ // With `waveGate` the plan's note says the later waves may stop at their own gates (#4003).
242
+ command: ["chant", "components", "pr-plan", "--base", '"$BASE_SHA"', "--pr", '"$PR_NUMBER"', ...common, ...(options.waveGate ? ["--wave-gate", options.waveGate] : [])].join(" "),
243
+ env: planEnv,
186
244
  ...build,
245
+ run: { command: ciRun("plan").join(" "), env: runEnv(planEnv) },
187
246
  },
188
247
  {
189
248
  jobName: "apply",
190
249
  command: [
191
250
  "chant", "components", "pr-apply", "--base", '"$BASE_SHA"', ...common,
192
251
  ...(options.requireReview === false ? [] : ["--require-review"]),
252
+ ...(options.waveGate ? ["--wave-gate", options.waveGate] : []),
193
253
  "--resume", PR_APPLY_RECORD,
194
254
  ].join(" "),
195
- env: github ? { BASE_SHA: "${{ github.event.before }}", ...jobEnv } : { BASE_SHA: "$CI_COMMIT_BEFORE_SHA", ...jobEnv },
196
- ...(github ? {} : { setup: [gitlabBaseFallback(options.branch)] }),
255
+ env: applyEnv,
256
+ setup: [github ? githubBaseFallback(options.branch) : gitlabBaseFallback(options.branch)],
197
257
  ...build,
258
+ run: { command: ciRun("apply").join(" "), env: runEnv(applyEnv) },
198
259
  },
199
260
  ];
200
261
  }
201
262
 
263
+ /**
264
+ * The pull-request options with `--wave-gate` beside `--pr-loop` (#4003):
265
+ * the apply gets a gate per wave. A canary or a fixed base is refused, since
266
+ * the pull request's waves are its derivation's and each push is measured
267
+ * from the commit before it.
268
+ */
269
+ export function prLoopWithWaves(prLoop: PrLoopPipelineOptions, gatedWaves?: GatedWavePipelineOptions): PrLoopPipelineOptions {
270
+ if (!gatedWaves) return prLoop;
271
+ if (gatedWaves.canary?.length) throw new Error("a pull-request pipeline's waves are the change's derivation, so it takes no --canary; drop --canary");
272
+ if (gatedWaves.base !== undefined) throw new Error("a pull-request pipeline measures each push from the commit before it, so it takes no --base; drop --base");
273
+ return { ...prLoop, waveGate: gatedWaves.gate };
274
+ }
275
+
276
+ /** The name of the apply job for wave `wave` (#4003). */
277
+ export function prApplyWaveJobName(wave: number): string {
278
+ return `apply-wave-${wave}`;
279
+ }
280
+
281
+ /**
282
+ * One apply job per wave of the component graph (#4003), each `apply`'s
283
+ * command with `--wave <k>`. A change selects a subset, which never layers
284
+ * deeper than the graph, so a job past the change's last wave finds nothing
285
+ * left and exits 0.
286
+ */
287
+ export function prLoopWaveJobs(components: DriverComponent[], apply: PrLoopJob): PrLoopJob[] {
288
+ const count = Math.max(1, layerWaves(components.map((c) => ({ name: c.name, dependsOn: c.dependsOn ?? [] }))).length);
289
+ return Array.from({ length: count }, (_, i) => ({
290
+ ...apply,
291
+ command: `${apply.command} --wave ${i + 1}`,
292
+ wave: i + 1,
293
+ // #4156: the job runs it through chant ci run, which appends the same --wave to pr-apply.
294
+ run: { ...apply.run, command: `${apply.run.command} --wave ${i + 1}` },
295
+ }));
296
+ }
297
+
202
298
  /**
203
299
  * The concurrency group (GitHub, Forgejo) or resource group (GitLab) that
204
300
  * keeps one apply at a time per environment, and per member in a workspace.
@@ -227,19 +323,38 @@ export function prApplyRecordKey(env: string, commit: string, member?: string):
227
323
  }
228
324
 
229
325
  /**
230
- * GitLab sets `CI_COMMIT_BEFORE_SHA` to forty zeros on a branch's first push.
231
- * The line replaces it with the merge request's diff base when the pipeline
232
- * has one, and otherwise with the merge base of the target branch and the
233
- * pushed commit, or the pushed commit's parent when that is the commit itself.
326
+ * The shell that settles an unusable push base. `before` is empty or forty
327
+ * zeros on a branch's first push; then the base is `diffBase` when the forge
328
+ * gives one, else the merge base of `target` and `commit`, else `commit`'s
329
+ * parent when the merge base is `commit` itself, else, for a root commit, the
330
+ * empty tree.
234
331
  */
235
- export function gitlabBaseFallback(branch?: string): string {
236
- const target = branch ? JSON.stringify(branch) : "$CI_DEFAULT_BRANCH";
332
+ function pushBaseFallback(target: string, commit: string, diffBase?: string): string {
333
+ const fromBranch =
334
+ `git fetch origin ${target} && BASE_SHA="$(git merge-base FETCH_HEAD "${commit}")"; ` +
335
+ `if [ "$BASE_SHA" = "${commit}" ]; then BASE_SHA="$(git rev-parse --verify --quiet "${commit}^" || echo ${EMPTY_TREE_SHA})"; fi; `;
237
336
  return (
238
337
  'if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then ' +
239
- 'BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA:-}"; ' +
240
- 'if [ -z "$BASE_SHA" ]; then ' +
241
- `git fetch origin ${target} && BASE_SHA="$(git merge-base FETCH_HEAD "$CI_COMMIT_SHA")"; ` +
242
- 'if [ "$BASE_SHA" = "$CI_COMMIT_SHA" ]; then BASE_SHA="$(git rev-parse "$CI_COMMIT_SHA^")"; fi; ' +
243
- "fi; fi; export BASE_SHA"
338
+ (diffBase ? `BASE_SHA="\${${diffBase}:-}"; if [ -z "$BASE_SHA" ]; then ${fromBranch}fi; ` : fromBranch) +
339
+ "fi; export BASE_SHA"
244
340
  );
245
341
  }
342
+
343
+ /**
344
+ * GitLab sets `CI_COMMIT_BEFORE_SHA` to forty zeros on a branch's first push.
345
+ * The line replaces it with the merge request's diff base when the pipeline
346
+ * has one, and otherwise as {@link pushBaseFallback} does.
347
+ */
348
+ export function gitlabBaseFallback(branch?: string): string {
349
+ return pushBaseFallback(branch ? JSON.stringify(branch) : "$CI_DEFAULT_BRANCH", "$CI_COMMIT_SHA", "CI_MERGE_REQUEST_DIFF_BASE_SHA");
350
+ }
351
+
352
+ /**
353
+ * GitHub and Forgejo set `github.event.before` to forty zeros on a branch's
354
+ * first push (#4004). The line replaces it as {@link pushBaseFallback} does,
355
+ * with the target branch `main` unless the pipeline names another, the
356
+ * generators' default.
357
+ */
358
+ export function githubBaseFallback(branch?: string): string {
359
+ return pushBaseFallback(JSON.stringify(branch ?? "main"), "$GITHUB_SHA");
360
+ }