Skip to content

Commit d1f3ad5

Browse files
Merge commit from andygrunwald#724
1 parent 51c7813 commit d1f3ad5

File tree

6 files changed

+133
-61
lines changed

6 files changed

+133
-61
lines changed

cloud/board.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ type BoardListOptions struct {
5454
// Relevance meaning that the JQL filter defined in board contains a reference to a project.
5555
ProjectKeyOrID string `url:"projectKeyOrId,omitempty"`
5656

57+
// StartAt: The starting index of the returned projects. Base index: 0.
58+
StartAt int `url:"startAt,omitempty"`
59+
5760
SearchOptions
5861
}
5962

cloud/examples/jql/main.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,18 @@ import (
88
)
99

1010
func main() {
11-
jiraClient, _ := jira.NewClient("https://issues.apache.org/jira/", nil)
11+
tp := jira.BasicAuthTransport{
12+
Username: "<username>",
13+
APIToken: "<api-token>"}
14+
jiraClient, _ := jira.NewClient("https://go-jira-opensource.atlassian.net/", tp.Client())
1215

1316
// Running JQL query
14-
15-
jql := "project = Mesos and type = Bug and Status NOT IN (Resolved)"
17+
jql := "type = Bug and Status NOT IN (Resolved)"
1618
fmt.Printf("Usecase: Running a JQL query '%s'\n", jql)
17-
issues, resp, err := jiraClient.Issue.Search(context.Background(), jql, nil)
18-
if err != nil {
19-
panic(err)
19+
options := &jira.SearchOptions{
20+
Fields: []string{"*all"},
2021
}
21-
outputResponse(issues, resp)
22-
23-
fmt.Println("")
24-
fmt.Println("")
25-
26-
// Running an empty JQL query to get all tickets
27-
jql = ""
28-
fmt.Printf("Usecase: Running an empty JQL query to get all tickets\n")
29-
issues, resp, err = jiraClient.Issue.Search(context.Background(), jql, nil)
22+
issues, resp, err := jiraClient.Issue.Search(context.Background(), jql, options)
3023
if err != nil {
3124
panic(err)
3225
}

cloud/examples/pagination/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ func GetAllIssues(client *jira.Client, searchString string) ([]jira.Issue, error
1717
for {
1818
opt := &jira.SearchOptions{
1919
MaxResults: 1000, // Max results can go up to 1000
20-
StartAt: last,
2120
}
2221

2322
chunk, resp, err := client.Issue.Search(context.Background(), searchString, opt)

cloud/issue.go

Lines changed: 96 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -516,25 +516,76 @@ type CommentVisibility struct {
516516
// response size for resources that return potentially large collection of items.
517517
// A request to a pages API will result in a values array wrapped in a JSON object with some paging metadata
518518
// Default Pagination options
519+
//
520+
// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-search-jql-get
519521
type SearchOptions struct {
520-
// StartAt: The starting index of the returned projects. Base index: 0.
521-
StartAt int `url:"startAt,omitempty"`
522-
// MaxResults: The maximum number of projects to return per page. Default: 50.
522+
// NextPageToken: The token for a page to fetch that is not the first page.
523+
// The first page has a nextPageToken of null.
524+
// Use the nextPageToken to fetch the next page of issues.
525+
// Note: The nextPageToken field is not included in the response for the last page,
526+
// indicating there is no next page.
527+
NextPageToken string `url:"nextPageToken,omitempty"`
528+
529+
// MaxResults: The maximum number of items to return per page.
530+
// To manage page size, API may return fewer items per page where a large number of fields or properties are requested.
531+
// The greatest number of items returned per page is achieved when requesting id or key only.
532+
// It returns max 5000 issues.
533+
// Default: 50
523534
MaxResults int `url:"maxResults,omitempty"`
524-
// Expand: Expand specific sections in the returned issues
525-
Expand string `url:"expand,omitempty"`
535+
// Fields: A list of fields to return for each issue
536+
537+
// Fields: A list of fields to return for each issue, use it to retrieve a subset of fields.
538+
// This parameter accepts a comma-separated list. Expand options include:
539+
//
540+
// `*all` Returns all fields.
541+
// `*navigable` Returns navigable fields.
542+
// `id` Returns only issue IDs.
543+
// Any issue field, prefixed with a minus to exclude.
544+
//
545+
// The default is id.
546+
//
547+
// Examples:
548+
//
549+
// `summary,comment` Returns only the summary and comments fields only.
550+
// `-description` Returns all navigable (default) fields except description.
551+
// `*all,-comment` Returns all fields except comments.
552+
//
553+
// Multiple `fields` parameters can be included in a request.
554+
//
555+
// Note: By default, this resource returns IDs only. This differs from GET issue where the default is all fields.
526556
Fields []string
527-
// ValidateQuery: The validateQuery param offers control over whether to validate and how strictly to treat the validation. Default: strict.
528-
ValidateQuery string `url:"validateQuery,omitempty"`
557+
558+
// Expand: Use expand to include additional information about issues in the response.
559+
// TODO add proper docs, see https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-search-jql-get
560+
Expand string `url:"expand,omitempty"`
561+
// A list of up to 5 issue properties to include in the results
562+
Properties []string `url:"properties,omitempty"`
563+
// FieldsByKeys: Reference fields by their key (rather than ID).
564+
// The default is false.
565+
FieldsByKeys bool `url:"fieldsByKeys,omitempty"`
566+
// FailFast: Fail this request early if we can't retrieve all field data.
567+
// Default false.
568+
FailFast bool `url:"failFast,omitempty"`
569+
// ReconcileIssues: Strong consistency issue ids to be reconciled with search results. Accepts max 50 ids
570+
ReconcileIssues []int `url:"reconcileIssues,omitempty"`
529571
}
530572

531573
// searchResult is only a small wrapper around the Search (with JQL) method
532574
// to be able to parse the results
533575
type searchResult struct {
534-
Issues []Issue `json:"issues" structs:"issues"`
535-
StartAt int `json:"startAt" structs:"startAt"`
536-
MaxResults int `json:"maxResults" structs:"maxResults"`
537-
Total int `json:"total" structs:"total"`
576+
// IsLast: Indicates whether this is the last page of the paginated response.
577+
IsLast bool `json:"isLast" structs:"isLast"`
578+
// Issues: The list of issues found by the search or reconsiliation.
579+
Issues []Issue `json:"issues" structs:"issues"`
580+
581+
// TODO Missing
582+
// Field names object
583+
// Field schema object
584+
585+
// NextPageToken: Continuation token to fetch the next page.
586+
// If this result represents the last or the only page this token will be null.
587+
// This token will expire in 7 days.
588+
NextPageToken string `json:"nextPageToken" structs:"nextPageToken"`
538589
}
539590

540591
// GetQueryOptions specifies the optional parameters for the Get Issue methods
@@ -1046,28 +1097,50 @@ func (s *IssueService) AddLink(ctx context.Context, issueLink *IssueLink) (*Resp
10461097
// This double check effort is done for v2 - Remove this two lines if this is completed.
10471098
func (s *IssueService) Search(ctx context.Context, jql string, options *SearchOptions) ([]Issue, *Response, error) {
10481099
u := url.URL{
1049-
Path: "rest/api/2/search",
1100+
Path: "rest/api/3/search/jql",
10501101
}
10511102
uv := url.Values{}
10521103
if jql != "" {
10531104
uv.Add("jql", jql)
10541105
}
10551106

1107+
// TODO Check this out if this works with addOptions as well
10561108
if options != nil {
1057-
if options.StartAt != 0 {
1058-
uv.Add("startAt", strconv.Itoa(options.StartAt))
1109+
if options.NextPageToken != "" {
1110+
uv.Add("nextPageToken", options.NextPageToken)
10591111
}
10601112
if options.MaxResults != 0 {
10611113
uv.Add("maxResults", strconv.Itoa(options.MaxResults))
10621114
}
1115+
if strings.Join(options.Fields, ",") != "" {
1116+
uv.Add("fields", strings.Join(options.Fields, ","))
1117+
}
10631118
if options.Expand != "" {
10641119
uv.Add("expand", options.Expand)
10651120
}
1066-
if strings.Join(options.Fields, ",") != "" {
1067-
uv.Add("fields", strings.Join(options.Fields, ","))
1121+
if len(options.Properties) > 5 {
1122+
return nil, nil, fmt.Errorf("Search option Properties accepts maximum five entries")
1123+
}
1124+
if strings.Join(options.Properties, ",") != "" {
1125+
uv.Add("properties", strings.Join(options.Properties, ","))
1126+
}
1127+
if options.FieldsByKeys {
1128+
uv.Add("fieldsByKeys", "true")
1129+
}
1130+
if options.FailFast {
1131+
uv.Add("failFast", "true")
10681132
}
1069-
if options.ValidateQuery != "" {
1070-
uv.Add("validateQuery", options.ValidateQuery)
1133+
if len(options.ReconcileIssues) > 50 {
1134+
return nil, nil, fmt.Errorf("Search option ReconcileIssue accepts maximum 50 entries")
1135+
}
1136+
if len(options.ReconcileIssues) > 0 {
1137+
// TODO Extract this
1138+
// Convert []int to []string for strings.Join
1139+
reconcileIssuesStr := make([]string, len(options.ReconcileIssues))
1140+
for i, v := range options.ReconcileIssues {
1141+
reconcileIssuesStr[i] = strconv.Itoa(v)
1142+
}
1143+
uv.Add("reconcileIssues", strings.Join(reconcileIssuesStr, ","))
10711144
}
10721145
}
10731146

@@ -1095,7 +1168,6 @@ func (s *IssueService) Search(ctx context.Context, jql string, options *SearchOp
10951168
func (s *IssueService) SearchPages(ctx context.Context, jql string, options *SearchOptions, f func(Issue) error) error {
10961169
if options == nil {
10971170
options = &SearchOptions{
1098-
StartAt: 0,
10991171
MaxResults: 50,
11001172
}
11011173
}
@@ -1121,16 +1193,18 @@ func (s *IssueService) SearchPages(ctx context.Context, jql string, options *Sea
11211193
}
11221194
}
11231195

1124-
if resp.StartAt+resp.MaxResults >= resp.Total {
1125-
return nil
1196+
if len(resp.NextPageToken) == 0 {
1197+
break
11261198
}
11271199

1128-
options.StartAt += resp.MaxResults
1200+
options.NextPageToken = resp.NextPageToken
11291201
issues, resp, err = s.Search(ctx, jql, options)
11301202
if err != nil {
11311203
return err
11321204
}
11331205
}
1206+
1207+
return nil
11341208
}
11351209

11361210
// GetCustomFields returns a map of customfield_* keys with string values

0 commit comments

Comments
 (0)