mirror of
https://gitea.com/gitea/tea.git
synced 2026-04-25 17:53:37 +02:00
fix(pagination): replace Page:-1 with explicit pagination loops (#967)
## Summary \`Page: -1\` in the Gitea SDK calls \`setDefaults()\` which sets both \`Page=0\` and \`PageSize=0\`, resulting in \`?page=0&limit=0\` being sent to the server. The server interprets \`limit=0\` as "use server default" (typically 30 items via \`DEFAULT_PAGING_NUM\`), not "return everything". Any resource beyond the first page of results was silently invisible. This affected 8 call sites, with the most user-visible impact being \`tea issues edit --add-labels\` and \`tea pulls edit --add-labels\` silently failing to apply labels on repositories with more than ~30 labels. ## Affected call sites | File | API call | User-visible impact | |---|---|---| | \`modules/task/labels.go\` | \`ListRepoLabels\` | \`issues/pulls edit --add-labels\` fails silently | | \`modules/interact/issue_create.go\` | \`ListRepoLabels\` | interactive label picker missing labels | | \`modules/task/pull_review_comment.go\` | \`ListPullReviews\` | review comments truncated | | \`modules/task/login_ssh.go\` | \`ListMyPublicKeys\` | SSH key auto-detection fails | | \`modules/task/login_create.go\` | \`ListAccessTokens\` | token name deduplication misses existing tokens | | \`cmd/pulls.go\` | \`ListPullReviews\` | PR detail view missing reviews | | \`cmd/releases/utils.go\` | \`ListReleases\` | tag lookup fails on repos with many releases | | \`cmd/attachments/delete.go\` | \`ListReleaseAttachments\` | attachment deletion fails when many attachments exist | ## Fix Each call site is replaced with an explicit pagination loop that follows \`resp.NextPage\` until all pages are exhausted. Reviewed-on: https://gitea.com/gitea/tea/pulls/967 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Alain Thiffault <athiffau@effectivemomentum.com> Co-committed-by: Alain Thiffault <athiffau@effectivemomentum.com>
This commit is contained in:
committed by
Lunny Xiao
parent
a58c35c3e2
commit
5103496232
@@ -61,11 +61,19 @@ func runReleaseAttachmentDelete(_ stdctx.Context, cmd *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
existing, _, err := client.ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
|
var existing []*gitea.Attachment
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for page := 1; ; {
|
||||||
})
|
page_attachments, resp, err := client.ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{
|
||||||
if err != nil {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
return err
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
existing = append(existing, page_attachments...)
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range ctx.Args().Slice()[1:] {
|
for _, name := range ctx.Args().Slice()[1:] {
|
||||||
|
|||||||
19
cmd/pulls.go
19
cmd/pulls.go
@@ -109,11 +109,20 @@ func runPullDetail(_ stdctx.Context, cmd *cli.Command, index string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews, _, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
|
var reviews []*gitea.PullReview
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for page := 1; ; {
|
||||||
})
|
page_reviews, resp, err := client.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
|
||||||
if err != nil {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
fmt.Printf("error while loading reviews: %v\n", err)
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error while loading reviews: %v\n", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
reviews = append(reviews, page_reviews...)
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.IsSet("output") {
|
if ctx.IsSet("output") {
|
||||||
|
|||||||
@@ -11,19 +11,25 @@ import (
|
|||||||
|
|
||||||
// GetReleaseByTag finds a release by its tag name.
|
// GetReleaseByTag finds a release by its tag name.
|
||||||
func GetReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
|
func GetReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
|
||||||
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{
|
for page := 1; ; {
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
rl, resp, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{
|
||||||
})
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
if err != nil {
|
})
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
if len(rl) == 0 {
|
|
||||||
return nil, fmt.Errorf("repo does not have any release")
|
|
||||||
}
|
|
||||||
for _, r := range rl {
|
|
||||||
if r.TagName == tag {
|
|
||||||
return r, nil
|
|
||||||
}
|
}
|
||||||
|
if page == 1 && len(rl) == 0 {
|
||||||
|
return nil, fmt.Errorf("repo does not have any release")
|
||||||
|
}
|
||||||
|
for _, r := range rl {
|
||||||
|
if r.TagName == tag {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("release tag does not exist")
|
return nil, fmt.Errorf("release tag does not exist")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,19 +180,25 @@ func fetchIssueSelectables(login *config.Login, owner, repo string, done chan is
|
|||||||
r.MilestoneList[i] = m.Title
|
r.MilestoneList[i] = m.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
labels, _, err := c.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
|
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
r.Err = err
|
|
||||||
done <- r
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.LabelMap = make(map[string]int64)
|
r.LabelMap = make(map[string]int64)
|
||||||
r.LabelList = make([]string, len(labels))
|
r.LabelList = make([]string, 0)
|
||||||
for i, l := range labels {
|
for page := 1; ; {
|
||||||
r.LabelMap[l.Name] = l.ID
|
labels, resp, err := c.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
|
||||||
r.LabelList[i] = l.Name
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
done <- r
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, l := range labels {
|
||||||
|
r.LabelMap[l.Name] = l.ID
|
||||||
|
r.LabelList = append(r.LabelList, l.Name)
|
||||||
|
}
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
|
|
||||||
done <- r
|
done <- r
|
||||||
|
|||||||
@@ -13,16 +13,23 @@ import (
|
|||||||
// ResolveLabelNames returns a list of label IDs for a given list of label names
|
// ResolveLabelNames returns a list of label IDs for a given list of label names
|
||||||
func ResolveLabelNames(client *gitea.Client, owner, repo string, labelNames []string) ([]int64, error) {
|
func ResolveLabelNames(client *gitea.Client, owner, repo string, labelNames []string) ([]int64, error) {
|
||||||
labelIDs := make([]int64, 0, len(labelNames))
|
labelIDs := make([]int64, 0, len(labelNames))
|
||||||
labels, _, err := client.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
|
page := 1
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for {
|
||||||
})
|
labels, resp, err := client.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{
|
||||||
if err != nil {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
return nil, err
|
})
|
||||||
}
|
if err != nil {
|
||||||
for _, l := range labels {
|
return nil, err
|
||||||
if utils.Contains(labelNames, l.Name) {
|
|
||||||
labelIDs = append(labelIDs, l.ID)
|
|
||||||
}
|
}
|
||||||
|
for _, l := range labels {
|
||||||
|
if utils.Contains(labelNames, l.Name) {
|
||||||
|
labelIDs = append(labelIDs, l.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
return labelIDs, nil
|
return labelIDs, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,11 +166,19 @@ func generateToken(login config.Login, user, pass, otp, scopes string) (string,
|
|||||||
}
|
}
|
||||||
client := login.Client(opts...)
|
client := login.Client(opts...)
|
||||||
|
|
||||||
tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{
|
var tl []*gitea.AccessToken
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for page := 1; ; {
|
||||||
})
|
page_tokens, resp, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{
|
||||||
if err != nil {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
return "", err
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
tl = append(tl, page_tokens...)
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
host, _ := os.Hostname()
|
host, _ := os.Hostname()
|
||||||
tokenName := host + "-tea"
|
tokenName := host + "-tea"
|
||||||
|
|||||||
@@ -19,11 +19,22 @@ import (
|
|||||||
// a matching private key in ~/.ssh/. If no match is found, path is empty.
|
// a matching private key in ~/.ssh/. If no match is found, path is empty.
|
||||||
func findSSHKey(client *gitea.Client) (string, error) {
|
func findSSHKey(client *gitea.Client) (string, error) {
|
||||||
// get keys registered on gitea instance
|
// get keys registered on gitea instance
|
||||||
keys, _, err := client.ListMyPublicKeys(gitea.ListPublicKeysOptions{
|
var keys []*gitea.PublicKey
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for page := 1; ; {
|
||||||
})
|
page_keys, resp, err := client.ListMyPublicKeys(gitea.ListPublicKeysOptions{
|
||||||
if err != nil || len(keys) == 0 {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
return "", err
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
keys = append(keys, page_keys...)
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// enumerate ~/.ssh/*.pub files
|
// enumerate ~/.ssh/*.pub files
|
||||||
|
|||||||
@@ -14,11 +14,19 @@ import (
|
|||||||
func ListPullReviewComments(ctx *context.TeaContext, idx int64) ([]*gitea.PullReviewComment, error) {
|
func ListPullReviewComments(ctx *context.TeaContext, idx int64) ([]*gitea.PullReviewComment, error) {
|
||||||
c := ctx.Login.Client()
|
c := ctx.Login.Client()
|
||||||
|
|
||||||
reviews, _, err := c.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
|
var reviews []*gitea.PullReview
|
||||||
ListOptions: gitea.ListOptions{Page: -1},
|
for page := 1; ; {
|
||||||
})
|
page_reviews, resp, err := c.ListPullReviews(ctx.Owner, ctx.Repo, idx, gitea.ListPullReviewsOptions{
|
||||||
if err != nil {
|
ListOptions: gitea.ListOptions{Page: page, PageSize: 50},
|
||||||
return nil, err
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reviews = append(reviews, page_reviews...)
|
||||||
|
if resp == nil || resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = resp.NextPage
|
||||||
}
|
}
|
||||||
|
|
||||||
var allComments []*gitea.PullReviewComment
|
var allComments []*gitea.PullReviewComment
|
||||||
|
|||||||
Reference in New Issue
Block a user