-
-
Notifications
You must be signed in to change notification settings - Fork 371
feat: implement cursor-based pagination for Jira Cloud v3 API #965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7c2d322
f8b3102
07cf5ba
376544a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,12 +15,70 @@ type SearchResult struct { | |
| Issues []*Issue `json:"issues"` | ||
| } | ||
|
|
||
| const maxPageSize uint = 100 | ||
|
|
||
| // Search searches for issues using v3 version of the Jira GET /search endpoint. | ||
| // This performs a single request and returns up to `limit` results. | ||
| func (c *Client) Search(jql string, limit uint) (*SearchResult, error) { | ||
| path := fmt.Sprintf("/search/jql?jql=%s&maxResults=%d&fields=*all", url.QueryEscape(jql), limit) | ||
| return c.search(path, apiVersion3) | ||
| } | ||
|
|
||
| // SearchAll searches for issues using v3 version of the Jira GET /search endpoint | ||
| // with automatic cursor-based pagination via nextPageToken. It fetches pages of up | ||
| // to 100 issues at a time until `totalLimit` issues are collected or all results | ||
| // are exhausted (isLast == true). | ||
| func (c *Client) SearchAll(jql string, totalLimit uint) (*SearchResult, error) { | ||
| var allIssues []*Issue | ||
|
|
||
| pageSize := totalLimit | ||
| if pageSize == 0 || pageSize > maxPageSize { | ||
| pageSize = maxPageSize | ||
| } | ||
|
|
||
| nextPageToken := "" | ||
| for { | ||
| path := fmt.Sprintf("/search/jql?jql=%s&maxResults=%d&fields=*all", url.QueryEscape(jql), pageSize) | ||
| if nextPageToken != "" { | ||
| path += fmt.Sprintf("&nextPageToken=%s", url.QueryEscape(nextPageToken)) | ||
| } | ||
|
|
||
| result, err := c.search(path, apiVersion3) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| allIssues = append(allIssues, result.Issues...) | ||
|
|
||
| if result.IsLast || result.NextPageToken == "" { | ||
| break | ||
| } | ||
| if totalLimit > 0 && uint(len(allIssues)) >= totalLimit { | ||
| break | ||
| } | ||
|
|
||
| nextPageToken = result.NextPageToken | ||
|
|
||
| // Adjust page size for the last page if needed. | ||
| if totalLimit > 0 { | ||
| remaining := totalLimit - uint(len(allIssues)) | ||
| if remaining < pageSize { | ||
| pageSize = remaining | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+31
to
+69
|
||
|
|
||
| // Trim to totalLimit if we overshot. | ||
| if totalLimit > 0 && uint(len(allIssues)) > totalLimit { | ||
| allIssues = allIssues[:totalLimit] | ||
| } | ||
|
|
||
| return &SearchResult{ | ||
| IsLast: true, | ||
| Issues: allIssues, | ||
| }, nil | ||
|
Comment on lines
+76
to
+79
|
||
| } | ||
|
|
||
| // SearchV2 searches an issues using v2 version of the Jira GET /search endpoint. | ||
| func (c *Client) SearchV2(jql string, from, limit uint) (*SearchResult, error) { | ||
| path := fmt.Sprintf("/search?jql=%s&startAt=%d&maxResults=%d", url.QueryEscape(jql), from, limit) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updated validation allows
from == 0(and the CLI default uses0:100), but both error messages say 'positive' which usually excludes 0. To avoid confusing users, update the wording to match the actual constraints (e.g., ' must be a non-negative integer and must be a positive integer'), and consider aligningerrInvalidPaginateArgwording similarly.