Skip to content

Commit

Permalink
onprem,cloud: add query params to Issue.Create
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir Chalupecky committed Dec 2, 2022
1 parent 689849a commit 7d9c08d
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 24 deletions.
2 changes: 1 addition & 1 deletion cloud/examples/create/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func main() {
},
}

issue, _, err := client.Issue.Create(context.Background(), &i)
issue, _, err := client.Issue.Create(context.Background(), &i, nil)
if err != nil {
panic(err)
}
Expand Down
4 changes: 3 additions & 1 deletion cloud/examples/createwithcustomfields/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ func main() {
},
}

issue, _, err := client.Issue.Create(context.Background(), &i)
issue, _, err := client.Issue.Create(context.Background(), &i, &jira.CreateIssueOptions{
UpdateHistory: true,
})
if err != nil {
panic(err)
}
Expand Down
31 changes: 23 additions & 8 deletions cloud/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,12 @@ type searchResult struct {
Total int `json:"total" structs:"total"`
}

// CreateIssueOptions specifies the optional parameters for the Create Issue
// method.
type CreateIssueOptions struct {
UpdateHistory bool `url:"updateHistory,omitempty"`
}

// GetQueryOptions specifies the optional parameters for the Get Issue methods
type GetQueryOptions struct {
// Fields is the list of fields to return for the issue. By default, all fields are returned.
Expand Down Expand Up @@ -798,17 +804,26 @@ func WithQueryOptions(options interface{}) func(*http.Request) error {
}
}

// 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:
// 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.
// Create creates an issue or a sub-task.
//
// 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 containing the
// ID or key of the parent issue.
//
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-createIssues
// Jira API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-post
//
// TODO Double check this method if this works as expected, is using the latest API and the response is complete
// This double check effort is done for v2 - Remove this two lines if this is completed.
func (s *IssueService) Create(ctx context.Context, issue *Issue) (*Issue, *Response, error) {
func (s *IssueService) Create(ctx context.Context, issue *Issue, opts *CreateIssueOptions) (*Issue, *Response, error) {
apiEndpoint := "rest/api/2/issue"
req, err := s.client.NewRequest(ctx, http.MethodPost, apiEndpoint, issue)

url, err := addOptions(apiEndpoint, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest(ctx, http.MethodPost, url, issue)
if err != nil {
return nil, nil, err
}
Expand All @@ -820,13 +835,13 @@ func (s *IssueService) Create(ctx context.Context, issue *Issue) (*Issue, *Respo
}
defer resp.Body.Close()

responseIssue := new(Issue)
var responseIssue Issue
err = json.NewDecoder(resp.Body).Decode(&responseIssue)
if err != nil {
return nil, resp, err
}

return responseIssue, resp, nil
return &responseIssue, resp, nil
}

// Update updates an issue from a JSON representation,
Expand Down
10 changes: 8 additions & 2 deletions cloud/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ func TestIssueService_Create(t *testing.T) {
testMux.HandleFunc("/rest/api/2/issue", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)
testRequestURL(t, r, "/rest/api/2/issue")
testRequestParams(t, r, map[string]string{
"updateHistory": "true",
})

w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group","value":"jira-developers"},"started":"2016-03-16T04:22:37.471+0000","timeSpent":"3h 20m","timeSpentSeconds":12000,"id":"100028","issueId":"10002"}]},"updated":"2016-04-06T02:36:53.594-0700","duedate":"2018-01-19","timetracking":{"originalEstimate":"10m","remainingEstimate":"3m","timeSpent":"6m","originalEstimateSeconds":600,"remainingEstimateSeconds":200,"timeSpentSeconds":400}},"names":{"watcher":"watcher","attachment":"attachment","sub-tasks":"sub-tasks","description":"description","project":"project","comment":"comment","issuelinks":"issuelinks","worklog":"worklog","updated":"updated","timetracking":"timetracking"},"schema":{}}`)
Expand All @@ -73,7 +76,7 @@ func TestIssueService_Create(t *testing.T) {
Description: "example bug report",
},
}
issue, _, err := testClient.Issue.Create(context.Background(), i)
issue, _, err := testClient.Issue.Create(context.Background(), i, &CreateIssueOptions{UpdateHistory: true})
if issue == nil {
t.Error("Expected issue. Issue is nil")
}
Expand All @@ -88,6 +91,9 @@ func TestIssueService_CreateThenGet(t *testing.T) {
testMux.HandleFunc("/rest/api/2/issue", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)
testRequestURL(t, r, "/rest/api/2/issue")
testRequestParams(t, r, map[string]string{
"updateHistory": "true",
})

w.WriteHeader(http.StatusCreated)
io.Copy(w, r.Body)
Expand All @@ -99,7 +105,7 @@ func TestIssueService_CreateThenGet(t *testing.T) {
Created: Time(time.Now()),
},
}
issue, _, err := testClient.Issue.Create(context.Background(), i)
issue, _, err := testClient.Issue.Create(context.Background(), i, &CreateIssueOptions{UpdateHistory: true})
if issue == nil {
t.Error("Expected issue. Issue is nil")
}
Expand Down
2 changes: 1 addition & 1 deletion onpremise/examples/create/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func main() {
},
}

issue, _, err := client.Issue.Create(context.Background(), &i)
issue, _, err := client.Issue.Create(context.Background(), &i, nil)
if err != nil {
panic(err)
}
Expand Down
4 changes: 3 additions & 1 deletion onpremise/examples/createwithcustomfields/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ func main() {
},
}

issue, _, err := client.Issue.Create(context.Background(), &i)
issue, _, err := client.Issue.Create(context.Background(), &i, &jira.CreateIssueOptions{
UpdateHistory: true,
})
if err != nil {
panic(err)
}
Expand Down
31 changes: 23 additions & 8 deletions onpremise/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,12 @@ type searchResult struct {
Total int `json:"total" structs:"total"`
}

// CreateIssueOptions specifies the optional parameters for the Create Issue
// method.
type CreateIssueOptions struct {
UpdateHistory bool `url:"updateHistory,omitempty"`
}

// GetQueryOptions specifies the optional parameters for the Get Issue methods
type GetQueryOptions struct {
// Fields is the list of fields to return for the issue. By default, all fields are returned.
Expand Down Expand Up @@ -798,17 +804,26 @@ func WithQueryOptions(options interface{}) func(*http.Request) error {
}
}

// 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:
// 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.
// Create creates an issue or a sub-task.
//
// 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 containing the
// ID or key of the parent issue.
//
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-createIssues
// Jira API docs: https://docs.atlassian.com/software/jira/docs/api/REST/9.4.0/#api/2/issue-createIssue
//
// TODO Double check this method if this works as expected, is using the latest API and the response is complete
// This double check effort is done for v2 - Remove this two lines if this is completed.
func (s *IssueService) Create(ctx context.Context, issue *Issue) (*Issue, *Response, error) {
func (s *IssueService) Create(ctx context.Context, issue *Issue, opts *CreateIssueOptions) (*Issue, *Response, error) {
apiEndpoint := "rest/api/2/issue"
req, err := s.client.NewRequest(ctx, http.MethodPost, apiEndpoint, issue)

url, err := addOptions(apiEndpoint, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest(ctx, http.MethodPost, url, issue)
if err != nil {
return nil, nil, err
}
Expand All @@ -820,13 +835,13 @@ func (s *IssueService) Create(ctx context.Context, issue *Issue) (*Issue, *Respo
}
defer resp.Body.Close()

responseIssue := new(Issue)
var responseIssue Issue
err = json.NewDecoder(resp.Body).Decode(&responseIssue)
if err != nil {
return nil, resp, err
}

return responseIssue, resp, nil
return &responseIssue, resp, nil
}

// Update updates an issue from a JSON representation,
Expand Down
10 changes: 8 additions & 2 deletions onpremise/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ func TestIssueService_Create(t *testing.T) {
testMux.HandleFunc("/rest/api/2/issue", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)
testRequestURL(t, r, "/rest/api/2/issue")
testRequestParams(t, r, map[string]string{
"updateHistory": "true",
})

w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, `{"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations","id":"10002","self":"http://www.example.com/jira/rest/api/2/issue/10002","key":"EX-1","fields":{"watcher":{"self":"http://www.example.com/jira/rest/api/2/issue/EX-1/watchers","isWatching":false,"watchCount":1,"watchers":[{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false}]},"attachment":[{"self":"http://www.example.com/jira/rest/api/2.0/attachments/10000","filename":"picture.jpg","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","avatarUrls":{"48x48":"http://www.example.com/jira/secure/useravatar?size=large&ownerId=fred","24x24":"http://www.example.com/jira/secure/useravatar?size=small&ownerId=fred","16x16":"http://www.example.com/jira/secure/useravatar?size=xsmall&ownerId=fred","32x32":"http://www.example.com/jira/secure/useravatar?size=medium&ownerId=fred"},"displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.461+0000","size":23123,"mimeType":"image/jpeg","content":"http://www.example.com/jira/attachments/10000","thumbnail":"http://www.example.com/jira/secure/thumbnail/10000"}],"sub-tasks":[{"id":"10000","type":{"id":"10000","name":"","inward":"Parent","outward":"Sub-task"},"outwardIssue":{"id":"10003","key":"EX-2","self":"http://www.example.com/jira/rest/api/2/issue/EX-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"description":"example bug report","project":{"self":"http://www.example.com/jira/rest/api/2/project/EX","id":"10000","key":"EX","name":"Example","avatarUrls":{"48x48":"http://www.example.com/jira/secure/projectavatar?size=large&pid=10000","24x24":"http://www.example.com/jira/secure/projectavatar?size=small&pid=10000","16x16":"http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000","32x32":"http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000"},"projectCategory":{"self":"http://www.example.com/jira/rest/api/2/projectCategory/10000","id":"10000","name":"FIRST","description":"First Project Category"}},"comment":{"comments":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/comment/10000","id":"10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"body":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.","updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"created":"2016-03-16T04:22:37.356+0000","updated":"2016-03-16T04:22:37.356+0000","visibility":{"type":"role","value":"Administrators"}}]},"issuelinks":[{"id":"10001","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"outwardIssue":{"id":"10004L","key":"PRJ-2","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-2","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}},{"id":"10002","type":{"id":"10000","name":"Dependent","inward":"depends on","outward":"is depended by"},"inwardIssue":{"id":"10004","key":"PRJ-3","self":"http://www.example.com/jira/rest/api/2/issue/PRJ-3","fields":{"status":{"iconUrl":"http://www.example.com/jira//images/icons/statuses/open.png","name":"Open"}}}}],"worklog":{"worklogs":[{"self":"http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000","author":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"updateAuthor":{"self":"http://www.example.com/jira/rest/api/2/user?username=fred","name":"fred","displayName":"Fred F. User","active":false},"comment":"I did some work here.","updated":"2016-03-16T04:22:37.471+0000","visibility":{"type":"group","value":"jira-developers"},"started":"2016-03-16T04:22:37.471+0000","timeSpent":"3h 20m","timeSpentSeconds":12000,"id":"100028","issueId":"10002"}]},"updated":"2016-04-06T02:36:53.594-0700","duedate":"2018-01-19","timetracking":{"originalEstimate":"10m","remainingEstimate":"3m","timeSpent":"6m","originalEstimateSeconds":600,"remainingEstimateSeconds":200,"timeSpentSeconds":400}},"names":{"watcher":"watcher","attachment":"attachment","sub-tasks":"sub-tasks","description":"description","project":"project","comment":"comment","issuelinks":"issuelinks","worklog":"worklog","updated":"updated","timetracking":"timetracking"},"schema":{}}`)
Expand All @@ -73,7 +76,7 @@ func TestIssueService_Create(t *testing.T) {
Description: "example bug report",
},
}
issue, _, err := testClient.Issue.Create(context.Background(), i)
issue, _, err := testClient.Issue.Create(context.Background(), i, &CreateIssueOptions{UpdateHistory: true})
if issue == nil {
t.Error("Expected issue. Issue is nil")
}
Expand All @@ -88,6 +91,9 @@ func TestIssueService_CreateThenGet(t *testing.T) {
testMux.HandleFunc("/rest/api/2/issue", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)
testRequestURL(t, r, "/rest/api/2/issue")
testRequestParams(t, r, map[string]string{
"updateHistory": "true",
})

w.WriteHeader(http.StatusCreated)
io.Copy(w, r.Body)
Expand All @@ -99,7 +105,7 @@ func TestIssueService_CreateThenGet(t *testing.T) {
Created: Time(time.Now()),
},
}
issue, _, err := testClient.Issue.Create(context.Background(), i)
issue, _, err := testClient.Issue.Create(context.Background(), i, &CreateIssueOptions{UpdateHistory: true})
if issue == nil {
t.Error("Expected issue. Issue is nil")
}
Expand Down

0 comments on commit 7d9c08d

Please sign in to comment.