From d32d52e0c80fda3651c26bd2731800f770c37192 Mon Sep 17 00:00:00 2001 From: Felipe Matarazzo Date: Mon, 4 May 2026 18:34:15 -0300 Subject: [PATCH 1/2] fetch timeline closer on closed PRs --- api/types.ts | 5 +++++ api/utils/github-api.ts | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/api/types.ts b/api/types.ts index 2feaf0d..f7e7a23 100644 --- a/api/types.ts +++ b/api/types.ts @@ -15,6 +15,11 @@ export interface GitHubPR { stargazerCount: number } url: string + timelineItems: { + nodes: Array<{ + closer: { __typename: string } | null + }> + } } export interface ProcessedPR { diff --git a/api/utils/github-api.ts b/api/utils/github-api.ts index 112e5af..de61497 100644 --- a/api/utils/github-api.ts +++ b/api/utils/github-api.ts @@ -33,6 +33,15 @@ const GET_USER_PRS_QUERY = ` stargazerCount } url + timelineItems(itemTypes: [CLOSED_EVENT], last: 1) { + nodes { + ... on ClosedEvent { + closer { + __typename + } + } + } + } } } } From cf0ad27cf42fac0561da3d9074ce81e8a8db5992 Mon Sep 17 00:00:00 2001 From: Felipe Matarazzo Date: Mon, 4 May 2026 18:34:20 -0300 Subject: [PATCH 2/2] count commit-closed PRs as merged --- api/utils/inner_data_processor.ts | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/api/utils/inner_data_processor.ts b/api/utils/inner_data_processor.ts index bb4d1d8..7f229a3 100644 --- a/api/utils/inner_data_processor.ts +++ b/api/utils/inner_data_processor.ts @@ -5,22 +5,36 @@ type StatusFilter = 'all' | 'merged' | 'open' | 'closed' | 'draft' export class DataProcessor { static processGitHubPRs(rawPRs: GitHubPR[]): ProcessedPR[] { - return rawPRs.map(pr => ({ - repo: `${pr.repository.owner.login}/${pr.repository.name}`, - stars: pr.repository.stargazerCount, - pr_title: pr.title, - pr_number: pr.number, - status: this.mapPRStatus(pr), - created_date: this.formatDate(pr.createdAt), - merged_date: pr.mergedAt ? this.formatDate(pr.mergedAt) : null, - url: pr.url - })) + return rawPRs.map(pr => { + const status = this.mapPRStatus(pr) + const upstreamMerged = status === 'merged' && pr.state === 'CLOSED' + return { + repo: `${pr.repository.owner.login}/${pr.repository.name}`, + stars: pr.repository.stargazerCount, + pr_title: pr.title, + pr_number: pr.number, + status, + created_date: this.formatDate(pr.createdAt), + merged_date: pr.mergedAt + ? this.formatDate(pr.mergedAt) + : upstreamMerged && pr.closedAt + ? this.formatDate(pr.closedAt) + : null, + url: pr.url + } + }) + } + + private static isClosedByCommit(pr: GitHubPR): boolean { + const closer = pr.timelineItems?.nodes?.[0]?.closer + return !!closer && closer.__typename === 'Commit' } private static mapPRStatus(pr: GitHubPR): 'merged' | 'open' | 'closed' | 'draft' { if (pr.isDraft) return 'draft' if (pr.state === 'MERGED') return 'merged' if (pr.state === 'OPEN') return 'open' + if (pr.state === 'CLOSED' && this.isClosedByCommit(pr)) return 'merged' return 'closed' }