feat(FN-4763): complete Step 1 — capture PR mergeable state

Fusion-Task-Id: FN-4763
Fusion-Task-Lineage: b3628e63-682b-4a39-9a7d-2c96278c5366
This commit is contained in:
Fusion (runfusion.ai)
2026-05-17 12:29:53 -07:00
committed by gsxdsm
parent 1f8d995b82
commit 9d5d310fdc
3 changed files with 88 additions and 2 deletions

View File

@@ -1105,6 +1105,8 @@ describe("GitHubClient", () => {
title: "Ready PR",
state: "OPEN",
reviewDecision: "APPROVED",
mergeable: "MERGEABLE",
mergeStateStatus: "CLEAN",
baseRefName: "main",
headRefName: "fusion/fn-093",
})
@@ -1116,6 +1118,8 @@ describe("GitHubClient", () => {
const result = await client.getPrMergeStatus("owner", "repo", 42);
expect(result.mergeReady).toBe(true);
expect(result.mergeable).toBe("clean");
expect(result.prInfo.mergeable).toBe("clean");
expect(result.blockingReasons).toEqual([]);
expect(result.checks).toEqual([
{
@@ -1130,6 +1134,44 @@ describe("GitHubClient", () => {
]);
});
it("maps DIRTY merge-state to conflicting even when mergeable is unknown", async () => {
mockRunGhJsonAsync
.mockResolvedValueOnce({
number: 42,
url: "https://github.com/owner/repo/pull/42",
title: "Dirty PR",
state: "OPEN",
reviewDecision: "APPROVED",
mergeable: "UNKNOWN",
mergeStateStatus: "DIRTY",
baseRefName: "main",
headRefName: "fusion/fn-093",
})
.mockResolvedValueOnce([{ name: "ci", state: "SUCCESS" }]);
const result = await client.getPrMergeStatus("owner", "repo", 42);
expect(result.mergeable).toBe("conflicting");
expect(result.prInfo.mergeable).toBe("conflicting");
});
it("maps missing mergeability fields to unknown", async () => {
mockRunGhJsonAsync
.mockResolvedValueOnce({
number: 42,
url: "https://github.com/owner/repo/pull/42",
title: "Unknown PR",
state: "OPEN",
reviewDecision: "APPROVED",
baseRefName: "main",
headRefName: "fusion/fn-093",
})
.mockResolvedValueOnce([{ name: "ci", state: "SUCCESS" }]);
const result = await client.getPrMergeStatus("owner", "repo", 42);
expect(result.mergeable).toBe("unknown");
expect(result.prInfo.mergeable).toBe("unknown");
});
it("falls back to GraphQL API when gh CLI merge-status lookup fails and token is available", async () => {
mockRunGhJsonAsync.mockRejectedValue(new Error("gh failed"));
const clientWithToken = new GitHubClient("ghp_token");
@@ -1144,6 +1186,8 @@ describe("GitHubClient", () => {
title: "Fallback PR",
state: "OPEN",
reviewDecision: null,
mergeable: "CONFLICTING",
mergeStateStatus: "DIRTY",
baseRefName: "main",
headRefName: "fusion/fn-093",
comments: { totalCount: 0 },
@@ -1196,6 +1240,8 @@ describe("GitHubClient", () => {
const result = await clientWithToken.getPrMergeStatus("owner", "repo", 42);
expect(result.mergeReady).toBe(true);
expect(result.mergeable).toBe("conflicting");
expect(result.prInfo.mergeable).toBe("conflicting");
expect(result.checks).toEqual([
{
name: "ci",