codebuild-notifier 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'
|