fix: reconcile PR merge race

This commit is contained in:
Berlin Luk
2026-05-11 11:46:50 +08:00
parent 878fba40ab
commit 356e959114
3 changed files with 111 additions and 2 deletions

View File

@@ -502,6 +502,80 @@ describe("processPullRequestMergeTask", () => {
expect(store.moveTask).toHaveBeenCalledWith("FN-9004", "done");
});
it("reconciles to done when PR merges after readiness check but before merge command completes", async () => {
const task: MockTask = {
id: "FN-9104",
title: "test",
description: "desc",
column: "in-review",
worktree: "/tmp/worktree-fn-9104",
prInfo: {
number: 124,
url: "https://github.com/x/y/pull/124",
status: "open",
headBranch: "fusion/fn-9104",
baseBranch: "main",
},
};
const store = makeStore(task);
execMock.mockImplementation(() => "");
const openPr = {
number: 124,
url: "https://github.com/x/y/pull/124",
status: "open" as const,
headBranch: "fusion/fn-9104",
baseBranch: "main",
};
const mergedPr = {
...openPr,
status: "merged" as const,
};
const github = {
findPrForBranch: vi.fn(),
createPr: vi.fn(),
getPrMergeStatus: vi
.fn()
.mockResolvedValueOnce({
prInfo: openPr,
reviewDecision: "APPROVED",
checks: [],
mergeReady: true,
blockingReasons: [],
})
.mockResolvedValueOnce({
prInfo: mergedPr,
reviewDecision: "APPROVED",
checks: [],
mergeReady: true,
blockingReasons: [],
}),
mergePr: vi.fn(async () => {
throw new Error("Pull request is not mergeable: the merge commit cannot be cleanly created");
}),
};
const result = await processPullRequestMergeTask(
store as never,
"/repo",
task.id,
github as never,
() => undefined,
);
expect(result).toBe("merged");
expect(github.mergePr).toHaveBeenCalledWith({ number: 124, method: "squash" });
expect(github.getPrMergeStatus).toHaveBeenCalledTimes(2);
expect(store.updatePrInfo).toHaveBeenLastCalledWith("FN-9104", expect.objectContaining({ status: "merged" }));
expect(store.updateTask).toHaveBeenCalledWith("FN-9104", { status: null, mergeRetries: 0 });
expect(store.moveTask).toHaveBeenCalledWith("FN-9104", "done");
expect(store.logEntry).toHaveBeenCalledWith(
"FN-9104",
"Pull request already merged after merge command failed; reconciled task state from GitHub",
"PR #124: https://github.com/x/y/pull/124",
);
});
it("preserves PR number/url through create, refresh, and merge completion", async () => {
const task: MockTask = {
id: "FN-9103",