@intentius/chant 0.124.34 → 0.124.36

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 (171) hide show
  1. package/dist/cli/handlers/graph.js +2 -2
  2. package/dist/cli/handlers/pr.d.ts.map +1 -1
  3. package/dist/cli/handlers/pr.js +147 -51
  4. package/dist/cli/handlers/promote.d.ts.map +1 -1
  5. package/dist/cli/handlers/promote.js +23 -8
  6. package/dist/cli/handlers/release.d.ts +12 -0
  7. package/dist/cli/handlers/release.d.ts.map +1 -1
  8. package/dist/cli/handlers/release.js +125 -10
  9. package/dist/cli/handlers/run.d.ts +3 -1
  10. package/dist/cli/handlers/run.d.ts.map +1 -1
  11. package/dist/cli/handlers/run.js +12 -2
  12. package/dist/cli/main.d.ts.map +1 -1
  13. package/dist/cli/main.js +19 -1
  14. package/dist/cli/parse-args.d.ts.map +1 -1
  15. package/dist/cli/parse-args.js +17 -0
  16. package/dist/cli/registry.d.ts +14 -0
  17. package/dist/cli/registry.d.ts.map +1 -1
  18. package/dist/components/auto-release.d.ts +8 -1
  19. package/dist/components/auto-release.d.ts.map +1 -1
  20. package/dist/components/auto-release.js +3 -2
  21. package/dist/components/green-cover.d.ts +77 -0
  22. package/dist/components/green-cover.d.ts.map +1 -0
  23. package/dist/components/green-cover.js +153 -0
  24. package/dist/components/pr-pipeline.d.ts +34 -0
  25. package/dist/components/pr-pipeline.d.ts.map +1 -1
  26. package/dist/components/pr-pipeline.js +39 -5
  27. package/dist/components/promote.d.ts +4 -1
  28. package/dist/components/promote.d.ts.map +1 -1
  29. package/dist/components/promote.js +6 -3
  30. package/dist/components/release-promote.d.ts +9 -0
  31. package/dist/components/release-promote.d.ts.map +1 -1
  32. package/dist/components/release-promote.js +15 -0
  33. package/dist/config.d.ts +3 -0
  34. package/dist/config.d.ts.map +1 -1
  35. package/dist/deep-observation.d.ts +11 -0
  36. package/dist/deep-observation.d.ts.map +1 -1
  37. package/dist/graph-declared.d.ts +5 -1
  38. package/dist/graph-declared.d.ts.map +1 -1
  39. package/dist/graph-declared.js +7 -2
  40. package/dist/graph-detail.d.ts.map +1 -1
  41. package/dist/graph-detail.js +30 -1
  42. package/dist/graph-ir.d.ts.map +1 -1
  43. package/dist/graph-ir.js +13 -2
  44. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +5 -0
  45. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -1
  46. package/dist/lifecycle/__fixtures__/publish-fakes.js +20 -2
  47. package/dist/lifecycle/compose-refs.d.ts +52 -0
  48. package/dist/lifecycle/compose-refs.d.ts.map +1 -0
  49. package/dist/lifecycle/compose-refs.js +115 -0
  50. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  51. package/dist/lifecycle/deep-observe.js +3 -2
  52. package/dist/lifecycle/green-apply.d.ts +39 -0
  53. package/dist/lifecycle/green-apply.d.ts.map +1 -0
  54. package/dist/lifecycle/green-apply.js +51 -0
  55. package/dist/lifecycle/publish-declaration.d.ts +6 -0
  56. package/dist/lifecycle/publish-declaration.d.ts.map +1 -1
  57. package/dist/lifecycle/publish-declaration.js +21 -0
  58. package/dist/lifecycle/publish-npm.d.ts +11 -4
  59. package/dist/lifecycle/publish-npm.d.ts.map +1 -1
  60. package/dist/lifecycle/publish-npm.js +104 -14
  61. package/dist/lifecycle/release-compose.d.ts +91 -0
  62. package/dist/lifecycle/release-compose.d.ts.map +1 -0
  63. package/dist/lifecycle/release-compose.js +235 -0
  64. package/dist/lifecycle/release-cut.d.ts +8 -0
  65. package/dist/lifecycle/release-cut.d.ts.map +1 -1
  66. package/dist/lifecycle/release-cut.js +2 -0
  67. package/dist/lifecycle/release-publish.d.ts +6 -0
  68. package/dist/lifecycle/release-publish.d.ts.map +1 -1
  69. package/dist/lifecycle/release-publish.js +2 -1
  70. package/dist/lifecycle/release-store.d.ts +15 -0
  71. package/dist/lifecycle/release-store.d.ts.map +1 -1
  72. package/dist/lifecycle/release-store.js +5 -1
  73. package/dist/wave-runtime.mjs +225 -223
  74. package/dist/workspace/checks/ci-workflow.d.ts.map +1 -1
  75. package/dist/workspace/checks/ci-workflow.js +8 -1
  76. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  77. package/dist/workspace/ci-green-cli.js +5 -3
  78. package/dist/workspace/ci-green-workflow.d.ts +18 -2
  79. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  80. package/dist/workspace/ci-green-workflow.js +27 -5
  81. package/dist/workspace/ci-green.d.ts +31 -0
  82. package/dist/workspace/ci-green.d.ts.map +1 -1
  83. package/dist/workspace/ci-green.js +78 -4
  84. package/dist/workspace/ci-run.d.ts +6 -0
  85. package/dist/workspace/ci-run.d.ts.map +1 -1
  86. package/dist/workspace/ci-run.js +2 -1
  87. package/dist/workspace/ci-serve.d.ts +94 -13
  88. package/dist/workspace/ci-serve.d.ts.map +1 -1
  89. package/dist/workspace/ci-serve.js +248 -30
  90. package/dist/workspace/ci-workflow.d.ts +4 -4
  91. package/dist/workspace/ci-workflow.d.ts.map +1 -1
  92. package/dist/workspace/ci-workflow.js +2 -2
  93. package/dist/workspace/delivery-metrics.d.ts +3 -1
  94. package/dist/workspace/delivery-metrics.d.ts.map +1 -1
  95. package/dist/workspace/delivery-metrics.js +12 -3
  96. package/dist/workspace/member-commands.d.ts.map +1 -1
  97. package/dist/workspace/member-commands.js +4 -0
  98. package/dist/workspace/nested-graph.d.ts.map +1 -1
  99. package/dist/workspace/nested-graph.js +1 -0
  100. package/dist/workspace/release-candidates.d.ts +28 -0
  101. package/dist/workspace/release-candidates.d.ts.map +1 -1
  102. package/dist/workspace/release-candidates.js +38 -2
  103. package/dist/workspace/release-candidates.schema.json +51 -0
  104. package/dist/workspace/releases.schema.json +30 -0
  105. package/package.json +1 -1
  106. package/src/cli/handlers/graph.ts +2 -2
  107. package/src/cli/handlers/pr-green.test.ts +230 -0
  108. package/src/cli/handlers/pr.ts +148 -66
  109. package/src/cli/handlers/promote.test.ts +34 -0
  110. package/src/cli/handlers/promote.ts +22 -8
  111. package/src/cli/handlers/release-compose.e2e.test.ts +133 -0
  112. package/src/cli/handlers/release-publish-targets.e2e.test.ts +4 -1
  113. package/src/cli/handlers/release.ts +112 -10
  114. package/src/cli/handlers/run.ts +12 -1
  115. package/src/cli/main.ts +19 -1
  116. package/src/cli/parse-args.ts +13 -0
  117. package/src/cli/registry.ts +14 -0
  118. package/src/codegen/release-wiring.test.ts +56 -9
  119. package/src/components/auto-release.test.ts +22 -0
  120. package/src/components/auto-release.ts +9 -2
  121. package/src/components/green-cover.test.ts +170 -0
  122. package/src/components/green-cover.ts +186 -0
  123. package/src/components/pr-pipeline.test.ts +14 -4
  124. package/src/components/pr-pipeline.ts +56 -5
  125. package/src/components/promote.test.ts +7 -0
  126. package/src/components/promote.ts +9 -4
  127. package/src/components/release-promote.test.ts +24 -1
  128. package/src/components/release-promote.ts +15 -0
  129. package/src/deep-observation.ts +8 -0
  130. package/src/graph-declared.test.ts +18 -0
  131. package/src/graph-declared.ts +8 -1
  132. package/src/graph-detail.test.ts +68 -1
  133. package/src/graph-detail.ts +29 -1
  134. package/src/graph-ir.ts +12 -4
  135. package/src/lifecycle/__fixtures__/publish-fakes.ts +20 -2
  136. package/src/lifecycle/compose-refs.ts +125 -0
  137. package/src/lifecycle/deep-observe.test.ts +20 -0
  138. package/src/lifecycle/deep-observe.ts +4 -2
  139. package/src/lifecycle/green-apply.ts +71 -0
  140. package/src/lifecycle/publish-declaration.ts +21 -0
  141. package/src/lifecycle/publish-npm.ts +100 -14
  142. package/src/lifecycle/publish-targets.test.ts +108 -0
  143. package/src/lifecycle/release-compose.test.ts +125 -0
  144. package/src/lifecycle/release-compose.ts +312 -0
  145. package/src/lifecycle/release-cut.ts +6 -0
  146. package/src/lifecycle/release-publish.ts +8 -1
  147. package/src/lifecycle/release-store.ts +16 -1
  148. package/src/workspace/checks/ci-workflow.test.ts +12 -2
  149. package/src/workspace/checks/ci-workflow.ts +7 -1
  150. package/src/workspace/ci-green-cli.ts +5 -3
  151. package/src/workspace/ci-green-workflow.test.ts +52 -0
  152. package/src/workspace/ci-green-workflow.ts +34 -5
  153. package/src/workspace/ci-green.test.ts +33 -0
  154. package/src/workspace/ci-green.ts +85 -4
  155. package/src/workspace/ci-run.test.ts +18 -13
  156. package/src/workspace/ci-run.ts +8 -1
  157. package/src/workspace/ci-serve-land.e2e.test.ts +138 -0
  158. package/src/workspace/ci-serve-land.test.ts +176 -0
  159. package/src/workspace/ci-serve.test.ts +77 -43
  160. package/src/workspace/ci-serve.ts +268 -34
  161. package/src/workspace/ci-workflow.ts +4 -4
  162. package/src/workspace/delivery-metrics.ts +12 -3
  163. package/src/workspace/graph-contract.test.ts +3 -2
  164. package/src/workspace/member-commands.test.ts +11 -4
  165. package/src/workspace/member-commands.ts +3 -0
  166. package/src/workspace/nested-graph.test.ts +4 -0
  167. package/src/workspace/nested-graph.ts +1 -0
  168. package/src/workspace/release-candidates.schema.json +51 -0
  169. package/src/workspace/release-candidates.test.ts +30 -3
  170. package/src/workspace/release-candidates.ts +54 -2
  171. package/src/workspace/releases.schema.json +30 -0
@@ -5,10 +5,13 @@
5
5
  * {@link ciRun} (./ci-run.ts): `plan` for each new pull request head, and
6
6
  * `record` for each new commit on the target branch (#4168), measured from
7
7
  * the head the previous poll saw (the push's `before`). The record applies
8
- * nothing; with `applyOnMerge` (`--apply-on-merge`) the commit gets `apply`
9
- * in its place, as before #4168. After each job settles it runs `ci tick`
10
- * from the runs the jobs recorded, when the declaration has `ci.green`.
11
- * What the list below says of the apply holds for it under `applyOnMerge`.
8
+ * nothing. With `applyOnMerge` (`--apply-on-merge`) the newest green commit
9
+ * of the branch, once no apply ran for it, gets `apply`: `pr-apply --green`
10
+ * at that commit, measured from the one last applied (#4168 step 9). After
11
+ * each job settles it runs `ci tick` from the runs the jobs recorded, when
12
+ * the declaration has `ci.green`, so a green commit follows the record that
13
+ * made its runs. What the list below says of the apply holds for it under
14
+ * `applyOnMerge`.
12
15
  *
13
16
  * - Dedupe. A state file in the state directory keeps every job it started,
14
17
  * keyed by job and commit (`plan:<pr>:<sha>`, `record:<sha>`, `apply:<sha>`), with how it
@@ -19,10 +22,11 @@
19
22
  * the one `chant operator` holds) named for `prApplyGroup`, renews it while
20
23
  * it runs and releases it after. An apply that finds it held waits for a
21
24
  * later poll, as a forge's concurrency group queues it.
22
- * - Merged pull request. An apply asks the forge for the pull request whose
23
- * merge commit the new head is (`pullRequestFor`, as pr-apply does) and
25
+ * - Merged pull request. A record asks the forge for the pull request whose
26
+ * merge commit the new head is (`pullRequestFor`, as pr-record does) and
24
27
  * passes it as `--pr`, so its commit status link and run index use
25
- * `<pr>/<commit>`. With none found it runs without `--pr`.
28
+ * `<pr>/<commit>`. With none found it runs without `--pr`. An apply covers
29
+ * every merge since the last applied green commit, so it passes none.
26
30
  * - Resume records. Each apply gets `<state>/resume/<prApplyRecordKey>.json`
27
31
  * as its `--resume` record, so a re-run of a failed apply at the same
28
32
  * commit finishes under the approval it has. This replaces the forge's CI
@@ -56,6 +60,24 @@
56
60
  * forge's keeps its facts, and the job's push sends them. Nothing here
57
61
  * pushes the ledger.
58
62
  *
63
+ * - Land branches (#4168 4.4). With `land`, each `chant/land/<name>` branch
64
+ * pushed to the remote is a change asking to land without a pull request.
65
+ * A head that does not descend from the target's is refused and left for
66
+ * its author to rebase. Otherwise `buildCommand` runs on it with
67
+ * `CHANT_BUILD_PHASES` set to `ci.green.preMerge` and `CHANT_BUILD_REASON`
68
+ * `land`, and the phases are judged from the Op run records on its head
69
+ * ({@link judgePreMerge}). When the command exits 0 and every phase
70
+ * passes, the target is pushed to the head, a fast-forward the remote
71
+ * refuses if the target moved, and the land branch is deleted. The next
72
+ * poll sees the new head and runs the record job, whose merge record
73
+ * names a work item or a direct push. A refused land stays in the state
74
+ * file under `land:<name>:<sha>`, so a new push to the branch is tried
75
+ * again and the same head is not.
76
+ * - The `git` forge kind (#4016 gap 6). With `forge: "git"` the serve reads
77
+ * only refs, through `git ls-remote` against `origin`, so any git server
78
+ * that takes pushes will do. It lists no pull requests and sets no commit
79
+ * status, and the jobs run without `--forge`.
80
+ *
59
81
  * Host mode only: each job runs in a fresh worktree on this host as this
60
82
  * user, with the clean environment `ciRun` gives it. A pull request from a
61
83
  * fork is never planned, and with `authors` only those people's pull requests
@@ -65,12 +87,13 @@
65
87
  * {@link ciServeObserve} is the poll that makes them; a webhook handler would
66
88
  * turn a checked payload into the same triggers and schedule them.
67
89
  */
68
- import { type BuildRequest } from "./ci-builds.js";
90
+ import { type BuildRequestReason } from "./ci-builds.js";
69
91
  import { type OpenPullRequest } from "../pr-forge.js";
70
92
  import type { CommandContext } from "../cli/registry.js";
71
93
  import { type CiJobName, type CiRunRequest, type CiRunResult } from "./ci-run.js";
72
- /** The forges `ci serve` polls. GitLab is later. */
73
- export type CiServeForgeKind = "github" | "forgejo";
94
+ import { type CommitVerdict } from "./ci-green.js";
95
+ /** The forges `ci serve` polls. GitLab is later. `git` is any git server, read through refs alone (#4016 gap 6). */
96
+ export type CiServeForgeKind = "github" | "forgejo" | "git";
74
97
  /** What `ci serve` reads from the forge: the two calls GitHub's and Forgejo's clients have (../pr-forge.ts). */
75
98
  export interface CiServeForge {
76
99
  openPullRequests(base: string): Promise<OpenPullRequest[]>;
@@ -80,8 +103,8 @@ export interface CiServeForge {
80
103
  }
81
104
  /**
82
105
  * A job the forge's state calls for: the plan of a pull request's head, or
83
- * for a target-branch commit its record (#4168) or, with `applyOnMerge`,
84
- * its apply.
106
+ * for a target-branch commit its record (#4168), or with `applyOnMerge` the
107
+ * apply of the newest green commit (#4168 step 9).
85
108
  */
86
109
  export type CiServeTrigger = {
87
110
  job: "plan";
@@ -95,6 +118,30 @@ export type CiServeTrigger = {
95
118
  base: string;
96
119
  rerun?: boolean;
97
120
  };
121
+ /**
122
+ * The `git` forge kind (#4016 gap 6): the branch head from `git ls-remote`
123
+ * against `remote`, and no pull requests. A remote that can't be reached is
124
+ * an error for the pass, as a forge API's would be.
125
+ */
126
+ export declare function gitCiServeForge(top: string, remote?: string): CiServeForge;
127
+ /** What a build runs: a `ci/build/<sha>` request (#4169), or a land branch's pre-merge phases (#4168 4.4). */
128
+ export interface CiServeBuildInput {
129
+ commit: string;
130
+ phases: string[];
131
+ reason: BuildRequestReason | "land";
132
+ }
133
+ /** Where pushed land branches live on the remote (#4168 4.4). */
134
+ export declare const LAND_BRANCH_PREFIX = "chant/land/";
135
+ /** One land branch head in the state file, by `land:<name>:<sha>`. */
136
+ export interface CiServeLandState {
137
+ branch: string;
138
+ commit: string;
139
+ status: "running" | "landed" | "refused";
140
+ /** Why it was refused, in a line. */
141
+ reason?: string;
142
+ startedAt: string;
143
+ settledAt?: string;
144
+ }
98
145
  /** One job in the state file. */
99
146
  export interface CiServeJobState {
100
147
  job: CiJobName;
@@ -132,6 +179,8 @@ export interface CiServeState {
132
179
  startedAt: string;
133
180
  settledAt?: string;
134
181
  }>;
182
+ /** The land branch heads seen (#4168 4.4), by `land:<name>:<sha>`. */
183
+ lands?: Record<string, CiServeLandState>;
135
184
  }
136
185
  /** What a pass did, in order, for the log. */
137
186
  export type CiServeEvent = {
@@ -189,6 +238,15 @@ export type CiServeEvent = {
189
238
  status: "started" | "ok" | "fail" | "held";
190
239
  exitCode?: number;
191
240
  }
241
+ /** A land branch (#4168 4.4): its pre-merge phases started, the target moved to it, or it was refused and left. */
242
+ | {
243
+ type: "land";
244
+ branch: string;
245
+ commit: string;
246
+ status: "started" | "landed" | "refused" | "held";
247
+ reason?: string;
248
+ warning?: string;
249
+ }
192
250
  /** `ci tick` after the pass (#4168): the tags it made from the runs. */
193
251
  | {
194
252
  type: "tick";
@@ -244,9 +302,21 @@ export interface CiServeOptions {
244
302
  /** Runs a build. Default: `sh -c <buildCommand>` in a detached worktree of the commit. */
245
303
  build?: (input: {
246
304
  top: string;
247
- request: BuildRequest;
305
+ request: CiServeBuildInput;
248
306
  command: string;
249
307
  }) => Promise<number>;
308
+ /**
309
+ * Land `chant/land/<name>` branches (#4168 4.4): the `ci.green.preMerge`
310
+ * phases each must pass first. Needs `buildCommand`, which runs them.
311
+ */
312
+ land?: {
313
+ phases: string[];
314
+ };
315
+ /** Judges a land head's phases. Default {@link judgePreMerge} from the Op run records. */
316
+ judgeLand?: (input: {
317
+ commit: string;
318
+ base: string;
319
+ }) => Promise<CommitVerdict>;
250
320
  }
251
321
  /** The jobs this process runs now, by state key, shared by every pass of one loop. */
252
322
  export interface CiServeRuntime {
@@ -321,6 +391,17 @@ export declare function ciServeBuilds(opts: CiServeOptions, rt: CiServeRuntime):
321
391
  started: Promise<void>[];
322
392
  events: CiServeEvent[];
323
393
  };
394
+ /**
395
+ * Serve the land branches (#4168 4.4): for each `chant/land/<name>` head not
396
+ * in the state file, refuse it unless it descends from the target's head,
397
+ * else run `buildCommand` on it with the pre-merge phases, judge them, and
398
+ * when they pass push the target to it and delete the branch. At most
399
+ * `maxJobs` builds and jobs run at once.
400
+ */
401
+ export declare function ciServeLands(opts: CiServeOptions, rt: CiServeRuntime): Promise<{
402
+ started: Promise<void>[];
403
+ events: CiServeEvent[];
404
+ }>;
324
405
  /**
325
406
  * The loop: a pass every `intervalMs` until `signal` aborts, jobs running
326
407
  * across passes up to `maxJobs`. A pass the forge fails is logged and the
@@ -1 +1 @@
1
- {"version":3,"file":"ci-serve.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-serve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ci-serve.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,EAA0C,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,OAAO,EAA0F,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACvK,OAAO,EAAsF,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAMpI,oHAAoH;AACpH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,gHAAgH;AAChH,MAAM,WAAW,YAAY;IAC3B,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,mIAAmI;IACnI,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACtD;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1E;IAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/E;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,YAAY,CAU5E;AAED,8GAA8G;AAC9G,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAAC;CACrC;AAED,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2FAA2F;IAC3F,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sGAAsG;IACtG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACpC,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnH,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC1C;AAED,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5G;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/H;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1H;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxI;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;AACpH,mHAAmH;GACjH;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;AACxI,wEAAwE;GACtE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,mHAAmH;AACnH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAC,CAAC;AAErJ,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,gBAAgB,CAAC;IACxB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iHAAiH;IACjH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,2FAA2F;IAC3F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IAC3C,gFAAgF;IAChF,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,yCAAyC;IACzC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,iBAAiB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACjG;;;OAGG;IACH,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC5B,0FAA0F;IAC1F,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACjF;AAED,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;CACzC;AAED,eAAO,MAAM,iBAAiB,QAAO,cAA2C,CAAC;AAEjF,8BAA8B;AAC9B,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAErF;AAsBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAwB5E;AAuBD,mIAAmI;AACnI,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI1D;AAsBD,oCAAoC;AACpC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,MAAM,CAAC,GAAG,YAAY,CAOzG;AAaD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,GAAE,cAAoC,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAiFpK;AAED,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;IACpC,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,cAAc,EAAE,EAAE,EAAE,GAAE,cAAoC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+EpK;AAgED,uGAAuG;AACvG,wBAAsB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,GAAE,cAAoC,EAAE,IAAI,UAAO,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,IAAI,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC,CAS3K;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CA4C5H;AAuBD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAqE1I;AAoCD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBpH;AAED,sDAAsD;AACtD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAwC1D;AAID;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAkBjE;AAUD,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKjE;AAcD,gCAAgC;AAChC,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqHrE"}
@@ -5,10 +5,13 @@
5
5
  * {@link ciRun} (./ci-run.ts): `plan` for each new pull request head, and
6
6
  * `record` for each new commit on the target branch (#4168), measured from
7
7
  * the head the previous poll saw (the push's `before`). The record applies
8
- * nothing; with `applyOnMerge` (`--apply-on-merge`) the commit gets `apply`
9
- * in its place, as before #4168. After each job settles it runs `ci tick`
10
- * from the runs the jobs recorded, when the declaration has `ci.green`.
11
- * What the list below says of the apply holds for it under `applyOnMerge`.
8
+ * nothing. With `applyOnMerge` (`--apply-on-merge`) the newest green commit
9
+ * of the branch, once no apply ran for it, gets `apply`: `pr-apply --green`
10
+ * at that commit, measured from the one last applied (#4168 step 9). After
11
+ * each job settles it runs `ci tick` from the runs the jobs recorded, when
12
+ * the declaration has `ci.green`, so a green commit follows the record that
13
+ * made its runs. What the list below says of the apply holds for it under
14
+ * `applyOnMerge`.
12
15
  *
13
16
  * - Dedupe. A state file in the state directory keeps every job it started,
14
17
  * keyed by job and commit (`plan:<pr>:<sha>`, `record:<sha>`, `apply:<sha>`), with how it
@@ -19,10 +22,11 @@
19
22
  * the one `chant operator` holds) named for `prApplyGroup`, renews it while
20
23
  * it runs and releases it after. An apply that finds it held waits for a
21
24
  * later poll, as a forge's concurrency group queues it.
22
- * - Merged pull request. An apply asks the forge for the pull request whose
23
- * merge commit the new head is (`pullRequestFor`, as pr-apply does) and
25
+ * - Merged pull request. A record asks the forge for the pull request whose
26
+ * merge commit the new head is (`pullRequestFor`, as pr-record does) and
24
27
  * passes it as `--pr`, so its commit status link and run index use
25
- * `<pr>/<commit>`. With none found it runs without `--pr`.
28
+ * `<pr>/<commit>`. With none found it runs without `--pr`. An apply covers
29
+ * every merge since the last applied green commit, so it passes none.
26
30
  * - Resume records. Each apply gets `<state>/resume/<prApplyRecordKey>.json`
27
31
  * as its `--resume` record, so a re-run of a failed apply at the same
28
32
  * commit finishes under the approval it has. This replaces the forge's CI
@@ -56,6 +60,24 @@
56
60
  * forge's keeps its facts, and the job's push sends them. Nothing here
57
61
  * pushes the ledger.
58
62
  *
63
+ * - Land branches (#4168 4.4). With `land`, each `chant/land/<name>` branch
64
+ * pushed to the remote is a change asking to land without a pull request.
65
+ * A head that does not descend from the target's is refused and left for
66
+ * its author to rebase. Otherwise `buildCommand` runs on it with
67
+ * `CHANT_BUILD_PHASES` set to `ci.green.preMerge` and `CHANT_BUILD_REASON`
68
+ * `land`, and the phases are judged from the Op run records on its head
69
+ * ({@link judgePreMerge}). When the command exits 0 and every phase
70
+ * passes, the target is pushed to the head, a fast-forward the remote
71
+ * refuses if the target moved, and the land branch is deleted. The next
72
+ * poll sees the new head and runs the record job, whose merge record
73
+ * names a work item or a direct push. A refused land stays in the state
74
+ * file under `land:<name>:<sha>`, so a new push to the branch is tried
75
+ * again and the same head is not.
76
+ * - The `git` forge kind (#4016 gap 6). With `forge: "git"` the serve reads
77
+ * only refs, through `git ls-remote` against `origin`, so any git server
78
+ * that takes pushes will do. It lists no pull requests and sets no commit
79
+ * status, and the jobs run without `--forge`.
80
+ *
59
81
  * Host mode only: each job runs in a fresh worktree on this host as this
60
82
  * user, with the clean environment `ciRun` gives it. A pull request from a
61
83
  * fork is never planned, and with `authors` only those people's pull requests
@@ -77,9 +99,31 @@ import { acquireLease, currentHolderId, releaseLease, DEFAULT_LEASE_TTL_MS } fro
77
99
  import { parseDuration } from "../op/duration.js";
78
100
  import { reportUrlOf } from "./ci-report-url.js";
79
101
  import { CI_JOB_OPS, ciJobPlace, ciLoopOptions, ciSecretsOf, ciRun, ciStatusFromEnv, CiRunError } from "./ci-run.js";
80
- import { CiGreenError, ciTick, RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green.js";
102
+ import { CiGreenError, ciTick, judgePreMerge, lastGreen, RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green.js";
81
103
  import { gitTop } from "./tree.js";
104
+ import { readDeclaration } from "./declaration.js";
105
+ import { locateWorkspace } from "./which-chant.js";
82
106
  import { ciServeRunnerKey, formatRunnerKeySetup, setupRunnerKey } from "./ci-runner-key.js";
107
+ /**
108
+ * The `git` forge kind (#4016 gap 6): the branch head from `git ls-remote`
109
+ * against `remote`, and no pull requests. A remote that can't be reached is
110
+ * an error for the pass, as a forge API's would be.
111
+ */
112
+ export function gitCiServeForge(top, remote = "origin") {
113
+ return {
114
+ openPullRequests: async () => [],
115
+ async branchHead(branch) {
116
+ const r = gitStatus(top, ["ls-remote", "--exit-code", remote, `refs/heads/${branch}`]);
117
+ if (r.code === 2)
118
+ return undefined;
119
+ if (r.code !== 0)
120
+ throw new CiRunError(`git ls-remote ${remote} could not read refs/heads/${branch}`);
121
+ return r.out.split(/\s+/)[0] || undefined;
122
+ },
123
+ };
124
+ }
125
+ /** Where pushed land branches live on the remote (#4168 4.4). */
126
+ export const LAND_BRANCH_PREFIX = "chant/land/";
83
127
  export const newCiServeRuntime = () => ({ inflight: new Map() });
84
128
  /** The state key of a job. */
85
129
  export function ciServeKey(t) {
@@ -224,8 +268,8 @@ export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
224
268
  const triggers = [];
225
269
  const events = [];
226
270
  const [head, prs] = await Promise.all([opts.client.branchHead(place.branch), opts.client.openPullRequests(place.branch)]);
227
- // #4168: a new target commit is recorded, and applied only with applyOnMerge.
228
- const onMerge = opts.applyOnMerge ? "apply" : "record";
271
+ // #4168: a new target commit is recorded. With applyOnMerge the newest green commit is applied, below.
272
+ const onMerge = "record";
229
273
  if (head === undefined) {
230
274
  events.push({ type: "no-branch", branch: place.branch });
231
275
  }
@@ -261,6 +305,17 @@ export async function ciServeObserve(opts, rt = newCiServeRuntime()) {
261
305
  if (opts.rerunFailed && failedEntry(entry, key, rt))
262
306
  triggers.push({ job: onMerge, commit: head, base: entry.base, rerun: true });
263
307
  }
308
+ if (opts.applyOnMerge && head !== undefined) {
309
+ const green = newestGreen(place.top, opts.cwd, place.branch);
310
+ if (green) {
311
+ const key = ciServeKey({ job: "apply", commit: green });
312
+ const entry = state.jobs[key];
313
+ if (!entry)
314
+ triggers.push({ job: "apply", commit: green, base: green });
315
+ else if (opts.rerunFailed && failedEntry(entry, key, rt))
316
+ triggers.push({ job: "apply", commit: green, base: entry.base, rerun: true });
317
+ }
318
+ }
264
319
  const authors = opts.authors?.length ? new Set(opts.authors.map((a) => a.toLowerCase())) : undefined;
265
320
  for (const pr of prs) {
266
321
  if (pr.fork) {
@@ -358,7 +413,7 @@ export async function ciServeSchedule(opts, triggers, rt = newCiServeRuntime())
358
413
  const entry = { job: t.job, commit: t.commit, base: t.base, ...pr, status: "running", runId, attempts: attempt, startedAt: now().toISOString() };
359
414
  update((s) => {
360
415
  s.jobs[key] = entry;
361
- if (t.job !== "plan" && !t.rerun)
416
+ if (t.job === "record" && !t.rerun)
362
417
  s.target = t.commit;
363
418
  });
364
419
  emit({ type: "started", job: t.job, commit: t.commit, ...pr, base: t.base, runId, attempt, ...(resume && existsSync(resume) ? { resume } : {}) });
@@ -395,7 +450,7 @@ async function runJob(opts, place, t, paths, held) {
395
450
  tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", t.job === "plan" ? `refs/pull/${t.pr}/head` : place.branch]);
396
451
  const hostEnv = { ...(opts.job?.hostEnv ?? process.env), GITHUB_REPOSITORY: opts.repo };
397
452
  // An apply is for a merge: pass the pull request whose merge commit it is, so the commit status link and the run index use `<pr>/<commit>`. None found, or a forge that errs, is today's behaviour.
398
- if (t.job !== "plan" && opts.client.pullRequestFor)
453
+ if (t.job === "record" && opts.client.pullRequestFor)
399
454
  merged = (await opts.client.pullRequestFor(t.commit).catch(() => null)) ?? undefined;
400
455
  const run = opts.run ?? ciRun;
401
456
  const r = await run({
@@ -404,7 +459,8 @@ async function runJob(opts, place, t, paths, held) {
404
459
  cwd: opts.cwd,
405
460
  job: t.job,
406
461
  env: opts.env,
407
- forge: opts.forge,
462
+ // #4016 gap 6: a plain git server has no API, so the job runs without --forge, shaped as a GitHub job.
463
+ ...(opts.forge === "git" ? { forge: "github", noForge: true } : { forge: opts.forge }),
408
464
  base: t.base,
409
465
  ...(t.job === "plan" ? { pr: t.pr } : merged !== undefined ? { pr: merged } : {}),
410
466
  commit: t.commit,
@@ -425,6 +481,21 @@ async function runJob(opts, place, t, paths, held) {
425
481
  await releaseLease(place.group, held.holder, held.lease.token, { cwd: opts.cwd }).catch(() => false);
426
482
  }
427
483
  }
484
+ /**
485
+ * The newest green commit of the target branch (#4168 step 9), after
486
+ * fetching the ci tags, or undefined when none is green or the workspace
487
+ * declares no `ci.green`.
488
+ */
489
+ function newestGreen(top, cwd, branch) {
490
+ tryGit(top, ["fetch", "--quiet", "origin", `+refs/heads/${branch}:refs/remotes/origin/${branch}`, "+refs/tags/ci/*:refs/tags/ci/*"]);
491
+ try {
492
+ const doc = lastGreen({ cwd });
493
+ return "commit" in doc && doc.commit ? doc.commit.sha : undefined;
494
+ }
495
+ catch {
496
+ return undefined;
497
+ }
498
+ }
428
499
  /** One pass: observe, schedule, serve build requests, and with `wait` wait for the jobs it started. */
429
500
  export async function ciServePass(opts, rt = newCiServeRuntime(), wait = true) {
430
501
  const observed = await ciServeObserve(opts, rt);
@@ -432,10 +503,11 @@ export async function ciServePass(opts, rt = newCiServeRuntime(), wait = true) {
432
503
  opts.log?.(e);
433
504
  const scheduled = await ciServeSchedule(opts, observed.triggers, rt);
434
505
  const builds = opts.buildCommand ? ciServeBuilds(opts, rt) : { started: [], events: [] };
506
+ const lands = opts.land && opts.buildCommand ? await ciServeLands(opts, rt) : { started: [], events: [] };
435
507
  const jobs = wait ? await Promise.all(scheduled.started) : [];
436
508
  if (wait)
437
- await Promise.all(builds.started);
438
- return { events: [...observed.events, ...scheduled.events, ...builds.events], jobs };
509
+ await Promise.all([...builds.started, ...lands.started]);
510
+ return { events: [...observed.events, ...scheduled.events, ...builds.events, ...lands.events], jobs };
439
511
  }
440
512
  /**
441
513
  * Serve the build requests (#4169): fetch the `ci/build/*` tags, and start
@@ -489,6 +561,110 @@ export function ciServeBuilds(opts, rt) {
489
561
  }
490
562
  return { started, events };
491
563
  }
564
+ /** The land branches on `origin`, by name, with their heads (#4168 4.4). */
565
+ function landBranches(top) {
566
+ const r = gitStatus(top, ["ls-remote", "origin", `refs/heads/${LAND_BRANCH_PREFIX}*`]);
567
+ if (r.code !== 0)
568
+ return [];
569
+ return r.out
570
+ .split("\n")
571
+ .map((line) => line.split(/\s+/))
572
+ .filter(([sha, ref]) => sha && ref?.startsWith(`refs/heads/${LAND_BRANCH_PREFIX}`))
573
+ .map(([head, ref]) => ({ name: ref.slice(`refs/heads/${LAND_BRANCH_PREFIX}`.length), head: head }))
574
+ .sort((a, b) => a.name.localeCompare(b.name));
575
+ }
576
+ /** Why a land's phases don't let it land, or undefined when every one passed. */
577
+ function landRefusal(verdict) {
578
+ if (verdict.verdict === "pass")
579
+ return undefined;
580
+ const failed = verdict.phases.filter((p) => p.verdict === "fail").map((p) => p.phase);
581
+ if (failed.length > 0)
582
+ return `the pre-merge phase${failed.length > 1 ? "s" : ""} ${failed.join(", ")} failed`;
583
+ const open = verdict.phases.filter((p) => p.verdict !== "pass").map((p) => p.phase);
584
+ return `the build recorded no finished run for ${open.join(", ")}`;
585
+ }
586
+ /**
587
+ * Serve the land branches (#4168 4.4): for each `chant/land/<name>` head not
588
+ * in the state file, refuse it unless it descends from the target's head,
589
+ * else run `buildCommand` on it with the pre-merge phases, judge them, and
590
+ * when they pass push the target to it and delete the branch. At most
591
+ * `maxJobs` builds and jobs run at once.
592
+ */
593
+ export async function ciServeLands(opts, rt) {
594
+ const place = servePlace(opts);
595
+ const fresh = { forge: opts.forge, repo: opts.repo, env: opts.env, branch: place.branch, ...(place.member ? { member: place.member } : {}) };
596
+ const update = (fn) => {
597
+ const st = readCiServeState(place.stateFile, fresh);
598
+ fn(st);
599
+ writeState(place.stateFile, st);
600
+ };
601
+ const events = [];
602
+ const started = [];
603
+ const now = opts.now ?? (() => new Date());
604
+ const log = (e) => {
605
+ events.push(e);
606
+ opts.log?.(e);
607
+ };
608
+ const phases = opts.land.phases;
609
+ const seen = readCiServeState(place.stateFile, fresh).lands ?? {};
610
+ for (const { name, head } of landBranches(place.top)) {
611
+ const key = `land:${name}:${head}`;
612
+ const branch = `${LAND_BRANCH_PREFIX}${name}`;
613
+ if (seen[key] || rt.inflight.has(key))
614
+ continue;
615
+ if (rt.inflight.size >= (opts.maxJobs ?? 1)) {
616
+ log({ type: "land", branch, commit: head, status: "held", reason: "--max-jobs jobs run" });
617
+ continue;
618
+ }
619
+ const settle = (status, reason, warning) => {
620
+ update((st) => {
621
+ st.lands = { ...st.lands, [key]: { branch, commit: head, status, ...(reason ? { reason } : {}), startedAt: st.lands?.[key]?.startedAt ?? now().toISOString(), settledAt: now().toISOString() } };
622
+ });
623
+ log({ type: "land", branch, commit: head, status, ...(reason ? { reason } : {}), ...(warning ? { warning } : {}) });
624
+ };
625
+ const target = await opts.client.branchHead(place.branch);
626
+ if (target === undefined) {
627
+ log({ type: "error", message: `${branch} waits: the remote has no branch ${place.branch} to land it on` });
628
+ continue;
629
+ }
630
+ tryGit(place.top, ["fetch", "--quiet", "--no-tags", "origin", place.branch, `+refs/heads/${branch}:refs/chant/ci-serve/land/${name}`]);
631
+ // #4168 4.4: a land only ever fast-forwards the target, so its head must descend from the target's.
632
+ if (gitStatus(place.top, ["merge-base", "--is-ancestor", target, head]).code !== 0) {
633
+ settle("refused", `${head.slice(0, 12)} does not descend from ${place.branch} at ${target.slice(0, 12)}; rebase ${branch} onto it and push again`);
634
+ continue;
635
+ }
636
+ update((st) => {
637
+ st.lands = { ...st.lands, [key]: { branch, commit: head, status: "running", startedAt: now().toISOString() } };
638
+ });
639
+ log({ type: "land", branch, commit: head, status: "started" });
640
+ const build = opts.build ?? runBuild;
641
+ const judge = opts.judgeLand ?? ((input) => judgePreMerge({ cwd: opts.cwd, ...input }));
642
+ const job = (async () => {
643
+ const code = await build({ top: place.top, request: { commit: head, phases, reason: "land" }, command: opts.buildCommand }).catch(() => 1);
644
+ if (code !== 0)
645
+ return settle("refused", `the build of ${phases.join(", ")} exited ${code}`);
646
+ let refusal;
647
+ try {
648
+ refusal = landRefusal(await judge({ commit: head, base: target }));
649
+ }
650
+ catch (err) {
651
+ refusal = `the pre-merge phases could not be judged: ${message(err)}`;
652
+ }
653
+ if (refusal)
654
+ return settle("refused", refusal);
655
+ // A plain push: the remote refuses it unless it fast-forwards the target, so a target that moved meanwhile refuses the land.
656
+ const pushed = spawnSync("git", ["push", "--quiet", "origin", `${head}:refs/heads/${place.branch}`], { cwd: place.top, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
657
+ if (pushed.status !== 0)
658
+ return settle("refused", `the push to ${place.branch} was refused: ${(pushed.stderr ?? "").trim().split("\n").pop() ?? ""}`);
659
+ const deleted = gitStatus(place.top, ["push", "--quiet", "origin", "--delete", `refs/heads/${branch}`]);
660
+ tryGit(place.top, ["update-ref", "-d", `refs/chant/ci-serve/land/${name}`]);
661
+ settle("landed", undefined, deleted.code === 0 ? undefined : `${branch} could not be deleted on the remote; delete it by hand`);
662
+ })().finally(() => rt.inflight.delete(key));
663
+ rt.inflight.set(key, job);
664
+ started.push(job);
665
+ }
666
+ return { started, events };
667
+ }
492
668
  /** `sh -c <command>` in a fresh detached worktree of the request's commit, removed after. Resolves to the exit code. */
493
669
  async function runBuild(input) {
494
670
  const dir = mkdtempSync(join(tmpdir(), "chant-ci-build-"));
@@ -579,6 +755,16 @@ export function formatCiServeEvent(e) {
579
755
  return `${what} waits: --max-jobs jobs run`;
580
756
  return e.status === "started" ? `${what} started` : e.status === "ok" ? `${what} passed` : `${what} failed${e.exitCode !== undefined ? ` with exit code ${e.exitCode}` : ""}`;
581
757
  }
758
+ case "land": {
759
+ const what = `${e.branch} at ${e.commit.slice(0, 12)}`;
760
+ if (e.status === "started")
761
+ return `${what}: the pre-merge phases started`;
762
+ if (e.status === "held")
763
+ return `${what} waits: ${e.reason ?? "--max-jobs jobs run"}`;
764
+ if (e.status === "refused")
765
+ return `${what} was refused and left on the remote: ${e.reason ?? "no reason given"}`;
766
+ return `${what} landed${e.warning ? `; ${e.warning}` : ", and the land branch was deleted"}`;
767
+ }
582
768
  case "tick":
583
769
  return e.made.length > 0 ? `ci tick made ${e.made.join(", ")}` : "ci tick: no tag due";
584
770
  case "error":
@@ -614,8 +800,8 @@ export function runnerKeySetupCommand(ctx) {
614
800
  return 0;
615
801
  }
616
802
  const USAGE = "chant ci serve --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>] | " +
617
- "chant ci serve --forge forgejo|github --repo <owner/repo> --env <env> [--interval <s>] [--max-jobs <n>] [--state <dir>] " +
618
- "[--author <login>]... [--once] [--rerun-failed] [--build-command <line>] [--gate <name>] [--wave-gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--no-status] [--status-url <url template>] " +
803
+ "chant ci serve --forge forgejo|github|git --repo <owner/repo> --env <env> [--interval <s>] [--max-jobs <n>] [--state <dir>] " +
804
+ "[--author <login>]... [--once] [--rerun-failed] [--build-command <line>] [--land] [--gate <name>] [--wave-gate <name>] [--branch <name>] [--events-json] [--report-url <url>] [--no-status] [--status-url <url template>] " +
619
805
  "[--image <image>] [--before-script <line>]... [--pr-build] [--pr-build-command <line>] [--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [--unsigned]";
620
806
  const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
621
807
  /** `--interval`: seconds, or a duration such as `30s` or `2m`. Default 30 seconds. */
@@ -627,6 +813,19 @@ export function ciServeInterval(value) {
627
813
  throw new CiRunError(`--interval takes seconds or a duration of a second or more, not ${JSON.stringify(value)}`);
628
814
  return ms;
629
815
  }
816
+ /** `ci.green.preMerge` where `cwd` is, for `--land` (#4168 4.4). Throws when the declaration names none. */
817
+ function preMergeOf(cwd) {
818
+ let pre;
819
+ try {
820
+ pre = readDeclaration(locateWorkspace(cwd).tree).ci?.green?.preMerge;
821
+ }
822
+ catch (err) {
823
+ throw new CiRunError(`--land reads ci.green.preMerge from the workspace declaration, which could not be read: ${message(err)}`);
824
+ }
825
+ if (!pre || pre.length === 0)
826
+ throw new CiRunError("--land runs the ci.green.preMerge phases on each land branch, and the declaration names none; add them to ci.green");
827
+ return pre;
828
+ }
630
829
  /** `chant ci serve` (#4095). */
631
830
  export async function runCiServe(ctx) {
632
831
  const { args } = ctx;
@@ -634,10 +833,14 @@ export async function runCiServe(ctx) {
634
833
  if (args.setupKey)
635
834
  return runnerKeySetupCommand(ctx);
636
835
  const forge = args.forge;
637
- if (forge !== "forgejo" && forge !== "github")
638
- throw new CiRunError(`--forge names the forge ci serve polls: --forge forgejo|github${forge ? `, not ${JSON.stringify(forge)}` : ""}`);
639
- if (!args.ciRepo)
836
+ if (forge !== "forgejo" && forge !== "github" && forge !== "git")
837
+ throw new CiRunError(`--forge names the forge ci serve polls: --forge forgejo|github|git${forge ? `, not ${JSON.stringify(forge)}` : ""}`);
838
+ // #4016 gap 6: a plain git server has no repository name to ask an API for, so --repo only labels the state file.
839
+ if (!args.ciRepo && forge !== "git")
640
840
  throw new CiRunError("--repo names the repository whose pull requests ci serve polls: --repo <owner/repo>");
841
+ // #4168 4.4: landing runs the pre-merge phases through the build command.
842
+ if (args.ciLand && !args.ciBuildCommand)
843
+ throw new CiRunError("--land runs each land branch's pre-merge phases with --build-command, so it needs one: --build-command '<line>'");
641
844
  if (!args.env)
642
845
  throw new CiRunError("--env names the environment the pipeline is for: --env <env>");
643
846
  for (const name of args.passEnv ?? [])
@@ -653,6 +856,8 @@ export async function runCiServe(ctx) {
653
856
  throw new CiRunError("ci serve runs in a clone of the repository it serves, and this directory is not in a git repository");
654
857
  const stateDir = args.statePath ? resolve(args.statePath) : defaultCiServeStateDir(cwd);
655
858
  const branch = args.branch ?? "main";
859
+ const repo = args.ciRepo ?? (tryGit(top, ["remote", "get-url", "origin"]) || "origin");
860
+ const landPhases = args.ciLand ? preMergeOf(cwd) : undefined;
656
861
  // #4099: the host's key, checked against .chant/trust.json at the target's head before the first poll.
657
862
  // #4156: signing is opt-in. Without ci.green.signedSince no key is quiet, and an untrusted one warns once and serves unsigned.
658
863
  const keyed = ciServeRunnerKey({
@@ -678,28 +883,41 @@ export async function runCiServe(ctx) {
678
883
  const reportUrl = await reportUrlOf(args.reportUrl, cwd);
679
884
  if (reportUrl && !args.reportUrl)
680
885
  console.error(`ci serve: reports and the run index go to ${reportUrl}, the declaration's ci.reportUrl`);
681
- const hostEnv = { ...process.env, GITHUB_REPOSITORY: args.ciRepo };
682
- const client = forgeFromEnv(forge, hostEnv);
683
- const { status, warning } = ciStatusFromEnv({ forge, hostEnv, noStatus: args.noStatus, statusUrl: args.statusUrl });
684
- if (warning)
685
- console.error(formatWarning({ message: warning }));
686
- if (!client.openPullRequests || !client.branchHead)
687
- throw new CiRunError(`the ${forge} client cannot list pull requests`);
886
+ const hostEnv = { ...process.env, GITHUB_REPOSITORY: repo };
887
+ let client;
888
+ let status;
889
+ if (forge === "git") {
890
+ // #4016 gap 6: refs only, and no commit status to set.
891
+ client = gitCiServeForge(top);
892
+ if (!args.noStatus)
893
+ console.error(formatWarning({ message: "the git forge kind has no API, so no commit status is set; each job's result is in the state file and its report" }));
894
+ }
895
+ else {
896
+ const api = forgeFromEnv(forge, hostEnv);
897
+ const fromEnv = ciStatusFromEnv({ forge, hostEnv, noStatus: args.noStatus, statusUrl: args.statusUrl });
898
+ if (fromEnv.warning)
899
+ console.error(formatWarning({ message: fromEnv.warning }));
900
+ status = fromEnv.status;
901
+ if (!api.openPullRequests || !api.branchHead)
902
+ throw new CiRunError(`the ${forge} client cannot list pull requests`);
903
+ client = { openPullRequests: api.openPullRequests.bind(api), branchHead: api.branchHead.bind(api), pullRequestFor: api.pullRequestFor.bind(api) };
904
+ }
688
905
  // #4168: a host that applied each merge before the upgrade hears that it no longer does.
689
906
  if (!args.applyOnMerge)
690
- console.error("ci serve: each new commit on the target branch gets the record job, which applies nothing (#4168); --apply-on-merge applies it");
907
+ console.error("ci serve: each new commit on the target branch gets the record job, which applies nothing (#4168); --apply-on-merge also applies each newest green commit");
691
908
  const opts = {
692
909
  cwd,
693
910
  forge,
694
- repo: args.ciRepo,
911
+ repo,
695
912
  env: args.env,
696
- client: { openPullRequests: client.openPullRequests.bind(client), branchHead: client.branchHead.bind(client), pullRequestFor: client.pullRequestFor.bind(client) },
913
+ client,
697
914
  stateDir,
698
915
  ...(args.maxJobs ? { maxJobs: args.maxJobs } : {}),
699
916
  ...(args.ciAuthors?.length ? { authors: args.ciAuthors } : {}),
700
917
  ...(args.rerunFailed ? { rerunFailed: true } : {}),
701
918
  ...(args.ciBuildCommand ? { buildCommand: args.ciBuildCommand } : {}),
702
919
  ...(args.applyOnMerge ? { applyOnMerge: true } : {}),
920
+ ...(landPhases ? { land: { phases: landPhases } } : {}),
703
921
  // #4168: the tick from the runs the jobs recorded, signed with the runs' key. No ci.green, no tick.
704
922
  tick: async () => {
705
923
  try {