fix(migrations): use cursor pagination for GitHub issue migration too (#39888) (#39941)

Backport #39888 by @yuhongwei380

For repos with many issues, the GitHub API only allows cursor-based
pagination instead of page-based pagination after a certain page.
A full migration of such repos failed with a 422 response.
Now, we dynamically switch how we migrate based on the response from the
GitHub API.

Fixes #39882
Assisted-by: Codex:GPT-6

Signed-off-by: Phoenix <44333391+yuhongwei380@users.noreply.github.com>
Co-authored-by: Phoenix <44333391+yuhongwei380@users.noreply.github.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
authored and GitHub committed 2026-10-22 13:33:39 +00:00
1 parent 3e5256b6ca
commit 640b528580
2 files changed
+115 -2

No files matched your search

+16 -2
View File
@@ -74,6 +74,10 @@ type GithubDownloaderV3 struct {
maxPerPage int
SkipReactions bool
SkipReviews bool
issuePage int
issueCursor string
nextIssueCursor string
}
// NewGithubDownloaderV3 creates a github Downloader via github v3 API
@@ -428,12 +432,21 @@ func (g *GithubDownloaderV3) GetIssues(ctx context.Context, page, perPage int) (
Page: page,
},
}
switch page {
case g.issuePage:
opt.After = g.issueCursor
case g.issuePage + 1:
opt.After = g.nextIssueCursor
}
if opt.After != "" {
opt.ListOptions.Page = 0
}
allIssues := make([]*base.Issue, 0, perPage)
g.waitAndPickClient(ctx)
issues, resp, err := g.getClient().Issues.ListByRepo(ctx, g.repoOwner, g.repoName, opt)
if err != nil {
return nil, false, fmt.Errorf("error while listing repos: %w", err)
return nil, false, fmt.Errorf("GetIssues: %w", err)
}
log.Trace("Request get issues %d/%d, but in fact get %d", perPage, page, len(issues))
g.setRate(&resp.Rate)
@@ -500,7 +513,8 @@ func (g *GithubDownloaderV3) GetIssues(ctx context.Context, page, perPage int) (
})
}
return allIssues, len(issues) < perPage, nil
g.issuePage, g.issueCursor, g.nextIssueCursor = page, opt.After, resp.After
return allIssues, resp.NextPage == 0 && resp.After == "", nil
}
// SupportGetRepoComments return true if it supports get repo comments