Merge a pull request marked ready at its head once its checks pass (issue 722)
mesh/merge-gate out of date: judged against trunk 482232e8c51c, the trunk is now 7e3e62062bef; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 482232e8c51c, the trunk is now 7e3e62062bef; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request

The operator wants a reviewed pull request merged without a session calling
the merge tool again after every recheck. The reviewer marks it ready (label
mesh/ready and a comment "ready at <full head sha>"); the forge's open-pulls
read carries the mark, and mesh-delivery merges through gitea_merge_pull_request
at that head, in a group's order once its composed check passed. A push after
the mark clears it; a failed check is said on the pull request and as a
stalled line.
This commit is contained in:
2026-10-14 21:23:26 +02:00
parent 482232e8c5
commit 7e0001e304
15 changed files with 688 additions and 10 deletions
+49
View File
@@ -137,3 +137,52 @@ test("a merged pull request whose branch was deleted is announced with its branc
assert.equal(headBranchOf({ ref: "refs/pull/7/head" }), "refs/pull/7/head");
assert.equal(headBranchOf(undefined), undefined);
});
// **A pull request marked ready says the head it is marked at** (novox/hq issue 722): the label mesh/ready and the
// newest comment "ready at <full head sha>". mesh-delivery merges on it; without the label no comment is read.
test("a pull request's ready mark is read: the label and the head the newest ready comment names", async () => {
const { GiteaClient } = await import("../client.ts");
const head = "c".repeat(40), older = "d".repeat(40);
const asked: string[] = [];
const server = createServer((req, res) => {
const url = req.url ?? "";
asked.push(url);
const send = (v: unknown) => res.end(JSON.stringify(v));
if (url.startsWith("/api/v1/repos/issues/search")) {
return send(url.includes("page=1") ? [
{ number: 7, repository: { owner: "novox", name: "hq", full_name: "novox/hq" },
labels: [{ id: 31, name: "mesh/ready" }, { id: 2, name: "bug" }] },
{ number: 8, repository: { owner: "novox", name: "hq", full_name: "novox/hq" }, labels: [] },
] : []);
}
if (url.startsWith("/api/v1/repos/novox/hq/pulls/7")) {
return send({ number: 7, state: "open", base: { ref: "main" }, head: { ref: "x", sha: head }, html_url: "h" });
}
if (url.startsWith("/api/v1/repos/novox/hq/pulls/8")) {
return send({ number: 8, state: "open", base: { ref: "main" }, head: { ref: "y", sha: older }, html_url: "h" });
}
if (url.startsWith("/api/v1/repos/novox/hq/issues/7/comments")) {
return send([
{ id: 1, user: { login: "mesh" }, body: `ready at ${older}`, created_at: "2026-10-14T10:00:00Z" },
{ id: 2, user: { login: "mesh" }, body: `Reviewed: approve.\nready at ${head}\n`, created_at: "2026-10-14T11:00:00Z" },
{ id: 3, user: { login: "jochen" }, body: "thanks", created_at: "2026-10-14T12:00:00Z" },
]);
}
if (url.includes("/branch_protections")) return send([]);
if (url.includes("/status")) return send({ statuses: [] });
res.statusCode = 404;
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 {
const open = await client.openPulls();
assert.deepEqual(open[0].labels, ["mesh/ready", "bug"]);
assert.deepEqual(open[0].ready, { head, by: "mesh", at: "2026-10-14T11:00:00Z", label_id: 31 },
"the newest comment that names a head");
assert.equal(open[1].ready, undefined, "no label, no mark");
assert.ok(!asked.some((u) => u.includes("/issues/8/comments")), "no comment read without the label");
} finally {
server.close();
}
});