1
0
mirror of https://github.com/interviewstreet/go-jira.git synced 2025-07-15 01:04:38 +02:00

updating with search and worklogs

This commit is contained in:
Douglas Chimento
2016-05-29 11:30:45 -04:00
parent 559b76c3ef
commit fe0595ab45
2 changed files with 87 additions and 4 deletions

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ _testmain.go
*.exe *.exe
*.test *.test
*.prof *.prof
*.iml

View File

@ -3,6 +3,9 @@ package jira
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"strings"
"time"
) )
const ( const (
@ -26,6 +29,8 @@ type Issue struct {
Fields *IssueFields `json:"fields,omitempty"` Fields *IssueFields `json:"fields,omitempty"`
} }
type Issues []*Issue
// IssueFields represents single fields of a JIRA issue. // IssueFields represents single fields of a JIRA issue.
// Every JIRA issue has several fields attached. // Every JIRA issue has several fields attached.
type IssueFields struct { type IssueFields struct {
@ -34,14 +39,12 @@ type IssueFields struct {
// * "aggregatetimespent": null, // * "aggregatetimespent": null,
// * "workratio": -1, // * "workratio": -1,
// * "lastViewed": null, // * "lastViewed": null,
// * "labels": [],
// * "timeestimate": null, // * "timeestimate": null,
// * "aggregatetimeoriginalestimate": null, // * "aggregatetimeoriginalestimate": null,
// * "timeoriginalestimate": null, // * "timeoriginalestimate": null,
// * "timetracking": {}, // * "timetracking": {},
// * "attachment": [], // * "attachment": [],
// * "aggregatetimeestimate": null, // * "aggregatetimeestimate": null,
// * "subtasks": [],
// * "environment": null, // * "environment": null,
// * "duedate": null, // * "duedate": null,
Type IssueType `json:"issuetype"` Type IssueType `json:"issuetype"`
@ -61,10 +64,12 @@ type IssueFields struct {
Status *Status `json:"status,omitempty"` Status *Status `json:"status,omitempty"`
Progress *Progress `json:"progress,omitempty"` Progress *Progress `json:"progress,omitempty"`
AggregateProgress *Progress `json:"aggregateprogress,omitempty"` AggregateProgress *Progress `json:"aggregateprogress,omitempty"`
Worklog []*Worklog `json:"worklog.worklogs,omitempty"` WorklogPage *WorklogPage `json:"worklog,omitempty"`
IssueLinks []*IssueLink `json:"issuelinks,omitempty"` IssueLinks []*IssueLink `json:"issuelinks,omitempty"`
Comments []*Comment `json:"comment.comments,omitempty"` Comments []*Comment `json:"comment.comments,omitempty"`
FixVersions []*FixVersion `json:"fixVersions,omitempty"` FixVersions []*FixVersion `json:"fixVersions,omitempty"`
Labels []string `json:"labels,omitempty"`
SubTasks Issues `json:"subtasks,omitempty"`
} }
// IssueType represents a type of a JIRA issue. // IssueType represents a type of a JIRA issue.
@ -158,10 +163,39 @@ type Progress struct {
Total int `json:"total"` Total int `json:"total"`
} }
type WorklogPage struct {
StartAt uint `json:"startAt"`
MaxResults uint `json:"maxResults"`
Total uint `json:"total"`
Worklogs []*Worklog `json:"worklogs"`
}
// Worklog represents the work log of a JIRA issue. // Worklog represents the work log of a JIRA issue.
// JIRA Wiki: https://confluence.atlassian.com/jira/logging-work-on-an-issue-185729605.html // JIRA Wiki: https://confluence.atlassian.com/jira/logging-work-on-an-issue-185729605.html
type Worklog struct { type Worklog struct {
// TODO Add Worklogs ID string `json:"id"`
Self string `json:"self"`
IssueId string `json:"issueId"`
TimeSpent string `json:"timeSpent"`
TimeSpentSeconds uint64 `json:"timeSpentSeconds"`
Comment string `json:"comment"`
Updated JiraTime `json:"updated"`
Created JiraTime `json:"created"`
Started JiraTime `json:"started"`
Author *Assignee `json:"author"`
}
type JiraTime struct {
Time time.Time
}
func (t *JiraTime) UnmarshalJSON(b []byte) error {
ti, err := time.Parse("\"2006-01-02T15:04:05.999-0700\"", string(b))
if err != nil {
return err
}
*t = JiraTime{ti}
return nil
} }
// IssueLink represents a link between two issues in JIRA. // IssueLink represents a link between two issues in JIRA.
@ -215,6 +249,10 @@ type CommentVisibility struct {
Value string `json:"value"` Value string `json:"value"`
} }
type SearchResult struct {
Issues Issues `json:"issues"`
}
// Get returns a full representation of the issue for the given issue key. // Get returns a full representation of the issue for the given issue key.
// JIRA will attempt to identify the issue by the issueIdOrKey path parameter. // JIRA will attempt to identify the issue by the issueIdOrKey path parameter.
// This can be an issue id, or an issue key. // This can be an issue id, or an issue key.
@ -237,6 +275,38 @@ func (s *IssueService) Get(issueID string) (*Issue, *http.Response, error) {
return issue, resp, nil return issue, resp, nil
} }
type CustomFields map[string]string
// Returns a map of customfield_* keys with string values
func (s *IssueService) GetCustomFields(issueID string) (CustomFields, *http.Response, error) {
apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s", issueID)
req, err := s.client.NewRequest("GET", apiEndpoint, nil)
if err != nil {
return nil, nil, err
}
issue := new(map[string]interface{})
resp, err := s.client.Do(req, issue)
if err != nil {
return nil, resp, err
}
m := *issue
f := m["fields"]
cf := make(CustomFields)
if f == nil {
return cf, resp, nil
}
if rec, ok := f.(map[string]interface{}); ok {
for key, val := range rec {
if strings.Contains(key, "customfield") {
cf[key] = fmt.Sprint(val)
}
}
}
return cf, resp, nil
}
// Create creates an issue or a sub-task from a JSON representation. // Create creates an issue or a sub-task from a JSON representation.
// Creating a sub-task is similar to creating a regular issue, with two important differences: // Creating a sub-task is similar to creating a regular issue, with two important differences:
// 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. // 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.
@ -290,3 +360,15 @@ func (s *IssueService) AddLink(issueLink *IssueLink) (*http.Response, error) {
resp, err := s.client.Do(req, nil) resp, err := s.client.Do(req, nil)
return resp, err return resp, err
} }
// Search for tickets
// 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) (*SearchResult, error) {
req, err := s.client.NewRequest("GET", "rest/api/2/search?jql="+url.QueryEscape(jql), nil)
if err != nil {
panic(err)
}
resp := new(SearchResult)
_, err = s.client.Do(req, resp)
return resp, err
}