Skip to content

Commit 9dc9434

Browse files
authored
Slack integration (#199)
Thanks to @nicholas-wu-hs !
1 parent cc015af commit 9dc9434

17 files changed

+1144
-33
lines changed

cmd/server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ var stringFlags = []stringFlag{
8484
env: "ATLANTIS_GITLAB_TOKEN",
8585
},
8686
{
87-
name: GitlabWebHookSecret,
87+
name: GitlabWebHookSecret,
8888
description: "Optional secret used to validate GitLab webhooks." +
8989
" If not specified, Atlantis won't be able to validate that the incoming webhook call came from GitLab. " +
9090
"Can also be specified via the ATLANTIS_GITLAB_WEBHOOK_SECRET environment variable.",

server/events/apply_executor.go

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/hootsuite/atlantis/server/events/run"
1313
"github.com/hootsuite/atlantis/server/events/terraform"
1414
"github.com/hootsuite/atlantis/server/events/vcs"
15+
"github.com/hootsuite/atlantis/server/events/webhooks"
1516
)
1617

1718
type ApplyExecutor struct {
@@ -21,6 +22,7 @@ type ApplyExecutor struct {
2122
Run *run.Run
2223
Workspace Workspace
2324
ProjectPreExecute *ProjectPreExecute
25+
Webhooks webhooks.Sender
2426
}
2527

2628
func (a *ApplyExecutor) Execute(ctx *CommandContext) CommandResponse {
@@ -92,6 +94,15 @@ func (a *ApplyExecutor) apply(ctx *CommandContext, repoDir string, plan models.P
9294
env := ctx.Command.Environment
9395
tfApplyCmd := append(append(append([]string{"apply", "-no-color"}, applyExtraArgs...), ctx.Command.Flags...), plan.LocalPath)
9496
output, err := a.Terraform.RunCommandWithVersion(ctx.Log, absolutePath, tfApplyCmd, terraformVersion, env)
97+
98+
a.Webhooks.Send(ctx.Log, webhooks.ApplyResult{ // nolint: errcheck
99+
Workspace: env,
100+
User: ctx.User,
101+
Repo: ctx.BaseRepo,
102+
Pull: ctx.Pull,
103+
Success: err == nil,
104+
})
105+
95106
if err != nil {
96107
return ProjectResult{Error: fmt.Errorf("%s\n%s", err.Error(), output)}
97108
}

server/events/command_handler_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func setup(t *testing.T) {
5757
MarkdownRenderer: &events.MarkdownRenderer{},
5858
GithubPullGetter: githubGetter,
5959
GitlabMergeRequestGetter: gitlabGetter,
60-
Logger: logger,
60+
Logger: logger,
6161
}
6262
}
6363

server/events/mocks/mock_commit_status_updater.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
package mocks
55

66
import (
7+
"reflect"
8+
79
events "github.com/hootsuite/atlantis/server/events"
810
models "github.com/hootsuite/atlantis/server/events/models"
911
vcs "github.com/hootsuite/atlantis/server/events/vcs"
1012
pegomock "github.com/petergtz/pegomock"
11-
"reflect"
1213
)
1314

1415
type MockCommitStatusUpdater struct {

server/events/pull_closed_executor_test.go

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package events_test
22

33
import (
4+
"errors"
45
"reflect"
6+
"testing"
57

8+
"github.com/hootsuite/atlantis/server/events"
9+
lockmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
10+
"github.com/hootsuite/atlantis/server/events/mocks"
611
"github.com/hootsuite/atlantis/server/events/models"
12+
"github.com/hootsuite/atlantis/server/events/models/fixtures"
13+
"github.com/hootsuite/atlantis/server/events/vcs"
14+
vcsmocks "github.com/hootsuite/atlantis/server/events/vcs/mocks"
715
. "github.com/hootsuite/atlantis/testing"
816
. "github.com/petergtz/pegomock"
9-
"testing"
10-
"github.com/hootsuite/atlantis/server/events/mocks"
11-
lockmocks "github.com/hootsuite/atlantis/server/events/locking/mocks"
12-
vcsmocks "github.com/hootsuite/atlantis/server/events/vcs/mocks"
13-
"github.com/hootsuite/atlantis/server/events"
14-
"errors"
15-
"github.com/hootsuite/atlantis/server/events/vcs"
16-
"github.com/hootsuite/atlantis/server/events/models/fixtures"
1717
)
1818

1919
func TestCleanUpPullWorkspaceErr(t *testing.T) {
@@ -155,4 +155,3 @@ func AnyPullRequest() models.PullRequest {
155155
RegisterMatcher(NewAnyMatcher(reflect.TypeOf(models.PullRequest{})))
156156
return models.PullRequest{}
157157
}
158-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Automatically generated by pegomock. DO NOT EDIT!
2+
// Source: github.com/hootsuite/atlantis/server/events/webhooks (interfaces: Sender)
3+
4+
package mocks
5+
6+
import (
7+
"reflect"
8+
9+
webhooks "github.com/hootsuite/atlantis/server/events/webhooks"
10+
logging "github.com/hootsuite/atlantis/server/logging"
11+
pegomock "github.com/petergtz/pegomock"
12+
)
13+
14+
type MockSender struct {
15+
fail func(message string, callerSkip ...int)
16+
}
17+
18+
func NewMockSender() *MockSender {
19+
return &MockSender{fail: pegomock.GlobalFailHandler}
20+
}
21+
22+
func (mock *MockSender) Send(log *logging.SimpleLogger, applyResult webhooks.ApplyResult) error {
23+
params := []pegomock.Param{log, applyResult}
24+
result := pegomock.GetGenericMockFrom(mock).Invoke("Send", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
25+
var ret0 error
26+
if len(result) != 0 {
27+
if result[0] != nil {
28+
ret0 = result[0].(error)
29+
}
30+
}
31+
return ret0
32+
}
33+
34+
func (mock *MockSender) VerifyWasCalledOnce() *VerifierSender {
35+
return &VerifierSender{mock, pegomock.Times(1), nil}
36+
}
37+
38+
func (mock *MockSender) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierSender {
39+
return &VerifierSender{mock, invocationCountMatcher, nil}
40+
}
41+
42+
func (mock *MockSender) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierSender {
43+
return &VerifierSender{mock, invocationCountMatcher, inOrderContext}
44+
}
45+
46+
type VerifierSender struct {
47+
mock *MockSender
48+
invocationCountMatcher pegomock.Matcher
49+
inOrderContext *pegomock.InOrderContext
50+
}
51+
52+
func (verifier *VerifierSender) Send(log *logging.SimpleLogger, applyResult webhooks.ApplyResult) *Sender_Send_OngoingVerification {
53+
params := []pegomock.Param{log, applyResult}
54+
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Send", params)
55+
return &Sender_Send_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
56+
}
57+
58+
type Sender_Send_OngoingVerification struct {
59+
mock *MockSender
60+
methodInvocations []pegomock.MethodInvocation
61+
}
62+
63+
func (c *Sender_Send_OngoingVerification) GetCapturedArguments() (*logging.SimpleLogger, webhooks.ApplyResult) {
64+
log, applyResult := c.GetAllCapturedArguments()
65+
return log[len(log)-1], applyResult[len(applyResult)-1]
66+
}
67+
68+
func (c *Sender_Send_OngoingVerification) GetAllCapturedArguments() (_param0 []*logging.SimpleLogger, _param1 []webhooks.ApplyResult) {
69+
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
70+
if len(params) > 0 {
71+
_param0 = make([]*logging.SimpleLogger, len(params[0]))
72+
for u, param := range params[0] {
73+
_param0[u] = param.(*logging.SimpleLogger)
74+
}
75+
_param1 = make([]webhooks.ApplyResult, len(params[1]))
76+
for u, param := range params[1] {
77+
_param1[u] = param.(webhooks.ApplyResult)
78+
}
79+
}
80+
return
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// Automatically generated by pegomock. DO NOT EDIT!
2+
// Source: github.com/hootsuite/atlantis/server/events/webhooks (interfaces: SlackClient)
3+
4+
package mocks
5+
6+
import (
7+
"reflect"
8+
9+
webhooks "github.com/hootsuite/atlantis/server/events/webhooks"
10+
pegomock "github.com/petergtz/pegomock"
11+
)
12+
13+
type MockSlackClient struct {
14+
fail func(message string, callerSkip ...int)
15+
}
16+
17+
func NewMockSlackClient() *MockSlackClient {
18+
return &MockSlackClient{fail: pegomock.GlobalFailHandler}
19+
}
20+
21+
func (mock *MockSlackClient) AuthTest() error {
22+
params := []pegomock.Param{}
23+
result := pegomock.GetGenericMockFrom(mock).Invoke("AuthTest", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
24+
var ret0 error
25+
if len(result) != 0 {
26+
if result[0] != nil {
27+
ret0 = result[0].(error)
28+
}
29+
}
30+
return ret0
31+
}
32+
33+
func (mock *MockSlackClient) TokenIsSet() bool {
34+
params := []pegomock.Param{}
35+
result := pegomock.GetGenericMockFrom(mock).Invoke("TokenIsSet", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
36+
var ret0 bool
37+
if len(result) != 0 {
38+
if result[0] != nil {
39+
ret0 = result[0].(bool)
40+
}
41+
}
42+
return ret0
43+
}
44+
45+
func (mock *MockSlackClient) ChannelExists(channelName string) (bool, error) {
46+
params := []pegomock.Param{channelName}
47+
result := pegomock.GetGenericMockFrom(mock).Invoke("ChannelExists", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
48+
var ret0 bool
49+
var ret1 error
50+
if len(result) != 0 {
51+
if result[0] != nil {
52+
ret0 = result[0].(bool)
53+
}
54+
if result[1] != nil {
55+
ret1 = result[1].(error)
56+
}
57+
}
58+
return ret0, ret1
59+
}
60+
61+
func (mock *MockSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) error {
62+
params := []pegomock.Param{channel, applyResult}
63+
result := pegomock.GetGenericMockFrom(mock).Invoke("PostMessage", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
64+
var ret0 error
65+
if len(result) != 0 {
66+
if result[0] != nil {
67+
ret0 = result[0].(error)
68+
}
69+
}
70+
return ret0
71+
}
72+
73+
func (mock *MockSlackClient) VerifyWasCalledOnce() *VerifierSlackClient {
74+
return &VerifierSlackClient{mock, pegomock.Times(1), nil}
75+
}
76+
77+
func (mock *MockSlackClient) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierSlackClient {
78+
return &VerifierSlackClient{mock, invocationCountMatcher, nil}
79+
}
80+
81+
func (mock *MockSlackClient) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierSlackClient {
82+
return &VerifierSlackClient{mock, invocationCountMatcher, inOrderContext}
83+
}
84+
85+
type VerifierSlackClient struct {
86+
mock *MockSlackClient
87+
invocationCountMatcher pegomock.Matcher
88+
inOrderContext *pegomock.InOrderContext
89+
}
90+
91+
func (verifier *VerifierSlackClient) AuthTest() *SlackClient_AuthTest_OngoingVerification {
92+
params := []pegomock.Param{}
93+
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "AuthTest", params)
94+
return &SlackClient_AuthTest_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
95+
}
96+
97+
type SlackClient_AuthTest_OngoingVerification struct {
98+
mock *MockSlackClient
99+
methodInvocations []pegomock.MethodInvocation
100+
}
101+
102+
func (c *SlackClient_AuthTest_OngoingVerification) GetCapturedArguments() {
103+
}
104+
105+
func (c *SlackClient_AuthTest_OngoingVerification) GetAllCapturedArguments() {
106+
}
107+
108+
func (verifier *VerifierSlackClient) TokenIsSet() *SlackClient_TokenIsSet_OngoingVerification {
109+
params := []pegomock.Param{}
110+
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "TokenIsSet", params)
111+
return &SlackClient_TokenIsSet_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
112+
}
113+
114+
type SlackClient_TokenIsSet_OngoingVerification struct {
115+
mock *MockSlackClient
116+
methodInvocations []pegomock.MethodInvocation
117+
}
118+
119+
func (c *SlackClient_TokenIsSet_OngoingVerification) GetCapturedArguments() {
120+
}
121+
122+
func (c *SlackClient_TokenIsSet_OngoingVerification) GetAllCapturedArguments() {
123+
}
124+
125+
func (verifier *VerifierSlackClient) ChannelExists(channelName string) *SlackClient_ChannelExists_OngoingVerification {
126+
params := []pegomock.Param{channelName}
127+
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ChannelExists", params)
128+
return &SlackClient_ChannelExists_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
129+
}
130+
131+
type SlackClient_ChannelExists_OngoingVerification struct {
132+
mock *MockSlackClient
133+
methodInvocations []pegomock.MethodInvocation
134+
}
135+
136+
func (c *SlackClient_ChannelExists_OngoingVerification) GetCapturedArguments() string {
137+
channelName := c.GetAllCapturedArguments()
138+
return channelName[len(channelName)-1]
139+
}
140+
141+
func (c *SlackClient_ChannelExists_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
142+
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
143+
if len(params) > 0 {
144+
_param0 = make([]string, len(params[0]))
145+
for u, param := range params[0] {
146+
_param0[u] = param.(string)
147+
}
148+
}
149+
return
150+
}
151+
152+
func (verifier *VerifierSlackClient) PostMessage(channel string, applyResult webhooks.ApplyResult) *SlackClient_PostMessage_OngoingVerification {
153+
params := []pegomock.Param{channel, applyResult}
154+
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PostMessage", params)
155+
return &SlackClient_PostMessage_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
156+
}
157+
158+
type SlackClient_PostMessage_OngoingVerification struct {
159+
mock *MockSlackClient
160+
methodInvocations []pegomock.MethodInvocation
161+
}
162+
163+
func (c *SlackClient_PostMessage_OngoingVerification) GetCapturedArguments() (string, webhooks.ApplyResult) {
164+
channel, applyResult := c.GetAllCapturedArguments()
165+
return channel[len(channel)-1], applyResult[len(applyResult)-1]
166+
}
167+
168+
func (c *SlackClient_PostMessage_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []webhooks.ApplyResult) {
169+
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
170+
if len(params) > 0 {
171+
_param0 = make([]string, len(params[0]))
172+
for u, param := range params[0] {
173+
_param0[u] = param.(string)
174+
}
175+
_param1 = make([]webhooks.ApplyResult, len(params[1]))
176+
for u, param := range params[1] {
177+
_param1[u] = param.(webhooks.ApplyResult)
178+
}
179+
}
180+
return
181+
}

0 commit comments

Comments
 (0)