Skip to content

Commit c3bf66d

Browse files
stakeswkyUser
andauthored
fix: handle fork PRs by fetching via refs/pull/N/head (#962) (#963)
When a PR originates from a fork, `git fetch origin <branch>` fails because the branch only exists on the fork's remote. Fix: detect cross-repository PRs via the `isCrossRepository` GraphQL field and fetch using `pull/<number>/head:<branch>` refspec instead, which is the standard GitHub mechanism for accessing fork PR branches. Changes: - Add `isCrossRepository` and `headRepository` to PR GraphQL query - Add corresponding fields to GitHubPullRequest type - Branch checkout uses pull ref for fork PRs - Update test fixtures with new fields Co-authored-by: User <user@example.com>
1 parent 3943183 commit c3bf66d

File tree

7 files changed

+39
-3
lines changed

7 files changed

+39
-3
lines changed

src/github/api/queries/github.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ export const PR_QUERY = `
1212
baseRefName
1313
headRefName
1414
headRefOid
15+
isCrossRepository
16+
headRepository {
17+
owner {
18+
login
19+
}
20+
name
21+
}
1522
createdAt
1623
updatedAt
1724
lastEditedAt

src/github/operations/branch.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,23 @@ export async function setupBranch(
166166
// Validate branch names before use to prevent command injection
167167
validateBranchName(branchName);
168168

169-
// Execute git commands to checkout PR branch (dynamic depth based on PR size)
170-
// Using execFileSync instead of shell template literals for security
171-
execGit(["fetch", "origin", `--depth=${fetchDepth}`, branchName]);
169+
// For cross-repository (fork) PRs, fetch via the pull ref since the
170+
// branch only exists on the fork's remote, not on origin.
171+
if (prData.isCrossRepository) {
172+
console.log(
173+
`PR #${entityNumber} is from a fork, fetching via refs/pull/${entityNumber}/head...`,
174+
);
175+
execGit([
176+
"fetch",
177+
"origin",
178+
`--depth=${fetchDepth}`,
179+
`pull/${entityNumber}/head:${branchName}`,
180+
]);
181+
} else {
182+
// Execute git commands to checkout PR branch (dynamic depth based on PR size)
183+
// Using execFileSync instead of shell template literals for security
184+
execGit(["fetch", "origin", `--depth=${fetchDepth}`, branchName]);
185+
}
172186
execGit(["checkout", branchName, "--"]);
173187

174188
console.log(`Successfully checked out PR branch for PR #${entityNumber}`);

src/github/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ export type GitHubPullRequest = {
5757
baseRefName: string;
5858
headRefName: string;
5959
headRefOid: string;
60+
isCrossRepository: boolean;
61+
headRepository: {
62+
owner: {
63+
login: string;
64+
};
65+
name: string;
66+
} | null;
6067
createdAt: string;
6168
updatedAt?: string;
6269
lastEditedAt?: string;

test/create-prompt.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ describe("generatePrompt", () => {
2727
baseRefName: "main",
2828
headRefName: "feature-branch",
2929
headRefOid: "abc123",
30+
isCrossRepository: false,
31+
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
3032
commits: {
3133
totalCount: 2,
3234
nodes: [

test/data-fetcher.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,8 @@ describe("fetchGitHubData integration with time filtering", () => {
10061006
baseRefName: "main",
10071007
headRefName: "feature",
10081008
headRefOid: "abc123",
1009+
isCrossRepository: false,
1010+
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
10091011
createdAt: "2024-01-15T10:00:00Z",
10101012
updatedAt: "2024-01-15T12:30:00Z", // Edited after trigger
10111013
lastEditedAt: "2024-01-15T12:30:00Z", // Edited after trigger

test/data-formatter.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ describe("formatContext", () => {
2424
baseRefName: "main",
2525
headRefName: "feature/test",
2626
headRefOid: "abc123",
27+
isCrossRepository: false,
28+
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
2729
createdAt: "2023-01-01T00:00:00Z",
2830
additions: 50,
2931
deletions: 30,

test/pull-request-target.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ describe("pull_request_target event support", () => {
1717
baseRefName: "main",
1818
headRefName: "feature-branch",
1919
headRefOid: "abc123",
20+
isCrossRepository: false,
21+
headRepository: { owner: { login: "testowner" }, name: "testrepo" },
2022
commits: {
2123
totalCount: 2,
2224
nodes: [

0 commit comments

Comments
 (0)