From 2fb8f4d4ffe8042c88210ef6a46bece6a37ef741 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Fri, 1 Mar 2019 10:19:43 -0500 Subject: [PATCH] Support bitbucket server pr:deleted event If a pull request is deleted, Atlantis should delete the locks. Fixes #498 --- server/events/event_parser.go | 2 +- server/events/event_parser_test.go | 4 + server/events/vcs/bitbucketserver/models.go | 1 + server/events_controller.go | 2 +- server/events_controller_test.go | 77 +++++++++++++ server/logging/simple_logger.go | 30 +++--- .../bb-server-pull-deleted-event.json | 101 ++++++++++++++++++ 7 files changed, 201 insertions(+), 16 deletions(-) create mode 100644 server/testfixtures/bb-server-pull-deleted-event.json diff --git a/server/events/event_parser.go b/server/events/event_parser.go index 637a2d666..30677a0d5 100644 --- a/server/events/event_parser.go +++ b/server/events/event_parser.go @@ -575,7 +575,7 @@ func (e *EventParser) GetBitbucketServerPullEventType(eventTypeHeader string) mo switch eventTypeHeader { case bitbucketserver.PullCreatedHeader: return models.OpenedPullEvent - case bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader: + case bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: return models.ClosedPullEvent } return models.OtherPullEvent diff --git a/server/events/event_parser_test.go b/server/events/event_parser_test.go index d9be128ce..ff64a6962 100644 --- a/server/events/event_parser_test.go +++ b/server/events/event_parser_test.go @@ -1026,6 +1026,10 @@ func TestGetBitbucketServerEventType(t *testing.T) { header: "pr:declined", exp: models.ClosedPullEvent, }, + { + header: "pr:deleted", + exp: models.ClosedPullEvent, + }, { header: "random", exp: models.OtherPullEvent, diff --git a/server/events/vcs/bitbucketserver/models.go b/server/events/vcs/bitbucketserver/models.go index 67bd48744..f9c34d4fc 100644 --- a/server/events/vcs/bitbucketserver/models.go +++ b/server/events/vcs/bitbucketserver/models.go @@ -5,6 +5,7 @@ const ( PullCreatedHeader = "pr:opened" PullMergedHeader = "pr:merged" PullDeclinedHeader = "pr:declined" + PullDeletedHeader = "pr:deleted" PullCommentCreatedHeader = "pr:comment:added" ) diff --git a/server/events_controller.go b/server/events_controller.go index 53709402b..f21ebf176 100644 --- a/server/events_controller.go +++ b/server/events_controller.go @@ -182,7 +182,7 @@ func (e *EventsController) handleBitbucketServerPost(w http.ResponseWriter, r *h } } switch eventType { - case bitbucketserver.PullCreatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader: + case bitbucketserver.PullCreatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: e.Logger.Debug("handling as pull request state changed event") e.handleBitbucketServerPullRequestEvent(w, eventType, body, reqID) return diff --git a/server/events_controller_test.go b/server/events_controller_test.go index 6692eb106..07950db45 100644 --- a/server/events_controller_test.go +++ b/server/events_controller_test.go @@ -524,6 +524,83 @@ func TestPost_GitlabMergeRequestSuccess(t *testing.T) { responseContains(t, w, http.StatusOK, "Pull request cleaned successfully") } +// Test Bitbucket server pull closed events. +func TestPost_BBServerPullClosed(t *testing.T) { + cases := []struct { + header string + }{ + { + "pr:deleted", + }, + { + "pr:merged", + }, + { + "pr:declined", + }, + } + + for _, c := range cases { + t.Run(c.header, func(t *testing.T) { + RegisterMockTestingT(t) + pullCleaner := emocks.NewMockPullCleaner() + whitelist, err := events.NewRepoWhitelistChecker("*") + Ok(t, err) + ec := &server.EventsController{ + PullCleaner: pullCleaner, + Parser: &events.EventParser{ + BitbucketUser: "bb-user", + BitbucketToken: "bb-token", + BitbucketServerURL: "https://bbserver.com", + }, + RepoWhitelistChecker: whitelist, + SupportedVCSHosts: []models.VCSHostType{models.BitbucketServer}, + VCSClient: nil, + } + + // Build HTTP request. + requestBytes, err := ioutil.ReadFile(filepath.Join("testfixtures", "bb-server-pull-deleted-event.json")) + // Replace the eventKey field with our event type. + requestJSON := strings.Replace(string(requestBytes), `"eventKey":"pr:deleted",`, fmt.Sprintf(`"eventKey":"%s",`, c.header), -1) + Ok(t, err) + req, err := http.NewRequest("POST", "/events", bytes.NewBuffer([]byte(requestJSON))) + Ok(t, err) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Event-Key", c.header) + req.Header.Set("X-Request-ID", "request-id") + + // Send the request. + w := httptest.NewRecorder() + ec.Post(w, req) + + // Make our assertions. + responseContains(t, w, 200, "Pull request cleaned successfully") + + expRepo := models.Repo{ + FullName: "project/repository", + Owner: "project", + Name: "repository", + CloneURL: "https://bb-user:bb-token@bbserver.com/scm/proj/repository.git", + SanitizedCloneURL: "https://bbserver.com/scm/proj/repository.git", + VCSHost: models.VCSHost{ + Hostname: "bbserver.com", + Type: models.BitbucketServer, + }, + } + pullCleaner.VerifyWasCalledOnce().CleanUpPull(expRepo, models.PullRequest{ + Num: 10, + HeadCommit: "2d9fb6b9a46eafb1dcef7b008d1a429d45ca742c", + URL: "https://bbserver.com/projects/PROJ/repos/repository/pull-requests/10", + HeadBranch: "decline-me", + BaseBranch: "master", + Author: "admin", + State: models.OpenPullState, + BaseRepo: expRepo, + }) + }) + } +} + func TestPost_PullOpenedOrUpdated(t *testing.T) { cases := []struct { Description string diff --git a/server/logging/simple_logger.go b/server/logging/simple_logger.go index 9bd64c133..3aa1a5cbd 100644 --- a/server/logging/simple_logger.go +++ b/server/logging/simple_logger.go @@ -147,23 +147,25 @@ func (l *SimpleLogger) Err(format string, a ...interface{}) { // Log writes the log at level. func (l *SimpleLogger) Log(level LogLevel, format string, a ...interface{}) { - levelStr := l.levelToString(level) - msg := l.capitalizeFirstLetter(fmt.Sprintf(format, a...)) + if l != nil { + levelStr := l.levelToString(level) + msg := l.capitalizeFirstLetter(fmt.Sprintf(format, a...)) - // Only log this message if configured to log at this level. - if l.Level <= level { - datetime := time.Now().Format("2006/01/02 15:04:05-0700") - var caller string - if l.Level <= Debug { - file, line := l.callSite(3) - caller = fmt.Sprintf(" %s:%d", file, line) + // Only log this message if configured to log at this level. + if l.Level <= level { + datetime := time.Now().Format("2006/01/02 15:04:05-0700") + var caller string + if l.Level <= Debug { + file, line := l.callSite(3) + caller = fmt.Sprintf(" %s:%d", file, line) + } + l.Logger.Printf("%s [%s]%s %s: %s\n", datetime, levelStr, caller, l.Source, msg) // noline: errcheck } - l.Logger.Printf("%s [%s]%s %s: %s\n", datetime, levelStr, caller, l.Source, msg) // noline: errcheck - } - // Keep history at all log levels. - if l.KeepHistory { - l.saveToHistory(levelStr, msg) + // Keep history at all log levels. + if l.KeepHistory { + l.saveToHistory(levelStr, msg) + } } } diff --git a/server/testfixtures/bb-server-pull-deleted-event.json b/server/testfixtures/bb-server-pull-deleted-event.json new file mode 100644 index 000000000..29f83137b --- /dev/null +++ b/server/testfixtures/bb-server-pull-deleted-event.json @@ -0,0 +1,101 @@ +{ + "eventKey":"pr:deleted", + "date":"2017-09-19T11:16:17+1000", + "actor":{ + "name":"admin", + "emailAddress":"admin@example.com", + "id":1, + "displayName":"Administrator", + "active":true, + "slug":"admin", + "type":"NORMAL" + }, + "pullRequest":{ + "id":10, + "version":3, + "title":"Commit message", + "state":"OPEN", + "open":true, + "closed":false, + "createdDate":1505783668760, + "updatedDate":1505783750704, + "fromRef":{ + "id":"refs/heads/decline-me", + "displayId":"decline-me", + "latestCommit":"2d9fb6b9a46eafb1dcef7b008d1a429d45ca742c", + "repository":{ + "slug":"repository", + "id":84, + "name":"repository", + "scmId":"git", + "state":"AVAILABLE", + "statusMessage":"Available", + "forkable":true, + "project":{ + "key":"PROJ", + "id":84, + "name":"project", + "public":false, + "type":"NORMAL" + }, + "public":false + } + }, + "toRef":{ + "id":"refs/heads/master", + "displayId":"master", + "latestCommit":"7e48f426f0a6e47c5b5e862c31be6ca965f82c9c", + "repository":{ + "slug":"repository", + "id":84, + "name":"repository", + "scmId":"git", + "state":"AVAILABLE", + "statusMessage":"Available", + "forkable":true, + "project":{ + "key":"PROJ", + "id":84, + "name":"project", + "public":false, + "type":"NORMAL" + }, + "public":false + } + }, + "locked":false, + "author":{ + "user":{ + "name":"admin", + "emailAddress":"admin@example.com", + "id":1, + "displayName":"Administrator", + "active":true, + "slug":"admin", + "type":"NORMAL" + }, + "role":"AUTHOR", + "approved":false, + "status":"UNAPPROVED" + }, + "reviewers":[ + { + "user":{ + "name":"user", + "emailAddress":"user@example.com", + "id":2, + "displayName":"User", + "active":true, + "slug":"user", + "type":"NORMAL" + }, + "role":"REVIEWER", + "approved":false, + "status":"UNAPPROVED" + } + ], + "participants":[ + + ] + } +}