@intentius/chant 0.124.31 → 0.124.33

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 (509) hide show
  1. package/bin/chant +7 -2
  2. package/dist/ci-jobs.d.ts +4 -0
  3. package/dist/ci-jobs.d.ts.map +1 -1
  4. package/dist/ci-jobs.js +9 -2
  5. package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
  6. package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
  7. package/dist/cli/commands/check-lexicon-plugin.js +10 -7
  8. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  9. package/dist/cli/commands/check-lexicon.js +18 -12
  10. package/dist/cli/commands/import.d.ts +10 -0
  11. package/dist/cli/commands/import.d.ts.map +1 -1
  12. package/dist/cli/commands/import.js +37 -0
  13. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  14. package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
  15. package/dist/cli/commands/onboard.d.ts.map +1 -1
  16. package/dist/cli/commands/onboard.js +8 -4
  17. package/dist/cli/commands/update.d.ts.map +1 -1
  18. package/dist/cli/commands/update.js +2 -1
  19. package/dist/cli/dependencies.d.ts +18 -0
  20. package/dist/cli/dependencies.d.ts.map +1 -0
  21. package/dist/cli/dependencies.js +120 -0
  22. package/dist/cli/handlers/build.d.ts.map +1 -1
  23. package/dist/cli/handlers/build.js +38 -4
  24. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  25. package/dist/cli/handlers/fan-out.js +12 -4
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/graph.js +16 -6
  28. package/dist/cli/handlers/lifecycle-health.d.ts +16 -0
  29. package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
  30. package/dist/cli/handlers/lifecycle-health.js +150 -0
  31. package/dist/cli/handlers/lifecycle.d.ts +26 -0
  32. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  33. package/dist/cli/handlers/lifecycle.js +1 -1
  34. package/dist/cli/handlers/lint.d.ts.map +1 -1
  35. package/dist/cli/handlers/lint.js +6 -0
  36. package/dist/cli/handlers/operator.d.ts +2 -2
  37. package/dist/cli/handlers/operator.js +3 -3
  38. package/dist/cli/handlers/pr.d.ts +16 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -1
  40. package/dist/cli/handlers/pr.js +610 -32
  41. package/dist/cli/handlers/promote.d.ts.map +1 -1
  42. package/dist/cli/handlers/promote.js +19 -2
  43. package/dist/cli/handlers/release.d.ts +16 -1
  44. package/dist/cli/handlers/release.d.ts.map +1 -1
  45. package/dist/cli/handlers/release.js +83 -11
  46. package/dist/cli/handlers/run.d.ts +13 -1
  47. package/dist/cli/handlers/run.d.ts.map +1 -1
  48. package/dist/cli/handlers/run.js +38 -15
  49. package/dist/cli/main.d.ts.map +1 -1
  50. package/dist/cli/main.js +121 -33
  51. package/dist/cli/parse-args.d.ts.map +1 -1
  52. package/dist/cli/parse-args.js +37 -0
  53. package/dist/cli/registry.d.ts +29 -6
  54. package/dist/cli/registry.d.ts.map +1 -1
  55. package/dist/cli/registry.js +6 -2
  56. package/dist/codegen/generate-post-synth-barrel.js +2 -2
  57. package/dist/codegen/lexicon-regen.d.ts +4 -0
  58. package/dist/codegen/lexicon-regen.d.ts.map +1 -1
  59. package/dist/codegen/lexicon-regen.js +1 -1
  60. package/dist/codegen/pinned-upgrade.js +2 -2
  61. package/dist/components/capability.d.ts +44 -3
  62. package/dist/components/capability.d.ts.map +1 -1
  63. package/dist/components/capability.js +21 -0
  64. package/dist/components/changed-files.d.ts +7 -1
  65. package/dist/components/changed-files.d.ts.map +1 -1
  66. package/dist/components/changed-files.js +9 -1
  67. package/dist/components/deploy-inputs.d.ts +91 -0
  68. package/dist/components/deploy-inputs.d.ts.map +1 -0
  69. package/dist/components/deploy-inputs.js +184 -0
  70. package/dist/components/driver.d.ts +38 -0
  71. package/dist/components/driver.d.ts.map +1 -1
  72. package/dist/components/driver.js +56 -6
  73. package/dist/components/fan-out-record.d.ts +6 -1
  74. package/dist/components/fan-out-record.d.ts.map +1 -1
  75. package/dist/components/fan-out-record.js +24 -0
  76. package/dist/components/fan-out-run.d.ts +20 -0
  77. package/dist/components/fan-out-run.d.ts.map +1 -1
  78. package/dist/components/fan-out-run.js +21 -1
  79. package/dist/components/gate-plan.d.ts +8 -0
  80. package/dist/components/gate-plan.d.ts.map +1 -1
  81. package/dist/components/gate-plan.js +6 -0
  82. package/dist/components/pr-pipeline.d.ts +98 -12
  83. package/dist/components/pr-pipeline.d.ts.map +1 -1
  84. package/dist/components/pr-pipeline.js +146 -23
  85. package/dist/components/pr-run.d.ts +128 -30
  86. package/dist/components/pr-run.d.ts.map +1 -1
  87. package/dist/components/pr-run.js +290 -70
  88. package/dist/components/release-compile.d.ts +37 -2
  89. package/dist/components/release-compile.d.ts.map +1 -1
  90. package/dist/components/release-compile.js +64 -8
  91. package/dist/components/release-promote.d.ts +17 -3
  92. package/dist/components/release-promote.d.ts.map +1 -1
  93. package/dist/components/release-promote.js +79 -18
  94. package/dist/components/verbs/bom-writer.d.ts +1 -1
  95. package/dist/components/verbs/bom-writer.d.ts.map +1 -1
  96. package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
  97. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
  98. package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
  99. package/dist/components/wave-plan.d.ts +15 -2
  100. package/dist/components/wave-plan.d.ts.map +1 -1
  101. package/dist/components/wave-plan.js +44 -5
  102. package/dist/discovery/fold-import.d.ts.map +1 -1
  103. package/dist/discovery/fold-import.js +16 -6
  104. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  105. package/dist/discovery/sandbox/bundle.js +6 -0
  106. package/dist/discovery/specifier-resolve.d.ts.map +1 -1
  107. package/dist/discovery/specifier-resolve.js +8 -2
  108. package/dist/fold/fold.d.ts.map +1 -1
  109. package/dist/fold/fold.js +68 -1
  110. package/dist/fold/subset.d.ts +37 -0
  111. package/dist/fold/subset.d.ts.map +1 -1
  112. package/dist/fold/subset.js +88 -0
  113. package/dist/graph-detail.d.ts.map +1 -1
  114. package/dist/graph-detail.js +32 -7
  115. package/dist/health.d.ts +110 -0
  116. package/dist/health.d.ts.map +1 -0
  117. package/dist/health.js +105 -0
  118. package/dist/health.schema.json +191 -0
  119. package/dist/lexicon-module.d.ts +10 -0
  120. package/dist/lexicon-module.d.ts.map +1 -1
  121. package/dist/lexicon-module.js +53 -8
  122. package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
  123. package/dist/lexicon-plugin-helpers.js +6 -4
  124. package/dist/lexicon.d.ts +29 -0
  125. package/dist/lexicon.d.ts.map +1 -1
  126. package/dist/lifecycle/affected.d.ts.map +1 -1
  127. package/dist/lifecycle/affected.js +7 -1
  128. package/dist/lifecycle/merge-record.d.ts +104 -0
  129. package/dist/lifecycle/merge-record.d.ts.map +1 -0
  130. package/dist/lifecycle/merge-record.js +102 -0
  131. package/dist/lifecycle/publish-attachments.d.ts +8 -5
  132. package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
  133. package/dist/lifecycle/publish-attachments.js +27 -13
  134. package/dist/lifecycle/publish-npm.d.ts +3 -2
  135. package/dist/lifecycle/publish-npm.d.ts.map +1 -1
  136. package/dist/lifecycle/publish-npm.js +4 -3
  137. package/dist/lifecycle/release-at.d.ts +40 -0
  138. package/dist/lifecycle/release-at.d.ts.map +1 -0
  139. package/dist/lifecycle/release-at.js +83 -0
  140. package/dist/lifecycle/release-cut.d.ts.map +1 -1
  141. package/dist/lifecycle/release-cut.js +23 -12
  142. package/dist/lifecycle/release-ledger.d.ts +21 -0
  143. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  144. package/dist/lifecycle/release-ledger.js +24 -0
  145. package/dist/lifecycle/release-publish.d.ts +28 -12
  146. package/dist/lifecycle/release-publish.d.ts.map +1 -1
  147. package/dist/lifecycle/release-publish.js +29 -17
  148. package/dist/lifecycle/release-store.d.ts +25 -2
  149. package/dist/lifecycle/release-store.d.ts.map +1 -1
  150. package/dist/lifecycle/release-store.js +40 -13
  151. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/run-ledger.js +1 -0
  153. package/dist/lifecycle/work-dir.d.ts +45 -0
  154. package/dist/lifecycle/work-dir.d.ts.map +1 -0
  155. package/dist/lifecycle/work-dir.js +78 -0
  156. package/dist/lint/discover.d.ts +17 -9
  157. package/dist/lint/discover.d.ts.map +1 -1
  158. package/dist/lint/discover.js +62 -54
  159. package/dist/lint/rules/op/index.d.ts +2 -1
  160. package/dist/lint/rules/op/index.d.ts.map +1 -1
  161. package/dist/lint/rules/op/index.js +4 -2
  162. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
  163. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
  164. package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
  165. package/dist/module-source.d.ts +57 -0
  166. package/dist/module-source.d.ts.map +1 -0
  167. package/dist/module-source.js +104 -0
  168. package/dist/op/activities/activity-contracts.d.ts +5 -0
  169. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  170. package/dist/op/activities/activity-contracts.js +3 -0
  171. package/dist/op/activities/factory.js +1 -1
  172. package/dist/op/activities/shell.d.ts +38 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -1
  174. package/dist/op/activities/shell.js +89 -3
  175. package/dist/op/builders.d.ts +7 -0
  176. package/dist/op/builders.d.ts.map +1 -1
  177. package/dist/op/builders.js +7 -0
  178. package/dist/op/discover.d.ts.map +1 -1
  179. package/dist/op/discover.js +13 -3
  180. package/dist/op/gate.d.ts.map +1 -1
  181. package/dist/op/gate.js +3 -0
  182. package/dist/op/op-waves-run.d.ts.map +1 -1
  183. package/dist/op/op-waves-run.js +20 -5
  184. package/dist/op/operator.d.ts +2 -2
  185. package/dist/op/operator.js +2 -2
  186. package/dist/op/runtime.d.ts +2 -0
  187. package/dist/op/runtime.d.ts.map +1 -1
  188. package/dist/op/steward.d.ts +6 -4
  189. package/dist/op/steward.d.ts.map +1 -1
  190. package/dist/op/steward.js +5 -3
  191. package/dist/op/work-lease-run.d.ts +20 -7
  192. package/dist/op/work-lease-run.d.ts.map +1 -1
  193. package/dist/op/work-lease-run.js +56 -12
  194. package/dist/pr-forge.d.ts +10 -0
  195. package/dist/pr-forge.d.ts.map +1 -1
  196. package/dist/pr-forge.js +39 -0
  197. package/dist/pr-loop.d.ts +155 -7
  198. package/dist/pr-loop.d.ts.map +1 -1
  199. package/dist/pr-loop.js +137 -11
  200. package/dist/pr-report-url.d.ts +4 -4
  201. package/dist/pr-report-url.d.ts.map +1 -1
  202. package/dist/pr-report-url.js +5 -5
  203. package/dist/runner-start.d.ts +179 -0
  204. package/dist/runner-start.d.ts.map +1 -0
  205. package/dist/runner-start.js +277 -0
  206. package/dist/ts-loader.d.ts +38 -4
  207. package/dist/ts-loader.d.ts.map +1 -1
  208. package/dist/ts-loader.js +190 -16
  209. package/dist/wave-runtime.mjs +238 -231
  210. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
  211. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
  212. package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
  213. package/dist/workspace/chant-migrations.d.ts.map +1 -1
  214. package/dist/workspace/chant-migrations.js +2 -0
  215. package/dist/workspace/check.schema.json +70 -2
  216. package/dist/workspace/checks/boxes.d.ts +6 -6
  217. package/dist/workspace/checks/boxes.js +9 -9
  218. package/dist/workspace/checks/security.d.ts +35 -0
  219. package/dist/workspace/checks/security.d.ts.map +1 -0
  220. package/dist/workspace/checks/security.js +305 -0
  221. package/dist/workspace/checks.d.ts +2 -0
  222. package/dist/workspace/checks.d.ts.map +1 -1
  223. package/dist/workspace/checks.js +5 -0
  224. package/dist/workspace/ci-builds.d.ts +163 -0
  225. package/dist/workspace/ci-builds.d.ts.map +1 -0
  226. package/dist/workspace/ci-builds.js +315 -0
  227. package/dist/workspace/ci-green-cli.d.ts +2 -1
  228. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  229. package/dist/workspace/ci-green-cli.js +25 -5
  230. package/dist/workspace/ci-green-forge.d.ts +18 -4
  231. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  232. package/dist/workspace/ci-green-forge.js +12 -0
  233. package/dist/workspace/ci-green-workflow.d.ts +55 -1
  234. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  235. package/dist/workspace/ci-green-workflow.js +128 -1
  236. package/dist/workspace/ci-green.d.ts +117 -16
  237. package/dist/workspace/ci-green.d.ts.map +1 -1
  238. package/dist/workspace/ci-green.js +358 -43
  239. package/dist/workspace/ci-last-green.schema.json +49 -0
  240. package/dist/workspace/ci-list.schema.json +47 -7
  241. package/dist/workspace/ci-report-url.d.ts +18 -0
  242. package/dist/workspace/ci-report-url.d.ts.map +1 -0
  243. package/dist/workspace/ci-report-url.js +33 -0
  244. package/dist/workspace/ci-run-index.d.ts +13 -1
  245. package/dist/workspace/ci-run-index.d.ts.map +1 -1
  246. package/dist/workspace/ci-run-index.js +6 -4
  247. package/dist/workspace/ci-run-index.schema.json +6 -4
  248. package/dist/workspace/ci-run.d.ts +85 -6
  249. package/dist/workspace/ci-run.d.ts.map +1 -1
  250. package/dist/workspace/ci-run.js +262 -64
  251. package/dist/workspace/ci-runner-key.d.ts +16 -3
  252. package/dist/workspace/ci-runner-key.d.ts.map +1 -1
  253. package/dist/workspace/ci-runner-key.js +30 -10
  254. package/dist/workspace/ci-runner-start.d.ts +77 -0
  255. package/dist/workspace/ci-runner-start.d.ts.map +1 -0
  256. package/dist/workspace/ci-runner-start.js +185 -0
  257. package/dist/workspace/ci-serve.d.ts +130 -11
  258. package/dist/workspace/ci-serve.d.ts.map +1 -1
  259. package/dist/workspace/ci-serve.js +323 -40
  260. package/dist/workspace/declaration.d.ts +25 -0
  261. package/dist/workspace/declaration.d.ts.map +1 -1
  262. package/dist/workspace/declaration.js +14 -2
  263. package/dist/workspace/declaration.schema.json +30 -2
  264. package/dist/workspace/export.d.ts +1 -1
  265. package/dist/workspace/export.d.ts.map +1 -1
  266. package/dist/workspace/export.js +7 -3
  267. package/dist/workspace/ls.d.ts +8 -1
  268. package/dist/workspace/ls.d.ts.map +1 -1
  269. package/dist/workspace/ls.js +2 -1
  270. package/dist/workspace/ls.schema.json +9 -2
  271. package/dist/workspace/member-pipeline.d.ts +1 -0
  272. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  273. package/dist/workspace/member-pipeline.js +2 -0
  274. package/dist/workspace/merge-record.schema.json +49 -0
  275. package/dist/workspace/pin-integrity.d.ts.map +1 -1
  276. package/dist/workspace/pin-integrity.js +3 -2
  277. package/dist/workspace/pr-report.schema.json +75 -8
  278. package/dist/workspace/reason-codes.d.ts +18 -1
  279. package/dist/workspace/reason-codes.d.ts.map +1 -1
  280. package/dist/workspace/reason-codes.js +20 -2
  281. package/dist/workspace/release-candidates.d.ts +129 -0
  282. package/dist/workspace/release-candidates.d.ts.map +1 -0
  283. package/dist/workspace/release-candidates.js +233 -0
  284. package/dist/workspace/release-candidates.schema.json +353 -0
  285. package/dist/workspace/run-event.schema.json +3 -1
  286. package/dist/workspace/security.d.ts +40 -0
  287. package/dist/workspace/security.d.ts.map +1 -0
  288. package/dist/workspace/security.js +99 -0
  289. package/dist/workspace/status.schema.json +3 -1
  290. package/dist/workspace/write-scope.d.ts +9 -0
  291. package/dist/workspace/write-scope.d.ts.map +1 -1
  292. package/dist/workspace/write-scope.js +11 -1
  293. package/package.json +8 -1
  294. package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
  295. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
  296. package/src/ci-jobs.ts +11 -2
  297. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
  298. package/src/cli/commands/audit.test.ts +2 -2
  299. package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
  300. package/src/cli/commands/check-lexicon-plugin.ts +11 -8
  301. package/src/cli/commands/check-lexicon.test.ts +1 -1
  302. package/src/cli/commands/check-lexicon.ts +16 -11
  303. package/src/cli/commands/import.ts +40 -0
  304. package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
  305. package/src/cli/commands/init-lexicon.test.ts +8 -5
  306. package/src/cli/commands/onboard.test.ts +45 -0
  307. package/src/cli/commands/onboard.ts +8 -4
  308. package/src/cli/commands/update.test.ts +6 -0
  309. package/src/cli/commands/update.ts +4 -1
  310. package/src/cli/compiled-cli.e2e.test.ts +76 -11
  311. package/src/cli/dependencies.e2e.test.ts +101 -0
  312. package/src/cli/dependencies.test.ts +93 -0
  313. package/src/cli/dependencies.ts +122 -0
  314. package/src/cli/handlers/build.test.ts +105 -0
  315. package/src/cli/handlers/build.ts +35 -4
  316. package/src/cli/handlers/fan-out.test.ts +73 -0
  317. package/src/cli/handlers/fan-out.ts +11 -4
  318. package/src/cli/handlers/graph.test.ts +76 -0
  319. package/src/cli/handlers/graph.ts +19 -12
  320. package/src/cli/handlers/lifecycle-health.test.ts +123 -0
  321. package/src/cli/handlers/lifecycle-health.ts +157 -0
  322. package/src/cli/handlers/lifecycle.ts +1 -1
  323. package/src/cli/handlers/lint.test.ts +42 -0
  324. package/src/cli/handlers/lint.ts +6 -0
  325. package/src/cli/handlers/operator.ts +3 -3
  326. package/src/cli/handlers/pr-deploy-inputs.test.ts +209 -0
  327. package/src/cli/handlers/pr-record.test.ts +201 -0
  328. package/src/cli/handlers/pr-waves.test.ts +449 -0
  329. package/src/cli/handlers/pr.test.ts +156 -0
  330. package/src/cli/handlers/pr.ts +648 -33
  331. package/src/cli/handlers/promote.test.ts +43 -1
  332. package/src/cli/handlers/promote.ts +19 -3
  333. package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
  334. package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
  335. package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
  336. package/src/cli/handlers/release.e2e.test.ts +19 -28
  337. package/src/cli/handlers/release.ts +81 -11
  338. package/src/cli/handlers/run-components-exit.test.ts +99 -0
  339. package/src/cli/handlers/run-signer.test.ts +79 -0
  340. package/src/cli/handlers/run.ts +34 -16
  341. package/src/cli/main.test.ts +18 -0
  342. package/src/cli/main.ts +120 -33
  343. package/src/cli/parse-args.ts +28 -0
  344. package/src/cli/registry.ts +35 -8
  345. package/src/codegen/generate-post-synth-barrel.ts +2 -2
  346. package/src/codegen/lexicon-regen.ts +1 -1
  347. package/src/codegen/pinned-upgrade.ts +2 -2
  348. package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
  349. package/src/components/capability.ts +51 -3
  350. package/src/components/changed-files.test.ts +16 -1
  351. package/src/components/changed-files.ts +9 -1
  352. package/src/components/deploy-inputs.test.ts +108 -0
  353. package/src/components/deploy-inputs.ts +225 -0
  354. package/src/components/driver.test.ts +36 -1
  355. package/src/components/driver.ts +87 -4
  356. package/src/components/fan-out-record.ts +29 -1
  357. package/src/components/fan-out-run.test.ts +35 -0
  358. package/src/components/fan-out-run.ts +40 -1
  359. package/src/components/gate-plan.ts +9 -0
  360. package/src/components/pr-pipeline.test.ts +100 -0
  361. package/src/components/pr-pipeline.ts +184 -28
  362. package/src/components/pr-run.test.ts +323 -18
  363. package/src/components/pr-run.ts +355 -76
  364. package/src/components/release-compile.test.ts +34 -0
  365. package/src/components/release-compile.ts +89 -8
  366. package/src/components/release-promote.test.ts +55 -2
  367. package/src/components/release-promote.ts +93 -23
  368. package/src/components/verbs/bom-writer.ts +1 -1
  369. package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
  370. package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
  371. package/src/components/wave-plan.ts +48 -8
  372. package/src/discovery/fold-host-method.test.ts +87 -0
  373. package/src/discovery/fold-import.ts +15 -5
  374. package/src/discovery/fold-package-composite.test.ts +27 -0
  375. package/src/discovery/fold-specifiers.test.ts +8 -0
  376. package/src/discovery/sandbox/bundle.ts +6 -0
  377. package/src/discovery/specifier-resolve.ts +8 -2
  378. package/src/fold/fold.test.ts +72 -0
  379. package/src/fold/fold.ts +71 -0
  380. package/src/fold/subset.test.ts +31 -0
  381. package/src/fold/subset.ts +99 -0
  382. package/src/graph-detail.test.ts +57 -0
  383. package/src/graph-detail.ts +33 -7
  384. package/src/health.schema.json +191 -0
  385. package/src/health.test.ts +62 -0
  386. package/src/health.ts +178 -0
  387. package/src/lexicon-dist.e2e.test.ts +254 -0
  388. package/src/lexicon-module.test.ts +47 -0
  389. package/src/lexicon-module.ts +49 -7
  390. package/src/lexicon-plugin-helpers.ts +6 -4
  391. package/src/lexicon.ts +43 -1
  392. package/src/lifecycle/affected.test.ts +7 -0
  393. package/src/lifecycle/affected.ts +6 -1
  394. package/src/lifecycle/merge-record.test.ts +111 -0
  395. package/src/lifecycle/merge-record.ts +154 -0
  396. package/src/lifecycle/publish-attachments.ts +25 -13
  397. package/src/lifecycle/publish-npm.ts +4 -3
  398. package/src/lifecycle/publish-targets.test.ts +34 -4
  399. package/src/lifecycle/release-at.test.ts +48 -0
  400. package/src/lifecycle/release-at.ts +100 -0
  401. package/src/lifecycle/release-cut.test.ts +41 -0
  402. package/src/lifecycle/release-cut.ts +22 -11
  403. package/src/lifecycle/release-ledger.ts +34 -0
  404. package/src/lifecycle/release-publish.test.ts +43 -13
  405. package/src/lifecycle/release-publish.ts +38 -18
  406. package/src/lifecycle/release-store.ts +57 -13
  407. package/src/lifecycle/run-ledger.test.ts +13 -0
  408. package/src/lifecycle/run-ledger.ts +1 -0
  409. package/src/lifecycle/work-dir.test.ts +77 -0
  410. package/src/lifecycle/work-dir.ts +82 -0
  411. package/src/lint/discover.test.ts +46 -2
  412. package/src/lint/discover.ts +55 -49
  413. package/src/lint/rules/op/index.ts +4 -2
  414. package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
  415. package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
  416. package/src/module-source.test.ts +85 -0
  417. package/src/module-source.ts +112 -0
  418. package/src/op/activities/activity-contracts.ts +3 -0
  419. package/src/op/activities/factory.ts +1 -1
  420. package/src/op/activities/shell-container.e2e.test.ts +67 -0
  421. package/src/op/activities/shell.test.ts +44 -1
  422. package/src/op/activities/shell.ts +110 -3
  423. package/src/op/builders.ts +7 -0
  424. package/src/op/discover-root.test.ts +31 -2
  425. package/src/op/discover.ts +14 -4
  426. package/src/op/gate.test.ts +30 -0
  427. package/src/op/gate.ts +3 -0
  428. package/src/op/op-waves-run.ts +20 -5
  429. package/src/op/op-waves.test.ts +49 -0
  430. package/src/op/operator.ts +2 -2
  431. package/src/op/runtime.ts +2 -0
  432. package/src/op/step-console.test.ts +4 -2
  433. package/src/op/steward.ts +6 -4
  434. package/src/op/work-lease-run.test.ts +88 -2
  435. package/src/op/work-lease-run.ts +52 -12
  436. package/src/pr-forge-bundle.test.ts +2 -2
  437. package/src/pr-forge.test.ts +42 -0
  438. package/src/pr-forge.ts +40 -0
  439. package/src/pr-loop-bundle.test.ts +2 -1
  440. package/src/pr-loop.test.ts +146 -1
  441. package/src/pr-loop.ts +278 -17
  442. package/src/pr-report-url.ts +7 -7
  443. package/src/runner-start-bundle.test.ts +29 -0
  444. package/src/runner-start.test.ts +179 -0
  445. package/src/runner-start.ts +329 -0
  446. package/src/terraform/__fixtures__/advise.test.ts +21 -2
  447. package/src/ts-loader.test.ts +89 -1
  448. package/src/ts-loader.ts +180 -13
  449. package/src/workspace/changes.test.ts +1 -1
  450. package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
  451. package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
  452. package/src/workspace/chant-migrations.e2e.test.ts +5 -0
  453. package/src/workspace/chant-migrations.ts +2 -0
  454. package/src/workspace/check-contract.test.ts +3 -2
  455. package/src/workspace/check.schema.json +70 -2
  456. package/src/workspace/checks/boxes.ts +9 -9
  457. package/src/workspace/checks/security.test.ts +138 -0
  458. package/src/workspace/checks/security.ts +305 -0
  459. package/src/workspace/checks.ts +5 -0
  460. package/src/workspace/ci-builds.e2e.test.ts +208 -0
  461. package/src/workspace/ci-builds.test.ts +174 -0
  462. package/src/workspace/ci-builds.ts +385 -0
  463. package/src/workspace/ci-green-builds.test.ts +180 -0
  464. package/src/workspace/ci-green-cli.test.ts +54 -0
  465. package/src/workspace/ci-green-cli.ts +26 -5
  466. package/src/workspace/ci-green-forge.ts +30 -4
  467. package/src/workspace/ci-green-runs.test.ts +53 -11
  468. package/src/workspace/ci-green-workflow.test.ts +84 -1
  469. package/src/workspace/ci-green-workflow.ts +139 -2
  470. package/src/workspace/ci-green.test.ts +6 -3
  471. package/src/workspace/ci-green.ts +408 -48
  472. package/src/workspace/ci-last-green.schema.json +49 -0
  473. package/src/workspace/ci-list.schema.json +47 -7
  474. package/src/workspace/ci-report-url.test.ts +220 -0
  475. package/src/workspace/ci-report-url.ts +33 -0
  476. package/src/workspace/ci-run-index.schema.json +6 -4
  477. package/src/workspace/ci-run-index.test.ts +42 -3
  478. package/src/workspace/ci-run-index.ts +19 -5
  479. package/src/workspace/ci-run.test.ts +203 -8
  480. package/src/workspace/ci-run.ts +295 -63
  481. package/src/workspace/ci-runner-key.test.ts +55 -17
  482. package/src/workspace/ci-runner-key.ts +36 -11
  483. package/src/workspace/ci-runner-start.test.ts +151 -0
  484. package/src/workspace/ci-runner-start.ts +193 -0
  485. package/src/workspace/ci-serve-builds.test.ts +86 -0
  486. package/src/workspace/ci-serve.test.ts +209 -6
  487. package/src/workspace/ci-serve.ts +341 -42
  488. package/src/workspace/declaration.schema.json +30 -2
  489. package/src/workspace/declaration.test.ts +40 -0
  490. package/src/workspace/declaration.ts +40 -3
  491. package/src/workspace/export.ts +6 -3
  492. package/src/workspace/ls.schema.json +9 -2
  493. package/src/workspace/ls.ts +10 -4
  494. package/src/workspace/member-pipeline.ts +2 -1
  495. package/src/workspace/merge-record.schema.json +49 -0
  496. package/src/workspace/pin-integrity.test.ts +5 -0
  497. package/src/workspace/pin-integrity.ts +3 -2
  498. package/src/workspace/pr-report.schema.json +75 -8
  499. package/src/workspace/reason-codes.test.ts +2 -0
  500. package/src/workspace/reason-codes.ts +20 -2
  501. package/src/workspace/release-candidates.schema.json +353 -0
  502. package/src/workspace/release-candidates.test.ts +106 -0
  503. package/src/workspace/release-candidates.ts +315 -0
  504. package/src/workspace/run-event.schema.json +3 -1
  505. package/src/workspace/security.test.ts +70 -0
  506. package/src/workspace/security.ts +118 -0
  507. package/src/workspace/status.schema.json +3 -1
  508. package/src/workspace/write-scope.test.ts +29 -1
  509. package/src/workspace/write-scope.ts +12 -1
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The apply job's base fallback (#4004), run in sh against a real
3
+ * repository. GitHub and Forgejo set `github.event.before`, and GitLab
4
+ * `CI_COMMIT_BEFORE_SHA`, to forty zeros on a branch's first push.
5
+ */
6
+
7
+ import { execFileSync } from "node:child_process";
8
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { afterAll, describe, expect, test } from "vitest";
12
+ import { EMPTY_TREE_SHA } from "./changed-files";
13
+ import { githubBaseFallback, gitlabBaseFallback, prLoopJobs } from "./pr-pipeline";
14
+
15
+ const ZEROS = "0".repeat(40);
16
+ const dir = mkdtempSync(join(tmpdir(), "chant-pr-base-"));
17
+ afterAll(() => rmSync(dir, { recursive: true, force: true }));
18
+ const ENV = { ...process.env, GIT_AUTHOR_NAME: "t", GIT_AUTHOR_EMAIL: "t@example.com", GIT_COMMITTER_NAME: "t", GIT_COMMITTER_EMAIL: "t@example.com" };
19
+
20
+ const git = (cwd: string, ...args: string[]): string => execFileSync("git", args, { cwd, encoding: "utf8", env: ENV }).trim();
21
+
22
+ /** A bare origin and a clone of it, `main` holding `commits` commits. */
23
+ function repo(name: string, commits: number): string {
24
+ const origin = join(dir, `${name}.git`);
25
+ const work = join(dir, name);
26
+ execFileSync("git", ["init", "-q", "--bare", "-b", "main", origin]);
27
+ execFileSync("git", ["init", "-q", "-b", "main", work]);
28
+ git(work, "remote", "add", "origin", origin);
29
+ for (let i = 0; i < commits; i++) {
30
+ writeFileSync(join(work, "f.txt"), `${i}\n`);
31
+ git(work, "add", "-A");
32
+ git(work, "commit", "-q", "-m", `c${i}`);
33
+ }
34
+ git(work, "push", "-q", "origin", "main");
35
+ return work;
36
+ }
37
+
38
+ /** BASE_SHA after `line` runs in `cwd` with `env`. */
39
+ function settle(cwd: string, line: string, env: Record<string, string>): string {
40
+ return execFileSync("sh", ["-ec", `${line}\nprintf %s "$BASE_SHA"`], { cwd, encoding: "utf8", env: { ...ENV, ...env } });
41
+ }
42
+
43
+ describe("githubBaseFallback (#4004)", () => {
44
+ test("a set base is kept", () => {
45
+ const work = repo("kept", 2);
46
+ const parent = git(work, "rev-parse", "HEAD^");
47
+ expect(settle(work, githubBaseFallback(), { BASE_SHA: parent, GITHUB_SHA: git(work, "rev-parse", "HEAD") })).toBe(parent);
48
+ });
49
+
50
+ test("forty zeros or empty on the target branch's first push: the pushed commit's parent", () => {
51
+ const work = repo("first", 2);
52
+ const head = git(work, "rev-parse", "HEAD");
53
+ const parent = git(work, "rev-parse", "HEAD^");
54
+ expect(settle(work, githubBaseFallback(), { BASE_SHA: ZEROS, GITHUB_SHA: head })).toBe(parent);
55
+ expect(settle(work, githubBaseFallback(), { BASE_SHA: "", GITHUB_SHA: head })).toBe(parent);
56
+ });
57
+
58
+ test("a branch's first push: the merge base with the target branch", () => {
59
+ const work = repo("branch", 1);
60
+ const fork = git(work, "rev-parse", "HEAD");
61
+ git(work, "checkout", "-q", "-b", "feature");
62
+ writeFileSync(join(work, "g.txt"), "g\n");
63
+ git(work, "add", "-A");
64
+ git(work, "commit", "-q", "-m", "feature");
65
+ expect(settle(work, githubBaseFallback(), { BASE_SHA: ZEROS, GITHUB_SHA: git(work, "rev-parse", "HEAD") })).toBe(fork);
66
+ });
67
+
68
+ test("a root commit: the empty tree", () => {
69
+ const work = repo("root", 1);
70
+ expect(settle(work, githubBaseFallback(), { BASE_SHA: ZEROS, GITHUB_SHA: git(work, "rev-parse", "HEAD") })).toBe(EMPTY_TREE_SHA);
71
+ });
72
+
73
+ test("a named branch is the one fetched", () => {
74
+ expect(githubBaseFallback()).toContain('git fetch origin "main"');
75
+ expect(githubBaseFallback("trunk")).toContain('git fetch origin "trunk"');
76
+ });
77
+ });
78
+
79
+ describe("gitlabBaseFallback", () => {
80
+ test("a root commit's first push: the empty tree, as on GitHub (#4004)", () => {
81
+ const work = repo("gitlab-root", 1);
82
+ expect(settle(work, gitlabBaseFallback("main"), { BASE_SHA: ZEROS, CI_COMMIT_SHA: git(work, "rev-parse", "HEAD") })).toBe(EMPTY_TREE_SHA);
83
+ });
84
+
85
+ test("the merge request's diff base comes first", () => {
86
+ const work = repo("gitlab-mr", 2);
87
+ const parent = git(work, "rev-parse", "HEAD^");
88
+ expect(settle(work, gitlabBaseFallback("main"), { BASE_SHA: ZEROS, CI_MERGE_REQUEST_DIFF_BASE_SHA: parent, CI_COMMIT_SHA: git(work, "rev-parse", "HEAD") })).toBe(parent);
89
+ });
90
+ });
91
+
92
+ describe("prLoopJobs", () => {
93
+ test("every forge's apply settles its base first; no plan does", () => {
94
+ for (const forge of ["github", "forgejo", "gitlab"] as const) {
95
+ const [plan, apply] = prLoopJobs(forge, "prod", { branch: "trunk" });
96
+ expect(plan!.setup).toBeUndefined();
97
+ expect(apply!.setup).toEqual([forge === "gitlab" ? gitlabBaseFallback("trunk") : githubBaseFallback("trunk")]);
98
+ }
99
+ });
100
+ });
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * The jobs of a generated pull-request pipeline (#3183): a plan job on every
3
- * pull request and an apply job on every push to the target branch.
3
+ * pull request and, on every push to the target branch, a record job, or an
4
+ * apply job when the pipeline opts into apply on merge (#4168).
4
5
  *
5
6
  * Each forge's generator (the github, gitlab and forgejo lexicons) adds its
6
7
  * own triggers, permissions and artifact handling; the commands and the
@@ -9,11 +10,19 @@
9
10
  * - The plan job runs `chant components pr-plan` against the pull request's
10
11
  * target commit. It posts the note and the `chant/plan` status and writes
11
12
  * nothing to `chant/lifecycle`, since it runs the pull request's code.
12
- * - The apply job runs `chant components pr-apply` against the commit the
13
+ * - The record job (#4168 step 1, the default) runs `chant components
14
+ * pr-record` against the commit the push replaced. It plans the same
15
+ * members on the merged commit, stores the change set and writes the merge
16
+ * record, `_merges/<commit>.json` on `chant/lifecycle`. It applies nothing:
17
+ * a release that carries the commit deploys it. It needs write access to
18
+ * `chant/lifecycle`. One record runs at a time per environment.
19
+ * - With `applyOnMerge` the apply job takes the record job's place. It runs
20
+ * `chant components pr-apply` against the commit the
13
21
  * push replaced, finds the pull request that merged the pushed commit
14
22
  * through the forge, and applies only when an approval stands for the
15
- * digest it plans. With `requireReview` (the default) the approver must
16
- * also have approved the pull request on the forge. It needs write access
23
+ * digest it plans. With `requireReview` (off by default since #4168, on
24
+ * under the `review-rules` security group) the approver must also have
25
+ * approved the pull request on the forge. It needs write access
17
26
  * to `chant/lifecycle`, to record the pending fact when the gate stops it.
18
27
  * One apply runs at a time per environment.
19
28
  *
@@ -35,6 +44,7 @@
35
44
  * it too. With `reportUrl` both pass `--report-url`, which copies the report,
36
45
  * the change set and the events where a reader outside CI can fetch them;
37
46
  * the job's own environment brings the credentials an `s3://` URL needs.
47
+ * The record job passes the same flags as the apply.
38
48
  *
39
49
  * With `build` (#4088) both jobs run the project's build and `chant lint`
40
50
  * before their command, and fail on an error. A `cfn-deploy` member's plan
@@ -42,6 +52,25 @@
42
52
  * build is `chant build --env <env>`, or `buildCommand` when the templates
43
53
  * come from several builds (`npm run build`).
44
54
  *
55
+ * With `waveGate` (#4003) the apply runs a wave at a time: `pr-apply
56
+ * --wave-gate <gate>`, each wave planned after the one before it applied. A
57
+ * generator writes one apply job per wave of the component graph
58
+ * (`prLoopWaveJobs`), job `apply-wave-<k>` passing `--wave <k>` and needing
59
+ * the job before it, and the attempt record carries the approved set from
60
+ * one job to the next. A wave whose plan the approved change set covers
61
+ * applies under the pull request's approval; one whose plan moved stops at
62
+ * `<gate>-wave-<k>` (exit 3), and re-running its job after the approval
63
+ * carries on. `chant ci serve` runs the one apply job, which runs the waves
64
+ * in order until one stops.
65
+ *
66
+ * Each generated job runs its command through `chant ci run plan|apply
67
+ * --in-place` (#4156, `PrLoopJob.run`), so a forge job writes the same run
68
+ * record the chant runner does: Op `pr-plan` or `pr-apply`, signed with
69
+ * the runner key a forge secret puts in `CHANT_RUNNER_KEY`, and naming the
70
+ * forge's run as its `runOrigin`. `ci run` runs `command` in the job's own
71
+ * checkout with the job's environment, less the key. The plan passes
72
+ * `--no-push`, so it still writes nothing to the remote `chant/lifecycle`.
73
+ *
45
74
  * In a workspace member (#3465) both commands run in the member's directory
46
75
  * and pass `--member <name>`, so the member's gate (`pr-<number>-<member>`),
47
76
  * note and statuses stay apart from every other member's on the same pull
@@ -52,6 +81,13 @@
52
81
  import type { ForgeKind } from "../pr-forge";
53
82
  import { PR_APPLY_GATE } from "../pr-loop";
54
83
  import { CI_IMAGE, GITHUB_JOB_TOKEN } from "../ci-jobs";
84
+ import { EMPTY_TREE_SHA } from "./changed-files";
85
+ import { layerWaves } from "../gated-waves";
86
+ import type { DriverComponent } from "./driver";
87
+ import type { GatedWavePipelineOptions } from "./gated-wave-pipeline";
88
+
89
+ /** The variable `chant ci run` reads its runner key from (`RUNNER_KEY_ENV` in ../workspace/ci-green.ts). */
90
+ const RUNNER_KEY_ENV = "CHANT_RUNNER_KEY";
55
91
 
56
92
  /** Where both jobs write their reports, kept as a CI artifact. */
57
93
  export const PR_LOOP_REPORT_DIR = ".chant/pr";
@@ -97,8 +133,16 @@ export interface PrLoopPipelineOptions {
97
133
  * GitHub and Forgejo; on GitLab, the project's default branch.
98
134
  */
99
135
  branch?: string;
100
- /** Count an approval only from someone who approved the pull request on the forge. Default true. */
136
+ /** Count an approval only from someone who approved the pull request on the forge. Default false (#4168): review rules are opt-in. */
101
137
  requireReview?: boolean;
138
+ /** The job on merge (apply, or record since #4168) has `chant ci run` refuse to start without a runner-start statement for it (`--require-runner-start`, #4147), as under the `isolated-runners` security group (#4168). Default false. */
139
+ requireRunnerStart?: boolean;
140
+ /**
141
+ * Apply the approved plan on merge (#4168), as every pull-request pipeline
142
+ * did before #4168: the apply job in place of the record job. Default
143
+ * false, so a merge deploys nothing. `waveGate` needs it.
144
+ */
145
+ applyOnMerge?: boolean;
102
146
  /**
103
147
  * Stream each job's run events (#4007): `--events-json` on both commands,
104
148
  * and `CHANT_RUN_EVENTS_DIR` set to {@link PR_LOOP_EVENTS_DIR}. Default false.
@@ -125,6 +169,12 @@ export interface PrLoopPipelineOptions {
125
169
  * `npm run build`. Setting it turns `build` on.
126
170
  */
127
171
  buildCommand?: string;
172
+ /**
173
+ * A gate per wave on merge (#4003): the apply runs `pr-apply --wave-gate
174
+ * <waveGate>`, a wave at a time, and a generator writes one apply job per
175
+ * wave. Set from `--wave-gate` beside `--pr-loop` ({@link prLoopWithWaves}).
176
+ */
177
+ waveGate?: string;
128
178
  /**
129
179
  * Which GitHub-shaped forge the workflow is for. Set by the forgejo
130
180
  * generator, which reuses the github one; a caller never needs to.
@@ -134,8 +184,8 @@ export interface PrLoopPipelineOptions {
134
184
 
135
185
  /** One job's command and the forge values it reads, as environment variables for its step. */
136
186
  export interface PrLoopJob {
137
- /** `plan` or `apply`. */
138
- jobName: "plan" | "apply";
187
+ /** `plan`, `apply` or `record` (#4168). */
188
+ jobName: "plan" | "apply" | "record";
139
189
  /** The command line. Reads `$BASE_SHA` and, for the plan, `$PR_NUMBER`. */
140
190
  command: string;
141
191
  /**
@@ -148,6 +198,17 @@ export interface PrLoopJob {
148
198
  setup?: string[];
149
199
  /** With `build` (#4088): the build line and the lint line, run in this order before the command. */
150
200
  build?: string[];
201
+ /** With `waveGate` (#4003): the wave a generated apply job runs, 1-based. */
202
+ wave?: number;
203
+ /**
204
+ * What the generated job runs in place of `command` (#4156): `chant ci run
205
+ * <job> --in-place` with the same environment, gate, forge, events and
206
+ * report URL, which runs `command` and records the run. `env` is the
207
+ * job's `env` and, on GitHub and Forgejo, `CHANT_RUNNER_KEY` from the
208
+ * repository secret of that name. GitLab hands its CI/CD variables to a
209
+ * job itself.
210
+ */
211
+ run: { command: string; env: Record<string, string> };
151
212
  }
152
213
 
153
214
  /** The lines `build` (#4088) runs before a job's command: the build, then the lint. Empty without the option. */
@@ -157,9 +218,10 @@ export function prLoopBuildLines(env: string, options: PrLoopPipelineOptions = {
157
218
  }
158
219
 
159
220
  /**
160
- * The two jobs for `forge`. `member` is the workspace member the pipeline is
161
- * generated for; the commands then run in its directory, so `--output` is
162
- * relative to it.
221
+ * The jobs for `forge`: plan, apply and record, in that order. A generator
222
+ * writes the plan and, on merge, {@link prLoopMergeJob}'s choice of the
223
+ * other two. `member` is the workspace member the pipeline is generated for;
224
+ * the commands then run in its directory, so `--output` is relative to it.
163
225
  */
164
226
  export function prLoopJobs(forge: ForgeKind, env: string, options: PrLoopPipelineOptions = {}, member?: string): PrLoopJob[] {
165
227
  const gate = options.gate ?? PR_APPLY_GATE;
@@ -176,29 +238,99 @@ export function prLoopJobs(forge: ForgeKind, env: string, options: PrLoopPipelin
176
238
  ...(github ? { GITHUB_TOKEN: GITHUB_JOB_TOKEN } : {}),
177
239
  ...(options.events ? { CHANT_RUN_EVENTS_DIR: PR_LOOP_EVENTS_DIR } : {}),
178
240
  };
241
+ // #4156: the flags `chant ci run` rebuilds `command` from. It finds the member from the directory it runs in.
242
+ const ciRun = (job: PrLoopJob["jobName"]): string[] => [
243
+ "chant", "ci", "run", job, "--in-place", ...(job === "plan" ? ["--no-push"] : []),
244
+ "--base", '"$BASE_SHA"', ...(job === "plan" ? ["--pr", '"$PR_NUMBER"'] : []),
245
+ "--env", env, "--gate", gate, "--forge", forge,
246
+ ...(job !== "record" && options.waveGate ? ["--wave-gate", options.waveGate] : []),
247
+ ...(job !== "plan" && options.branch ? ["--branch", JSON.stringify(options.branch)] : []),
248
+ ...(job === "apply" && options.requireReview === true ? ["--require-review"] : []),
249
+ ...(job !== "plan" && options.requireRunnerStart === true ? ["--require-runner-start"] : []),
250
+ ...(options.events ? ["--events-json"] : []),
251
+ ...(options.reportUrl ? ["--report-url", JSON.stringify(options.reportUrl)] : []),
252
+ ];
253
+ const runEnv = (env: Record<string, string>): Record<string, string> => (github ? { ...env, [RUNNER_KEY_ENV]: `\${{ secrets.${RUNNER_KEY_ENV} }}` } : env);
254
+ const planEnv = github
255
+ ? { BASE_SHA: "${{ github.event.pull_request.base.sha }}", PR_NUMBER: "${{ github.event.pull_request.number }}", ...jobEnv }
256
+ : { BASE_SHA: "$CI_MERGE_REQUEST_DIFF_BASE_SHA", PR_NUMBER: "$CI_MERGE_REQUEST_IID", ...jobEnv };
257
+ const applyEnv = github ? { BASE_SHA: "${{ github.event.before }}", ...jobEnv } : { BASE_SHA: "$CI_COMMIT_BEFORE_SHA", ...jobEnv };
179
258
  return [
180
259
  {
181
260
  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 },
261
+ // With `waveGate` the plan's note says the later waves may stop at their own gates (#4003).
262
+ command: ["chant", "components", "pr-plan", "--base", '"$BASE_SHA"', "--pr", '"$PR_NUMBER"', ...common, ...(options.waveGate ? ["--wave-gate", options.waveGate] : [])].join(" "),
263
+ env: planEnv,
186
264
  ...build,
265
+ run: { command: ciRun("plan").join(" "), env: runEnv(planEnv) },
187
266
  },
188
267
  {
189
268
  jobName: "apply",
190
269
  command: [
191
270
  "chant", "components", "pr-apply", "--base", '"$BASE_SHA"', ...common,
192
- ...(options.requireReview === false ? [] : ["--require-review"]),
271
+ ...(options.requireReview === true ? ["--require-review"] : []),
272
+ ...(options.waveGate ? ["--wave-gate", options.waveGate] : []),
193
273
  "--resume", PR_APPLY_RECORD,
194
274
  ].join(" "),
195
- env: github ? { BASE_SHA: "${{ github.event.before }}", ...jobEnv } : { BASE_SHA: "$CI_COMMIT_BEFORE_SHA", ...jobEnv },
196
- ...(github ? {} : { setup: [gitlabBaseFallback(options.branch)] }),
275
+ env: applyEnv,
276
+ setup: [github ? githubBaseFallback(options.branch) : gitlabBaseFallback(options.branch)],
277
+ ...build,
278
+ run: { command: ciRun("apply").join(" "), env: runEnv(applyEnv) },
279
+ },
280
+ {
281
+ jobName: "record",
282
+ command: ["chant", "components", "pr-record", "--base", '"$BASE_SHA"', ...common].join(" "),
283
+ env: applyEnv,
284
+ setup: [github ? githubBaseFallback(options.branch) : gitlabBaseFallback(options.branch)],
197
285
  ...build,
286
+ run: { command: ciRun("record").join(" "), env: runEnv(applyEnv) },
198
287
  },
199
288
  ];
200
289
  }
201
290
 
291
+ /** The job a push to the target branch runs (#4168): `record`, or `apply` when the pipeline opts into apply on merge. */
292
+ export function prLoopMergeJob(jobs: readonly PrLoopJob[], options: PrLoopPipelineOptions = {}): PrLoopJob {
293
+ return jobs.find((j) => j.jobName === (options.applyOnMerge ? "apply" : "record"))!;
294
+ }
295
+
296
+ /**
297
+ * The pull-request options with `--wave-gate` beside `--pr-loop` (#4003):
298
+ * the apply gets a gate per wave. A canary or a fixed base is refused, since
299
+ * the pull request's waves are its derivation's and each push is measured
300
+ * from the commit before it.
301
+ */
302
+ export function prLoopWithWaves(prLoop: PrLoopPipelineOptions, gatedWaves?: GatedWavePipelineOptions): PrLoopPipelineOptions {
303
+ if (!gatedWaves) return prLoop;
304
+ if (!prLoop.applyOnMerge) {
305
+ throw new Error("--wave-gate beside --pr-loop gates the apply on merge, so it needs --apply-on-merge (#4168); without it a merge records the plan and a release deploys it");
306
+ }
307
+ 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");
308
+ 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");
309
+ return { ...prLoop, waveGate: gatedWaves.gate };
310
+ }
311
+
312
+ /** The name of the apply job for wave `wave` (#4003). */
313
+ export function prApplyWaveJobName(wave: number): string {
314
+ return `apply-wave-${wave}`;
315
+ }
316
+
317
+ /**
318
+ * One apply job per wave of the component graph (#4003), each `apply`'s
319
+ * command with `--wave <k>`. A change selects a subset, which never layers
320
+ * deeper than the graph, so a job past the change's last wave finds nothing
321
+ * left and exits 0.
322
+ */
323
+ export function prLoopWaveJobs(components: DriverComponent[], apply: PrLoopJob): PrLoopJob[] {
324
+ const count = Math.max(1, layerWaves(components.map((c) => ({ name: c.name, dependsOn: c.dependsOn ?? [] }))).length);
325
+ return Array.from({ length: count }, (_, i) => ({
326
+ ...apply,
327
+ command: `${apply.command} --wave ${i + 1}`,
328
+ wave: i + 1,
329
+ // #4156: the job runs it through chant ci run, which appends the same --wave to pr-apply.
330
+ run: { ...apply.run, command: `${apply.run.command} --wave ${i + 1}` },
331
+ }));
332
+ }
333
+
202
334
  /**
203
335
  * The concurrency group (GitHub, Forgejo) or resource group (GitLab) that
204
336
  * keeps one apply at a time per environment, and per member in a workspace.
@@ -214,6 +346,11 @@ export function prApplyGroup(env: string, member?: string): string {
214
346
  return member ? `chant-apply.${member}.${env}` : `chant-apply-${env}`;
215
347
  }
216
348
 
349
+ /** The group that keeps one record job at a time per environment and member (#4168), named as {@link prApplyGroup} names the apply's. */
350
+ export function prRecordGroup(env: string, member?: string): string {
351
+ return member ? `chant-record.${member}.${env}` : `chant-record-${env}`;
352
+ }
353
+
217
354
  /**
218
355
  * The cache key the apply job keeps its attempt record under (#3543), with
219
356
  * `commit` the forge's expression for the pushed commit. A push of another
@@ -227,19 +364,38 @@ export function prApplyRecordKey(env: string, commit: string, member?: string):
227
364
  }
228
365
 
229
366
  /**
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.
367
+ * The shell that settles an unusable push base. `before` is empty or forty
368
+ * zeros on a branch's first push; then the base is `diffBase` when the forge
369
+ * gives one, else the merge base of `target` and `commit`, else `commit`'s
370
+ * parent when the merge base is `commit` itself, else, for a root commit, the
371
+ * empty tree.
234
372
  */
235
- export function gitlabBaseFallback(branch?: string): string {
236
- const target = branch ? JSON.stringify(branch) : "$CI_DEFAULT_BRANCH";
373
+ function pushBaseFallback(target: string, commit: string, diffBase?: string): string {
374
+ const fromBranch =
375
+ `git fetch origin ${target} && BASE_SHA="$(git merge-base FETCH_HEAD "${commit}")"; ` +
376
+ `if [ "$BASE_SHA" = "${commit}" ]; then BASE_SHA="$(git rev-parse --verify --quiet "${commit}^" || echo ${EMPTY_TREE_SHA})"; fi; `;
237
377
  return (
238
378
  '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"
379
+ (diffBase ? `BASE_SHA="\${${diffBase}:-}"; if [ -z "$BASE_SHA" ]; then ${fromBranch}fi; ` : fromBranch) +
380
+ "fi; export BASE_SHA"
244
381
  );
245
382
  }
383
+
384
+ /**
385
+ * GitLab sets `CI_COMMIT_BEFORE_SHA` to forty zeros on a branch's first push.
386
+ * The line replaces it with the merge request's diff base when the pipeline
387
+ * has one, and otherwise as {@link pushBaseFallback} does.
388
+ */
389
+ export function gitlabBaseFallback(branch?: string): string {
390
+ return pushBaseFallback(branch ? JSON.stringify(branch) : "$CI_DEFAULT_BRANCH", "$CI_COMMIT_SHA", "CI_MERGE_REQUEST_DIFF_BASE_SHA");
391
+ }
392
+
393
+ /**
394
+ * GitHub and Forgejo set `github.event.before` to forty zeros on a branch's
395
+ * first push (#4004). The line replaces it as {@link pushBaseFallback} does,
396
+ * with the target branch `main` unless the pipeline names another, the
397
+ * generators' default.
398
+ */
399
+ export function githubBaseFallback(branch?: string): string {
400
+ return pushBaseFallback(JSON.stringify(branch ?? "main"), "$GITHUB_SHA");
401
+ }