ndr_dev_support 4.0.0 → 4.1.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: a77c75ad60b45a91190083d470912db589015a7237713b510b9aa4b6cfc03284
4
- data.tar.gz: 9ddefdc49d88b6d445586537284590fb656fb8a97425c77e7881660bfb8f467d
3
+ metadata.gz: e2b84dc423c034b919fb74cd67458fc885d4f6565f4ad5798d2fbf201d8ddfc0
4
+ data.tar.gz: 26689488b7846c1edaf32f45f2a60976b4b7938a7af6d12a1626dce91d1c838a
5
5
  SHA512:
6
- metadata.gz: dd8c7362ccb13351c211cb068a61fe660a2f4fa36b7bc93d98b5f2c395a93cfa23e503ddb07578382d631e617a1c06593c32d53c3cbfa40fffc29103f92880ba
7
- data.tar.gz: 9534b04645eae6cae4d72902773f04809f8488c6a342e07e7fbf762da02372194c21f6ce0713a66856fb3034c04e341c861b939427c3205c5e37ae8d18f170a5
6
+ metadata.gz: 7f58716ac63abaeb4597084393f44528fa1f7426f3dce76f71fc771a3427a3dd5edcc5ee30df7e817ed35ba553107cca2997590aab1ff11811a850fe4941263e
7
+ data.tar.gz: a41b7019ba639d84bb3b28f01773c6aa3e69c217fadd8995655c90ec7c0392f7692288448dd23b029ffd92c86b97a6ca5a2fc6c2c4693830326b3a009dce9e62
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ rake_ci.*.yml
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ AllCops:
8
8
  # All cops should ignore files in the following locations:
9
9
  Exclude:
10
10
  - 'bin/*'
11
- - 'db/**/*'
11
+ - 'db/schema.rb'
12
12
  - 'lib/generators/**/templates/*'
13
13
  - 'tmp/**/*'
14
14
  - 'vendor/**/*'
@@ -44,15 +44,13 @@ Style/FrozenStringLiteralComment:
44
44
  # We're not confident enough to make this recommendation everywhere
45
45
  Enabled: false
46
46
 
47
- Metrics/LineLength:
48
- Max: 100
49
-
50
47
  Style/ModuleFunction:
51
48
  # `extend self` has fewer side effects than `module_function`.
52
49
  EnforcedStyle: extend_self
53
50
 
54
51
  Style/NumericLiterals:
55
52
  Exclude:
53
+ - 'db/migrate/*.rb'
56
54
  - 'test/**/*.rb'
57
55
 
58
56
  Style/YodaCondition:
@@ -75,6 +73,9 @@ Performance/Casecmp:
75
73
 
76
74
  Metrics/AbcSize:
77
75
  Max: 23
76
+ Exclude:
77
+ - 'db/migrate/*.rb'
78
+ - 'test/**/*.rb'
78
79
 
79
80
  Metrics/BlockLength:
80
81
  # We're already limiting method size, blocks outside of methods
@@ -84,6 +85,7 @@ Metrics/BlockLength:
84
85
  Metrics/ClassLength:
85
86
  Max: 150
86
87
  Exclude:
88
+ - 'db/migrate/*.rb'
87
89
  - 'test/**/*.rb'
88
90
 
89
91
  Metrics/ModuleLength:
@@ -97,11 +99,13 @@ Metrics/CyclomaticComplexity:
97
99
  Metrics/LineLength:
98
100
  Max: 100
99
101
  Exclude:
102
+ - 'db/migrate/*.rb'
100
103
  - 'test/**/*.rb'
101
104
 
102
105
  Metrics/MethodLength:
103
106
  Max: 15
104
107
  Exclude:
108
+ - 'db/migrate/*.rb'
105
109
  - 'test/**/*.rb'
106
110
 
107
111
  Metrics/PerceivedComplexity:
data/code_safety.yml CHANGED
@@ -2,8 +2,8 @@
2
2
  file safety:
3
3
  ".gitignore":
4
4
  comments:
5
- reviewed_by: timgentry
6
- safe_revision: c59a45986f8b6d087c8c21b1e889f31f7346da17
5
+ reviewed_by: josh.pencheon
6
+ safe_revision: 3e1fbd0a5931f7598a2dd3f929a7cd8366dc0e96
7
7
  ".hound.yml":
8
8
  comments:
9
9
  reviewed_by: timgentry
@@ -11,7 +11,7 @@ file safety:
11
11
  ".rubocop.yml":
12
12
  comments:
13
13
  reviewed_by: josh.pencheon
14
- safe_revision: 949a0ff086946426531a34d48f646b32c761c272
14
+ safe_revision: 33ecea8453c2b82c3e360819831bee5f1b8d3d4d
15
15
  ".travis.yml":
16
16
  comments:
17
17
  reviewed_by: josh.pencheon
@@ -44,6 +44,10 @@ file safety:
44
44
  comments:
45
45
  reviewed_by: timgentry
46
46
  safe_revision: c59a45986f8b6d087c8c21b1e889f31f7346da17
47
+ lib/minitest/rake_ci_reporter.rb:
48
+ comments:
49
+ reviewed_by: josh.pencheon
50
+ safe_revision: 3e1fbd0a5931f7598a2dd3f929a7cd8366dc0e96
47
51
  lib/ndr_dev_support.rb:
48
52
  comments:
49
53
  reviewed_by: timgentry
@@ -83,7 +87,7 @@ file safety:
83
87
  lib/ndr_dev_support/daemon/ci_server.rb:
84
88
  comments:
85
89
  reviewed_by: josh.pencheon
86
- safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
90
+ safe_revision: 66ce36e2646d392e3a67e19fcb9322ed8c5a6c16
87
91
  lib/ndr_dev_support/daemon/stoppable.rb:
88
92
  comments:
89
93
  reviewed_by: josh.pencheon
@@ -120,10 +124,34 @@ file safety:
120
124
  comments:
121
125
  reviewed_by: josh.pencheon
122
126
  safe_revision: 49caa4ef8ad9926843354d36f4610d40603ec632
127
+ lib/ndr_dev_support/rake_ci/commit_cop.rb:
128
+ comments:
129
+ reviewed_by: josh.pencheon
130
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
131
+ lib/ndr_dev_support/rake_ci/commit_cop/concerns/deputisable.rb:
132
+ comments:
133
+ reviewed_by: josh.pencheon
134
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
135
+ lib/ndr_dev_support/rake_ci/commit_cop/migration_without_structure_dump.rb:
136
+ comments:
137
+ reviewed_by: josh.pencheon
138
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
139
+ lib/ndr_dev_support/rake_ci/commit_cop/modified_migration.rb:
140
+ comments:
141
+ reviewed_by: josh.pencheon
142
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
143
+ lib/ndr_dev_support/rake_ci/commit_cop/renamed_migration.rb:
144
+ comments:
145
+ reviewed_by: josh.pencheon
146
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
123
147
  lib/ndr_dev_support/rake_ci/concerns/commit_metadata_persistable.rb:
124
148
  comments:
125
149
  reviewed_by: josh.pencheon
126
150
  safe_revision: 49caa4ef8ad9926843354d36f4610d40603ec632
151
+ lib/ndr_dev_support/rake_ci/redmine/ticket_resolver.rb:
152
+ comments:
153
+ reviewed_by: josh.pencheon
154
+ safe_revision: 2154aa7f32e731933ff6091b8f42b2b014028a6a
127
155
  lib/ndr_dev_support/rake_ci/simple_cov_helper.rb:
128
156
  comments:
129
157
  reviewed_by: josh.pencheon
@@ -151,11 +179,11 @@ file safety:
151
179
  lib/ndr_dev_support/tasks.rb:
152
180
  comments:
153
181
  reviewed_by: josh.pencheon
154
- safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
182
+ safe_revision: 2154aa7f32e731933ff6091b8f42b2b014028a6a
155
183
  lib/ndr_dev_support/version.rb:
156
184
  comments:
157
185
  reviewed_by: josh.pencheon
158
- safe_revision: 3efca19afad2f7dedc1d470cd8dd51e95ec77545
186
+ safe_revision: e3f427496995516245e0de5c371b6867cf0a04df
159
187
  lib/tasks/audit_code.rake:
160
188
  comments: Identical to the version reviewed by josh.pencheon when contained within
161
189
  ndr_support
@@ -169,6 +197,10 @@ file safety:
169
197
  comments:
170
198
  reviewed_by: josh.pencheon
171
199
  safe_revision: ddcf7de0bf1f5fb17cc28e2460009e162ff8917c
200
+ lib/tasks/ci/commit_cop.rake:
201
+ comments:
202
+ reviewed_by: josh.pencheon
203
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
172
204
  lib/tasks/ci/dependencies.rake:
173
205
  comments:
174
206
  reviewed_by: josh.pencheon
@@ -181,6 +213,10 @@ file safety:
181
213
  comments:
182
214
  reviewed_by: timgentry
183
215
  safe_revision: 00cd6c2f71612a467ee88ad53c21e08f073871d5
216
+ lib/tasks/ci/minitest.rake:
217
+ comments:
218
+ reviewed_by: josh.pencheon
219
+ safe_revision: 3e1fbd0a5931f7598a2dd3f929a7cd8366dc0e96
184
220
  lib/tasks/ci/notes.rake:
185
221
  comments:
186
222
  reviewed_by: timgentry
@@ -188,23 +224,27 @@ file safety:
188
224
  lib/tasks/ci/prometheus.rake:
189
225
  comments:
190
226
  reviewed_by: josh.pencheon
191
- safe_revision: a10b6f3f5c9261135fae534e5785e2342430dde2
227
+ safe_revision: 6cb22447594ebf450fc60deb90fd223c8067ff18
228
+ lib/tasks/ci/redmine.rake:
229
+ comments:
230
+ reviewed_by: josh.pencheon
231
+ safe_revision: 2154aa7f32e731933ff6091b8f42b2b014028a6a
192
232
  lib/tasks/ci/rugged.rake:
193
233
  comments:
194
234
  reviewed_by: timgentry
195
235
  safe_revision: 7ab7061b257f916eb43bc8d184aa425f1f08b739
196
236
  lib/tasks/ci/server.rake:
197
237
  comments:
198
- reviewed_by: timgentry
199
- safe_revision: e581239a77666500a3108bcb3d480e370a82adb8
238
+ reviewed_by: josh.pencheon
239
+ safe_revision: d8e52aab569d9efac3e27485b5721c9608a84b6c
200
240
  lib/tasks/ci/simplecov.rake:
201
241
  comments:
202
242
  reviewed_by: josh.pencheon
203
243
  safe_revision: 6240a84dc859af0623328f8667b93299c8eae257
204
244
  lib/tasks/ci/slack.rake:
205
245
  comments:
206
- reviewed_by: timgentry
207
- safe_revision: ad38e92c6e56b9d81fdab10681d8f2924eeadf5a
246
+ reviewed_by: josh.pencheon
247
+ safe_revision: 6cb22447594ebf450fc60deb90fd223c8067ff18
208
248
  lib/tasks/ci/stats.rake:
209
249
  comments:
210
250
  reviewed_by: josh.pencheon
@@ -216,7 +256,7 @@ file safety:
216
256
  ndr_dev_support.gemspec:
217
257
  comments:
218
258
  reviewed_by: josh.pencheon
219
- safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
259
+ safe_revision: 3e1fbd0a5931f7598a2dd3f929a7cd8366dc0e96
220
260
  test/daemon/ci_server_test.rb:
221
261
  comments:
222
262
  reviewed_by: josh.pencheon
@@ -225,6 +265,22 @@ file safety:
225
265
  comments:
226
266
  reviewed_by: timgentry
227
267
  safe_revision: 26a8907a7a8a6b0d836aa12ca0335fa40be12240
268
+ test/rake_ci/commit_cop/migration_without_structure_dump_test.rb:
269
+ comments:
270
+ reviewed_by: josh.pencheon
271
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
272
+ test/rake_ci/commit_cop/modified_migration_test.rb:
273
+ comments:
274
+ reviewed_by: josh.pencheon
275
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
276
+ test/rake_ci/commit_cop/renamed_migration_test.rb:
277
+ comments:
278
+ reviewed_by: josh.pencheon
279
+ safe_revision: a3f5b7d3709f7e340f2f7e81dab026a63b21e3ff
280
+ test/rake_ci/redmine/ticket_resolver_test.rb:
281
+ comments:
282
+ reviewed_by: josh.pencheon
283
+ safe_revision: 2154aa7f32e731933ff6091b8f42b2b014028a6a
228
284
  test/test_helper.rb:
229
285
  comments:
230
286
  reviewed_by: josh.pencheon
@@ -0,0 +1,115 @@
1
+ require 'minitest'
2
+ require 'rugged'
3
+ require 'ndr_dev_support/rake_ci/concerns/commit_metadata_persistable'
4
+
5
+ # The plugin needs to extend Minitest
6
+ module Minitest
7
+ # RakeCI Minitest Reporter
8
+ class RakeCIReporter < StatisticsReporter
9
+ include CommitMetadataPersistable
10
+
11
+ def report
12
+ super
13
+
14
+ hash = {
15
+ statistics: current_statistics,
16
+ # results: results,
17
+ metrics: current_metrics,
18
+ attachments: current_attachments
19
+ }
20
+
21
+ save_current_commit_data(hash)
22
+ end
23
+
24
+ def commit
25
+ return @commit if @commit
26
+
27
+ repo = Rugged::Repository.new('.')
28
+ @commit = repo.lookup(repo.head.target_id)
29
+ end
30
+
31
+ def load_current_commit_hash
32
+ load_current_commit_data
33
+ end
34
+
35
+ private
36
+
37
+ def current_statistics
38
+ @current_statistics ||= {
39
+ total_time: total_time, runs: count, assertions: assertions, failures: failures,
40
+ errors: errors, skips: skips
41
+ }
42
+ end
43
+
44
+ def current_metrics
45
+ return @current_metrics if @current_metrics
46
+
47
+ @current_metrics = []
48
+ (current_statistics.keys - %i[total_time]).each do |name|
49
+ metric = {
50
+ name: 'ci_test_count',
51
+ type: :gauge,
52
+ label_set: { name: name },
53
+ value: current_statistics[name]
54
+ }
55
+ @current_metrics << metric
56
+ io.puts metric.inspect
57
+ end
58
+ @current_metrics
59
+ end
60
+
61
+ def current_attachments
62
+ return @current_attachments if @current_attachments
63
+
64
+ @current_attachments = []
65
+ @current_attachments << failures_attachment if failures.positive?
66
+ @current_attachments << errors_attachment if errors.positive?
67
+ @current_attachments << pass_attachment if newly_passing?
68
+ @current_attachments
69
+ end
70
+
71
+ def failures_attachment
72
+ {
73
+ color: 'danger',
74
+ text: ActionController::Base.helpers.pluralize(failures, 'test failure'),
75
+ footer: 'bundle exec rake ci:minitest'
76
+ }
77
+ end
78
+
79
+ def errors_attachment
80
+ {
81
+ color: 'warning',
82
+ text: ActionController::Base.helpers.pluralize(errors, 'test error'),
83
+ footer: 'bundle exec rake ci:minitest'
84
+ }
85
+ end
86
+
87
+ def pass_attachment
88
+ {
89
+ color: 'good',
90
+ text: 'Tests now pass',
91
+ footer: 'bundle exec rake ci:minitest'
92
+ }
93
+ end
94
+
95
+ def newly_passing?
96
+ return false if failures.positive? || errors.positive?
97
+
98
+ last_commit_hash = load_last_commit_data
99
+ return false if last_commit_hash.nil?
100
+
101
+ last_commit_hash[:statistics][:failures].positive? ||
102
+ last_commit_hash[:statistics][:errors].positive?
103
+ end
104
+
105
+ def name
106
+ 'minitest'
107
+ end
108
+ end
109
+
110
+ def self.plugin_rake_ci_init(_options)
111
+ reporter << RakeCIReporter.new
112
+ end
113
+ end
114
+
115
+ Minitest.extensions << 'rake_ci'
@@ -1,6 +1,8 @@
1
1
  require 'English'
2
2
  require_relative 'stoppable'
3
+ require 'open3'
3
4
  require 'rugged'
5
+ require 'shellwords'
4
6
  require 'with_clean_rbenv'
5
7
 
6
8
  module NdrDevSupport
@@ -46,7 +48,7 @@ module NdrDevSupport
46
48
  git_checkout(MASTER_BRANCH_NAME)
47
49
 
48
50
  objectids_between_master_and_remote.each do |oid|
49
- `git rebase #{oid}`
51
+ git_rebase(oid)
50
52
 
51
53
  WithCleanRbenv.with_clean_rbenv do
52
54
  # TODO: rbenv_install
@@ -62,7 +64,19 @@ module NdrDevSupport
62
64
  end
63
65
 
64
66
  def git_checkout(oid)
65
- `git checkout #{oid}`
67
+ Open3.popen3('git', 'checkout', oid) do |_stdin, _stdout, stderr, wait_thr|
68
+ msg = stderr.read.strip
69
+ # TODO: Once https://github.com/PublicHealthEngland/ndr_dev_support/issues/27
70
+ # has been resolved, use logging instead of puts
71
+ puts msg unless msg == "Already on '#{oid}'"
72
+
73
+ process_status = wait_thr.value
74
+ raise stderr.read unless process_status.exited?
75
+ end
76
+ end
77
+
78
+ def git_rebase(oid)
79
+ `git rebase #{Shellwords.escape(oid)}`
66
80
  end
67
81
 
68
82
  def git_discard_changes
@@ -0,0 +1,64 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require_relative 'commit_cop/migration_without_structure_dump'
3
+ require_relative 'commit_cop/modified_migration'
4
+ require_relative 'commit_cop/renamed_migration'
5
+
6
+ module NdrDevSupport
7
+ module RakeCI
8
+ # This module encapsulates commit cop logic
9
+ module CommitCop
10
+ # This defines the regular expression that identifies the path to migration files.
11
+ mattr_accessor :migration_paths
12
+ self.migration_paths =
13
+ if defined?(Rails)
14
+ Rails.application.config.paths['db/migrate'].map(&:to_s)
15
+ else
16
+ []
17
+ end
18
+
19
+ # This defines the regular expression that identifies structure dump files.
20
+ mattr_accessor :structure_dump_pattern
21
+ self.structure_dump_pattern = %r{\Adb/(structure\.sql|schema\.rb)\z}
22
+
23
+ COMMIT_COPS = [
24
+ MigrationWithoutStructureDump,
25
+ ModifiedMigration,
26
+ RenamedMigration
27
+ ].freeze
28
+
29
+ # enumerates over each delta of the commmit
30
+ def self.each_delta(commit, &block)
31
+ diffs = commit.parents.first.diff(commit)
32
+ diffs.find_similar!
33
+ diffs.each_delta(&block)
34
+ end
35
+
36
+ # converts the deltas into a simpler changes hash of filename sets representation
37
+ def self.changes(commit)
38
+ changes = { added: Set.new, deleted: Set.new, modified: Set.new, renamed: Set.new }
39
+
40
+ each_delta(commit) do |delta|
41
+ if delta.status == :renamed
42
+ changes[delta.status].add([delta.old_file[:path], delta.new_file[:path]])
43
+ else
44
+ # old_file and new_file are the same
45
+ changes[delta.status].add(delta.old_file[:path])
46
+ end
47
+ end
48
+
49
+ changes
50
+ end
51
+
52
+ # Isolates migration/structure pattern changes by resetting them after yielding
53
+ def self.with_pattern
54
+ default_migration_paths = migration_paths
55
+ default_structure_dump_pattern = structure_dump_pattern
56
+
57
+ yield
58
+
59
+ self.migration_paths = default_migration_paths
60
+ self.structure_dump_pattern = default_structure_dump_pattern
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support/concern'
2
+
3
+ module NdrDevSupport
4
+ module RakeCI
5
+ module CommitCop
6
+ # Deputisable cop concern
7
+ module Deputisable
8
+ extend ActiveSupport::Concern
9
+
10
+ private
11
+
12
+ def migration_file?
13
+ proc do |file|
14
+ if file.is_a?(Array)
15
+ file.any?(&migration_file?)
16
+ else
17
+ file.start_with?(*NdrDevSupport::RakeCI::CommitCop.migration_paths) &&
18
+ file =~ /\d{14}_.*\.rb\z/
19
+ end
20
+ end
21
+ end
22
+
23
+ def unscoped_migration_file?
24
+ proc do |file|
25
+ file.start_with?(*NdrDevSupport::RakeCI::CommitCop.migration_paths) &&
26
+ file =~ /\d{14}_[^\.]*\.rb\z/
27
+ end
28
+ end
29
+
30
+ def structure_dump_file?
31
+ proc { |file| file =~ NdrDevSupport::RakeCI::CommitCop.structure_dump_pattern }
32
+ end
33
+
34
+ def attachment(severity, title, text)
35
+ {
36
+ color: severity.to_s, title: title, text: text, mrkdwn_in: ['text']
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'concerns/deputisable'
2
+
3
+ module NdrDevSupport
4
+ module RakeCI
5
+ module CommitCop
6
+ # This cop checks for new migrations with no accompanying structure dump
7
+ class MigrationWithoutStructureDump
8
+ include Deputisable
9
+
10
+ def check(changes)
11
+ return unless changes[:added].any?(&unscoped_migration_file?) &&
12
+ changes[:modified].none?(&structure_dump_file?)
13
+
14
+ attachment(:danger,
15
+ 'No structure file committed',
16
+ 'Migration(s) were added with no accompanying structure file(s)')
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'concerns/deputisable'
2
+
3
+ module NdrDevSupport
4
+ module RakeCI
5
+ module CommitCop
6
+ # This cop checks for modified migrations
7
+ class ModifiedMigration
8
+ include Deputisable
9
+
10
+ def check(changes)
11
+ return if changes[:modified].none?(&migration_file?)
12
+
13
+ attachment(:danger,
14
+ 'Modified Migration',
15
+ 'Migrations should not be modified. Create another migration.')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'concerns/deputisable'
2
+
3
+ module NdrDevSupport
4
+ module RakeCI
5
+ module CommitCop
6
+ # This cop checks for renamed migrations that change timestamp
7
+ class RenamedMigration
8
+ include Deputisable
9
+
10
+ def check(changes)
11
+ renamed_migrations = changes[:renamed].select(&migration_file?)
12
+ return if renamed_migrations.all? do |old_file, new_file|
13
+ File.basename(old_file)[0, 14] == File.basename(new_file)[0, 14]
14
+ end
15
+
16
+ attachment(:danger,
17
+ 'Renamed Migration',
18
+ 'Migrations should not change timestamp')
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,101 @@
1
+ require 'json'
2
+ require 'net/http'
3
+
4
+ module NdrDevSupport
5
+ module RakeCI
6
+ module Redmine
7
+ # This class encapsulates Redmine ticket logic
8
+ class TicketResolver
9
+ CLOSE_REGEX =
10
+ /
11
+ (
12
+ (?:close[sd]?) # close, closes, closed
13
+ | (?:resolve[sd]?) # resolve, resolves, resolved
14
+ | (?:fix(?:e[sd])?) # fix, fixes, fixed
15
+ )
16
+ /ix
17
+
18
+ MEGA_REGEX =
19
+ /
20
+ #{CLOSE_REGEX}
21
+ | (relate[sd]\sto) # relates to, related to
22
+ | (?:
23
+ \[? # optional square bracket
24
+ \#(\d+) # ticket number with preceding hash character
25
+ (?:\#note-\d+)? # optional note reference, ignored
26
+ \]? # optional square bracket
27
+ \b # word boundary
28
+ )
29
+ /ix
30
+
31
+ def initialize(api_key, hostname)
32
+ @headers = {
33
+ 'X-Redmine-API-Key' => api_key,
34
+ 'Content-Type' => 'application/json'
35
+ }
36
+ @hostname = hostname
37
+ end
38
+
39
+ def process_commit(user, revision, message)
40
+ resolved_tickets = []
41
+
42
+ each_ticket_from(message) do |ticket, resolved|
43
+ update_ticket(message, user, revision, ticket, resolved)
44
+
45
+ resolved_tickets << ticket if resolved
46
+ end
47
+
48
+ resolved_tickets
49
+ end
50
+
51
+ def each_ticket_from(message, &block)
52
+ return enum_for(:each_ticket_from, message) unless block
53
+
54
+ key_words = message.scan(MEGA_REGEX).flatten.compact
55
+ action_groups = key_words.slice_when { |_l, r| r.to_i.to_s != r }.to_a
56
+
57
+ action_groups.each do |group|
58
+ resolved = group.any? { |word| word =~ CLOSE_REGEX }
59
+ tickets = group.select { |word| word.to_i.to_s == word }.uniq
60
+
61
+ tickets.each { |ticket| yield(ticket, resolved) }
62
+ end
63
+ end
64
+
65
+ def update_payload(message, user, revision, ticket_closed, resolved)
66
+ payload = {
67
+ notes: "_#{resolved ? 'Resolved' : 'Referenced'} by #{user} in #{revision}_:" \
68
+ "#{resolved ? message.gsub(CLOSE_REGEX, '+\1+') : message}"
69
+ }
70
+
71
+ payload[:status_id] = 3 if resolved && !ticket_closed
72
+ payload
73
+ end
74
+
75
+ private
76
+
77
+ # Connect lazily
78
+ def http
79
+ return @http if @http
80
+ @http = Net::HTTP.new(@hostname, 443)
81
+ @http.use_ssl = true
82
+ @http
83
+ end
84
+
85
+ def update_ticket(message, user, revision, ticket, resolved)
86
+ payload = update_payload(message, user, revision, ticket_closed?(ticket), resolved)
87
+
88
+ http.send_request('PUT',
89
+ "/issues/#{ticket.to_i}.json",
90
+ JSON.dump(issue: payload),
91
+ @headers)
92
+ end
93
+
94
+ def ticket_closed?(ticket)
95
+ response = http.send_request('GET', "/issues/#{ticket.to_i}.json", nil, @headers)
96
+ JSON.parse(response.body)['issue']['status']['id'] == 5
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,11 +1,14 @@
1
1
  load 'tasks/audit_code.rake'
2
2
  load 'tasks/ci/brakeman.rake'
3
3
  load 'tasks/ci/bundle_audit.rake'
4
+ load 'tasks/ci/commit_cop.rake'
4
5
  load 'tasks/ci/dependencies.rake'
5
6
  load 'tasks/ci/housekeep.rake'
6
7
  load 'tasks/ci/linguist.rake'
8
+ load 'tasks/ci/minitest.rake'
7
9
  load 'tasks/ci/notes.rake'
8
10
  load 'tasks/ci/prometheus.rake'
11
+ load 'tasks/ci/redmine.rake'
9
12
  load 'tasks/ci/rugged.rake'
10
13
  load 'tasks/ci/server.rake'
11
14
  load 'tasks/ci/simplecov.rake'
@@ -2,5 +2,5 @@
2
2
  # This defines the NdrDevSupport version. If you change it, rebuild and commit the gem.
3
3
  # Use "rake build" to build the gem, see rake -T for all bundler rake tasks (and our own).
4
4
  module NdrDevSupport
5
- VERSION = '4.0.0'.freeze
5
+ VERSION = '4.1.0'.freeze
6
6
  end
@@ -0,0 +1,28 @@
1
+ namespace :ci do
2
+ desc 'commit_cop'
3
+ task commit_cop: 'ci:rugged:setup' do |t|
4
+ # Usage: bin/rake ci:commit_cop
5
+ require 'ndr_dev_support/rake_ci/commit_cop'
6
+
7
+ @attachments ||= []
8
+ changes = NdrDevSupport::RakeCI::CommitCop.changes(@commit)
9
+
10
+ NdrDevSupport::RakeCI::CommitCop::COMMIT_COPS.each do |klass|
11
+ attachment = klass.new.check(changes)
12
+ next if attachment.nil?
13
+
14
+ @attachments << attachment.merge(footer: "bundle exec rake #{t.name}")
15
+ puts attachment.to_yaml
16
+ end
17
+ end
18
+
19
+ desc 'changes'
20
+ task changes: 'ci:rugged:setup' do
21
+ # Usage: bin/rake ci:changes
22
+ require 'ndr_dev_support/rake_ci/commit_cop'
23
+
24
+ changes = NdrDevSupport::RakeCI::CommitCop.changes(@commit)
25
+
26
+ puts changes.inspect
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ namespace :ci do
2
+ desc 'Test the system'
3
+ task :minitest do
4
+ raise 'Your test command must be the rake default' unless Rake::Task.task_defined?('default')
5
+
6
+ # Run the tests
7
+ test_cmd = 'bundle exec rake ci:minitest:setup ci:simplecov:setup default'
8
+ test_cmd += ' 2>&1 >/dev/null' if ENV['RAKECI_HEADLESS']
9
+ system test_cmd
10
+
11
+ Rake::Task['ci:minitest:process'].invoke
12
+
13
+ next if ENV['RAKECI_HEADLESS']
14
+ puts @metrics.inspect
15
+ puts @attachments.inspect
16
+ end
17
+
18
+ namespace :minitest do
19
+ desc 'setup'
20
+ task :setup do
21
+ # Load the RakeCI reporter:
22
+ require 'minitest/rake_ci_reporter'
23
+
24
+ # Ensure spawned processes do the same:
25
+ ENV['RUBYOPT'] += ' -rminitest/rake_ci_reporter'
26
+ end
27
+
28
+ desc 'process'
29
+ task :process do
30
+ require 'minitest/rake_ci_reporter'
31
+
32
+ @attachments ||= []
33
+ @metrics ||= []
34
+
35
+ rake_ci_reporter = Minitest::RakeCIReporter.new
36
+ hash = rake_ci_reporter.load_current_commit_hash
37
+ if hash.nil?
38
+ # Tests didn't run properly
39
+ attachment = {
40
+ color: 'danger',
41
+ title: 'Testing Error',
42
+ text: "Minitest didn't run properly",
43
+ footer: 'bundle exec rake ci:minitest',
44
+ mrkdwn_in: ['text']
45
+ }
46
+ @attachments << attachment
47
+
48
+ next
49
+ end
50
+
51
+ # Test(s) ran
52
+ Rake::Task['ci:simplecov:process'].invoke
53
+
54
+ if hash[:statistics][:failures].zero? && hash[:statistics][:errors].zero? &&
55
+ Rake::Task.task_defined?('ci:redmine:update_tickets')
56
+ # Test(s) passing
57
+ Rake::Task['ci:redmine:update_tickets'].invoke
58
+ end
59
+
60
+ @attachments.concat(hash[:attachments])
61
+ @metrics.concat(hash[:metrics])
62
+ end
63
+ end
64
+ end
@@ -2,6 +2,7 @@ namespace :ci do
2
2
  namespace :prometheus do
3
3
  desc 'Set up Prometheus'
4
4
  task :setup do
5
+ require 'highline/import'
5
6
  @metrics = []
6
7
 
7
8
  ENV['PROMETHEUS_PUSHGATEWAY'] ||= ask('Prometheus pushgateway (host:port): ')
@@ -0,0 +1,41 @@
1
+ namespace :ci do
2
+ namespace :redmine do
3
+ desc 'Set up Redmine'
4
+ task :setup do
5
+ ENV['REDMINE_HOSTNAME'] ||= ask('Redmine URL: ')
6
+ ENV['REDMINE_HOSTNAME'] = nil if ENV['REDMINE_HOSTNAME'] == ''
7
+
8
+ ENV['REDMINE_API_KEY'] ||= ask('Redmine API Key: ') { |q| q.echo = '*' }
9
+ ENV['REDMINE_API_KEY'] = nil if ENV['REDMINE_API_KEY'] == ''
10
+ end
11
+
12
+ desc 'Update Redmine tickets'
13
+ task update_tickets: ['ci:rugged:setup', 'ci:redmine:setup'] do
14
+ api_key = ENV['REDMINE_API_KEY']
15
+ hostname = ENV['REDMINE_HOSTNAME']
16
+ next if api_key.nil? || hostname.nil?
17
+
18
+ require 'ndr_dev_support/rake_ci/redmine/ticket_resolver'
19
+
20
+ ticket_resolver = NdrDevSupport::RakeCI::Redmine::TicketResolver.new(api_key, hostname)
21
+ resolved_tickets = ticket_resolver.process_commit(@commit.author[:name],
22
+ @friendly_revision_name,
23
+ @commit.message)
24
+
25
+ next if resolved_tickets.empty?
26
+ resolved_tickets.map! { |ticket_id| "https://#{hostname}/issues/#{ticket_id}" }
27
+
28
+ issue_s = resolved_tickets.count == 1 ? 'issue' : 'issues'
29
+ attachment = {
30
+ color: 'good',
31
+ title: "#{issue_s.capitalize} Resolved",
32
+ text: "Tests pass, so #{issue_s} #{resolved_tickets.join(', ')}" \
33
+ " #{resolved_tickets.count == 1 ? 'has' : 'have'} been resolved",
34
+ footer: 'bundle exec rake ci:minitest',
35
+ mrkdwn_in: ['text']
36
+ }
37
+ @attachments ||= []
38
+ @attachments << attachment
39
+ end
40
+ end
41
+ end
@@ -2,6 +2,12 @@ namespace :ci do
2
2
  # Stub ci:all rake task
3
3
  task :all
4
4
 
5
+ desc 'publish'
6
+ task publish: [
7
+ 'ci:slack:publish',
8
+ 'ci:prometheus:publish'
9
+ ]
10
+
5
11
  desc 'Runs the Rake CI server'
6
12
  task :server do
7
13
  require 'ndr_dev_support/daemon/ci_server'
@@ -2,6 +2,7 @@ namespace :ci do
2
2
  namespace :slack do
3
3
  desc 'Set up Slack'
4
4
  task :setup do
5
+ require 'highline/import'
5
6
  @attachments = []
6
7
 
7
8
  ENV['SLACK_WEBHOOK_URL'] ||= ask('Slack Webhook URL: ')
@@ -45,6 +45,7 @@ Gem::Specification.new do |spec|
45
45
  spec.add_dependency 'github-linguist'
46
46
  spec.add_dependency 'prometheus-client'
47
47
  spec.add_dependency 'rugged'
48
+ spec.add_dependency 'simplecov'
48
49
  spec.add_dependency 'with_clean_rbenv'
49
50
 
50
51
  # Deployment dependencies:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndr_dev_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - NCRS Development Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-17 00:00:00.000000000 Z
11
+ date: 2018-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -234,6 +234,20 @@ dependencies:
234
234
  - - ">="
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: simplecov
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :runtime
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
237
251
  - !ruby/object:Gem::Dependency
238
252
  name: with_clean_rbenv
239
253
  requirement: !ruby/object:Gem::Requirement
@@ -335,6 +349,7 @@ files:
335
349
  - bin/console
336
350
  - bin/setup
337
351
  - code_safety.yml
352
+ - lib/minitest/rake_ci_reporter.rb
338
353
  - lib/ndr_dev_support.rb
339
354
  - lib/ndr_dev_support/capistrano/assets.rb
340
355
  - lib/ndr_dev_support/capistrano/ndr_model.rb
@@ -354,7 +369,13 @@ files:
354
369
  - lib/ndr_dev_support/integration_testing/drivers/switchable.rb
355
370
  - lib/ndr_dev_support/integration_testing/dsl.rb
356
371
  - lib/ndr_dev_support/rake_ci/brakeman_helper.rb
372
+ - lib/ndr_dev_support/rake_ci/commit_cop.rb
373
+ - lib/ndr_dev_support/rake_ci/commit_cop/concerns/deputisable.rb
374
+ - lib/ndr_dev_support/rake_ci/commit_cop/migration_without_structure_dump.rb
375
+ - lib/ndr_dev_support/rake_ci/commit_cop/modified_migration.rb
376
+ - lib/ndr_dev_support/rake_ci/commit_cop/renamed_migration.rb
357
377
  - lib/ndr_dev_support/rake_ci/concerns/commit_metadata_persistable.rb
378
+ - lib/ndr_dev_support/rake_ci/redmine/ticket_resolver.rb
358
379
  - lib/ndr_dev_support/rake_ci/simple_cov_helper.rb
359
380
  - lib/ndr_dev_support/rubocop/executor.rb
360
381
  - lib/ndr_dev_support/rubocop/range_augmenter.rb
@@ -366,11 +387,14 @@ files:
366
387
  - lib/tasks/audit_code.rake
367
388
  - lib/tasks/ci/brakeman.rake
368
389
  - lib/tasks/ci/bundle_audit.rake
390
+ - lib/tasks/ci/commit_cop.rake
369
391
  - lib/tasks/ci/dependencies.rake
370
392
  - lib/tasks/ci/housekeep.rake
371
393
  - lib/tasks/ci/linguist.rake
394
+ - lib/tasks/ci/minitest.rake
372
395
  - lib/tasks/ci/notes.rake
373
396
  - lib/tasks/ci/prometheus.rake
397
+ - lib/tasks/ci/redmine.rake
374
398
  - lib/tasks/ci/rugged.rake
375
399
  - lib/tasks/ci/server.rake
376
400
  - lib/tasks/ci/simplecov.rake