diff --git a/src/github/backfill.ts b/src/github/backfill.ts index 582262cf50..05f36449ad 100644 --- a/src/github/backfill.ts +++ b/src/github/backfill.ts @@ -921,7 +921,7 @@ async function refreshRepoGithubTotals( const query = `query GittensoryRepoTotals { rateLimit { remaining resetAt } repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) { - issues(states: OPEN) { totalCount } + issues(states: OPEN, filter: {issueTypes: ISSUE}) { totalCount } openPullRequests: pullRequests(states: OPEN) { totalCount } mergedPullRequests: pullRequests(states: MERGED) { totalCount } closedPullRequests: pullRequests(states: CLOSED) { totalCount } @@ -1230,9 +1230,10 @@ async function supplementOpenIssuesFromGraphQl(env: Env, repo: RepositoryRecord, for (;;) { const query = `query GittensoryOpenIssuesSupplement { repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) { - issues(states: OPEN, first: 100${after}) { + issues(states: OPEN, filter: {issueTypes: ISSUE}, first: 100${after}) { pageInfo { hasNextPage endCursor } nodes { + __typename number title state @@ -1251,6 +1252,7 @@ async function supplementOpenIssuesFromGraphQl(env: Env, repo: RepositoryRecord, const response = await githubGraphQl(env, query, token); const issues = response.data?.repository?.issues; for (const issue of issues?.nodes ?? []) { + if (issue?.__typename === "PullRequest") continue; if (!issue?.number || existingNumbers.has(issue.number)) continue; const payload: GitHubIssuePayload = { number: issue.number, diff --git a/test/unit/backfill.test.ts b/test/unit/backfill.test.ts index 750a136857..a81e4d755d 100644 --- a/test/unit/backfill.test.ts +++ b/test/unit/backfill.test.ts @@ -945,12 +945,33 @@ describe("GitHub backfill", () => { expect(result).toMatchObject({ status: "queued", totals: { openIssuesTotal: 2911, openPullRequestsTotal: 167 } }); expect(await listRepoSyncStates(env)).toMatchObject([{ status: "running", openIssuesCount: 1100, openPullRequestsCount: 167, lastCompletedAt: "2026-05-24T00:00:00.000Z" }]); - expect(sent).toEqual( - expect.arrayContaining([ - expect.objectContaining({ type: "backfill-repo-segment", repoFullName: "JSONbored/gittensory", segment: "open_issues", mode: "resume", force: true }), - expect.objectContaining({ type: "backfill-repo-segment", repoFullName: "JSONbored/gittensory", segment: "open_pull_requests", mode: "resume", force: true }), - ]), - ); + }); + + it("persists openIssuesTotal without subtracting open pull requests from issues GraphQL total", async () => { + const env = createTestEnv({ GITHUB_PUBLIC_TOKEN: "public-token" }); + await seedRegisteredRepo(env); + let graphqlBody = ""; + vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => { + const url = input.toString(); + if (url === "https://api.github.com/graphql") { + graphqlBody = String(init?.body ?? ""); + return githubTotalsResponse({ openIssues: 10, openPullRequests: 3, mergedPullRequests: 0, closedPullRequests: 0, labels: 1 }); + } + return new Response("unexpected", { status: 500 }); + }); + + const result = await enqueueRepositoryOpenDataBackfill(env, { + repoFullName: "JSONbored/gittensory", + requestedBy: "api", + mode: "full", + force: true, + }); + + expect(result.totals?.openIssuesTotal).toBe(10); + expect(graphqlBody).toContain("issueTypes"); + expect(await listLatestRepoGithubTotalsSnapshots(env)).toMatchObject([ + { repoFullName: "JSONbored/gittensory", openIssuesTotal: 10, openPullRequestsTotal: 3 }, + ]); }); it("drains open issue segments against GitHub totals without counting PR rows from /issues", async () => {