mirror of
https://github.com/interviewstreet/go-jira.git
synced 2025-02-01 13:07:50 +02:00
Wrap http.Response in Response struct
The Response struct has StartAt, MaxResults and Total fields, which are returned from JIRA API in issue search responses. They are now accessible in Response object.
This commit is contained in:
parent
6b49178e1f
commit
facc86872b
26
issue.go
26
issue.go
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
@ -281,7 +280,10 @@ type CommentVisibility struct {
|
||||
// searchResult is only a small wrapper arround the Search (with JQL) method
|
||||
// to be able to parse the results
|
||||
type searchResult struct {
|
||||
Issues []Issue `json:"issues"`
|
||||
Issues []Issue `json:"issues"`
|
||||
StartAt int `json:"startAt"`
|
||||
MaxResults int `json:"maxResults"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// CustomFields represents custom fields of JIRA
|
||||
@ -294,7 +296,7 @@ type CustomFields map[string]string
|
||||
// If the issue cannot be found via an exact match, JIRA will also look for the issue in a case-insensitive way, or by looking to see if the issue was moved.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-getIssue
|
||||
func (s *IssueService) Get(issueID string) (*Issue, *http.Response, error) {
|
||||
func (s *IssueService) Get(issueID string) (*Issue, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
@ -310,11 +312,11 @@ func (s *IssueService) Get(issueID string) (*Issue, *http.Response, error) {
|
||||
return issue, resp, nil
|
||||
}
|
||||
|
||||
// DownloadAttachment returns a http.Response of an attachment for a given attachmentID.
|
||||
// The attachment is in the http.Response.Body of the response.
|
||||
// DownloadAttachment returns a Response of an attachment for a given attachmentID.
|
||||
// The attachment is in the Response.Body of the response.
|
||||
// This is an io.ReadCloser.
|
||||
// The caller should close the resp.Body.
|
||||
func (s *IssueService) DownloadAttachment(attachmentID string) (*http.Response, error) {
|
||||
func (s *IssueService) DownloadAttachment(attachmentID string) (*Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("secure/attachment/%s/", attachmentID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
@ -330,7 +332,7 @@ func (s *IssueService) DownloadAttachment(attachmentID string) (*http.Response,
|
||||
}
|
||||
|
||||
// PostAttachment uploads r (io.Reader) as an attachment to a given attachmentID
|
||||
func (s *IssueService) PostAttachment(attachmentID string, r io.Reader, attachmentName string) (*[]Attachment, *http.Response, error) {
|
||||
func (s *IssueService) PostAttachment(attachmentID string, r io.Reader, attachmentName string) (*[]Attachment, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/attachments", attachmentID)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
@ -371,7 +373,7 @@ func (s *IssueService) PostAttachment(attachmentID string, r io.Reader, attachme
|
||||
// The issueType field must correspond to a sub-task issue type and you must provide a parent field in the issue create request containing the id or key of the parent issue.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-createIssues
|
||||
func (s *IssueService) Create(issue *Issue) (*Issue, *http.Response, error) {
|
||||
func (s *IssueService) Create(issue *Issue) (*Issue, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/issue/"
|
||||
req, err := s.client.NewRequest("POST", apiEndpoint, issue)
|
||||
if err != nil {
|
||||
@ -390,7 +392,7 @@ func (s *IssueService) Create(issue *Issue) (*Issue, *http.Response, error) {
|
||||
// AddComment adds a new comment to issueID.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-addComment
|
||||
func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *http.Response, error) {
|
||||
func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/comment", issueID)
|
||||
req, err := s.client.NewRequest("POST", apiEndpoint, comment)
|
||||
if err != nil {
|
||||
@ -409,7 +411,7 @@ func (s *IssueService) AddComment(issueID string, comment *Comment) (*Comment, *
|
||||
// AddLink adds a link between two issues.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issueLink
|
||||
func (s *IssueService) AddLink(issueLink *IssueLink) (*http.Response, error) {
|
||||
func (s *IssueService) AddLink(issueLink *IssueLink) (*Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issueLink")
|
||||
req, err := s.client.NewRequest("POST", apiEndpoint, issueLink)
|
||||
if err != nil {
|
||||
@ -423,7 +425,7 @@ func (s *IssueService) AddLink(issueLink *IssueLink) (*http.Response, error) {
|
||||
// Search will search for tickets according to the jql
|
||||
//
|
||||
// JIRA API docs: https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-query-issues
|
||||
func (s *IssueService) Search(jql string) ([]Issue, *http.Response, error) {
|
||||
func (s *IssueService) Search(jql string) ([]Issue, *Response, error) {
|
||||
u := fmt.Sprintf("rest/api/2/search?jql=%s", url.QueryEscape(jql))
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
@ -436,7 +438,7 @@ func (s *IssueService) Search(jql string) ([]Issue, *http.Response, error) {
|
||||
}
|
||||
|
||||
// GetCustomFields returns a map of customfield_* keys with string values
|
||||
func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *http.Response, error) {
|
||||
func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
|
@ -318,7 +318,7 @@ func TestIssue_Search(t *testing.T) {
|
||||
testMethod(t, r, "GET")
|
||||
testRequestURL(t, r, "/rest/api/2/search?jql=something")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, `{"expand": "schema,names","startAt": 0,"maxResults": 50,"total": 6,"issues": [{"expand": "html","id": "10230","self": "http://kelpie9:8081/rest/api/2/issue/BULK-62","key": "BULK-62","fields": {"summary": "testing","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/5","id": "5","description": "The sub-task of the issue","iconUrl": "http://kelpie9:8081/images/icons/issue_subtask.gif","name": "Sub-task","subtask": true},"customfield_10071": null}},{"expand": "html","id": "10004","self": "http://kelpie9:8081/rest/api/2/issue/BULK-47","key": "BULK-47","fields": {"summary": "Cheese v1 2.0 issue","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/3","id": "3","description": "A task that needs to be done.","iconUrl": "http://kelpie9:8081/images/icons/task.gif","name": "Task","subtask": false}}}]}`)
|
||||
fmt.Fprint(w, `{"expand": "schema,names","startAt": 1,"maxResults": 40,"total": 6,"issues": [{"expand": "html","id": "10230","self": "http://kelpie9:8081/rest/api/2/issue/BULK-62","key": "BULK-62","fields": {"summary": "testing","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/5","id": "5","description": "The sub-task of the issue","iconUrl": "http://kelpie9:8081/images/icons/issue_subtask.gif","name": "Sub-task","subtask": true},"customfield_10071": null}},{"expand": "html","id": "10004","self": "http://kelpie9:8081/rest/api/2/issue/BULK-47","key": "BULK-47","fields": {"summary": "Cheese v1 2.0 issue","timetracking": null,"issuetype": {"self": "http://kelpie9:8081/rest/api/2/issuetype/3","id": "3","description": "A task that needs to be done.","iconUrl": "http://kelpie9:8081/images/icons/task.gif","name": "Task","subtask": false}}}]}`)
|
||||
})
|
||||
_, resp, err := testClient.Issue.Search("something")
|
||||
|
||||
@ -328,6 +328,16 @@ func TestIssue_Search(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error given: %s", err)
|
||||
}
|
||||
|
||||
if resp.StartAt != 1 {
|
||||
t.Errorf("StartAt should populate with 1, %v given", resp.StartAt)
|
||||
}
|
||||
if resp.MaxResults != 40 {
|
||||
t.Errorf("StartAt should populate with 40, %v given", resp.MaxResults)
|
||||
}
|
||||
if resp.Total != 6 {
|
||||
t.Errorf("StartAt should populate with 6, %v given", resp.Total)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CustomFields(t *testing.T) {
|
||||
|
41
jira.go
41
jira.go
@ -122,25 +122,26 @@ func (c *Client) NewMultiPartRequest(method, urlStr string, buf *bytes.Buffer) (
|
||||
|
||||
// Do sends an API request and returns the API response.
|
||||
// The API response is JSON decoded and stored in the value pointed to by v, or returned as an error if an API error has occurred.
|
||||
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
||||
httpResp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = CheckResponse(resp)
|
||||
err = CheckResponse(httpResp)
|
||||
if err != nil {
|
||||
// Even though there was an error, we still return the response
|
||||
// in case the caller wants to inspect it further
|
||||
return resp, err
|
||||
return newResponse(httpResp, nil), err
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
// Open a NewDecoder and defer closing the reader only if there is a provided interface to decode to
|
||||
defer resp.Body.Close()
|
||||
err = json.NewDecoder(resp.Body).Decode(v)
|
||||
defer httpResp.Body.Close()
|
||||
err = json.NewDecoder(httpResp.Body).Decode(v)
|
||||
}
|
||||
|
||||
resp := newResponse(httpResp, v)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
@ -162,3 +163,31 @@ func CheckResponse(r *http.Response) error {
|
||||
func (c *Client) GetBaseURL() url.URL {
|
||||
return *c.baseURL
|
||||
}
|
||||
|
||||
// Response represents JIRA API response. It wraps http.Response returned from
|
||||
// API and provides information about paging.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
|
||||
StartAt int
|
||||
MaxResults int
|
||||
Total int
|
||||
}
|
||||
|
||||
func newResponse(r *http.Response, v interface{}) *Response {
|
||||
resp := &Response{Response: r}
|
||||
resp.populatePageValues(v)
|
||||
return resp
|
||||
}
|
||||
|
||||
// Sets paging values if response json was parsed to searchResult type
|
||||
// (can be extended with other types if they also need paging info)
|
||||
func (r *Response) populatePageValues(v interface{}) {
|
||||
switch value := v.(type) {
|
||||
case *searchResult:
|
||||
r.StartAt = value.StartAt
|
||||
r.MaxResults = value.MaxResults
|
||||
r.Total = value.Total
|
||||
}
|
||||
return
|
||||
}
|
||||
|
21
jira_test.go
21
jira_test.go
@ -296,3 +296,24 @@ func TestGetBaseURL_WithURL(t *testing.T) {
|
||||
t.Errorf("Base URLs are not equal. Expected %+v, got %+v", *u, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPagingInfoEmptyByDefault(t *testing.T) {
|
||||
c, _ := NewClient(nil, testJIRAInstanceURL)
|
||||
req, _ := c.NewRequest("GET", "/", nil)
|
||||
type foo struct {
|
||||
A string
|
||||
}
|
||||
body := new(foo)
|
||||
|
||||
resp, _ := c.Do(req, body)
|
||||
|
||||
if resp.StartAt != 0 {
|
||||
t.Errorf("StartAt not equal to 0")
|
||||
}
|
||||
if resp.MaxResults != 0 {
|
||||
t.Errorf("StartAt not equal to 0")
|
||||
}
|
||||
if resp.Total != 0 {
|
||||
t.Errorf("StartAt not equal to 0")
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ProjectService handles projects for the JIRA instance / API.
|
||||
@ -73,7 +72,7 @@ type ProjectComponent struct {
|
||||
// GetList gets all projects form JIRA
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
|
||||
func (s *ProjectService) GetList() (*ProjectList, *http.Response, error) {
|
||||
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
|
||||
apiEndpoint := "rest/api/2/project"
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
@ -93,7 +92,7 @@ func (s *ProjectService) GetList() (*ProjectList, *http.Response, error) {
|
||||
// This can be an project id, or an project key.
|
||||
//
|
||||
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
|
||||
func (s *ProjectService) Get(projectID string) (*Project, *http.Response, error) {
|
||||
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
|
||||
apiEndpoint := fmt.Sprintf("/rest/api/2/project/%s", projectID)
|
||||
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user