Repository: ctreminiom/go-atlassian
Pull request #8 (2021-03-24 22:01:15)

:sparkles: feature-adf-comments


Patch:
diff --git a/.gitignore b/.gitignore
index d69b87f..d9592b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,5 +14,3 @@
 # Dependency directories (remove the comment below to include it)
 # vendor/
 .idea/
-jira/examples/
-/jira/examples/
diff --git a/jira/examples/issue/comment/add/add.go b/jira/examples/issue/comment/add/add.go
new file mode 100644
index 0000000..ded4c5a
--- /dev/null
+++ b/jira/examples/issue/comment/add/add.go
@@ -0,0 +1,64 @@
+package main
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/jira"
+	"log"
+	"os"
+)
+
+func main() {
+
+	var (
+		host  = os.Getenv("HOST")
+		mail  = os.Getenv("MAIL")
+		token = os.Getenv("TOKEN")
+	)
+
+	atlassian, err := jira.New(nil, host)
+	if err != nil {
+		return
+	}
+
+	atlassian.Auth.SetBasicAuth(mail, token)
+	atlassian.Auth.SetUserAgent("curl/7.54.0")
+
+	commentBody := jira.CommentNodeScheme{}
+	commentBody.Version = 1
+	commentBody.Type = "doc"
+
+	commentBody.AppendNode(&jira.CommentNodeScheme{
+		Type: "paragraph",
+		Content: []*jira.CommentNodeScheme{
+			{
+				Type: "text",
+				Text: "Carlos Test",
+			},
+			{
+				Type: "emoji",
+				Attrs: map[string]interface{}{
+					"shortName": ":grin",
+					"id":        "1f601",
+					"text":      "😁",
+				},
+			},
+			{
+				Type: "text",
+				Text: " ",
+			},
+		},
+	})
+
+	newComment, response, err := atlassian.Issue.Comment.Add(context.Background(), "KP-2", "role", "Administrators", &commentBody, nil)
+	if err != nil {
+		if response != nil {
+			log.Println("Response HTTP Response", string(response.BodyAsBytes))
+		}
+		log.Fatal(err)
+	}
+
+	log.Println("Response HTTP Code", response.StatusCode)
+	log.Println("HTTP Endpoint Used", response.Endpoint)
+
+	log.Println(newComment.ID)
+}
diff --git a/jira/issueComment.go b/jira/issueComment.go
index 28b2f76..7a6de01 100644
--- a/jira/issueComment.go
+++ b/jira/issueComment.go
@@ -160,3 +160,84 @@ func (c *CommentService) Delete(ctx context.Context, issueKeyOrID, commentID str
 
 	return
 }
+
+func (c *CommentService) Add(ctx context.Context, issueKeyOrID, visibilityType, visibilityValue string, body *CommentNodeScheme, expands []string) (result *CommentScheme, response *Response, err error) {
+
+	if len(issueKeyOrID) == 0 {
+		return nil, nil, fmt.Errorf("error, please provide a valid issueKeyOrID value")
+	}
+
+	if body == nil {
+		return nil, nil, fmt.Errorf("error, please provide a valid CommentNodeScheme pointer")
+	}
+
+	var commentPayload = map[string]interface{}{}
+	commentPayload["body"] = body
+
+	var visibilityPayload = map[string]interface{}{}
+	visibilityPayload["type"] = visibilityType
+	visibilityPayload["value"] = visibilityValue
+
+	commentPayload["visibility"] = visibilityPayload
+
+	params := url.Values{}
+	var expand string
+	for index, value := range expands {
+
+		if index == 0 {
+			expand = value
+			continue
+		}
+
+		expand += "," + value
+	}
+
+	if len(expand) != 0 {
+		params.Add("expand", expand)
+	}
+
+	var endpoint string
+	if len(params.Encode()) != 0 {
+		endpoint = fmt.Sprintf("rest/api/3/issue/%v/comment?%v", issueKeyOrID, params.Encode())
+	} else {
+		endpoint = fmt.Sprintf("rest/api/3/issue/%v/comment", issueKeyOrID)
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodPost, endpoint, &commentPayload)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = c.client.Do(request)
+	if err != nil {
+		return
+	}
+
+	result = new(CommentScheme)
+	if err = json.Unmarshal(response.BodyAsBytes, &result); err != nil {
+		return
+	}
+
+	return
+}
+
+type CommentNodeScheme struct {
+	Version int                    `json:"version,omitempty"`
+	Type    string                 `json:"type,omitempty"`
+	Content []*CommentNodeScheme   `json:"content,omitempty"`
+	Text    string                 `json:"text,omitempty"`
+	Attrs   map[string]interface{} `json:"attrs,omitempty"`
+	Marks   []*MarkScheme          `json:"marks,omitempty"`
+}
+
+func (n *CommentNodeScheme) AppendNode(node *CommentNodeScheme) {
+	n.Content = append(n.Content, node)
+}
+
+type MarkScheme struct {
+	Type  string                 `json:"type"`
+	Attrs map[string]interface{} `json:"attrs"`
+}


Test patch:
diff --git a/jira/issueComment_test.go b/jira/issueComment_test.go
index 340c735..380e657 100644
--- a/jira/issueComment_test.go
+++ b/jira/issueComment_test.go
@@ -293,6 +293,28 @@ func TestCommentService_Delete(t *testing.T) {
 			wantHTTPCodeReturn: http.StatusBadRequest,
 			wantErr:            true,
 		},
+
+		{
+			name:               "DeleteIssueCommentWhenTheContextIsNil",
+			issueKeyOrID:       "DUMMY-3",
+			commentID:          "10001",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment/10001",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "DeleteIssueCommentWhenTheEndpointIsEmpty",
+			issueKeyOrID:       "DUMMY-3",
+			commentID:          "10001",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
 	}
 
 	for _, testCase := range testCases {
@@ -540,3 +562,259 @@ func TestCommentService_Get(t *testing.T) {
 	}
 
 }
+
+func TestCommentService_Add(t *testing.T) {
+
+	commentBody := CommentNodeScheme{}
+	commentBody.Version = 1
+	commentBody.Type = "doc"
+
+	commentBody.AppendNode(&CommentNodeScheme{
+		Type: "paragraph",
+		Content: []*CommentNodeScheme{
+			{
+				Type: "text",
+				Text: "Carlos Test",
+				Marks: []*MarkScheme{
+					{
+						Type: "strong",
+					},
+				},
+			},
+			{
+				Type: "emoji",
+				Attrs: map[string]interface{}{
+					"shortName": ":grin",
+					"id":        "1f601",
+					"text":      "😁",
+				},
+			},
+			{
+				Type: "text",
+				Text: " ",
+			},
+		},
+	})
+
+	testCases := []struct {
+		name                                          string
+		issueKeyOrID, visibilityType, visibilityValue string
+		body                                          *CommentNodeScheme
+		expands                                       []string
+		mockFile                                      string
+		wantHTTPMethod                                string
+		endpoint                                      string
+		context                                       context.Context
+		wantHTTPCodeReturn                            int
+		wantErr                                       bool
+	}{
+		{
+			name:               "AddIssueCommentWhenTheParametersAreCorrect",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody", "comment.id"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody%2Ccomment.id",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            false,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheResponseBodyHasADifferentFormat",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/empty_json.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheIssueKeyIsNotSet",
+			issueKeyOrID:       "",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheCommentBodyIsNotSet",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               nil,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheVisibilityIsNotSet",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "",
+			visibilityValue:    "",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            false,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheExpandsAreNotSet",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            nil,
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheRequestMethodIsIncorrect",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheStatusCodeIsIncorrect",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AddIssueCommentWhenTheContextIsNil",
+			issueKeyOrID:       "DUMMY-3",
+			visibilityType:     "role",
+			visibilityValue:    "Administrators",
+			body:               &commentBody,
+			expands:            []string{"renderedBody"},
+			mockFile:           "./mocks/get-issue-comment-by-id.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/issue/DUMMY-3/comment?expand=renderedBody",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &CommentService{client: mockClient}
+
+			gotResult, gotResponse, err := i.Add(testCase.context,
+				testCase.issueKeyOrID, testCase.visibilityType,
+				testCase.visibilityValue, testCase.body,
+				testCase.expands)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Log("-------------------------")
+				t.Logf("Comment ID: %v", gotResult.ID)
+				t.Logf("Comment Created: %v", gotResult.Created)
+				t.Logf("Comment Author EmailAddress: %v", gotResult.Author.EmailAddress)
+				t.Logf("Comment Author AccountID: %v", gotResult.Author.AccountID)
+				t.Log("------------------------- \n")
+
+			}
+		})
+
+	}
+
+}