mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
The announcer read only the repositories whose update time moved since its last pass, less a minute. Opening, reopening or retargeting a pull request does not move a repository's update time, so a pull request opened more than a minute after its push was never announced, never checked, and nothing said so (mesh-sdk #14, 2026-10-09). - Each pass also looks at every repository holding a pull request updated since the floor, by the forge's own search; every ten minutes, or when the search fails, at every repository. - Every five minutes the forge is asked for every open pull request; one on a base requiring mesh/merge-gate whose head has had none for ten minutes is said as the forge failing that pull request's merge check (a provider standing, ADR 0224), which the controller keeps as a condition, and is recovered when a check arrives or it closes. - The client refuses a pull request or issue number that is not one before asking the forge (a misnamed tool argument sent pulls/NaN).
62 lines
3.5 KiB
TypeScript
62 lines
3.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import { createServer } from "node:http";
|
|
|
|
// **A pull request opened after its push is still checked** (novox/hq issue 347). The announcer read only the
|
|
// repositories whose update time moved since its last pass, less a minute's margin; opening, reopening or
|
|
// retargeting a pull request does not move a repository's update time, so a pull request opened more than a
|
|
// minute or so after its push was never announced, never checked, and nothing said so.
|
|
|
|
const repo = (full: string, updated: string) => {
|
|
const [owner, name] = full.split("/");
|
|
return { full_name: full, owner, name, private: false, html_url: "", updated_at: updated };
|
|
};
|
|
|
|
test("a pull request opened after the margin is looked at, by its own update time", async () => {
|
|
const { reposToLook } = await import("../pulls.ts");
|
|
const pushed = "2026-10-09T10:00:00Z"; // the branch pushed: the repository's update time
|
|
// The pull request opened two minutes later; the last pass was at 10:02:30, so the floor is 10:01:30.
|
|
const floor = "2026-10-09T10:01:30Z";
|
|
const repos = [repo("novox/mesh-sdk", pushed), repo("novox/hq", "2026-10-09T09:00:00Z")];
|
|
const opened = [{ owner: "novox", name: "mesh-sdk", updated_at: "2026-10-09T10:02:00Z" }];
|
|
assert.deepEqual(reposToLook(repos, floor, opened, false).map((r) => r.full_name), ["novox/mesh-sdk"],
|
|
"the repository of a pull request updated since the floor, though the repository itself did not move");
|
|
assert.deepEqual(reposToLook(repos, floor, [], false).map((r) => r.full_name), [],
|
|
"without the pull request's own time nothing is looked at — the fault");
|
|
assert.deepEqual(reposToLook(repos, floor, [], true).map((r) => r.full_name).sort(), ["novox/hq", "novox/mesh-sdk"],
|
|
"a sweep looks at every repository");
|
|
assert.deepEqual(reposToLook(repos, "", [], false).length, 2, "the first pass looks at every repository");
|
|
});
|
|
|
|
test("an open pull request on a protected branch with no merge check for ten minutes is said, and nothing else", async () => {
|
|
const { unannounced } = await import("../pulls.ts");
|
|
const now = Date.parse("2026-10-09T10:30:00Z");
|
|
const pull = {
|
|
key: "novox/mesh-sdk#14", base: "main", head_sha: "bfe82315f42c", updated_at: "2026-10-09T10:12:00Z",
|
|
statuses: [] as string[], required: ["mesh/merge-gate", "mesh/repo-check"],
|
|
};
|
|
assert.deepEqual(unannounced([pull], now).map((p) => p.key), ["novox/mesh-sdk#14"]);
|
|
assert.deepEqual(unannounced([{ ...pull, statuses: ["mesh/merge-gate"] }], now), [], "a head with a merge check");
|
|
assert.deepEqual(unannounced([{ ...pull, required: [] }], now), [], "a branch that requires no merge check");
|
|
assert.deepEqual(unannounced([{ ...pull, updated_at: "2026-10-09T10:25:00Z" }], now), [], "a head five minutes old");
|
|
});
|
|
|
|
test("a pull request or issue number that is not one is refused before the forge is asked", async () => {
|
|
const { GiteaClient } = await import("../client.ts");
|
|
let asked = 0;
|
|
const server = createServer((_req, res) => {
|
|
asked++;
|
|
res.end("{}");
|
|
});
|
|
await new Promise<void>((r) => server.listen(0, r));
|
|
const client = new GiteaClient(`http://127.0.0.1:${(server.address() as any).port}`, "t");
|
|
try {
|
|
await assert.rejects(client.getPullRequest("novox", "hq", Number(undefined)), /whole number/);
|
|
await assert.rejects(client.addComment("novox", "hq", 0, "x"), /whole number/);
|
|
await assert.rejects(client.listPullFiles("novox", "hq", 1.5), /whole number/);
|
|
assert.equal(asked, 0, "the forge was asked about pulls/NaN");
|
|
} finally {
|
|
server.close();
|
|
}
|
|
});
|