mesh/delivery merged: source.main moved to novox/mesh-catalog@774fcdfa93ad
mesh/check being carried to 470687ea4cce on 774fcdfa93ad | from 2a03c106f4b9
An edited pull request is announced into its new base at once; a close without a merge is announced by its event; the 30 s/5 min polls and the 10 min sweep are gone.
74 lines
3.3 KiB
TypeScript
74 lines
3.3 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { mock, test } from "node:test";
|
|
import type { GiteaPull } from "../client.ts";
|
|
|
|
// **No poll of the forge** (issue 1422, notes 10 and 11): the forge's events announce heads and merges; a pass runs once at
|
|
// the start and when the receiver listens.
|
|
|
|
const edited = (base: string) => ({ name: "forge.pull-request.edited", body: { owner: "novox", repo: "hq", number: 7, base, merged: false } });
|
|
|
|
function deps() {
|
|
const calls: string[] = [];
|
|
return { calls, d: {
|
|
getRepo: async () => ({ r: 1 }),
|
|
getPull: async () => ({ state: "open", base: "trunk" }) as any,
|
|
announceHead: async () => { calls.push("head"); },
|
|
announceMerge: async () => { calls.push("merge"); },
|
|
announceClosed: async () => { calls.push("closed"); },
|
|
siblingMoves: async () => { calls.push("siblings"); },
|
|
} };
|
|
}
|
|
|
|
test("an edited event announces the head into the base it now has, without a poll", async () => {
|
|
const { actOn } = await import("../watch.ts");
|
|
const { calls, d } = deps();
|
|
await actOn(edited("trunk"), d);
|
|
assert.deepEqual(calls, ["head"]);
|
|
});
|
|
|
|
test("a close without a merge is announced by its event, a merged close is left to the merge event", async () => {
|
|
const { actOn } = await import("../watch.ts");
|
|
const { calls, d } = deps();
|
|
await actOn({ name: "forge.pull-request.closed", body: { owner: "novox", repo: "hq", number: 7, merged: false } }, d);
|
|
assert.deepEqual(calls, ["closed", "siblings"]);
|
|
calls.length = 0;
|
|
await actOn({ name: "forge.pull-request.closed", body: { owner: "novox", repo: "hq", number: 7, merged: true } }, d);
|
|
assert.deepEqual(calls, []);
|
|
});
|
|
|
|
test("no timer polls after the start: one pass ends and nothing is scheduled; a failed one is asked again", async () => {
|
|
const { startPass } = await import("../watch.ts");
|
|
mock.timers.enable({ apis: ["setTimeout", "setInterval"] });
|
|
try {
|
|
let runs = 0;
|
|
await startPass(async () => { runs++; }, { retryMs: 60_000, log: () => {} });
|
|
mock.timers.tick(24 * 3600_000);
|
|
assert.equal(runs, 1, "a day later the forge was not asked again");
|
|
let tries = 0;
|
|
const retried = startPass(async () => { if (++tries < 2) throw new Error("forge down"); }, { retryMs: 60_000, log: () => {} });
|
|
await Promise.resolve(); await Promise.resolve();
|
|
mock.timers.tick(60_000);
|
|
await retried;
|
|
assert.equal(tries, 2);
|
|
} finally {
|
|
mock.timers.reset();
|
|
}
|
|
});
|
|
|
|
test("a start pass announces a head nobody announced, and only remembers one the forge shows a check of", async () => {
|
|
const { announceNewHeads } = await import("../watch.ts");
|
|
const pull = (n: number, sha: string): GiteaPull => ({ number: n, state: "open", head_sha: sha, base: "main",
|
|
updated_at: new Date().toISOString() } as unknown as GiteaPull);
|
|
const announced: number[] = [], said: string[] = [];
|
|
const heads: Record<string, string> = {};
|
|
await announceNewHeads("novox/hq", [pull(1, "a".repeat(40)), pull(2, "b".repeat(40))], heads, false,
|
|
new Date(Date.now() - 24 * 3600_000).toISOString(), {
|
|
alreadyChecked: async (p) => p.number === 2,
|
|
announceHead: async (p) => { announced.push(p.number); return true; },
|
|
missed: (w) => said.push(w),
|
|
});
|
|
assert.deepEqual(announced, [1]);
|
|
assert.equal(heads["novox/hq#2@main"], "b".repeat(40), "the checked head is remembered, not announced");
|
|
assert.equal(said.length, 1);
|
|
});
|