Files
jira/search.go
T
2020-01-16 09:03:15 +01:00

144 lines
3.8 KiB
Go

package jira
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"github.com/Kuchenm0nster/jira/jiradata"
)
type SearchProvider interface {
ProvideSearchRequest() *jiradata.SearchRequest
}
type SearchOptions struct {
Assignee string `yaml:"assignee,omitempty" json:"assignee,omitempty"`
Query string `yaml:"query,omitempty" json:"query,omitempty"`
QueryFields string `yaml:"query-fields,omitempty" json:"query-fields,omitempty"`
Project string `yaml:"project,omitempty" json:"project,omitempty"`
Component string `yaml:"component,omitempty" json:"component,omitempty"`
IssueType string `yaml:"issue-type,omitempty" json:"issue-type,omitempty"`
Watcher string `yaml:"watcher,omitempty" json:"watcher,omitempty"`
Reporter string `yaml:"reporter,omitempty" json:"reporter,omitempty"`
Status string `yaml:"status,omitempty" json:"status,omitempty"`
Sort string `yaml:"sort,omitempty" json:"sort,omitempty"`
MaxResults int `yaml:"max-results,omitempty" json:"max-results,omitempty"`
}
func (o *SearchOptions) ProvideSearchRequest() *jiradata.SearchRequest {
req := &jiradata.SearchRequest{}
if o.Query == "" {
qbuff := bytes.NewBufferString("resolution = unresolved")
if o.Project != "" {
qbuff.WriteString(fmt.Sprintf(" AND project = '%s'", o.Project))
}
if o.Component != "" {
qbuff.WriteString(fmt.Sprintf(" AND component = '%s'", o.Component))
}
if o.Assignee != "" {
qbuff.WriteString(fmt.Sprintf(" AND assignee = '%s'", o.Assignee))
}
if o.IssueType != "" {
qbuff.WriteString(fmt.Sprintf(" AND issuetype = '%s'", o.IssueType))
}
if o.Watcher != "" {
qbuff.WriteString(fmt.Sprintf(" AND watcher = '%s'", o.Watcher))
}
if o.Reporter != "" {
qbuff.WriteString(fmt.Sprintf(" AND reporter = '%s'", o.Reporter))
}
if o.Status != "" {
qbuff.WriteString(fmt.Sprintf(" AND status = '%s'", o.Status))
}
if o.Sort != "" {
qbuff.WriteString(fmt.Sprintf(" ORDER BY %s", o.Sort))
}
req.JQL = qbuff.String()
} else {
req.JQL = o.Query
}
req.Fields = append(req.Fields, "summary")
if o.QueryFields != "" {
fields := strings.Split(o.QueryFields, ",")
req.Fields = append(req.Fields, fields...)
}
req.StartAt = 0
req.MaxResults = o.MaxResults
return req
}
// https://docs.atlassian.com/jira/REST/cloud/#api/2/search-searchUsingSearchRequest
func (j *Jira) Search(sp SearchProvider, opts ...SearchOpt) (*jiradata.SearchResults, error) {
return Search(j.UA, j.Endpoint, sp, opts...)
}
type searchConfig struct {
autoPaginate bool
}
type SearchOpt func(*searchConfig)
func WithAutoPagination() SearchOpt {
return func(c *searchConfig) {
c.autoPaginate = true
}
}
func Search(ua HttpClient, endpoint string, sp SearchProvider, opts ...SearchOpt) (*jiradata.SearchResults, error) {
c := &searchConfig{}
for _, opt := range opts {
opt(c)
}
req := sp.ProvideSearchRequest()
limit := req.MaxResults
if limit == 0 {
// max page size is 100
req.MaxResults = 100
}
issues := jiradata.Issues{}
for {
encoded, err := json.Marshal(req)
if err != nil {
return nil, err
}
uri := URLJoin(endpoint, "rest/api/2/search")
resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, responseError(resp)
}
page := &jiradata.SearchResults{}
err = json.NewDecoder(resp.Body).Decode(page)
if err != nil {
return nil, err
}
if !c.autoPaginate {
return page, nil
}
issues = append(issues, page.Issues...)
// if we are done paginating just force all issues onto current
// response and return
if (limit > 0 && len(issues) >= limit) || len(issues) >= page.Total {
page.Issues = issues
return page, nil
}
req.StartAt = len(issues)
if len(issues)+req.MaxResults > limit {
req.MaxResults = limit - len(issues)
}
}
}