codebuild-notifier 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17bc724453d29a4b9aebd6973816c86833effb926f93451fa2aa9872a8ffa0e5
4
- data.tar.gz: c5ce3faadd2d87b2e778cc96e8bc27b4d8dde795b247292860ba0eed126d83b9
3
+ metadata.gz: 83a2bb81dc8815d9ccfa7073d97408297584a1e6f104f894d1f26c2e2cfd2453
4
+ data.tar.gz: bcf314b4c5f2e3b708ba5ff8a63b3deda7255291b803f3bd266c76219ffb4aad
5
5
  SHA512:
6
- metadata.gz: 76104e28f126b94b13cd826ade8627fc94ef87070ba3071ade7795ce103e3dd18b5a663661841a38368886edd86753bc0de0769c3760e91ef2e40351171e39b5
7
- data.tar.gz: 283a0f3a162e9672d718ffc9a420ecbb51c4dd8744d48c4f20a80b814c5f6a26b4d5a5123763e2ebfc179c6907e90817d95bff51ecf282e68718e065b94506b7
6
+ metadata.gz: e1671f03687d58d57ac917a08511e6cabeee8a687fb33087339d22c0ffae40a0e1b9efb69232ff4a5aa3cff1325c22c26560dd6af9c0084b0ea5caca18403675
7
+ data.tar.gz: d7e658e90f1bed0eb2ba2d413b4ef9548da102019690fb39bd8263ebbfbcc6206e113caac8ca9ef4264bd6d0657662c7d21bdb59acdac1065dc362ea05f9509d
@@ -18,6 +18,9 @@ Style/Documentation:
18
18
  Style/FrozenStringLiteralComment:
19
19
  Enabled: false
20
20
 
21
+ Style/AsciiComments:
22
+ Enabled: false
23
+
21
24
  Style/AccessModifierDeclarations:
22
25
  EnforcedStyle: inline
23
26
 
data/README.md CHANGED
@@ -192,6 +192,27 @@ phases:
192
192
  that region.
193
193
  </td>
194
194
  </tr>
195
+ <tr>
196
+ <th>
197
+ CBN_DEFAULT_NOTIFY_STRATEGY
198
+ </th>
199
+ <td>
200
+ <nobr>--default-notify-strategy</nobr>
201
+ </td>
202
+ <td>
203
+ fail_or_status_change
204
+ </td>
205
+ <td>
206
+ Determines when notifications will be sent.
207
+ 'status_change' sends notifications for the first build in a PR or
208
+ whitelisted branch, thereafter if a build in that PR/branch has a
209
+ different status to the previous build.
210
+ 'every_build' sends a notification regardless of status.
211
+ 'fail_or_status_change', the default value, will send if the status
212
+ changes, but will also send notifications of every failure,
213
+ regardless of previous status.
214
+ </td>
215
+ </tr>
195
216
  <tr>
196
217
  <th>
197
218
  CBN_DYNAMO_TABLE
@@ -207,6 +228,25 @@ phases:
207
228
  in <a href="#infrastructure-requirements">Infrastructure Requirements</a>
208
229
  </td>
209
230
  </tr>
231
+ <tr>
232
+ <th>
233
+ CBN_OVERRIDE_NOTIFY_STRATEGY
234
+ </th>
235
+ <td>
236
+ <nobr>--override-notify-strategy</nobr>
237
+ </td>
238
+ <td>
239
+ not set
240
+ </td>
241
+ <td>
242
+ Allows overriding default notify strategy.
243
+ Specify a branch and strategy for that branch, with a colon separator.
244
+ Valid strategies are:
245
+ status_change, every_build, fail_or_status_change
246
+ Specify multiple branch strategies delimited by comma.
247
+ e.g. 'master:every_build,jira-15650:status_change'
248
+ </td>
249
+ </tr>
210
250
  <tr>
211
251
  <th>
212
252
  CBN_SLACK_ADMIN_USERNAMES
@@ -60,29 +60,58 @@ OptionParser.new do |opts|
60
60
  '--additional-channel=CHANNEL',
61
61
  'status notifications for whitelisted branches will be sent here ' \
62
62
  'as well as to author/committer'
63
- ) { |usernames| command_line_opts[:slack_admin_users] = usernames }
63
+ ) do |usernames|
64
+ command_line_opts[:slack_admin_users] = usernames
65
+ end
64
66
 
65
67
  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 }
68
+ '--default-notify-strategy=STRATEGY',
69
+ 'when to send notifications, in the absence of a branch-specific ' \
70
+ 'override -- valid options are: status_change (the default), ' \
71
+ 'every_build, fail_or_status_change'
72
+ ) do |default_strategy|
73
+ command_line_opts[:default_strategy] = default_strategy
74
+ end
70
75
 
71
76
  opts.on(
72
77
  '--dynamo-table=TABLE',
73
78
  'table for storing build statuses'
74
- ) { |table| command_line_opts[:dynamo_table] = table }
79
+ ) do |table|
80
+ command_line_opts[:dynamo_table] = table
81
+ end
82
+
83
+ opts.on(
84
+ '--override-notify-strategy=BRANCH_STRATEGY_PAIRS',
85
+ 'overrides default notify strategy; specify pairs of branch:strategy ' \
86
+ 'Valid strategies are: status_change, every_build, fail_or_status_change ' \
87
+ 'separate pairs with a comma' \
88
+ 'e.g. master:every_build,jira-15650:status_change'
89
+ ) do |overrides|
90
+ command_line_opts[:strategy_overrides] = overrides
91
+ end
92
+
93
+ opts.on(
94
+ '--slack-admin-usernames=USERS',
95
+ 'comma-separated list of slack users to be notified if build status ' \
96
+ 'notifications fail to send'
97
+ ) do |usernames|
98
+ command_line_opts[:slack_admin_users] = usernames
99
+ end
75
100
 
76
101
  opts.on(
77
102
  '--slack-secret-name=SECRET',
78
103
  'name of Secrets Manager secret with slack app/bot auth token'
79
- ) { |slack_secret| command_line_opts[:slack_secret_name] = slack_secret }
104
+ ) do |slack_secret|
105
+ command_line_opts[:slack_secret_name] = slack_secret
106
+ end
80
107
 
81
108
  opts.on(
82
109
  '--whitelist-branches=BRANCHES',
83
110
  'comma-separated list of branches that will have build notifications ' \
84
111
  'sent even if there is no open Pull Request'
85
- ) { |whitelist| command_line_opts[:whitelist_branches] = whitelist }
112
+ ) do |whitelist|
113
+ command_line_opts[:whitelist_branches] = whitelist
114
+ end
86
115
 
87
116
  opts.on('--region=REGION', 'AWS region') do |region|
88
117
  command_line_opts[:region] = region
@@ -95,6 +124,7 @@ build = CodeBuildNotifier::CurrentBuild.new
95
124
  history = CodeBuildNotifier::BuildHistory.new(config, build)
96
125
 
97
126
  last_build = history.last_entry
127
+ build.previous_build = last_build
98
128
 
99
129
  if build.launched_by_retry?
100
130
  # Whenever a build is triggered by a PR or whitelisted branch, we update
@@ -103,27 +133,33 @@ if build.launched_by_retry?
103
133
  # only if the re-tried build was for the latest commit. Otherwise re-trying
104
134
  # an older commit could result in inaccurate notifications.
105
135
  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
136
  else
110
137
  # We only want to track information for whitelisted branches and branches
111
138
  # with open Pull Requests.
112
139
  unless config.non_pr_branch_ids.include?(build.trigger) || build.for_pr?
113
140
  quit(not_pr_or_whitelisted_branch_message(config))
114
141
  end
115
- source_id = build.source_id
116
- source_ref = build.trigger
117
142
  end
118
143
 
119
144
  # Update record for this project + branch/pr in DynamoDb even if the
120
145
  # status hasn't changed, so the latest commit hash is stored.
121
- history.write_entry(source_id) do |new_item|
146
+ history.write_entry(build.source_id) do |new_item|
122
147
  cb_puts "Updating dynamo table #{config.dynamo_table} with: #{new_item}"
123
148
  end
124
149
 
125
- quit(no_status_diff_message(build)) if last_build&.status == build.status
150
+ status_changed = last_build&.status != build.status
151
+
152
+ strategy = config.strategy_for_branch(build.branch_name)
153
+
154
+ unless strategy == 'every_build'
155
+ if strategy == 'status_change'
156
+ quit(no_status_diff_message(build)) unless status_changed
157
+ elsif strategy == 'fail_or_status_change'
158
+ # TODO: Find good wording for a different exit message for this case.
159
+ quit(no_status_diff_message(build)) if build.status == 'SUCCEEDED' && !status_changed
160
+ end
161
+ end
126
162
 
127
- slack_message = CodeBuildNotifier::SlackMessage.new(build, config, source_ref)
163
+ slack_message = CodeBuildNotifier::SlackMessage.new(build, config, build.source_ref)
128
164
  sender = CodeBuildNotifier::SlackSender.new(config)
129
165
  sender.send(slack_message)
@@ -25,7 +25,7 @@ module CodeBuildNotifier
25
25
  attr_reader :config, :current_build
26
26
 
27
27
  delegate :dynamo_table, to: :config
28
- delegate :launched_by_retry?, to: :current_build
28
+ delegate :branch_name, :launched_by_retry?, to: :current_build
29
29
 
30
30
  def initialize(config, current_build)
31
31
  @config = config
@@ -86,7 +86,10 @@ module CodeBuildNotifier
86
86
  # If launched via manual re-try instead of via a webhook, we don't
87
87
  # want to overwrite the current source_ref value that tells us which
88
88
  # branch or pull request originally created the dynamo record.
89
- memo[:source_ref] = current_build.trigger unless launched_by_retry?
89
+ unless launched_by_retry?
90
+ memo[:source_ref] = current_build.trigger
91
+ memo[:branch_name] = branch_name unless branch_name.empty?
92
+ end
90
93
  end
91
94
  end
92
95
 
@@ -19,27 +19,36 @@ module CodeBuildNotifier
19
19
  class Config
20
20
  DEFAULT_WHITELIST = %w[master release]
21
21
 
22
- attr_reader :additional_channel, :dynamo_table, :region, :slack_admins,
23
- :slack_secret_name, :whitelist_branches
22
+ attr_reader :additional_channel, :default_strategy, :dynamo_table, :region,
23
+ :slack_admins, :slack_secret_name, :whitelist_branches
24
24
 
25
25
  # Configuration values specific to CodeBuild Notifier. CBN_ prefix is
26
26
  # used because ENV vars with CODEBUILD_ prefix are reserved for use by AWS.
27
27
  def initialize(
28
28
  additional_channel: ENV['CBN_ADDITIONAL_CHANNEL'],
29
+ default_strategy: ENV['CBN_DEFAULT_NOTIFY_STRATEGY'] || 'fail_or_status_change',
29
30
  dynamo_table: ENV['CBN_DYNAMO_TABLE'] || 'branch-build-status',
30
31
  region: ENV['CBN_AWS_REGION'] || ENV['AWS_REGION'],
31
32
  slack_admins: ENV['CBN_SLACK_ADMIN_USERNAMES'],
32
33
  slack_secret_name: ENV['CBN_SLACK_SECRET_NAME'] || 'slack/codebuild',
34
+ strategy_overrides: ENV['CBN_OVERRIDE_NOTIFY_STRATEGY'],
33
35
  whitelist_branches: ENV['CBN_WHITELIST_BRANCHES']
34
36
  )
35
37
  @additional_channel = additional_channel
38
+ @default_strategy = default_strategy
36
39
  @dynamo_table = dynamo_table
37
40
  @region = region
38
41
  @slack_admins = slack_admins&.split(',') || []
39
42
  @slack_secret_name = slack_secret_name
43
+ @strategy_overrides = strategy_overrides&.split(',') || []
40
44
  @whitelist_branches = whitelist_branches&.split(',') || DEFAULT_WHITELIST
41
45
  end
42
46
 
47
+ def strategy_for_branch(branch_name)
48
+ lookup = @strategy_overrides.map { |override| override.split(':') }.to_h
49
+ lookup.fetch(branch_name, default_strategy)
50
+ end
51
+
43
52
  # Match the format of the CodeBuild trigger variable
44
53
  def non_pr_branch_ids
45
54
  whitelist_branches.map { |name| "branch/#{name}" }
@@ -18,6 +18,7 @@
18
18
  module CodeBuildNotifier
19
19
  class CurrentBuild
20
20
  attr_reader :build_id, :commit_hash, :git_repo_url, :status_code, :trigger
21
+ attr_accessor :previous_build
21
22
 
22
23
  # Default values are extracted from CODEBUILD_* ENV vars present in each
23
24
  # CodeBuild # job container.
@@ -25,6 +26,7 @@ module CodeBuildNotifier
25
26
  build_id: ENV['CODEBUILD_BUILD_ID'],
26
27
  commit_hash: ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'],
27
28
  git_repo: ENV['CODEBUILD_SOURCE_REPO_URL'],
29
+ head_ref: ENV['CODEBUILD_WEBHOOK_HEAD_REF'],
28
30
  status_code: ENV['CODEBUILD_BUILD_SUCCEEDING'],
29
31
  trigger: ENV['CODEBUILD_WEBHOOK_TRIGGER']
30
32
  )
@@ -32,10 +34,22 @@ module CodeBuildNotifier
32
34
  @commit_hash = commit_hash
33
35
  # Handle repos specified with and without optional .git suffix.
34
36
  @git_repo_url = git_repo.to_s.gsub(/\.git\z/, '')
37
+ @head_ref = head_ref
35
38
  @status_code = status_code
36
39
  @trigger = trigger
37
40
  end
38
41
 
42
+ # If launched via retry, the webhook head ref env var is blank,
43
+ # but if the previous build for this branch has been located,
44
+ # the branch_name of that build is the same as for this build
45
+ def branch_name
46
+ if launched_by_retry?
47
+ previous_build&.branch_name
48
+ else
49
+ @head_ref.to_s.gsub(%r{^refs/heads/}, '')
50
+ end
51
+ end
52
+
39
53
  def status
40
54
  status_code.to_s == '1' ? 'SUCCEEDED' : 'FAILED'
41
55
  end
@@ -63,7 +77,25 @@ module CodeBuildNotifier
63
77
  # multiple projects, for example, with different buildspec files for
64
78
  # different ruby versions, or for rspec vs cucumber.
65
79
  def source_id
66
- "#{project_code}:#{trigger}"
80
+ # If launched via retry, trigger is blank, but if the previous
81
+ # build for this branch has been located, the source_id of that
82
+ # build is the same as for this build
83
+ if launched_by_retry?
84
+ previous_build&.source_id
85
+ else
86
+ "#{project_code}:#{trigger}"
87
+ end
88
+ end
89
+
90
+ def source_ref
91
+ # If launched via retry, trigger is blank, but if the previous
92
+ # build for this branch has been located, the source_ref of that
93
+ # build is the same as for this build
94
+ if launched_by_retry?
95
+ previous_build&.source_ref
96
+ else
97
+ trigger
98
+ end
67
99
  end
68
100
  end
69
101
  end
@@ -18,12 +18,13 @@
18
18
  module CodeBuildNotifier
19
19
  class SlackMessage
20
20
  attr_reader :author_email, :author_name, :build, :committer_email,
21
- :commit_message_subject, :config, :short_hash, :source_ref
21
+ :commit_message_subject, :config, :short_hash
22
22
 
23
- def initialize(build, config, source_ref)
23
+ delegate :source_ref, to: :build
24
+
25
+ def initialize(build, config)
24
26
  @build = build
25
27
  @config = config
26
- @source_ref = source_ref
27
28
  @short_hash, @author_name, @author_email,
28
29
  @committer_email, @commit_message_subject = git_info
29
30
  end
@@ -16,5 +16,5 @@
16
16
  # along with codebuild-notifier. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  module CodeBuildNotifier
19
- VERSION = '0.2.0'
19
+ VERSION = '0.3.0'.freeze
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codebuild-notifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VHL Ops Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-05 00:00:00.000000000 Z
11
+ date: 2019-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport