codebuild-notifier 0.2.0 → 0.3.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 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