Watch
0
0
Fork
You've already forked hyperhive
0

hive-forge: fetch issue comments in one request; the endpoint has no paging

The forge's issue-comments endpoint takes no page or limit and always
returns the whole thread. #5055 wrapped view's fetch in all_pages, which
never saw a short page on a thread of 50+ comments and fetched the same
list 50 times: `issue view 3782` printed 3000 comments instead of 60.
`comments --limit K` sent K as a page size the forge ignored, so it
returned the whole thread.

view and pr status's last_comment now send one request. comments fetches
the thread once and cuts the --limit / --tail window client-side; the
X-Total-Count probe and the computed-page tail walk are gone, and the
count of comments outside the window is the length of the list.
--since is unchanged.

tests/comments_no_paging.rs runs the binary against a loopback mock
forge whose comments route ignores page and limit, as Forgejo's does.
This commit is contained in:
atlas 2026-10-09 21:04:40 +02:00
commit 1d56a74aad
6 changed files with 215 additions and 262 deletions

View file

@ -138,10 +138,9 @@ fn truncation_note(more_before: usize, more_after: usize) -> Option<String> {
}
/// Total timeline-event count for an issue/PR, read off this endpoint's
/// own `X-Total-Count` header via a cheap `page_size=1` request. Unlike
/// `comments.rs`'s `fetch_total` (which reads a field straight off the
/// issue object) there's no cheaper alternate endpoint carrying this
/// count — this request-then-discard-the-one-item IS the cheap path.
/// own `X-Total-Count` header via a cheap `page_size=1` request. No
/// cheaper alternate endpoint carries this count — this
/// request-then-discard-the-one-item IS the cheap path.
fn fetch_total(client: &Client, number: u64) -> Result<usize> {
let (owner, name) = client.owner_repo()?;
let (headers, _) = client
@ -193,8 +192,7 @@ fn fetch_head(client: &Client, number: u64, limit: u64) -> Result<(Vec<TimelineC
/// Fetch the last `n` timeline events (chronological). `total` (from
/// [`fetch_total`]) drives the pagination plan and is the caller's, not
/// fetched again here — same shape as `comments.rs`'s `fetch_tail`:
/// Forgejo paginates oldest-first with no `direction=desc` knob, so this
/// fetched again here. Forgejo paginates oldest-first with no `direction=desc` knob, so this
/// starts fetching from the page that contains item `total - n` rather
/// than paging the whole thread.
fn fetch_tail(
@ -472,8 +470,7 @@ mod tests {
/// Pure helper mirroring the page-arithmetic in `fetch_tail`: given a
/// total event count + requested tail size, return the (`start_page`,
/// `last_page`) pair the network loop would walk. Same shape as
/// `comments.rs`'s `tail_plan` test helper — lets us pin the
/// `last_page`) pair the network loop would walk — lets us pin the
/// pagination plan without touching the network.
fn tail_plan(total: usize, n: usize) -> (usize, usize) {
let n = n.min(total);