feat(cmd): pagination unification + fj api --paginate
Before this, only `release list` walked pages. `repo list`, `pr list` (the
non-filter branch), and `issue list` all passed `PageSize: limit` directly
to the gitea SDK — which silently caps PageSize at 50, so any request for
more than 50 results was truncated to 50 with no warning. `--limit` was
effectively a per-page hint, not a real limit.
## Changes
- New `cmd/paginate.go` — generic `paginateGitea[T any]` that walks pages
until the response is short or the limit is reached. Uses Go 1.20
generics so each list command keeps its existing typed slice without
conversion overhead.
- `repo list` — paginates ListUserRepos.
- `pr list` — paginates ListRepoPullRequests in both branches:
- With client-side filters (assignee, author, labels, search, draft,
head, base): pull all pages then filter+limit.
- Without filters: paginate up to limit.
- `issue list` — paginates ListRepoIssues. Overshoots 2x because the API
returns both issues AND PRs and we filter PRs out client-side; the
overshoot keeps us bounded but reduces the chance of returning fewer
results than `--limit`.
## `fj api --paginate`
Mirrors `gh api --paginate`:
- Follows RFC 5988 `Link: rel="next"` headers (Forgejo emits these on
list endpoints).
- Concatenates each page's JSON array into a single array via
`concatPaginatedJSON`. If a page is not a JSON array, errors with a
clear message — `--paginate` only makes sense for paginatable endpoints.
- GET-only (errors on POST/PUT/DELETE).
- Reuses the same auth and custom headers across pages; the body-size
limit applies per-page.
Refactored the request execution into a `doOnce` closure so the loop body
isn't a copy of the single-request path.
Verified live:
$ fj api 'repos/public/claude-code-proxy/commits?limit=2' \
--paginate --jq '. | length'
44
(44 = total commits in the repo, walked via Link headers from a 2-per-page
starting query.)
Out of scope for this commit, deferred:
- De-duplicating cmd/aliases.go ↔ cmd/actions.go subtrees (the type
mismatch they caused is already fixed in the prior commit; the
duplication itself is polish).
This commit is contained in:
parent
0c181df1d1
commit
133fb2fea4
5 changed files with 199 additions and 66 deletions
28
cmd/issue.go
28
cmd/issue.go
|
|
@ -221,13 +221,24 @@ func runIssueList(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
ios.StartSpinner("Fetching issues...")
|
||||
issues, _, err := client.ListRepoIssues(owner, name, gitea.ListIssueOption{
|
||||
State: stateType,
|
||||
Labels: labels,
|
||||
KeyWord: search,
|
||||
CreatedBy: author,
|
||||
AssignedBy: assignee,
|
||||
ListOptions: gitea.ListOptions{PageSize: limit},
|
||||
// ListRepoIssues returns both issues AND PRs (we filter PRs out below).
|
||||
// Pull more than `limit` so post-filter we still have `limit` real issues
|
||||
// — overshoot 2x as a heuristic. paginateGitea(0, ...) would be safer
|
||||
// but spends extra round-trips; keep it bounded.
|
||||
fetchLimit := limit * 2
|
||||
if fetchLimit < 50 {
|
||||
fetchLimit = 50
|
||||
}
|
||||
issues, err := paginateGitea(fetchLimit, func(page, pageSize int) ([]*gitea.Issue, error) {
|
||||
batch, _, err := client.ListRepoIssues(owner, name, gitea.ListIssueOption{
|
||||
State: stateType,
|
||||
Labels: labels,
|
||||
KeyWord: search,
|
||||
CreatedBy: author,
|
||||
AssignedBy: assignee,
|
||||
ListOptions: gitea.ListOptions{Page: page, PageSize: pageSize},
|
||||
})
|
||||
return batch, err
|
||||
})
|
||||
ios.StopSpinner()
|
||||
if err != nil {
|
||||
|
|
@ -240,6 +251,9 @@ func runIssueList(cmd *cobra.Command, args []string) error {
|
|||
nonPRIssues = append(nonPRIssues, issue)
|
||||
}
|
||||
}
|
||||
if limit > 0 && len(nonPRIssues) > limit {
|
||||
nonPRIssues = nonPRIssues[:limit]
|
||||
}
|
||||
|
||||
if wantJSON(cmd) {
|
||||
return outputJSON(cmd, nonPRIssues)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue