From 7a4671aa1ae16d9dd866216a57e2364671ac7b85 Mon Sep 17 00:00:00 2001 From: Omer Zidkoni <50792403+omerzi@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:55:44 +0300 Subject: [PATCH] Remove Pull Request comment (#99) --- vcsclient/azurerepos.go | 22 +++++++++++++ vcsclient/azurerepos_test.go | 11 +++++++ vcsclient/bitbucketcloud.go | 5 +++ vcsclient/bitbucketserver.go | 24 ++++++++++++++ vcsclient/bitbucketserver_test.go | 19 +++++++++++- vcsclient/github.go | 24 ++++++++++++++ vcsclient/github_test.go | 11 +++++++ vcsclient/gitlab.go | 30 ++++++++++++------ vcsclient/gitlab_test.go | 12 +++++-- .../azurerepos/resourcesResponse.json | 31 +++++++++++++------ vcsclient/vcsclient.go | 9 ++++++ 11 files changed, 175 insertions(+), 23 deletions(-) diff --git a/vcsclient/azurerepos.go b/vcsclient/azurerepos.go index 58875441..f3cd63e9 100644 --- a/vcsclient/azurerepos.go +++ b/vcsclient/azurerepos.go @@ -239,8 +239,14 @@ func (client *AzureReposClient) ListPullRequestComments(ctx context.Context, _, } var commentInfo []CommentInfo for _, thread := range *threads { + if thread.IsDeleted != nil && *thread.IsDeleted { + continue + } var commentsAggregator strings.Builder for _, comment := range *thread.Comments { + if comment.IsDeleted != nil && *comment.IsDeleted { + continue + } _, err = commentsAggregator.WriteString( fmt.Sprintf("Author: %s, Id: %d, Content:%s\n", *comment.Author.DisplayName, @@ -259,6 +265,22 @@ func (client *AzureReposClient) ListPullRequestComments(ctx context.Context, _, return commentInfo, nil } +// DeletePullRequestComment on Azure Repos +func (client *AzureReposClient) DeletePullRequestComment(ctx context.Context, _, repository string, pullRequestID, commentID int) error { + azureReposGitClient, err := client.buildAzureReposClient(ctx) + if err != nil { + return err + } + firstCommentInThreadID := 1 + return azureReposGitClient.DeleteComment(ctx, git.DeleteCommentArgs{ + RepositoryId: &repository, + PullRequestId: &pullRequestID, + ThreadId: &commentID, + Project: &client.vcsInfo.Project, + CommentId: &firstCommentInThreadID, + }) +} + // ListOpenPullRequestsWithBody on Azure Repos func (client *AzureReposClient) ListOpenPullRequestsWithBody(ctx context.Context, owner, repository string) ([]PullRequestInfo, error) { return client.getOpenPullRequests(ctx, owner, repository, true) diff --git a/vcsclient/azurerepos_test.go b/vcsclient/azurerepos_test.go index c2a3c39a..1d66f3e6 100644 --- a/vcsclient/azurerepos_test.go +++ b/vcsclient/azurerepos_test.go @@ -560,6 +560,17 @@ func TestAzureReposClient_GetModifiedFiles(t *testing.T) { }) } +func TestAzureReposClient_DeletePullRequestComment(t *testing.T) { + client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "deletePullRequestComments", createAzureReposHandler) + defer cleanUp() + err := client.DeletePullRequestComment(context.Background(), "", repo1, 1, 1) + assert.NoError(t, err) + badClient, badClientCleanup := createBadAzureReposClient(t, []byte{}) + defer badClientCleanup() + err = badClient.DeletePullRequestComment(context.Background(), "", repo1, 1, 1) + assert.Error(t, err) +} + func TestAzureReposClient_GetCommitStatus(t *testing.T) { ctx := context.Background() commitHash := "86d6919952702f9ab03bc95b45687f145a663de0" diff --git a/vcsclient/bitbucketcloud.go b/vcsclient/bitbucketcloud.go index 7048edbf..d20f9682 100644 --- a/vcsclient/bitbucketcloud.go +++ b/vcsclient/bitbucketcloud.go @@ -429,6 +429,11 @@ func (client *BitbucketCloudClient) ListPullRequestComments(ctx context.Context, return mapBitbucketCloudCommentToCommentInfo(&parsedComments), nil } +// DeletePullRequestComment on Bitbucket cloud +func (client *BitbucketCloudClient) DeletePullRequestComment(_ context.Context, _, _ string, _, _ int) error { + return nil +} + // GetLatestCommit on Bitbucket cloud func (client *BitbucketCloudClient) GetLatestCommit(ctx context.Context, owner, repository, branch string) (CommitInfo, error) { err := validateParametersNotBlank(map[string]string{ diff --git a/vcsclient/bitbucketserver.go b/vcsclient/bitbucketserver.go index 417d4322..ab0b7f7d 100644 --- a/vcsclient/bitbucketserver.go +++ b/vcsclient/bitbucketserver.go @@ -467,6 +467,7 @@ func (client *BitbucketServerClient) ListPullRequestComments(ctx context.Context ID: int64(activity.Comment.ID), Created: time.Unix(activity.Comment.CreatedDate, 0), Content: activity.Comment.Text, + Version: activity.Comment.Version, }) } } @@ -474,6 +475,29 @@ func (client *BitbucketServerClient) ListPullRequestComments(ctx context.Context return results, nil } +// DeletePullRequestComment on Bitbucket Server +func (client *BitbucketServerClient) DeletePullRequestComment(ctx context.Context, owner, repository string, pullRequestID, commentID int) error { + bitbucketClient, err := client.buildBitbucketClient(ctx) + if err != nil { + return err + } + comments, err := client.ListPullRequestComments(ctx, owner, repository, pullRequestID) + if err != nil { + return err + } + commentVersion := 0 + for _, comment := range comments { + if comment.ID == int64(commentID) { + commentVersion = comment.Version + break + } + } + if _, err = bitbucketClient.DeleteComment_2(owner, repository, int64(pullRequestID), int64(commentID), map[string]interface{}{"version": int32(commentVersion)}); err != nil && err != io.EOF { + return fmt.Errorf("an error occurred while deleting pull request comment:\n%s", err.Error()) + } + return nil +} + type projectsResponse struct { Values []struct { Key string `json:"key,omitempty"` diff --git a/vcsclient/bitbucketserver_test.go b/vcsclient/bitbucketserver_test.go index 2cf4d2de..ae1f4542 100644 --- a/vcsclient/bitbucketserver_test.go +++ b/vcsclient/bitbucketserver_test.go @@ -297,6 +297,7 @@ func TestBitbucketServer_ListPullRequestComments(t *testing.T) { ID: 1, Content: "A measured reply.", Created: time.Unix(1548720847370, 0), + Version: 1, }, result[0]) } @@ -668,7 +669,7 @@ func createBitbucketServerHandler(t *testing.T, expectedURI string, response []b w.WriteHeader(expectedStatusCode) _, err := w.Write(response) require.NoError(t, err) - assert.Equal(t, expectedURI, r.RequestURI) + assert.Contains(t, expectedURI, r.RequestURI) assert.Equal(t, "Bearer "+token, r.Header.Get("Authorization")) } } @@ -768,6 +769,22 @@ func TestBitbucketServer_TestGetCommitStatus(t *testing.T) { }) } +func TestBitbucketServerClient_DeletePullRequestComment(t *testing.T) { + ctx := context.Background() + prId := 4 + commentId := 10 + version := 0 + client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, true, nil, fmt.Sprintf("/rest/api/1.0/projects/jfrog/repos/repo-1/pull-requests/%v/activities?start=%v", prId, version)+ + fmt.Sprintf("/rest/api/1.0/projects/jfrog/repos/repo-1/pull-requests/%v/comments/%v?version=%v", prId, commentId, version), createBitbucketServerHandler) + defer cleanUp() + + err := client.DeletePullRequestComment(ctx, owner, repo1, prId, commentId) + assert.NoError(t, err) + + err = createBadBitbucketServerClient(t).DeletePullRequestComment(ctx, owner, repo1, prId, commentId) + assert.Error(t, err) +} + func createBadBitbucketServerClient(t *testing.T) VcsClient { client, err := NewClientBuilder(vcsutils.BitbucketServer).ApiEndpoint("https://bad^endpoint").Build() require.NoError(t, err) diff --git a/vcsclient/github.go b/vcsclient/github.go index baceeeb8..48ce9d69 100644 --- a/vcsclient/github.go +++ b/vcsclient/github.go @@ -396,6 +396,30 @@ func (client *GitHubClient) ListPullRequestComments(ctx context.Context, owner, return mapGitHubCommentToCommentInfoList(commentsList) } +// DeletePullRequestComment on GitHub +func (client *GitHubClient) DeletePullRequestComment(ctx context.Context, owner, repository string, _, commentID int) error { + err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository}) + if err != nil { + return err + } + ghClient, err := client.buildGithubClient(ctx) + if err != nil { + return err + } + resp, err := ghClient.Issues.DeleteComment(ctx, owner, repository, int64(commentID)) + if err != nil { + return err + } + var statusCode int + if resp.Response != nil { + statusCode = resp.Response.StatusCode + } + if statusCode != http.StatusNoContent && statusCode != http.StatusOK { + return fmt.Errorf("expected %d status code while received %d status code", http.StatusNoContent, resp.Response.StatusCode) + } + return nil +} + // GetLatestCommit on GitHub func (client *GitHubClient) GetLatestCommit(ctx context.Context, owner, repository, branch string) (CommitInfo, error) { err := validateParametersNotBlank(map[string]string{ diff --git a/vcsclient/github_test.go b/vcsclient/github_test.go index b8495fb2..775b3e0f 100644 --- a/vcsclient/github_test.go +++ b/vcsclient/github_test.go @@ -839,6 +839,17 @@ func TestGitHubClient_getGitHubGitRemoteUrl(t *testing.T) { } } +func TestGitHubClient_DeletePullRequestComment(t *testing.T) { + ctx := context.Background() + client, cleanUp := createServerAndClient(t, vcsutils.GitHub, false, nil, fmt.Sprintf("/repos/%v/%v/issues/comments/1", owner, repo1), createGitHubHandler) + defer cleanUp() + err := client.DeletePullRequestComment(ctx, owner, repo1, 1, 1) + assert.NoError(t, err) + client = createBadGitHubClient(t) + err = client.DeletePullRequestComment(ctx, owner, repo1, 1, 1) + assert.Error(t, err) +} + func createBadGitHubClient(t *testing.T) VcsClient { client, err := NewClientBuilder(vcsutils.GitHub).ApiEndpoint("https://bad^endpoint").Build() require.NoError(t, err) diff --git a/vcsclient/gitlab.go b/vcsclient/gitlab.go index b0645a4b..fbe536bf 100644 --- a/vcsclient/gitlab.go +++ b/vcsclient/gitlab.go @@ -249,25 +249,24 @@ func (client *GitLabClient) UpdatePullRequest(ctx context.Context, owner, reposi } // ListOpenPullRequestsWithBody on GitLab -func (client *GitLabClient) ListOpenPullRequestsWithBody(ctx context.Context, _, repository string) ([]PullRequestInfo, error) { - return client.getOpenPullRequests(ctx, repository, true) +func (client *GitLabClient) ListOpenPullRequestsWithBody(ctx context.Context, owner, repository string) ([]PullRequestInfo, error) { + return client.getOpenPullRequests(ctx, owner, repository, true) } // ListOpenPullRequests on GitLab -func (client *GitLabClient) ListOpenPullRequests(ctx context.Context, _, repository string) ([]PullRequestInfo, error) { - return client.getOpenPullRequests(ctx, repository, false) +func (client *GitLabClient) ListOpenPullRequests(ctx context.Context, owner, repository string) ([]PullRequestInfo, error) { + return client.getOpenPullRequests(ctx, owner, repository, false) } -func (client *GitLabClient) getOpenPullRequests(ctx context.Context, repository string, withBody bool) ([]PullRequestInfo, error) { +func (client *GitLabClient) getOpenPullRequests(ctx context.Context, owner, repository string, withBody bool) ([]PullRequestInfo, error) { openState := "opened" allScope := "all" - options := &gitlab.ListMergeRequestsOptions{ + options := &gitlab.ListProjectMergeRequestsOptions{ State: &openState, Scope: &allScope, } - client.logger.Debug("fetching open merge requests in", repository) - mergeRequests, _, err := client.glClient.MergeRequests.ListMergeRequests(options, - gitlab.WithContext(ctx)) + //client.logger.Debug("fetching open merge requests in", repository) + mergeRequests, _, err := client.glClient.MergeRequests.ListProjectMergeRequests(getProjectID(owner, repository), options, gitlab.WithContext(ctx)) if err != nil { return []PullRequestInfo{}, err } @@ -275,7 +274,7 @@ func (client *GitLabClient) getOpenPullRequests(ctx context.Context, repository } // GetPullRequestInfoById on GitLab -func (client *GitLabClient) GetPullRequestByID(ctx context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) { +func (client *GitLabClient) GetPullRequestByID(_ context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) { client.logger.Debug("fetching merge requests by ID in", repository) mergeRequest, response, err := client.glClient.MergeRequests.GetMergeRequest(getProjectID(owner, repository), pullRequestId, nil) if err != nil || response.StatusCode != http.StatusOK { @@ -318,6 +317,17 @@ func (client *GitLabClient) ListPullRequestComments(ctx context.Context, owner, return mapGitLabNotesToCommentInfoList(commentsList), nil } +// DeletePullRequestComment on GitLab +func (client *GitLabClient) DeletePullRequestComment(ctx context.Context, owner, repository string, pullRequestID, commentID int) error { + if err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository}); err != nil { + return err + } + if _, err := client.glClient.Notes.DeleteMergeRequestNote(getProjectID(owner, repository), pullRequestID, commentID, gitlab.WithContext(ctx)); err != nil { + return fmt.Errorf("an error occurred while deleting pull request comment:\n%s", err.Error()) + } + return nil +} + // GetLatestCommit on GitLab func (client *GitLabClient) GetLatestCommit(ctx context.Context, owner, repository, branch string) (CommitInfo, error) { err := validateParametersNotBlank(map[string]string{ diff --git a/vcsclient/gitlab_test.go b/vcsclient/gitlab_test.go index d862a802..a30ec526 100644 --- a/vcsclient/gitlab_test.go +++ b/vcsclient/gitlab_test.go @@ -218,7 +218,7 @@ func TestGitLabClient_ListOpenPullRequests(t *testing.T) { assert.NoError(t, err) client, cleanUp := createServerAndClient(t, vcsutils.GitLab, false, response, - "/api/v4/merge_requests?scope=all&state=opened", createGitLabHandler) + "/api/v4/projects/jfrog%2Frepo-1/merge_requests?scope=all&state=opened", createGitLabHandler) defer cleanUp() result, err := client.ListOpenPullRequests(ctx, owner, repo1) @@ -231,7 +231,6 @@ func TestGitLabClient_ListOpenPullRequests(t *testing.T) { }, result[0])) // With body - result, err = client.ListOpenPullRequestsWithBody(ctx, owner, repo1) require.NoError(t, err) assert.Len(t, result, 1) @@ -523,6 +522,15 @@ func TestGitlabClient_GetRepositoryEnvironmentInfo(t *testing.T) { assert.ErrorIs(t, err, errGitLabGetRepoEnvironmentInfoNotSupported) } +func TestGitLabClient_DeletePullRequestComment(t *testing.T) { + ctx := context.Background() + client, cleanUp := createServerAndClient(t, vcsutils.GitLab, false, "", + fmt.Sprintf("/api/v4/projects/%s/merge_requests/1/notes/1", url.PathEscape(owner+"/"+repo1)), createGitLabHandler) + defer cleanUp() + err := client.DeletePullRequestComment(ctx, owner, repo1, 1, 1) + assert.NoError(t, err) +} + func TestGitLabClient_GetModifiedFiles(t *testing.T) { ctx := context.Background() t.Run("ok", func(t *testing.T) { diff --git a/vcsclient/testdata/azurerepos/resourcesResponse.json b/vcsclient/testdata/azurerepos/resourcesResponse.json index 6715abbb..855beb4f 100644 --- a/vcsclient/testdata/azurerepos/resourcesResponse.json +++ b/vcsclient/testdata/azurerepos/resourcesResponse.json @@ -89,17 +89,28 @@ "minVersion": "3.2", "maxVersion": "7.1", "releasedVersion": "0.0" - }, + }, + { + "id": "fb93c0db-47ed-4a31-8c20-47552878fb44", + "area": "Location", + "resourceName": "ResourceAreas", + "routeTemplate": "_apis/{resource}/DownloadFileFromRepo", + "resourceVersion": 1, + "minVersion": "3.2", + "maxVersion": "7.1", + "releasedVersion": "0.0" + }, + { + "id": "965a3ec7-5ed8-455a-bdcb-835a5ea7fe7b", + "area": "Location", + "resourceName": "ResourceAreas", + "routeTemplate": "_apis/{resource}/deletePullRequestComments", + "resourceVersion": 1, + "minVersion": "3.2", + "maxVersion": "7.1", + "releasedVersion": "0.0" + }, { - "id": "fb93c0db-47ed-4a31-8c20-47552878fb44", - "area": "Location", - "resourceName": "ResourceAreas", - "routeTemplate": "_apis/{resource}/DownloadFileFromRepo", - "resourceVersion": 1, - "minVersion": "3.2", - "maxVersion": "7.1", - "releasedVersion": "0.0" - } , { "id": "01a46dea-7d46-4d40-bc84-319e7c260d99", "area": "Location", "resourceName": "ResourceAreas", diff --git a/vcsclient/vcsclient.go b/vcsclient/vcsclient.go index 8bebb80b..d4df7464 100644 --- a/vcsclient/vcsclient.go +++ b/vcsclient/vcsclient.go @@ -170,6 +170,14 @@ type VcsClient interface { // pullRequestID - Pull request ID ListPullRequestComments(ctx context.Context, owner, repository string, pullRequestID int) ([]CommentInfo, error) + // DeletePullRequestComment deleted a specific comment in a pull request. + // owner - User or organization + // repository - VCS repository name + // pullRequestID - Pull request ID + // commentID - The ID of the comment + // commentVersion - The version of the comment + DeletePullRequestComment(ctx context.Context, owner, repository string, pullRequestID, commentID int) error + // ListOpenPullRequestsWithBody Gets all open pull requests ids and the pull request body. // owner - User or organization // repository - VCS repository name @@ -286,6 +294,7 @@ type CommentInfo struct { ID int64 Content string Created time.Time + Version int } type PullRequestInfo struct {