From 63e53f4622c2cedb95ce55650a60ba81bf4bffe2 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 5 Oct 2026 17:46:54 +0200 Subject: [PATCH] gitea: read every page of a pull request's changed files The forge caps a page at fifty when asked for a hundred, so a large merge's file list was cut short and reported whole: a module whose own files moved was not rebuilt. Read until a page comes back short. hq issue 252. --- modules/gitea/client.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/gitea/client.ts b/modules/gitea/client.ts index c43e6e8..0aafb42 100644 --- a/modules/gitea/client.ts +++ b/modules/gitea/client.ts @@ -249,10 +249,24 @@ export class GiteaClient { * `limit` is what is asked for, and a merge that changed more says so rather than being read * page by page: what the mesh does with a partial list is treat the whole repository as changed, * so more pages would buy nothing. */ - async listPullFiles(owner: string, repo: string, index: number, limit = 100): Promise<{ paths: string[]; truncated: boolean }> { - const files = await this.request(`/repos/${owner}/${repo}/pulls/${index}/files?limit=${limit}`); - const paths = (files ?? []).map((f) => String(f?.filename ?? "")).filter((p) => p !== ""); - return { paths, truncated: paths.length >= limit }; + /** Every file a pull request changed, page by page. **The forge caps a page below what is asked** + * (fifty, asked for a hundred), so one page read as the whole list dropped files silently, and a module + * whose own files moved was not rebuilt (novox/hq issue 252). Read until a page comes back short; past + * `most` files the list is cut and says so, and the mesh then rebuilds everything built from the + * repository, the safe direction. */ + async listPullFiles(owner: string, repo: string, index: number, most = 3000): Promise<{ paths: string[]; truncated: boolean }> { + const paths: string[] = []; + let pageSize = 0; + for (let page = 1; ; page++) { + const files = (await this.request(`/repos/${owner}/${repo}/pulls/${index}/files?limit=50&page=${page}`)) ?? []; + if (page === 1) pageSize = files.length; + for (const f of files) { + const name = String(f?.filename ?? ""); + if (name !== "") paths.push(name); + } + if (files.length === 0 || files.length < pageSize) return { paths, truncated: false }; + if (paths.length >= most) return { paths, truncated: true }; + } } async createPullRequest(