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
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:
+38
-4
@@ -101,6 +101,34 @@ export interface OpenPull {
|
||||
/** The head's statuses by context, the newest of each, with its state (novox/hq issue 438): what tells a check
|
||||
* that started and never answered — pending — from one that answered. */
|
||||
checks: Record<string, HeadCheck>;
|
||||
/** The pull request's labels, by name. */
|
||||
labels?: string[];
|
||||
/** Its ready mark (novox/hq issue 722): the label `mesh/ready` and the newest comment "ready at <full head sha>", the
|
||||
* head a reviewer approved. Absent without the label; `head` empty when the label names no head in a comment. */
|
||||
ready?: ReadyMark;
|
||||
}
|
||||
|
||||
/** The label that marks a pull request ready to merge at the head a comment names (novox/hq issue 722). */
|
||||
export const READY_LABEL = "mesh/ready";
|
||||
|
||||
/** A comment that names the head a pull request is marked ready at: "ready at <full sha>", on a line of its own. */
|
||||
const READY_AT = /^\s*ready at ([0-9a-f]{40}|[0-9a-f]{64})\b/im;
|
||||
|
||||
/** A pull request's ready mark: the head it names, who said it and when, and the label's id, to take it off. */
|
||||
export interface ReadyMark {
|
||||
head: string;
|
||||
by?: string;
|
||||
at?: string;
|
||||
label_id: number;
|
||||
}
|
||||
|
||||
/** The ready mark a pull request's comments make, oldest first as the forge lists them: the newest that names a head. */
|
||||
export function readyMarkOf(labelID: number, comments: GiteaComment[]): ReadyMark {
|
||||
for (let i = comments.length - 1; i >= 0; i--) {
|
||||
const m = READY_AT.exec(comments[i].body);
|
||||
if (m) return { head: m[1].toLowerCase(), by: comments[i].user, at: comments[i].created_at, label_id: labelID };
|
||||
}
|
||||
return { head: "", label_id: labelID };
|
||||
}
|
||||
|
||||
/** One status on a head, the newest of its context: its state, what it said, and when it was set. */
|
||||
@@ -332,8 +360,9 @@ export class GiteaClient {
|
||||
|
||||
/** The open pull requests of every repository the mesh's account sees, updated since a moment when one is given,
|
||||
* page by page (novox/hq issue 347): each with its repository and its own update time. */
|
||||
async searchOpenPulls(since?: string): Promise<{ owner: string; name: string; number: number; updated_at?: string }[]> {
|
||||
const out: { owner: string; name: string; number: number; updated_at?: string }[] = [];
|
||||
async searchOpenPulls(since?: string): Promise<{ owner: string; name: string; number: number; updated_at?: string;
|
||||
labels?: { id: number; name: string }[] }[]> {
|
||||
const out: { owner: string; name: string; number: number; updated_at?: string; labels?: { id: number; name: string }[] }[] = [];
|
||||
for (let page = 1; page <= 20; page++) {
|
||||
const qs = new URLSearchParams({ type: "pulls", state: "open", limit: "50", page: String(page) });
|
||||
if (since) qs.set("since", since);
|
||||
@@ -343,7 +372,8 @@ export class GiteaClient {
|
||||
const [fo, fn] = String(r.full_name ?? "").split("/");
|
||||
const owner = String(r.owner ?? fo ?? "");
|
||||
const name = String(r.name ?? fn ?? "");
|
||||
if (owner && name && i?.number) out.push({ owner, name, number: Number(i.number), updated_at: i.updated_at });
|
||||
const labels = (Array.isArray(i?.labels) ? i.labels : []).map((l: any) => ({ id: Number(l?.id ?? 0), name: String(l?.name ?? "") }));
|
||||
if (owner && name && i?.number) out.push({ owner, name, number: Number(i.number), updated_at: i.updated_at, labels });
|
||||
}
|
||||
if (!found || found.length < 50) break;
|
||||
}
|
||||
@@ -364,9 +394,13 @@ export class GiteaClient {
|
||||
if (!rules.has(full)) rules.set(full, await this.branchProtections(found.owner, found.name).catch(() => undefined));
|
||||
const rule = rules.get(full)?.find((p) => (p.rule_name ?? p.branch_name) === (pull.base || "main"));
|
||||
const checks = await this.headChecks(found.owner, found.name, pull.head_sha);
|
||||
const labels = found.labels ?? [];
|
||||
// The ready mark (novox/hq issue 722): its comments are read only for a pull request that carries the label.
|
||||
const label = labels.find((l) => l.name === READY_LABEL);
|
||||
const ready = label ? readyMarkOf(label.id, await this.listComments(found.owner, found.name, pull.number)) : undefined;
|
||||
out.push({ owner: found.owner, repo: found.name, number: pull.number, base: pull.base ?? "", head_sha: pull.head_sha,
|
||||
html_url: pull.html_url, required: rule?.enable_status_check ? (rule.status_check_contexts ?? []) : [],
|
||||
statuses: Object.keys(checks), checks });
|
||||
statuses: Object.keys(checks), checks, labels: labels.map((l) => l.name), ...(ready ? { ready } : {}) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user