-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
auto-claude: 155-fix-pr-list-diff-display-metrics #1458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
ee67205
dafb94e
40c9e0f
96d9206
83efe67
4030124
6d2e89e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ | |
| DEFAULT_FEATURE_THINKING, | ||
| } from "../../../shared/constants"; | ||
| import type { AuthFailureInfo } from "../../../shared/types/terminal"; | ||
| import { getGitHubConfig, githubFetch } from "./utils"; | ||
| import { getGitHubConfig, githubFetch, normalizeRepoReference } from "./utils"; | ||
| import { readSettingsFile } from "../../settings-utils"; | ||
| import { getAugmentedEnv } from "../../env-utils"; | ||
| import { getMemoryService, getDefaultDbPath } from "../../memory-service"; | ||
|
|
@@ -36,6 +36,102 @@ | |
| buildRunnerArgs, | ||
| } from "./utils/subprocess-runner"; | ||
|
|
||
| /** | ||
| * GraphQL response type for PR list query | ||
| * Note: repository can be null if the repo doesn't exist or user lacks access | ||
| */ | ||
| interface GraphQLPRListResponse { | ||
| data: { | ||
| repository: { | ||
| pullRequests: { | ||
| pageInfo: { | ||
| hasNextPage: boolean; | ||
| endCursor: string | null; | ||
| }; | ||
| nodes: Array<{ | ||
| number: number; | ||
| title: string; | ||
| body: string | null; | ||
| state: string; | ||
| author: { login: string } | null; | ||
| headRefName: string; | ||
| baseRefName: string; | ||
| additions: number; | ||
| deletions: number; | ||
| changedFiles: number; | ||
| assignees: { nodes: Array<{ login: string }> }; | ||
| createdAt: string; | ||
| updatedAt: string; | ||
| url: string; | ||
| }>; | ||
| }; | ||
| } | null; | ||
| }; | ||
| errors?: Array<{ message: string }>; | ||
| } | ||
|
|
||
| /** | ||
| * Make a GraphQL request to GitHub API | ||
| */ | ||
| async function githubGraphQL<T>( | ||
| token: string, | ||
| query: string, | ||
| variables: Record<string, unknown> = {} | ||
| ): Promise<T> { | ||
| const response = await fetch("https://api.github.com/graphql", { | ||
| method: "POST", | ||
| headers: { | ||
| "Authorization": `Bearer ${token}`, | ||
| "Content-Type": "application/json", | ||
| "User-Agent": "Auto-Claude-UI", | ||
| }, | ||
| body: JSON.stringify({ query, variables }), | ||
|
||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| const errorBody = await response.text(); | ||
| throw new Error(`GitHub GraphQL error: ${response.status} ${response.statusText} - ${errorBody}`); | ||
| } | ||
|
|
||
| const result = await response.json() as T & { errors?: Array<{ message: string }> }; | ||
|
|
||
| // Check for GraphQL-level errors | ||
| if (result.errors && result.errors.length > 0) { | ||
| throw new Error(`GitHub GraphQL error: ${result.errors.map(e => e.message).join(", ")}`); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * GraphQL query to fetch PRs with diff stats | ||
| */ | ||
| const LIST_PRS_QUERY = ` | ||
| query($owner: String!, $repo: String!, $first: Int!, $after: String) { | ||
| repository(owner: $owner, name: $repo) { | ||
| pullRequests(states: OPEN, first: $first, after: $after, orderBy: {field: UPDATED_AT, direction: DESC}) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| number | ||
| title | ||
| body | ||
| state | ||
| author { login } | ||
| headRefName | ||
| baseRefName | ||
| additions | ||
| deletions | ||
| changedFiles | ||
| assignees(first: 10) { nodes { login } } | ||
| createdAt | ||
| updatedAt | ||
| url | ||
| } | ||
| } | ||
| } | ||
| } | ||
| `; | ||
|
|
||
| /** | ||
| * Sanitize network data before writing to file | ||
| * Removes potentially dangerous characters and limits length | ||
|
|
@@ -1231,11 +1327,11 @@ | |
| export function registerPRHandlers(getMainWindow: () => BrowserWindow | null): void { | ||
| debugLog("Registering PR handlers"); | ||
|
|
||
| // List open PRs with pagination support | ||
| // List open PRs - fetches up to 100 open PRs at once, client handles display pagination | ||
| ipcMain.handle( | ||
| IPC_CHANNELS.GITHUB_PR_LIST, | ||
| async (_, projectId: string, page: number = 1): Promise<PRData[]> => { | ||
| debugLog("listPRs handler called", { projectId, page }); | ||
| async (_, projectId: string): Promise<PRData[]> => { | ||
| debugLog("listPRs handler called", { projectId }); | ||
| const result = await withProjectOrNull(projectId, async (project) => { | ||
| const config = getGitHubConfig(project); | ||
| if (!config) { | ||
|
|
@@ -1244,44 +1340,53 @@ | |
| } | ||
|
|
||
| try { | ||
| // Use pagination: per_page=100 (GitHub max), page=1,2,3... | ||
| const prs = (await githubFetch( | ||
| // Parse owner/repo from config | ||
| const normalizedRepo = normalizeRepoReference(config.repo); | ||
| const [owner, repo] = normalizedRepo.split("/"); | ||
| if (!owner || !repo) { | ||
| debugLog("Invalid repo format", { repo: config.repo }); | ||
| return []; | ||
| } | ||
|
|
||
| // Use GraphQL API to get PRs with diff stats (REST list endpoint doesn't include them) | ||
| // Fetches up to 100 open PRs (GitHub GraphQL max per request) | ||
| // Client-side pagination can be implemented if needed for repos with >100 open PRs | ||
| const response = await githubGraphQL<GraphQLPRListResponse>( | ||
| config.token, | ||
| `/repos/${config.repo}/pulls?state=open&per_page=100&page=${page}` | ||
| )) as Array<{ | ||
| number: number; | ||
| title: string; | ||
| body?: string; | ||
| state: string; | ||
| user: { login: string }; | ||
| head: { ref: string }; | ||
| base: { ref: string }; | ||
| additions: number; | ||
| deletions: number; | ||
| changed_files: number; | ||
| assignees?: Array<{ login: string }>; | ||
| created_at: string; | ||
| updated_at: string; | ||
| html_url: string; | ||
| }>; | ||
| LIST_PRS_QUERY, | ||
| { | ||
| owner, | ||
| repo, | ||
| first: 100, // GitHub GraphQL max is 100 | ||
| after: null, // Start from beginning | ||
| } | ||
| ); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pagination broken: page parameter always ignoredHigh Severity The |
||
|
|
||
| // Handle case where repository doesn't exist or user lacks access | ||
| if (!response.data.repository) { | ||
| debugLog("Repository not found or access denied", { owner, repo }); | ||
| return []; | ||
| } | ||
|
|
||
| debugLog("Fetched PRs", { count: prs.length, page, samplePr: prs[0] }); | ||
| const prs = response.data.repository.pullRequests.nodes; | ||
|
||
|
|
||
| debugLog("Fetched PRs via GraphQL", { count: prs.length, samplePr: prs[0] }); | ||
| return prs.map((pr) => ({ | ||
| number: pr.number, | ||
| title: pr.title, | ||
| body: pr.body ?? "", | ||
| state: pr.state, | ||
| author: { login: pr.user.login }, | ||
| headRefName: pr.head.ref, | ||
| baseRefName: pr.base.ref, | ||
| additions: pr.additions ?? 0, | ||
| deletions: pr.deletions ?? 0, | ||
| changedFiles: pr.changed_files ?? 0, | ||
| assignees: pr.assignees?.map((a: { login: string }) => ({ login: a.login })) ?? [], | ||
| state: pr.state.toLowerCase(), | ||
| author: { login: pr.author?.login ?? "unknown" }, | ||
| headRefName: pr.headRefName, | ||
| baseRefName: pr.baseRefName, | ||
| additions: pr.additions, | ||
| deletions: pr.deletions, | ||
| changedFiles: pr.changedFiles, | ||
| assignees: pr.assignees.nodes.map((a) => ({ login: a.login })), | ||
|
||
| files: [], | ||
| createdAt: pr.created_at, | ||
| updatedAt: pr.updated_at, | ||
| htmlUrl: pr.html_url, | ||
| createdAt: pr.createdAt, | ||
| updatedAt: pr.updatedAt, | ||
| htmlUrl: pr.url, | ||
| })); | ||
| } catch (error) { | ||
| debugLog("Failed to fetch PRs", { | ||
|
|
||
Check warning
Code scanning / CodeQL
File data in outbound network request Medium