From 520b63ad88aaccf446fd205992f38f924fda9cf0 Mon Sep 17 00:00:00 2001 From: rtweed Date: Thu, 8 Feb 2024 17:18:28 +0000 Subject: [PATCH] feature: add UpdateIssueWithOptions and add testing for addOptions to make clear what it does Signed-off-by: rtweed --- cloud/issue.go | 24 +++++++++++++++--- cloud/issue_test.go | 24 ++++++++++++++++++ cloud/jira_test.go | 13 ++++++++++ onpremise/issue.go | 4 +-- onpremise/issue_test.go | 54 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 6 deletions(-) diff --git a/cloud/issue.go b/cloud/issue.go index 56d868ef..234d08f4 100644 --- a/cloud/issue.go +++ b/cloud/issue.go @@ -31,7 +31,7 @@ type IssueService service // UpdateQueryOptions specifies the optional parameters to the Edit issue type UpdateQueryOptions struct { - NotifyUsers bool `url:"notifyUsers,omitempty"` + NotifyUsers bool `url:"notifyUsers"` // can't be omitted as this means it's omitted when false which isn't desired as this defaults to true OverrideScreenSecurity bool `url:"overrideScreenSecurity,omitempty"` OverrideEditableFlag bool `url:"overrideEditableFlag,omitempty"` } @@ -559,7 +559,7 @@ type GetWorklogsQueryOptions struct { } type AddWorklogQueryOptions struct { - NotifyUsers bool `url:"notifyUsers,omitempty"` + NotifyUsers bool `url:"notifyUsers"` // can't be omitted as this means it's omitted when false which isn't desired as this defaults to true AdjustEstimate string `url:"adjustEstimate,omitempty"` NewEstimate string `url:"newEstimate,omitempty"` ReduceBy string `url:"reduceBy,omitempty"` @@ -868,8 +868,24 @@ func (s *IssueService) Update(ctx context.Context, issue *Issue, opts *UpdateQue // 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) UpdateIssue(ctx context.Context, jiraID string, data map[string]interface{}) (*Response, error) { - apiEndpoint := fmt.Sprintf("rest/api/2/issue/%v", jiraID) - req, err := s.client.NewRequest(ctx, http.MethodPut, apiEndpoint, data) + return s.UpdateIssueWithOptions(ctx, jiraID, data, &UpdateQueryOptions{}) +} + +// UpdateIssueWithOptions updates an issue from a JSON patch, +// while also specifying query params. The issue is found by key. +// +// Jira API docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues/#api-rest-api-2-issue-issueidorkey-put +// Caller must close resp.Body +// +// 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) UpdateIssueWithOptions(ctx context.Context, jiraID string, data map[string]interface{}, opts *UpdateQueryOptions) (*Response, error) { + a := fmt.Sprintf("rest/api/2/issue/%v", jiraID) + url, err := addOptions(a, opts) + if err != nil { + return nil, err + } + req, err := s.client.NewRequest(ctx, http.MethodPut, url, data) if err != nil { return nil, err } diff --git a/cloud/issue_test.go b/cloud/issue_test.go index a8ad6487..cb6c144f 100644 --- a/cloud/issue_test.go +++ b/cloud/issue_test.go @@ -178,6 +178,30 @@ func TestIssueService_UpdateIssue(t *testing.T) { } +func TestIssueService_UpdateIssueWithOptions(t *testing.T) { + setup() + defer teardown() + testMux.HandleFunc("/rest/api/2/issue/PROJ-9001", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPut) + testRequestURL(t, r, "/rest/api/2/issue/PROJ-9001") + testRequestParams(t, r, map[string]string{"notifyUsers": "true"}) + + w.WriteHeader(http.StatusNoContent) + }) + jID := "PROJ-9001" + i := make(map[string]interface{}) + fields := make(map[string]interface{}) + i["fields"] = fields + resp, err := testClient.Issue.client.Issue.UpdateIssueWithOptions(context.Background(), jID, i, &UpdateQueryOptions{NotifyUsers: false}) + if resp == nil { + t.Error("Expected resp. resp is nil") + } + if err != nil { + t.Errorf("Error given: %s", err) + } + +} + func TestIssueService_AddComment(t *testing.T) { setup() defer teardown() diff --git a/cloud/jira_test.go b/cloud/jira_test.go index 61d4b81a..b6f0c748 100644 --- a/cloud/jira_test.go +++ b/cloud/jira_test.go @@ -73,6 +73,19 @@ func testRequestParams(t *testing.T, r *http.Request, want map[string]string) { } +func Test_addOptions(t *testing.T) { + v, err := addOptions("rest/api/2/issue/123", &UpdateQueryOptions{NotifyUsers: false}) + if err != nil { + t.Errorf("Expected no error. Got: %+v", err) + } + + expectedOutput := "rest/api/2/issue/123?notifyUsers=false" + if v != expectedOutput { + t.Errorf("Expected: %+v, got: %+v", expectedOutput, v) + } + +} + func TestNewClient_WrongUrl(t *testing.T) { c, err := NewClient("://issues.apache.org/jira/", nil) diff --git a/onpremise/issue.go b/onpremise/issue.go index d1bca7aa..d304ff15 100644 --- a/onpremise/issue.go +++ b/onpremise/issue.go @@ -31,7 +31,7 @@ type IssueService service // UpdateQueryOptions specifies the optional parameters to the Edit issue type UpdateQueryOptions struct { - NotifyUsers bool `url:"notifyUsers,omitempty"` + NotifyUsers bool `url:"notifyUsers"` // can't be omitted as this means it's omitted when false which isn't desired as this defaults to true OverrideScreenSecurity bool `url:"overrideScreenSecurity,omitempty"` OverrideEditableFlag bool `url:"overrideEditableFlag,omitempty"` } @@ -839,7 +839,7 @@ func (s *IssueService) Create(ctx context.Context, issue *Issue) (*Issue, *Respo // This double check effort is done for v2 - Remove this two lines if this is completed. func (s *IssueService) Update(ctx context.Context, issue *Issue, opts *UpdateQueryOptions) (*Issue, *Response, error) { apiEndpoint := fmt.Sprintf("rest/api/2/issue/%v", issue.Key) - url, err := addOptions(apiEndpoint, opts) + url, err := addOptions(apiEndpoint, *opts) if err != nil { return nil, nil, err } diff --git a/onpremise/issue_test.go b/onpremise/issue_test.go index 36b6aa31..441701c1 100644 --- a/onpremise/issue_test.go +++ b/onpremise/issue_test.go @@ -155,6 +155,60 @@ func TestIssueService_Update(t *testing.T) { } } +func TestIssueService_Update_with_false_opts(t *testing.T) { + setup() + defer teardown() + testMux.HandleFunc("/rest/api/2/issue/PROJ-9001", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPut) + testRequestURL(t, r, "/rest/api/2/issue/PROJ-9001") + testRequestParams(t, r, map[string]string{"notifyUsers": "false"}) + + w.WriteHeader(http.StatusNoContent) + }) + + i := &Issue{ + Key: "PROJ-9001", + Fields: &IssueFields{ + Description: "example bug report", + }, + } + issue, _, err := testClient.Issue.Update(context.Background(), i, &UpdateQueryOptions{NotifyUsers: false}) + if issue == nil { + t.Error("Expected issue. Issue is nil") + } + if err != nil { + t.Errorf("Error given: %s", err) + } + +} + +func TestIssueService_Update_with_multiple_opts(t *testing.T) { + setup() + defer teardown() + testMux.HandleFunc("/rest/api/2/issue/PROJ-9001", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPut) + testRequestURL(t, r, "/rest/api/2/issue/PROJ-9001") + testRequestParams(t, r, map[string]string{"notifyUsers": "false", "overrideScreenSecurity": "true"}) + + w.WriteHeader(http.StatusNoContent) + }) + + i := &Issue{ + Key: "PROJ-9001", + Fields: &IssueFields{ + Description: "example bug report", + }, + } + issue, _, err := testClient.Issue.Update(context.Background(), i, &UpdateQueryOptions{NotifyUsers: false, OverrideScreenSecurity: true}) + if issue == nil { + t.Error("Expected issue. Issue is nil") + } + if err != nil { + t.Errorf("Error given: %s", err) + } + +} + func TestIssueService_UpdateIssue(t *testing.T) { setup() defer teardown()