fix(ci): paginate interactive job selection
What does this MR do and why?
Interactive CI job selection loops forever when a pipeline has more than 100
jobs. getJobIdInteractive uses gitlab.ScanAndCollect, but its closure drops
the pagination option supplied by the iterator:
jobs, err := gitlab.ScanAndCollect(func(p gitlab.PaginationOptionFunc) ([]*gitlab.Job, *gitlab.Response, error) {
return opts.Client.Jobs.ListPipelineJobs(opts.Repo.FullName(), pipelineId, listOptions)
})Page 1 advertises NextPage: 2, so ScanAndCollect derives a request option
for page=2. Because the closure ignores it, the next call requests page 1
again. That response still advertises page 2, and the scan repeats forever
while appending duplicate jobs.
The path is shared by interactive ci trace, ci retry, ci trigger, and the
trace action in ci status.
This MR passes both the pagination option and gitlab.WithContext(ctx) to
ListPipelineJobs, matching the canonical ScanAndCollect pattern used by
the rest of the repository. The scan now reaches page 2 and respects command
cancellation while the API request is in flight.
Test coverage
TestGetJobIdInteractivePaginates applies every request option to a real
retryable HTTP request and records the resulting page query. It also selects
a job that exists only on page 2, verifying the user-visible result.
On unmodified origin/main, the regression test fails with:
expected: []string{"", "2"}
actual: []string{"", ""}With the fix:
go test ./internal/commands/ci/ciutils -count=1
ok gitlab.com/gitlab-org/cli/internal/commands/ci/ciutilsgit diff --check also passes.
Related issues
Closes #8417 (closed)