codebuild-notifier 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +58 -0
- data/COPYING +674 -0
- data/Gemfile +3 -0
- data/README.md +261 -0
- data/bin/update-build-status +129 -0
- data/codebuild-notifier.gemspec +50 -0
- data/lib/codebuild-notifier.rb +24 -0
- data/lib/codebuild-notifier/build_history.rb +110 -0
- data/lib/codebuild-notifier/config.rb +52 -0
- data/lib/codebuild-notifier/current_build.rb +69 -0
- data/lib/codebuild-notifier/git.rb +25 -0
- data/lib/codebuild-notifier/slack_message.rb +98 -0
- data/lib/codebuild-notifier/slack_sender.rb +97 -0
- data/lib/codebuild-notifier/version.rb +20 -0
- data/lib/codebuild_notifier.rb +1 -0
- metadata +201 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
# codebuild-notifier
|
2
|
+
Reports status of AWS CodeBuild CI jobs to slack.
|
3
|
+
|
4
|
+
# Infrastructure Requirements
|
5
|
+
|
6
|
+
### Slack App or Bot in your workspace
|
7
|
+
|
8
|
+
Notifications will be sent as slack Direct Messages to users from the default
|
9
|
+
Slack bot in your workspace (e.g. @slackbot)
|
10
|
+
- Go to <a href="https://api.slack.com/apps">https://api.slack.com/apps</a>
|
11
|
+
- Create a New App, e.g. App Name: CodeBuild Notifier
|
12
|
+
- Under *Add features and functionality* select "Permissions" and grant these scopes:
|
13
|
+
- chat:write:bot
|
14
|
+
- users:read
|
15
|
+
- users:read.email
|
16
|
+
- Click *Install App To Workspace* and store the OAuth token generated in a new
|
17
|
+
secret in AWS Secrets Manager (<a href="#secret-in-aws-secrets-manager">see below</a>)
|
18
|
+
|
19
|
+
*Optional* Add a Bot User to your app - instead of the default Slack bot, messages
|
20
|
+
will come from a user with a name you choose, e.g. CodeBuildBot
|
21
|
+
- Under Features / Bot Users, click *Add a Bot User*
|
22
|
+
- Select a name and display name; the always show as online option does not matter
|
23
|
+
- After adding the Bot User, re-install the app to your workspace
|
24
|
+
- A new OAuth token will be generated specific to the Bot User. Store this in
|
25
|
+
AWS Secrets Manager instead of the App token.
|
26
|
+
|
27
|
+
### DynamoDB table
|
28
|
+
- expected to be named 'branch-build-status', but can be configured
|
29
|
+
- the following definition:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
AttributeDefinitions [
|
33
|
+
{ AttributeName: 'source_id', AttributeType: 'S' },
|
34
|
+
{ AttributeName: 'commit_hash', AttributeType: 'S' }
|
35
|
+
]
|
36
|
+
GlobalSecondaryIndexes [
|
37
|
+
{
|
38
|
+
IndexName: 'commit_hash_index',
|
39
|
+
KeySchema: [
|
40
|
+
{ AttributeName: 'commit_hash', KeyType: 'HASH' }
|
41
|
+
],
|
42
|
+
Projection: { ProjectionType: 'ALL' },
|
43
|
+
}
|
44
|
+
]
|
45
|
+
KeySchema [
|
46
|
+
{ AttributeName: 'source_id', KeyType: 'HASH' }
|
47
|
+
]
|
48
|
+
```
|
49
|
+
|
50
|
+
### Secret in AWS Secrets Manager
|
51
|
+
- expected to be named 'slack/codebuild', but can be configured
|
52
|
+
- contents should be:
|
53
|
+
```json
|
54
|
+
{ "token": "xoxo-your-slack-app-token" }
|
55
|
+
```
|
56
|
+
|
57
|
+
### IAM Service Role for CodeBuild projects
|
58
|
+
|
59
|
+
You will likely already have a service role granting CloudWatch access, to
|
60
|
+
which you will want to add the following, substituing your region,
|
61
|
+
account id, and if different, dynamo table name and secrets-manager secret
|
62
|
+
name:
|
63
|
+
```json
|
64
|
+
{
|
65
|
+
"Action": [
|
66
|
+
"dynamodb:BatchGetItem",
|
67
|
+
"dynamodb:GetItem",
|
68
|
+
"dynamodb:PutItem",
|
69
|
+
"dynamodb:Query",
|
70
|
+
"dynamodb:Scan",
|
71
|
+
"dynamodb:UpdateItem"
|
72
|
+
],
|
73
|
+
"Effect": "Allow",
|
74
|
+
"Resource": [
|
75
|
+
"arn:aws:dynamodb:<your-region>:<your-account-id>:table/branch-build-status",
|
76
|
+
"arn:aws:dynamodb:<your-region>:<your-account-id>:table/branch-build-status/*"
|
77
|
+
]
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"Action": "secretsmanager:GetSecretValue",
|
81
|
+
"Effect": "Allow",
|
82
|
+
"Resource": [
|
83
|
+
"arn:aws:secretsmanager:<your-region>:<your-account-id>:secret:slack/codebuild*"
|
84
|
+
]
|
85
|
+
}
|
86
|
+
```
|
87
|
+
|
88
|
+
# Configuration
|
89
|
+
|
90
|
+
## Installation
|
91
|
+
|
92
|
+
### Pre-requisites
|
93
|
+
|
94
|
+
The base docker image used for your CodeBuild project must include ruby, or
|
95
|
+
you must install it using the project's buildspec.yml file.
|
96
|
+
Any ruby from 2.3.x to 2.5.x will work.
|
97
|
+
|
98
|
+
### Using buildspec
|
99
|
+
|
100
|
+
Add to the `install:` phase of your buildspec.yml
|
101
|
+
|
102
|
+
```yml
|
103
|
+
phases:
|
104
|
+
install:
|
105
|
+
commands:
|
106
|
+
- gem install codebuild-notifier
|
107
|
+
```
|
108
|
+
|
109
|
+
### Using custom Docker image
|
110
|
+
|
111
|
+
Add to your Dockerfile
|
112
|
+
```
|
113
|
+
RUN gem install codebuild-notifier
|
114
|
+
```
|
115
|
+
|
116
|
+
## Usage
|
117
|
+
|
118
|
+
Add to the `post_build:` phase of your buildspec.yml file
|
119
|
+
|
120
|
+
```yml
|
121
|
+
phases:
|
122
|
+
post_build:
|
123
|
+
commands:
|
124
|
+
- update-build-status
|
125
|
+
```
|
126
|
+
|
127
|
+
## Configuration
|
128
|
+
|
129
|
+
### ENV vars
|
130
|
+
|
131
|
+
ENV vars can either be set in Dockerfile e.g.
|
132
|
+
```
|
133
|
+
ENV CBN_SLACK_ADMIN_USERNAMES scooby,shaggy
|
134
|
+
```
|
135
|
+
|
136
|
+
Or in buildspec.yml
|
137
|
+
```
|
138
|
+
env:
|
139
|
+
variables:
|
140
|
+
CBN_SLACK_ADMIN_USERNAMES: 'fred,velma'
|
141
|
+
```
|
142
|
+
|
143
|
+
### command-line
|
144
|
+
|
145
|
+
In buildspec.yml
|
146
|
+
|
147
|
+
```yml
|
148
|
+
phases:
|
149
|
+
post_build:
|
150
|
+
commands:
|
151
|
+
- update-build-status --slack-admin-usernames="fred,velma"
|
152
|
+
```
|
153
|
+
|
154
|
+
### Options
|
155
|
+
|
156
|
+
<table>
|
157
|
+
<tr>
|
158
|
+
<th>ENV var</th>
|
159
|
+
<th>command-line</th>
|
160
|
+
<th>Default value</th>
|
161
|
+
<th>Notes</th>
|
162
|
+
</tr>
|
163
|
+
<tr>
|
164
|
+
<th>
|
165
|
+
CBN_ADDITIONAL_CHANNEL
|
166
|
+
</th>
|
167
|
+
<td>
|
168
|
+
<nobr>--additional-channel</nobr>
|
169
|
+
</td>
|
170
|
+
<td>
|
171
|
+
not set
|
172
|
+
</td>
|
173
|
+
<td>
|
174
|
+
If whitelist branches are set, status notifications for these
|
175
|
+
branches can be sent to this channel, as well as direct messages
|
176
|
+
to the author/committer of the commit triggering the build.
|
177
|
+
</td>
|
178
|
+
</tr>
|
179
|
+
<tr>
|
180
|
+
<th>
|
181
|
+
CBN_AWS_REGION
|
182
|
+
</th>
|
183
|
+
<td>
|
184
|
+
<nobr>--region</nobr>
|
185
|
+
</td>
|
186
|
+
<td>
|
187
|
+
value of AWS_REGION env var in CodeBuild container
|
188
|
+
</td>
|
189
|
+
<td>
|
190
|
+
If for some reason the dynamo table and secrets-manager live in a
|
191
|
+
different region than where CodeBuild is executing, you can specify
|
192
|
+
that region.
|
193
|
+
</td>
|
194
|
+
</tr>
|
195
|
+
<tr>
|
196
|
+
<th>
|
197
|
+
CBN_DYNAMO_TABLE
|
198
|
+
</th>
|
199
|
+
<td>
|
200
|
+
<nobr>--dynamo-table</nobr>
|
201
|
+
</td>
|
202
|
+
<td>
|
203
|
+
branch-build-status
|
204
|
+
</td>
|
205
|
+
<td>
|
206
|
+
This table must be created and permissions granted to it as described
|
207
|
+
in <a href="#infrastructure-requirements">Infrastructure Requirements</a>
|
208
|
+
</td>
|
209
|
+
</tr>
|
210
|
+
<tr>
|
211
|
+
<th>
|
212
|
+
CBN_SLACK_ADMIN_USERNAMES
|
213
|
+
</th>
|
214
|
+
<td>
|
215
|
+
<nobr>--slack-admin-usernames</nobr>
|
216
|
+
</td>
|
217
|
+
<td>
|
218
|
+
not set
|
219
|
+
</td>
|
220
|
+
<td>
|
221
|
+
If no slack user can be found in your workspace with the email
|
222
|
+
address of the author or committer of a commit, a message will be
|
223
|
+
sent to the slack usernames specified.<br />
|
224
|
+
Separate multiple values with commas, with no spaces.<br />
|
225
|
+
e.g. fred,velma
|
226
|
+
</td>
|
227
|
+
</tr>
|
228
|
+
<tr>
|
229
|
+
<th>
|
230
|
+
CBN_SLACK_SECRET_NAME
|
231
|
+
</th>
|
232
|
+
<td>
|
233
|
+
<nobr>--slack-secret-name</nobr>
|
234
|
+
</td>
|
235
|
+
<td>
|
236
|
+
slack/codebuild
|
237
|
+
</td>
|
238
|
+
<td>
|
239
|
+
The name of a secret in AWS Secrets Manager with the app or bot auth token.
|
240
|
+
</td>
|
241
|
+
</tr>
|
242
|
+
<tr>
|
243
|
+
<th>
|
244
|
+
CBN_WHITELIST_BRANCHES
|
245
|
+
</th>
|
246
|
+
<td>
|
247
|
+
<nobr>--whitelist-branches</nobr>
|
248
|
+
</td>
|
249
|
+
<td>
|
250
|
+
master,release
|
251
|
+
</td>
|
252
|
+
<td>
|
253
|
+
Normally statuses will be stored and notifications sent only for builds
|
254
|
+
triggered by commits to branches with open Pull Requests. However, it
|
255
|
+
can be useful to get notifications for all commits to certain branches,
|
256
|
+
regardless of Pull Request status.<br />
|
257
|
+
Separate multiple values with commas, without spaces.<br />
|
258
|
+
e.g. 'master,nightly,jira-50012'
|
259
|
+
</td>
|
260
|
+
</tr>
|
261
|
+
</table>
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# codebuild-notifier
|
4
|
+
# Copyright © 2018 Adam Alboyadjian <adam@cassia.tech>
|
5
|
+
# Copyright © 2018 Vista Higher Learning, Inc.
|
6
|
+
#
|
7
|
+
# codebuild-notifier is free software: you can redistribute it
|
8
|
+
# and/or modify it under the terms of the GNU General Public
|
9
|
+
# License as published by the Free Software Foundation, either
|
10
|
+
# version 3 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# codebuild-notifier is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with codebuild-notifier. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'codebuild-notifier'
|
21
|
+
require 'optparse'
|
22
|
+
# This script updates a DynamoDb table with the last codebuild build status
|
23
|
+
# for the current project and branch or pr. If the current build status is
|
24
|
+
# different from the previous status, the email address of the author of the
|
25
|
+
# last commit is extracted from the git commit, and a notification is sent
|
26
|
+
# via slack.
|
27
|
+
|
28
|
+
def quit(message)
|
29
|
+
cb_puts(message)
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
def cb_puts(message)
|
34
|
+
puts "CODEBUILD NOTIFIER: #{message}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def not_latest_commit_in_branch_message(build, config)
|
38
|
+
"Commit #{build.commit_hash} in project #{build.project_code} did " \
|
39
|
+
'not match the most recent commit for any Pull Requests or the ' \
|
40
|
+
"whitelisted branches: #{config.whitelist}. Skipping status updates."
|
41
|
+
end
|
42
|
+
|
43
|
+
def not_pr_or_whitelisted_branch_message(config)
|
44
|
+
'Build is neither for a Pull Request nor for one of whitelisted ' \
|
45
|
+
"branches: #{config.whitelist}. Skipping status updates."
|
46
|
+
end
|
47
|
+
|
48
|
+
def no_status_diff_message(build)
|
49
|
+
"Current status #{build.status} is same as last status. " \
|
50
|
+
'Skipping slack notifications.'
|
51
|
+
end
|
52
|
+
|
53
|
+
command_line_opts = {}
|
54
|
+
|
55
|
+
# rubocop:disable Metrics/BlockLength
|
56
|
+
OptionParser.new do |opts|
|
57
|
+
opts.banner = 'Usage: update-build-status [OPTIONS]'
|
58
|
+
|
59
|
+
opts.on(
|
60
|
+
'--additional-channel=CHANNEL',
|
61
|
+
'status notifications for whitelisted branches will be sent here ' \
|
62
|
+
'as well as to author/committer'
|
63
|
+
) { |usernames| command_line_opts[:slack_admin_users] = usernames }
|
64
|
+
|
65
|
+
opts.on(
|
66
|
+
'--slack-admin-usernames=USERS',
|
67
|
+
'comma-separated list of slack users to be notified if build status ' \
|
68
|
+
'notifications fail to send'
|
69
|
+
) { |usernames| command_line_opts[:slack_admin_users] = usernames }
|
70
|
+
|
71
|
+
opts.on(
|
72
|
+
'--dynamo-table=TABLE',
|
73
|
+
'table for storing build statuses'
|
74
|
+
) { |table| command_line_opts[:dynamo_table] = table }
|
75
|
+
|
76
|
+
opts.on(
|
77
|
+
'--slack-secret-name=SECRET',
|
78
|
+
'name of Secrets Manager secret with slack app/bot auth token'
|
79
|
+
) { |slack_secret| command_line_opts[:slack_secret_name] = slack_secret }
|
80
|
+
|
81
|
+
opts.on(
|
82
|
+
'--whitelist-branches=BRANCHES',
|
83
|
+
'comma-separated list of branches that will have build notifications ' \
|
84
|
+
'sent even if there is no open Pull Request'
|
85
|
+
) { |whitelist| command_line_opts[:whitelist_branches] = whitelist }
|
86
|
+
|
87
|
+
opts.on('--region=REGION', 'AWS region') do |region|
|
88
|
+
command_line_opts[:region] = region
|
89
|
+
end
|
90
|
+
end.parse!
|
91
|
+
# rubocop:enable Metrics/BlockLength
|
92
|
+
|
93
|
+
config = CodeBuildNotifier::Config.new(command_line_opts)
|
94
|
+
build = CodeBuildNotifier::CurrentBuild.new
|
95
|
+
history = CodeBuildNotifier::BuildHistory.new(config, build)
|
96
|
+
|
97
|
+
last_build = history.last_entry
|
98
|
+
|
99
|
+
if build.launched_by_retry?
|
100
|
+
# Whenever a build is triggered by a PR or whitelisted branch, we update
|
101
|
+
# the record for that trigger with the commit hash. If a build is then
|
102
|
+
# launched using Retry, the status is updated and are notifications sent
|
103
|
+
# only if the re-tried build was for the latest commit. Otherwise re-trying
|
104
|
+
# an older commit could result in inaccurate notifications.
|
105
|
+
quit(not_latest_commit_in_branch_message(build, config)) unless last_build
|
106
|
+
|
107
|
+
source_id = last_build.source_id
|
108
|
+
source_ref = last_build.source_ref
|
109
|
+
else
|
110
|
+
# We only want to track information for whitelisted branches and branches
|
111
|
+
# with open Pull Requests.
|
112
|
+
unless config.non_pr_branch_ids.include?(build.trigger) || build.for_pr?
|
113
|
+
quit(not_pr_or_whitelisted_branch_message(config))
|
114
|
+
end
|
115
|
+
source_id = build.source_id
|
116
|
+
source_ref = build.trigger
|
117
|
+
end
|
118
|
+
|
119
|
+
# Update record for this project + branch/pr in DynamoDb even if the
|
120
|
+
# status hasn't changed, so the latest commit hash is stored.
|
121
|
+
history.write_entry(source_id) do |new_item|
|
122
|
+
cb_puts "Updating dynamo table #{config.dynamo_table} with: #{new_item}"
|
123
|
+
end
|
124
|
+
|
125
|
+
quit(no_status_diff_message(build)) if last_build&.status == build.status
|
126
|
+
|
127
|
+
slack_message = CodeBuildNotifier::SlackMessage.new(build, config, source_ref)
|
128
|
+
sender = CodeBuildNotifier::SlackSender.new(config)
|
129
|
+
sender.send(slack_message)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# codebuild-notifier
|
2
|
+
# Copyright © 2018 Adam Alboyadjian <adam@cassia.tech>
|
3
|
+
# Copyright © 2018 Vista Higher Learning, Inc.
|
4
|
+
#
|
5
|
+
# codebuild-notifier is free software: you can redistribute it
|
6
|
+
# and/or modify it under the terms of the GNU General Public
|
7
|
+
# License as published by the Free Software Foundation, either
|
8
|
+
# version 3 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# codebuild-notifier is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with codebuild-notifier. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
lib = File.expand_path('lib', __dir__)
|
19
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
20
|
+
|
21
|
+
require 'codebuild-notifier/version'
|
22
|
+
|
23
|
+
Gem::Specification.new do |spec|
|
24
|
+
spec.name = 'codebuild-notifier'
|
25
|
+
spec.version = CodeBuildNotifier::VERSION
|
26
|
+
spec.authors = ['VHL Ops Team']
|
27
|
+
spec.email = ['ops@vistahigherlearning.com']
|
28
|
+
spec.summary = 'Slack notifications for CodeBuild jobs.'
|
29
|
+
spec.description = 'CodeBuild Notifier tracks the past status of CI jobs ' \
|
30
|
+
'run on AWS CodeBuild for each pr or whitelisted branch' \
|
31
|
+
'for a given project, and sends slack notifications ' \
|
32
|
+
'when a branch/pr changes build status.'
|
33
|
+
spec.homepage = 'https://github.com/vhl/codebuild-notifier'
|
34
|
+
spec.executables = ['update-build-status']
|
35
|
+
|
36
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |file|
|
37
|
+
file.match(%r{^(test|spec|features)/})
|
38
|
+
end
|
39
|
+
|
40
|
+
spec.add_dependency 'activesupport', '> 2.0', '< 6.0'
|
41
|
+
spec.add_dependency 'aws-sdk-dynamodb', '~> 1.16'
|
42
|
+
spec.add_dependency 'aws-sdk-secretsmanager', '~> 1.19'
|
43
|
+
spec.add_dependency 'hashie', '> 1.0', '< 4.0'
|
44
|
+
spec.add_dependency 'slack-ruby-client', '~> 0.13'
|
45
|
+
|
46
|
+
spec.add_development_dependency 'rspec', '~> 3.8'
|
47
|
+
spec.add_development_dependency 'rubocop', '0.58.2'
|
48
|
+
spec.add_development_dependency 'rubocop-rspec', '1.30.0'
|
49
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# codebuild-notifier
|
2
|
+
# Copyright © 2018 Adam Alboyadjian <adam@cassia.tech>
|
3
|
+
# Copyright © 2018 Vista Higher Learning, Inc.
|
4
|
+
#
|
5
|
+
# codebuild-notifier is free software: you can redistribute it
|
6
|
+
# and/or modify it under the terms of the GNU General Public
|
7
|
+
# License as published by the Free Software Foundation, either
|
8
|
+
# version 3 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# codebuild-notifier is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with codebuild-notifier. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require 'codebuild-notifier/config'
|
19
|
+
require 'codebuild-notifier/build_history'
|
20
|
+
require 'codebuild-notifier/current_build'
|
21
|
+
require 'codebuild-notifier/git'
|
22
|
+
require 'codebuild-notifier/slack_message'
|
23
|
+
require 'codebuild-notifier/slack_sender'
|
24
|
+
require 'codebuild-notifier/version'
|