Skip to content

Commit

Permalink
feat: Add GitLab Reaction Emojis on MR Comments (#3456)
Browse files Browse the repository at this point in the history
* Add GitLab Reaction Emoji

* Update docs

* update docs

* Update event_parser_test
  • Loading branch information
X-Guardian authored Jun 13, 2023
1 parent 14b6b0e commit 86607d8
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 40 deletions.
9 changes: 9 additions & 0 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,15 @@ and set `--autoplan-modules` to `false`.
```
Stops atlantis from locking projects and or workspaces when running terraform.

### `--emoji-reaction`
```bash
atlantis server --emoji-reaction thumbsup
# or
ATLANTIS_EMOJI_REACTION=thumbsup
```
The emoji reaction to use for marking processed comments. Currently supported on Azure DevOps, GitHub and GitLab.
Defaults to `eyes`.

### `--enable-policy-checks`
```bash
atlantis server --enable-policy-checks
Expand Down
6 changes: 3 additions & 3 deletions server/controllers/events/events_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,12 +515,12 @@ func (e *VCSEventsController) handleGitlabPost(w http.ResponseWriter, r *http.Re
// commands can come from. It's exported to make testing easier.
func (e *VCSEventsController) HandleGitlabCommentEvent(w http.ResponseWriter, event gitlab.MergeCommentEvent) {
// todo: can gitlab return the pull request here too?
baseRepo, headRepo, user, err := e.Parser.ParseGitlabMergeRequestCommentEvent(event)
baseRepo, headRepo, commentID, user, err := e.Parser.ParseGitlabMergeRequestCommentEvent(event)
if err != nil {
e.respond(w, logging.Error, http.StatusBadRequest, "Error parsing webhook: %s", err)
return
}
resp := e.handleCommentEvent(e.Logger, baseRepo, &headRepo, nil, user, event.MergeRequest.IID, event.ObjectAttributes.Note, -1, models.Gitlab)
resp := e.handleCommentEvent(e.Logger, baseRepo, &headRepo, nil, user, event.MergeRequest.IID, event.ObjectAttributes.Note, int64(commentID), models.Gitlab)

//TODO: move this to the outer most function similar to github
lvl := logging.Debug
Expand Down Expand Up @@ -567,7 +567,7 @@ func (e *VCSEventsController) handleCommentEvent(logger logging.SimpleLogging, b

// It's a comment we're gonna react to, so add a reaction.
if e.EmojiReaction != "" {
err := e.VCSClient.ReactToComment(baseRepo, commentID, e.EmojiReaction)
err := e.VCSClient.ReactToComment(baseRepo, pullNum, commentID, e.EmojiReaction)
if err != nil {
logger.Warn("Failed to react to comment: %s", err)
}
Expand Down
16 changes: 14 additions & 2 deletions server/controllers/events/events_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func TestPost_GithubCommentInvalidCommand(t *testing.T) {
w := httptest.NewRecorder()
e.Post(w, req)
ResponseContains(t, w, http.StatusOK, "Ignoring non-command comment: \"\"")
vcsClient.VerifyWasCalled(Never()).ReactToComment(models.Repo{}, 1, "eyes")
vcsClient.VerifyWasCalled(Never()).ReactToComment(models.Repo{}, 1, 1, "eyes")
}

func TestPost_GitlabCommentNotAllowlisted(t *testing.T) {
Expand Down Expand Up @@ -398,7 +398,19 @@ func TestPost_GithubCommentReaction(t *testing.T) {
e.Post(w, req)
ResponseContains(t, w, http.StatusOK, "Processing...")

vcsClient.VerifyWasCalledOnce().ReactToComment(baseRepo, 1, "eyes")
vcsClient.VerifyWasCalledOnce().ReactToComment(baseRepo, 1, 1, "eyes")
}

func TestPost_GilabCommentReaction(t *testing.T) {
t.Log("when the event is a gitlab comment with a valid command we call the ReactToComment handler")
e, _, gl, _, _, _, _, vcsClient, _ := setup(t)
req, _ := http.NewRequest("GET", "", bytes.NewBuffer(nil))
req.Header.Set(gitlabHeader, "value")
When(gl.ParseAndValidate(req, secret)).ThenReturn(gitlab.MergeCommentEvent{}, nil)
w := httptest.NewRecorder()
e.Post(w, req)
ResponseContains(t, w, http.StatusOK, "Processing...")
vcsClient.VerifyWasCalledOnce().ReactToComment(models.Repo{}, 0, 0, "eyes")
}

func TestPost_GithubPullRequestInvalid(t *testing.T) {
Expand Down
6 changes: 4 additions & 2 deletions server/events/event_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ type EventParsing interface {
// headRepo is the repo the merge request branch is from.
// user is the pull request author.
ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) (
baseRepo models.Repo, headRepo models.Repo, user models.User, err error)
baseRepo models.Repo, headRepo models.Repo, commentID int, user models.User, err error)

// ParseGitlabMergeRequest parses the response from the GitLab API endpoint
// that returns a merge request.
Expand Down Expand Up @@ -672,10 +672,12 @@ func (e *EventParser) ParseGitlabMergeRequestEvent(event gitlab.MergeEvent) (pul
// ParseGitlabMergeRequestCommentEvent parses GitLab merge request comment
// events.
// See EventParsing for return value docs.
func (e *EventParser) ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, user models.User, err error) {
func (e *EventParser) ParseGitlabMergeRequestCommentEvent(event gitlab.MergeCommentEvent) (baseRepo models.Repo, headRepo models.Repo, commentID int, user models.User, err error) {
// Parse the base repo first.

repoFullName := event.Project.PathWithNamespace
cloneURL := event.Project.GitHTTPURL
commentID = event.ObjectAttributes.ID
baseRepo, err = models.NewRepo(models.Gitlab, repoFullName, cloneURL, e.GitlabUser, e.GitlabToken)
if err != nil {
return
Expand Down
6 changes: 4 additions & 2 deletions server/events/event_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ func TestParseGitlabMergeCommentEvent(t *testing.T) {
var event *gitlab.MergeCommentEvent
err = json.Unmarshal(bytes, &event)
Ok(t, err)
baseRepo, headRepo, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event)
baseRepo, headRepo, commentID, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event)
Ok(t, err)
Equals(t, models.Repo{
FullName: "gitlabhq/gitlab-test",
Expand All @@ -660,6 +660,7 @@ func TestParseGitlabMergeCommentEvent(t *testing.T) {
Type: models.Gitlab,
},
}, headRepo)
Equals(t, 1244, commentID)
Equals(t, models.User{
Username: "root",
}, user)
Expand All @@ -673,7 +674,7 @@ func TestParseGitlabMergeCommentEvent_Subgroup(t *testing.T) {
var event *gitlab.MergeCommentEvent
err = json.Unmarshal(bytes, &event)
Ok(t, err)
baseRepo, headRepo, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event)
baseRepo, headRepo, commentID, user, err := parser.ParseGitlabMergeRequestCommentEvent(*event)
Ok(t, err)

Equals(t, models.Repo{
Expand All @@ -698,6 +699,7 @@ func TestParseGitlabMergeCommentEvent_Subgroup(t *testing.T) {
Type: models.Gitlab,
},
}, headRepo)
Equals(t, 96056916, commentID)
Equals(t, models.User{
Username: "lkysow",
}, user)
Expand Down
18 changes: 11 additions & 7 deletions server/events/mocks/mock_event_parsing.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/events/vcs/azuredevops_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (g *AzureDevopsClient) CreateComment(repo models.Repo, pullNum int, comment
return nil
}

func (g *AzureDevopsClient) ReactToComment(repo models.Repo, commentID int64, reaction string) error { //nolint: revive
func (g *AzureDevopsClient) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error { //nolint: revive
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion server/events/vcs/bitbucketcloud/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, co
}

// UpdateComment updates the body of a comment on the merge request.
func (b *Client) ReactToComment(repo models.Repo, commentID int64, reaction string) error { // nolint revive
func (b *Client) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error { // nolint revive
// TODO: Bitbucket support for reactions
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion server/events/vcs/bitbucketserver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (b *Client) CreateComment(repo models.Repo, pullNum int, comment string, co
return nil
}

func (b *Client) ReactToComment(repo models.Repo, commentID int64, reaction string) error { // nolint: revive
func (b *Client) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error { // nolint: revive
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion server/events/vcs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Client interface {
GetModifiedFiles(repo models.Repo, pull models.PullRequest) ([]string, error)
CreateComment(repo models.Repo, pullNum int, comment string, command string) error

ReactToComment(repo models.Repo, commentID int64, reaction string) error
ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error
HidePrevCommandComments(repo models.Repo, pullNum int, command string) error
PullIsApproved(repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error)
PullIsMergeable(repo models.Repo, pull models.PullRequest, vcsstatusname string) (bool, error)
Expand Down
2 changes: 1 addition & 1 deletion server/events/vcs/github_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func (g *GithubClient) CreateComment(repo models.Repo, pullNum int, comment stri
}

// ReactToComment adds a reaction to a comment.
func (g *GithubClient) ReactToComment(repo models.Repo, commentID int64, reaction string) error {
func (g *GithubClient) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error {
g.logger.Debug("POST /repos/%v/%v/issues/comments/%d/reactions", repo.Owner, repo.Name, commentID)
_, _, err := g.client.Reactions.CreateIssueCommentReaction(g.ctx, repo.Owner, repo.Name, commentID, reaction)
return err
Expand Down
6 changes: 4 additions & 2 deletions server/events/vcs/gitlab_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,10 @@ func (g *GitlabClient) CreateComment(repo models.Repo, pullNum int, comment stri
return nil
}

func (g *GitlabClient) ReactToComment(repo models.Repo, commentID int64, reaction string) error { // nolint: revive
return nil
// ReactToComment adds a reaction to a comment.
func (g *GitlabClient) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error {
_, _, err := g.Client.AwardEmoji.CreateMergeRequestAwardEmojiOnNote(repo.FullName, pullNum, int(commentID), &gitlab.CreateAwardEmojiOptions{Name: reaction})
return err
}

func (g *GitlabClient) HidePrevCommandComments(repo models.Repo, pullNum int, command string) error {
Expand Down
4 changes: 2 additions & 2 deletions server/events/vcs/instrumented_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (c *InstrumentedClient) CreateComment(repo models.Repo, pullNum int, commen
return nil
}

func (c *InstrumentedClient) ReactToComment(repo models.Repo, commentID int64, reaction string) error {
func (c *InstrumentedClient) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error {
scope := c.StatsScope.SubScope("react_to_comment")

executionTime := scope.Timer(metrics.ExecutionTimeMetric).Start()
Expand All @@ -137,7 +137,7 @@ func (c *InstrumentedClient) ReactToComment(repo models.Repo, commentID int64, r
executionSuccess := scope.Counter(metrics.ExecutionSuccessMetric)
executionError := scope.Counter(metrics.ExecutionErrorMetric)

if err := c.Client.ReactToComment(repo, commentID, reaction); err != nil {
if err := c.Client.ReactToComment(repo, pullNum, commentID, reaction); err != nil {
executionError.Inc(1)
c.Logger.Err("Unable to react to comment, error: %s", err.Error())
return err
Expand Down
28 changes: 16 additions & 12 deletions server/events/vcs/mocks/mock_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/events/vcs/not_configured_vcs_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (a *NotConfiguredVCSClient) CreateComment(repo models.Repo, pullNum int, co
func (a *NotConfiguredVCSClient) HidePrevCommandComments(repo models.Repo, pullNum int, command string) error {
return nil
}
func (a *NotConfiguredVCSClient) ReactToComment(repo models.Repo, commentID int64, reaction string) error { // nolint: revive
func (a *NotConfiguredVCSClient) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error { // nolint: revive
return nil
}
func (a *NotConfiguredVCSClient) PullIsApproved(repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) {
Expand Down
4 changes: 2 additions & 2 deletions server/events/vcs/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ func (d *ClientProxy) HidePrevCommandComments(repo models.Repo, pullNum int, com
return d.clients[repo.VCSHost.Type].HidePrevCommandComments(repo, pullNum, command)
}

func (d *ClientProxy) ReactToComment(repo models.Repo, commentID int64, reaction string) error {
return d.clients[repo.VCSHost.Type].ReactToComment(repo, commentID, reaction)
func (d *ClientProxy) ReactToComment(repo models.Repo, pullNum int, commentID int64, reaction string) error {
return d.clients[repo.VCSHost.Type].ReactToComment(repo, pullNum, commentID, reaction)
}

func (d *ClientProxy) PullIsApproved(repo models.Repo, pull models.PullRequest) (models.ApprovalStatus, error) {
Expand Down

0 comments on commit 86607d8

Please sign in to comment.