From faa21f4504c8633bc268bad0da98b660e9bbe356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C5=ABdolfs=20O=C5=A1i=C5=86=C5=A1?= Date: Fri, 17 Jul 2026 11:20:06 +0200 Subject: [PATCH] Use the dedicated commit-count endpoint So the header and history stop fetching full tree stats just for the commit count. Falls back to the previous behaviour when the backend doesn't serve the new endpoint. --- http-client/lib/repo.ts | 31 ++++++++++++++++++++++++++++ http-client/tests/repo.test.ts | 4 ++++ src/views/repos/History.svelte | 4 ++-- src/views/repos/Source/Header.svelte | 6 +++--- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/http-client/lib/repo.ts b/http-client/lib/repo.ts index e349fe1cc..217d9097d 100644 --- a/http-client/lib/repo.ts +++ b/http-client/lib/repo.ts @@ -1,4 +1,6 @@ import type { Fetcher, RequestOptions } from "./fetcher.js"; + +import { ResponseError } from "./fetcher.js"; import type { Commit, Commits } from "./repo/commit.js"; import type { Issue } from "./repo/issue.js"; import type { Patch } from "./repo/patch.js"; @@ -136,6 +138,8 @@ const treeStatsSchema = object({ export type TreeStats = z.infer; +const commitCountSchema = object({ commits: number() }); + export type Tree = z.infer; const treeSchema = object({ @@ -337,6 +341,33 @@ export class Client { return tree; } + public async getCommitCountBySha( + rid: string, + sha: string, + options?: RequestOptions, + ): Promise { + try { + const { commits } = await this.#fetcher.fetchOk( + { + method: "GET", + path: `repos/${rid}/stats/commits/${sha}`, + options, + }, + commitCountSchema, + ); + return commits; + } catch (error) { + // Older nodes don't serve the dedicated commit-count endpoint, so fall + // back to the tree stats endpoint, which also returns the commit count. + // TODO: Drop this fallback once enough nodes serve /stats/commits. + if (error instanceof ResponseError && error.status === 404) { + const stats = await this.getTreeStatsBySha(rid, sha, options); + return stats.commits; + } + throw error; + } + } + public async getAllRemotes( rid: string, options?: RequestOptions, diff --git a/http-client/tests/repo.test.ts b/http-client/tests/repo.test.ts index e676a34b9..96435309e 100644 --- a/http-client/tests/repo.test.ts +++ b/http-client/tests/repo.test.ts @@ -48,6 +48,10 @@ describe("repo", () => { await api.repo.getTreeStatsBySha(sourceBrowsingRid, aliceMainHead); }); + test("#getCommitCountBySha(rid, sha)", async () => { + await api.repo.getCommitCountBySha(sourceBrowsingRid, aliceMainHead); + }); + test("#getTree(rid, sha, path)", async () => { await api.repo.getTree(sourceBrowsingRid, aliceMainHead, "src"); }); diff --git a/src/views/repos/History.svelte b/src/views/repos/History.svelte index 2eb518aa3..717648eb1 100644 --- a/src/views/repos/History.svelte +++ b/src/views/repos/History.svelte @@ -47,8 +47,8 @@ let totalCommits: number | undefined = undefined; function fetchTotalCommits(rid: string, sha: string) { - void api.repo.getTreeStatsBySha(rid, sha).then(stats => { - totalCommits = stats.commits; + void api.repo.getCommitCountBySha(rid, sha).then(commits => { + totalCommits = commits; }); } diff --git a/src/views/repos/Source/Header.svelte b/src/views/repos/Source/Header.svelte index 3baed4ffb..d4bea54d3 100644 --- a/src/views/repos/Source/Header.svelte +++ b/src/views/repos/Source/Header.svelte @@ -40,9 +40,9 @@ if (cached !== undefined) { commitCount = cached; } else { - void api.repo.getTreeStatsBySha(rid, sha).then(stats => { - commitCountCache[sha] = stats.commits; - commitCount = stats.commits; + void api.repo.getCommitCountBySha(rid, sha).then(commits => { + commitCountCache[sha] = commits; + commitCount = commits; }); } }