fix: make pr merge idempotent for merged prs

This commit is contained in:
Codex
2026-06-05 15:10:24 +00:00
parent a951f6ff60
commit 74dc0b8c62
3 changed files with 23 additions and 0 deletions
File diff suppressed because one or more lines are too long
+9
View File
@@ -561,6 +561,15 @@ export async function runGhCliPrContract(): Promise<JsonRecord> {
assertCondition(mergeRequest !== undefined, "pr merge should call GitHub REST merge endpoint", mock.requests);
const mergePayload = JSON.parse(mergeRequest?.body ?? "{}") as JsonRecord;
assertCondition(mergePayload.merge_method === "squash", "pr merge should pass selected merge method", mergePayload);
const mergeRequestCount = mock.requests.filter((request) => request.method === "PUT" && request.url === "/repos/pikasTech/unidesk/pulls/42/merge").length;
const alreadyMerged = await runCli(["gh", "pr", "merge", "43", "--repo", "pikasTech/unidesk", "--squash"], env);
assertCondition(alreadyMerged.status === 0, "pr merge should treat an already merged PR as idempotent success", alreadyMerged.json ?? { stdout: alreadyMerged.stdout });
const alreadyMergedData = dataOf(alreadyMerged.json ?? {});
assertCondition(alreadyMergedData.alreadyMerged === true, "already merged PR response should expose alreadyMerged=true", alreadyMergedData);
const alreadyMergedPullRequest = alreadyMergedData.pullRequest as JsonRecord | undefined;
assertCondition(alreadyMergedPullRequest?.merged === true, "already merged PR response should expose merged pullRequest", alreadyMergedData);
const mergeRequestCountAfterAlreadyMerged = mock.requests.filter((request) => request.method === "PUT" && request.url === "/repos/pikasTech/unidesk/pulls/42/merge").length;
assertCondition(mergeRequestCountAfterAlreadyMerged === mergeRequestCount, "already merged PR should not call REST merge endpoint again", mock.requests);
const preflight = await runBun([
"scripts/code-queue-pr-preflight-example.ts",
+13
View File
@@ -4900,6 +4900,19 @@ async function prMerge(repo: string, token: string, number: number, options: Git
const pr = await githubRequest<GitHubPullRequest>(token, "GET", `/repos/${owner}/${name}/pulls/${number}`);
if (isGitHubError(pr)) return commandError("pr merge", repo, pr, { number, phase: "fetch-pr" });
const summary = prSummary(pr);
if (summary.merged === true) {
return {
ok: true,
command: "pr merge",
repo,
number,
method: options.mergeMethod,
alreadyMerged: true,
pullRequest: summary,
branchDeletion: { attempted: false, skippedReason: "already-merged" },
rest: true,
};
}
const metadata = await prGraphqlMetadata(repo, token, number);
if (isGitHubError(metadata)) return commandError("pr merge", repo, metadata, { number, phase: "fetch-pr-closeout-metadata", pullRequest: summary });
const statusChecks = statusRollupSummary(repo, number, metadata.statusCheckRollup, false);