@intentius/chant 0.124.33 → 0.124.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/handlers/graph.js +2 -2
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +147 -51
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +284 -81
- package/dist/cli/handlers/release.d.ts +12 -0
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +125 -10
- package/dist/cli/handlers/run.d.ts +3 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +12 -2
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +37 -2
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +24 -0
- package/dist/cli/registry.d.ts +17 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +8 -1
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/auto-release.js +3 -2
- package/dist/components/green-cover.d.ts +77 -0
- package/dist/components/green-cover.d.ts.map +1 -0
- package/dist/components/green-cover.js +153 -0
- package/dist/components/pr-pipeline.d.ts +34 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +39 -5
- package/dist/components/promote-rounds.d.ts +102 -0
- package/dist/components/promote-rounds.d.ts.map +1 -0
- package/dist/components/promote-rounds.js +174 -0
- package/dist/components/promote.d.ts +4 -1
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +6 -3
- package/dist/components/release-gate.d.ts +30 -0
- package/dist/components/release-gate.d.ts.map +1 -1
- package/dist/components/release-gate.js +92 -42
- package/dist/components/release-promote.d.ts +9 -0
- package/dist/components/release-promote.d.ts.map +1 -1
- package/dist/components/release-promote.js +15 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/deep-observation.d.ts +11 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/graph-declared.d.ts +9 -1
- package/dist/graph-declared.d.ts.map +1 -1
- package/dist/graph-declared.js +18 -3
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +30 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-ir.js +13 -2
- package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -1
- package/dist/lifecycle/__fixtures__/publish-fakes.js +5 -1
- package/dist/lifecycle/compose-refs.d.ts +52 -0
- package/dist/lifecycle/compose-refs.d.ts.map +1 -0
- package/dist/lifecycle/compose-refs.js +115 -0
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.js +3 -2
- package/dist/lifecycle/green-apply.d.ts +39 -0
- package/dist/lifecycle/green-apply.d.ts.map +1 -0
- package/dist/lifecycle/green-apply.js +51 -0
- package/dist/lifecycle/publish-declaration.d.ts +4 -0
- package/dist/lifecycle/publish-declaration.d.ts.map +1 -1
- package/dist/lifecycle/publish-declaration.js +15 -0
- package/dist/lifecycle/publish-npm.d.ts +7 -4
- package/dist/lifecycle/publish-npm.d.ts.map +1 -1
- package/dist/lifecycle/publish-npm.js +60 -13
- package/dist/lifecycle/release-compose.d.ts +91 -0
- package/dist/lifecycle/release-compose.d.ts.map +1 -0
- package/dist/lifecycle/release-compose.js +235 -0
- package/dist/lifecycle/release-cut.d.ts +8 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -1
- package/dist/lifecycle/release-cut.js +2 -0
- package/dist/lifecycle/release-publish.d.ts +2 -0
- package/dist/lifecycle/release-publish.d.ts.map +1 -1
- package/dist/lifecycle/release-publish.js +2 -1
- package/dist/lifecycle/release-store.d.ts +15 -0
- package/dist/lifecycle/release-store.d.ts.map +1 -1
- package/dist/lifecycle/release-store.js +5 -1
- package/dist/wave-runtime.mjs +226 -224
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.js +13 -2
- package/dist/workspace/check.schema.json +20 -2
- package/dist/workspace/checks/ci-workflow.d.ts +17 -0
- package/dist/workspace/checks/ci-workflow.d.ts.map +1 -0
- package/dist/workspace/checks/ci-workflow.js +130 -0
- package/dist/workspace/checks/security.d.ts +16 -1
- package/dist/workspace/checks/security.d.ts.map +1 -1
- package/dist/workspace/checks/security.js +4 -4
- package/dist/workspace/checks.d.ts +1 -1
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +4 -1
- package/dist/workspace/ci-green-cli.d.ts.map +1 -1
- package/dist/workspace/ci-green-cli.js +5 -3
- package/dist/workspace/ci-green-workflow.d.ts +18 -2
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +27 -5
- package/dist/workspace/ci-green.d.ts +31 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +78 -4
- package/dist/workspace/ci-init.d.ts +100 -0
- package/dist/workspace/ci-init.d.ts.map +1 -0
- package/dist/workspace/ci-init.js +434 -0
- package/dist/workspace/ci-run.d.ts +6 -0
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +2 -1
- package/dist/workspace/ci-serve.d.ts +94 -13
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +248 -30
- package/dist/workspace/ci-workflow.d.ts +91 -0
- package/dist/workspace/ci-workflow.d.ts.map +1 -0
- package/dist/workspace/ci-workflow.js +33 -0
- package/dist/workspace/declaration.d.ts +18 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +9 -2
- package/dist/workspace/declaration.schema.json +28 -0
- package/dist/workspace/delivery-metrics.d.ts +3 -1
- package/dist/workspace/delivery-metrics.d.ts.map +1 -1
- package/dist/workspace/delivery-metrics.js +12 -3
- package/dist/workspace/init.js +2 -2
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/member-commands.js +4 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -1
- package/dist/workspace/nested-graph.js +1 -0
- package/dist/workspace/reason-codes.d.ts +9 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +10 -0
- package/dist/workspace/release-candidates.d.ts +28 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -1
- package/dist/workspace/release-candidates.js +38 -2
- package/dist/workspace/release-candidates.schema.json +51 -0
- package/dist/workspace/release-workflow.d.ts +31 -0
- package/dist/workspace/release-workflow.d.ts.map +1 -0
- package/dist/workspace/release-workflow.js +150 -0
- package/dist/workspace/releases.schema.json +30 -0
- package/package.json +1 -1
- package/src/cli/handlers/graph.ts +2 -2
- package/src/cli/handlers/pr-green.test.ts +230 -0
- package/src/cli/handlers/pr.ts +148 -66
- package/src/cli/handlers/promote.test.ts +34 -0
- package/src/cli/handlers/promote.ts +302 -91
- package/src/cli/handlers/release-compose.e2e.test.ts +133 -0
- package/src/cli/handlers/release.ts +112 -10
- package/src/cli/handlers/run.ts +12 -1
- package/src/cli/main.ts +37 -2
- package/src/cli/parse-args.ts +18 -0
- package/src/cli/registry.ts +17 -1
- package/src/codegen/release-wiring.test.ts +56 -9
- package/src/components/auto-release.test.ts +22 -0
- package/src/components/auto-release.ts +9 -2
- package/src/components/green-cover.test.ts +170 -0
- package/src/components/green-cover.ts +186 -0
- package/src/components/pr-pipeline.test.ts +14 -4
- package/src/components/pr-pipeline.ts +56 -5
- package/src/components/promote-rounds.test.ts +220 -0
- package/src/components/promote-rounds.ts +232 -0
- package/src/components/promote.test.ts +7 -0
- package/src/components/promote.ts +9 -4
- package/src/components/release-gate.test.ts +47 -0
- package/src/components/release-gate.ts +111 -46
- package/src/components/release-promote.test.ts +24 -1
- package/src/components/release-promote.ts +15 -0
- package/src/deep-observation.ts +8 -0
- package/src/graph-declared-exports.test.ts +40 -0
- package/src/graph-declared.test.ts +18 -0
- package/src/graph-declared.ts +17 -2
- package/src/graph-detail.test.ts +68 -1
- package/src/graph-detail.ts +29 -1
- package/src/graph-ir.ts +12 -4
- package/src/lifecycle/__fixtures__/publish-fakes.ts +5 -1
- package/src/lifecycle/compose-refs.ts +125 -0
- package/src/lifecycle/deep-observe.test.ts +20 -0
- package/src/lifecycle/deep-observe.ts +4 -2
- package/src/lifecycle/green-apply.ts +71 -0
- package/src/lifecycle/publish-declaration.ts +15 -0
- package/src/lifecycle/publish-npm.ts +55 -13
- package/src/lifecycle/publish-targets.test.ts +45 -0
- package/src/lifecycle/release-compose.test.ts +125 -0
- package/src/lifecycle/release-compose.ts +312 -0
- package/src/lifecycle/release-cut.ts +6 -0
- package/src/lifecycle/release-publish.ts +4 -1
- package/src/lifecycle/release-store.ts +16 -1
- package/src/workspace/__fixtures__/contract-repo.ts +11 -2
- package/src/workspace/check-contract.test.ts +3 -2
- package/src/workspace/check.schema.json +20 -2
- package/src/workspace/checks/ci-workflow.test.ts +160 -0
- package/src/workspace/checks/ci-workflow.ts +135 -0
- package/src/workspace/checks/security.ts +4 -4
- package/src/workspace/checks.ts +4 -1
- package/src/workspace/ci-green-cli.ts +5 -3
- package/src/workspace/ci-green-workflow.test.ts +52 -0
- package/src/workspace/ci-green-workflow.ts +34 -5
- package/src/workspace/ci-green.test.ts +33 -0
- package/src/workspace/ci-green.ts +85 -4
- package/src/workspace/ci-init.test.ts +159 -0
- package/src/workspace/ci-init.ts +445 -0
- package/src/workspace/ci-report-url.test.ts +6 -1
- package/src/workspace/ci-run.test.ts +18 -13
- package/src/workspace/ci-run.ts +8 -1
- package/src/workspace/ci-serve-land.e2e.test.ts +138 -0
- package/src/workspace/ci-serve-land.test.ts +176 -0
- package/src/workspace/ci-serve.test.ts +77 -43
- package/src/workspace/ci-serve.ts +268 -34
- package/src/workspace/ci-workflow.ts +71 -0
- package/src/workspace/declaration.schema.json +28 -0
- package/src/workspace/declaration.ts +32 -3
- package/src/workspace/delivery-metrics.ts +12 -3
- package/src/workspace/graph-contract.test.ts +3 -2
- package/src/workspace/init.ts +2 -2
- package/src/workspace/member-commands.test.ts +11 -4
- package/src/workspace/member-commands.ts +3 -0
- package/src/workspace/nested-graph.test.ts +4 -0
- package/src/workspace/nested-graph.ts +1 -0
- package/src/workspace/reason-codes.test.ts +2 -0
- package/src/workspace/reason-codes.ts +10 -0
- package/src/workspace/release-candidates.schema.json +51 -0
- package/src/workspace/release-candidates.test.ts +30 -3
- package/src/workspace/release-candidates.ts +54 -2
- package/src/workspace/release-workflow.ts +167 -0
- package/src/workspace/releases.schema.json +30 -0
|
@@ -143,8 +143,8 @@ function serve(app: string, client: CiServeForge, extra: Partial<CiServeOptions>
|
|
|
143
143
|
client,
|
|
144
144
|
stateDir: state,
|
|
145
145
|
holder: "serve-test",
|
|
146
|
-
//
|
|
147
|
-
applyOnMerge:
|
|
146
|
+
// #4168: a merge gets the record job; the apply-on-merge tests pass true and tag a commit green.
|
|
147
|
+
applyOnMerge: false,
|
|
148
148
|
// A job image of its own, so no setup line downloads OpenTofu.
|
|
149
149
|
job: { image: "chant-ci-serve-test:local", chant: fakeChant(), hostEnv: env, passEnv: Object.keys(hostEnv ?? {}) },
|
|
150
150
|
log: (e) => events.push(e),
|
|
@@ -155,6 +155,23 @@ function serve(app: string, client: CiServeForge, extra: Partial<CiServeOptions>
|
|
|
155
155
|
|
|
156
156
|
const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
157
157
|
|
|
158
|
+
/** A workspace that declares `ci.green`, so a `ci/green/<sha>` tag counts (#4168 step 9), with that commit pushed as main. */
|
|
159
|
+
function greenWorkspace(): ReturnType<typeof workspace> {
|
|
160
|
+
const w = workspace();
|
|
161
|
+
writeFiles(w.root, {
|
|
162
|
+
"chant.workspace.json": declaration([{ name: "app", dir: "app", kind: "other", because: "the app" }], { ci: { green: { branch: "main", phases: { test: ["test"] }, require: ["test"], source: "runs" } } }),
|
|
163
|
+
});
|
|
164
|
+
const main = commit(w.root, "app/green.txt", "declare ci.green");
|
|
165
|
+
git(w.root, "push", "-q", "origin", "main");
|
|
166
|
+
return { ...w, main };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Tag `sha` green on the forge, as the tick does. */
|
|
170
|
+
function tagGreen(root: string, sha: string): void {
|
|
171
|
+
git(root, "tag", "-f", `ci/green/${sha}`, sha);
|
|
172
|
+
git(root, "push", "-q", "-f", "origin", `refs/tags/ci/green/${sha}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
158
175
|
/** A commit on no branch, with `parent` when given, as a ledger commit stands in. */
|
|
159
176
|
const ledgerCommit = (root: string, message: string, parent?: string): string => git(root, "commit-tree", EMPTY_TREE, ...(parent ? ["-p", parent] : []), "-m", message);
|
|
160
177
|
|
|
@@ -183,7 +200,7 @@ describe("ci serve records each merge unless apply on merge is opted in (#4168)"
|
|
|
183
200
|
test("a merge to the target branch gets the record job, measured from the head before it, and no resume record", async () => {
|
|
184
201
|
const { root, app, main } = workspace();
|
|
185
202
|
const forge = fakeForge(main);
|
|
186
|
-
const { opts, events, state } = serve(app, forge
|
|
203
|
+
const { opts, events, state } = serve(app, forge);
|
|
187
204
|
await ciServePass(opts);
|
|
188
205
|
const merged = commit(root, "app/merged.txt");
|
|
189
206
|
git(root, "push", "-q", "origin", "main");
|
|
@@ -209,7 +226,6 @@ describe("ci serve records each merge unless apply on merge is opted in (#4168)"
|
|
|
209
226
|
const ticks: string[] = [];
|
|
210
227
|
let fail = false;
|
|
211
228
|
const { opts, events } = serve(app, forge, {
|
|
212
|
-
applyOnMerge: false,
|
|
213
229
|
tick: async () => {
|
|
214
230
|
ticks.push("tick");
|
|
215
231
|
if (fail) throw new Error("forge said no");
|
|
@@ -267,28 +283,49 @@ describe("chant ci serve (#4095)", () => {
|
|
|
267
283
|
expect(forge.polls).toBe(2);
|
|
268
284
|
});
|
|
269
285
|
|
|
270
|
-
test("a merge
|
|
271
|
-
const { root, app, main } =
|
|
286
|
+
test("under apply on merge a merge gets the record job, and the newest green commit the apply, once (#4168 step 9)", async () => {
|
|
287
|
+
const { root, app, main } = greenWorkspace();
|
|
272
288
|
const forge = fakeForge(main);
|
|
273
|
-
const { opts, events } = serve(app, forge);
|
|
289
|
+
const { opts, events } = serve(app, forge, { applyOnMerge: true });
|
|
274
290
|
expect((await ciServePass(opts)).jobs).toEqual([]);
|
|
275
291
|
expect(ofType(events, "baseline")).toHaveLength(1);
|
|
276
292
|
|
|
277
293
|
const merged = commit(root, "app/merged.txt");
|
|
278
294
|
git(root, "push", "-q", "origin", "main");
|
|
279
295
|
forge.head = merged;
|
|
296
|
+
// Not green yet: the merge is recorded, and nothing applies.
|
|
297
|
+
const recorded = await ciServePass(opts);
|
|
298
|
+
expect(recorded.jobs).toEqual([expect.objectContaining({ job: "record", commit: merged, base: main, status: "ok" })]);
|
|
299
|
+
|
|
300
|
+
tagGreen(root, merged);
|
|
280
301
|
const pass = await ciServePass(opts);
|
|
281
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged,
|
|
302
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged, status: "ok" })]);
|
|
303
|
+
expect(pass.jobs[0]!.pr).toBeUndefined();
|
|
282
304
|
const argv = argsOf(pass.jobs[0]!.report!, "pr-apply");
|
|
283
|
-
expect(argv.slice(0,
|
|
305
|
+
expect(argv.slice(0, 3)).toEqual(["components", "pr-apply", "--green"]);
|
|
306
|
+
expect(argv).not.toContain("--base");
|
|
284
307
|
expect(argv.slice(-2)).toEqual(["--resume", ".chant/pr-resume/pr-apply.json"]);
|
|
285
308
|
// The run was recorded on chant/lifecycle and pushed.
|
|
286
309
|
expect(git(root, "ls-remote", "origin", "chant/lifecycle")).toContain(git(root, "rev-parse", "chant/lifecycle"));
|
|
287
|
-
|
|
310
|
+
// The green commit is applied once, and the branch head the serve tracks stays the merge's.
|
|
288
311
|
expect((await ciServePass(opts)).jobs).toEqual([]);
|
|
312
|
+
const saved = readCiServeState(join(opts.stateDir!, `${prApplyGroup("prod", "app")}.json`), { forge: "forgejo", repo: "demo/estate", env: "prod", branch: "main" });
|
|
313
|
+
expect(saved.target).toBe(merged);
|
|
289
314
|
});
|
|
290
315
|
|
|
291
|
-
test("
|
|
316
|
+
test("without ci.green apply on merge has nothing to apply, and the merge is recorded", async () => {
|
|
317
|
+
const { root, app, main } = workspace();
|
|
318
|
+
const forge = fakeForge(main);
|
|
319
|
+
const { opts } = serve(app, forge, { applyOnMerge: true });
|
|
320
|
+
await ciServePass(opts);
|
|
321
|
+
const merged = commit(root, "app/merged.txt");
|
|
322
|
+
git(root, "push", "-q", "origin", "main");
|
|
323
|
+
forge.head = merged;
|
|
324
|
+
tagGreen(root, merged);
|
|
325
|
+
expect((await ciServePass(opts)).jobs).toEqual([expect.objectContaining({ job: "record", commit: merged, status: "ok" })]);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("a record gets the number of the pull request whose merge commit it is (#4112)", async () => {
|
|
292
329
|
const { root, app, main } = workspace();
|
|
293
330
|
const forge = fakeForge(main);
|
|
294
331
|
const seen: Array<number | undefined> = [];
|
|
@@ -301,7 +338,7 @@ describe("chant ci serve (#4095)", () => {
|
|
|
301
338
|
|
|
302
339
|
const pass = await ciServePass(opts);
|
|
303
340
|
expect(forge.asked).toEqual([merged]);
|
|
304
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
341
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", commit: merged, pr: 17, status: "ok" })]);
|
|
305
342
|
expect(seen).toEqual([17]);
|
|
306
343
|
});
|
|
307
344
|
|
|
@@ -315,25 +352,25 @@ describe("chant ci serve (#4095)", () => {
|
|
|
315
352
|
return { root, forge, seen, opts };
|
|
316
353
|
}
|
|
317
354
|
|
|
318
|
-
test("
|
|
355
|
+
test("a record with no pull request found runs without --pr (#4112)", async () => {
|
|
319
356
|
const { root, forge, seen, opts } = await mergeWithoutPr();
|
|
320
357
|
const direct = commit(root, "app/direct.txt");
|
|
321
358
|
git(root, "push", "-q", "origin", "main");
|
|
322
359
|
forge.head = direct;
|
|
323
360
|
const pass = await ciServePass(opts);
|
|
324
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
361
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", commit: direct, status: "ok" })]);
|
|
325
362
|
expect(pass.jobs[0]!.pr).toBeUndefined();
|
|
326
363
|
expect(seen).toEqual([undefined]);
|
|
327
364
|
});
|
|
328
365
|
|
|
329
|
-
test("
|
|
366
|
+
test("a record whose pull request lookup fails runs without --pr (#4112)", async () => {
|
|
330
367
|
const { root, forge, seen, opts } = await mergeWithoutPr();
|
|
331
368
|
const broken = commit(root, "app/broken.txt");
|
|
332
369
|
git(root, "push", "-q", "origin", "main");
|
|
333
370
|
forge.head = broken;
|
|
334
371
|
forge.merges.set(broken, "throw");
|
|
335
372
|
const pass = await ciServePass(opts);
|
|
336
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
373
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", commit: broken, status: "ok" })]);
|
|
337
374
|
expect(pass.jobs[0]!.pr).toBeUndefined();
|
|
338
375
|
expect(seen).toEqual([undefined]);
|
|
339
376
|
});
|
|
@@ -353,13 +390,12 @@ describe("chant ci serve (#4095)", () => {
|
|
|
353
390
|
});
|
|
354
391
|
|
|
355
392
|
test("the group's lease held elsewhere holds the apply until it is released", async () => {
|
|
356
|
-
const { root, app, main } =
|
|
393
|
+
const { root, app, main } = greenWorkspace();
|
|
357
394
|
const forge = fakeForge(main);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
forge.head = merged;
|
|
395
|
+
// The branch head is the green commit from the first poll, so only the apply is due.
|
|
396
|
+
const merged = main;
|
|
397
|
+
tagGreen(root, merged);
|
|
398
|
+
const { opts, events } = serve(app, forge, { applyOnMerge: true });
|
|
363
399
|
|
|
364
400
|
const group = prApplyGroup("prod", "app");
|
|
365
401
|
const other = await acquireLease(group, "other-host", { cwd: app, mode: "claim", requirePush: true });
|
|
@@ -371,7 +407,7 @@ describe("chant ci serve (#4095)", () => {
|
|
|
371
407
|
|
|
372
408
|
expect(await releaseLease(group, "other-host", other.lease!.token, { cwd: app })).toBe(true);
|
|
373
409
|
const ran = await ciServePass(opts);
|
|
374
|
-
expect(ran.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged,
|
|
410
|
+
expect(ran.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged, status: "ok" })]);
|
|
375
411
|
// The serve released its own lease after the apply.
|
|
376
412
|
expect((await acquireLease(group, "after", { cwd: app, mode: "claim" })).acquired).toBe(true);
|
|
377
413
|
});
|
|
@@ -387,13 +423,11 @@ describe("chant ci serve (#4095)", () => {
|
|
|
387
423
|
let record: string;
|
|
388
424
|
|
|
389
425
|
beforeAll(async () => {
|
|
390
|
-
w =
|
|
426
|
+
w = greenWorkspace();
|
|
391
427
|
forge = fakeForge(w.main);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
git(w.root, "push", "-q", "origin", "main");
|
|
396
|
-
forge.head = merged;
|
|
428
|
+
merged = w.main;
|
|
429
|
+
tagGreen(w.root, merged);
|
|
430
|
+
failing = serve(w.app, forge, { applyOnMerge: true, hostEnv: { FAKE_EXIT: "3", FAKE_ATTEMPT: "1" } });
|
|
397
431
|
failed = await ciServePass(failing.opts);
|
|
398
432
|
record = join(failing.state, "resume", `${prApplyRecordKey("prod", merged, "app")}.json`);
|
|
399
433
|
});
|
|
@@ -408,9 +442,9 @@ describe("chant ci serve (#4095)", () => {
|
|
|
408
442
|
});
|
|
409
443
|
|
|
410
444
|
test("--rerun-failed runs it again with its resume record", async () => {
|
|
411
|
-
const retry = serve(w.app, forge, { stateDir: failing.state, rerunFailed: true, hostEnv: { FAKE_EXIT: "0", FAKE_ATTEMPT: "2" } });
|
|
445
|
+
const retry = serve(w.app, forge, { applyOnMerge: true, stateDir: failing.state, rerunFailed: true, hostEnv: { FAKE_EXIT: "0", FAKE_ATTEMPT: "2" } });
|
|
412
446
|
const again = await ciServePass(retry.opts);
|
|
413
|
-
expect(again.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged,
|
|
447
|
+
expect(again.jobs).toEqual([expect.objectContaining({ job: "apply", commit: merged, status: "ok", attempts: 2 })]);
|
|
414
448
|
expect(ofType(retry.events, "started")[0]).toMatchObject({ attempt: 2, resume: record });
|
|
415
449
|
// The job read the first attempt's record, and left its own.
|
|
416
450
|
expect(JSON.parse(readFileSync(join(again.jobs[0]!.report!, "resume-in.json"), "utf-8"))).toEqual({ attempt: "1" });
|
|
@@ -450,7 +484,7 @@ describe("chant ci serve (#4095)", () => {
|
|
|
450
484
|
});
|
|
451
485
|
|
|
452
486
|
describe("ci serve follows the forge's chant/lifecycle (#4121)", () => {
|
|
453
|
-
/** A serve past its baseline pass, with one merge waiting to
|
|
487
|
+
/** A serve past its baseline pass, with one merge waiting to be recorded, and each run's result in `results`. */
|
|
454
488
|
async function mergeWaiting() {
|
|
455
489
|
const w = workspace();
|
|
456
490
|
const seed = seedLedger(w.root);
|
|
@@ -464,14 +498,14 @@ describe("ci serve follows the forge's chant/lifecycle (#4121)", () => {
|
|
|
464
498
|
return { ...w, seed, opts, events, results };
|
|
465
499
|
}
|
|
466
500
|
|
|
467
|
-
test("a ledger the forge deleted is deleted here, and the next
|
|
501
|
+
test("a ledger the forge deleted is deleted here, and the next job runs clean", async () => {
|
|
468
502
|
const { root, origin, seed, opts, events, results } = await mergeWaiting();
|
|
469
503
|
git(origin, "update-ref", "-d", "refs/heads/chant/lifecycle");
|
|
470
504
|
|
|
471
505
|
const pass = await ciServePass(opts);
|
|
472
506
|
expect(ofType(events, "ledger")).toEqual([{ type: "ledger", action: "deleted", local: seed }]);
|
|
473
507
|
expect(formatCiServeEvent(ofType(events, "ledger")[0]!)).toContain("was deleted");
|
|
474
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
508
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", status: "ok" })]);
|
|
475
509
|
expect(results[0]).toMatchObject({ pushed: true });
|
|
476
510
|
const tip = git(origin, "rev-parse", "refs/heads/chant/lifecycle");
|
|
477
511
|
expect(git(root, "rev-parse", "chant/lifecycle")).toBe(tip);
|
|
@@ -486,28 +520,28 @@ describe("ci serve follows the forge's chant/lifecycle (#4121)", () => {
|
|
|
486
520
|
|
|
487
521
|
const pass = await ciServePass(opts);
|
|
488
522
|
expect(ofType(events, "ledger")).toEqual([{ type: "ledger", action: "reset", local: seed, forge: rewritten }]);
|
|
489
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
523
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", status: "ok" })]);
|
|
490
524
|
expect(results[0]).toMatchObject({ pushed: true });
|
|
491
525
|
const tip = git(origin, "rev-parse", "refs/heads/chant/lifecycle");
|
|
492
526
|
expect(isAncestor(origin, rewritten, tip)).toBe(true);
|
|
493
527
|
expect(isAncestor(root, seed, tip)).toBe(false);
|
|
494
528
|
});
|
|
495
529
|
|
|
496
|
-
test("a ledger ahead of the forge's keeps its facts, and the
|
|
530
|
+
test("a ledger ahead of the forge's keeps its facts, and the job pushes them", async () => {
|
|
497
531
|
const { root, origin, seed, opts, events, results } = await mergeWaiting();
|
|
498
532
|
const ahead = ledgerCommit(root, "unpushed fact", seed);
|
|
499
533
|
git(root, "update-ref", "refs/heads/chant/lifecycle", ahead);
|
|
500
534
|
|
|
501
535
|
const pass = await ciServePass(opts);
|
|
502
536
|
expect(ofType(events, "ledger")).toEqual([]);
|
|
503
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
537
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", status: "ok" })]);
|
|
504
538
|
expect(results[0]).toMatchObject({ pushed: true });
|
|
505
539
|
expect(isAncestor(origin, ahead, git(origin, "rev-parse", "refs/heads/chant/lifecycle"))).toBe(true);
|
|
506
540
|
});
|
|
507
541
|
});
|
|
508
542
|
|
|
509
|
-
describe("ci serve
|
|
510
|
-
test("a force push back to an older commit is recorded as seen and not
|
|
543
|
+
describe("ci serve runs fast-forwards only, and honours [skip ci] (#4122)", () => {
|
|
544
|
+
test("a force push back to an older commit is recorded as seen and not run, and the next fast-forward is recorded", async () => {
|
|
511
545
|
const { root, app, main } = workspace();
|
|
512
546
|
const later = commit(root, "app/later.txt");
|
|
513
547
|
git(root, "push", "-q", "origin", "main");
|
|
@@ -521,7 +555,7 @@ describe("ci serve applies fast-forwards only, and honours [skip ci] (#4122)", (
|
|
|
521
555
|
forge.head = main;
|
|
522
556
|
const back = await ciServePass(opts);
|
|
523
557
|
expect(back.jobs).toEqual([]);
|
|
524
|
-
expect(ofType(events, "not-run")).toEqual([{ type: "not-run", job: "
|
|
558
|
+
expect(ofType(events, "not-run")).toEqual([{ type: "not-run", job: "record", commit: main, reason: "not-fast-forward", branch: "main", from: later }]);
|
|
525
559
|
expect(formatCiServeEvent(ofType(events, "not-run")[0]!)).toContain("not a fast-forward");
|
|
526
560
|
const file = join(state, `${prApplyGroup("prod", "app")}.json`);
|
|
527
561
|
expect(readCiServeState(file, { forge: "forgejo", repo: "demo/estate", env: "prod", branch: "main" }).target).toBe(main);
|
|
@@ -530,10 +564,10 @@ describe("ci serve applies fast-forwards only, and honours [skip ci] (#4122)", (
|
|
|
530
564
|
git(root, "push", "-q", "origin", "main");
|
|
531
565
|
forge.head = next;
|
|
532
566
|
const pass = await ciServePass(opts);
|
|
533
|
-
expect(pass.jobs).toEqual([expect.objectContaining({ job: "
|
|
567
|
+
expect(pass.jobs).toEqual([expect.objectContaining({ job: "record", commit: next, base: main, status: "ok" })]);
|
|
534
568
|
});
|
|
535
569
|
|
|
536
|
-
test("a target head whose message says [skip ci] is recorded as seen and not
|
|
570
|
+
test("a target head whose message says [skip ci] is recorded as seen and not run", async () => {
|
|
537
571
|
const { root, app, main } = workspace();
|
|
538
572
|
const forge = fakeForge(main);
|
|
539
573
|
const { opts, events, state } = serve(app, forge);
|
|
@@ -543,7 +577,7 @@ describe("ci serve applies fast-forwards only, and honours [skip ci] (#4122)", (
|
|
|
543
577
|
forge.head = skip;
|
|
544
578
|
|
|
545
579
|
expect((await ciServePass(opts)).jobs).toEqual([]);
|
|
546
|
-
expect(ofType(events, "not-run")).toEqual([{ type: "not-run", job: "
|
|
580
|
+
expect(ofType(events, "not-run")).toEqual([{ type: "not-run", job: "record", commit: skip, reason: "skip-ci" }]);
|
|
547
581
|
expect(formatCiServeEvent(ofType(events, "not-run")[0]!)).toContain("says [skip ci]");
|
|
548
582
|
const file = join(state, `${prApplyGroup("prod", "app")}.json`);
|
|
549
583
|
expect(readCiServeState(file, { forge: "forgejo", repo: "demo/estate", env: "prod", branch: "main" }).target).toBe(skip);
|