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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +8 -4
- data/code_safety.yml +68 -12
- data/lib/minitest/rake_ci_reporter.rb +115 -0
- data/lib/ndr_dev_support/daemon/ci_server.rb +16 -2
- data/lib/ndr_dev_support/rake_ci/commit_cop.rb +64 -0
- data/lib/ndr_dev_support/rake_ci/commit_cop/concerns/deputisable.rb +42 -0
- data/lib/ndr_dev_support/rake_ci/commit_cop/migration_without_structure_dump.rb +21 -0
- data/lib/ndr_dev_support/rake_ci/commit_cop/modified_migration.rb +20 -0
- data/lib/ndr_dev_support/rake_ci/commit_cop/renamed_migration.rb +23 -0
- data/lib/ndr_dev_support/rake_ci/redmine/ticket_resolver.rb +101 -0
- data/lib/ndr_dev_support/tasks.rb +3 -0
- data/lib/ndr_dev_support/version.rb +1 -1
- data/lib/tasks/ci/commit_cop.rake +28 -0
- data/lib/tasks/ci/minitest.rake +64 -0
- data/lib/tasks/ci/prometheus.rake +1 -0
- data/lib/tasks/ci/redmine.rake +41 -0
- data/lib/tasks/ci/server.rake +6 -0
- data/lib/tasks/ci/slack.rake +1 -0
- data/ndr_dev_support.gemspec +1 -0
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2b84dc423c034b919fb74cd67458fc885d4f6565f4ad5798d2fbf201d8ddfc0
|
4
|
+
data.tar.gz: 26689488b7846c1edaf32f45f2a60976b4b7938a7af6d12a1626dce91d1c838a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f58716ac63abaeb4597084393f44528fa1f7426f3dce76f71fc771a3427a3dd5edcc5ee30df7e817ed35ba553107cca2997590aab1ff11811a850fe4941263e
|
7
|
+
data.tar.gz: a41b7019ba639d84bb3b28f01773c6aa3e69c217fadd8995655c90ec7c0392f7692288448dd23b029ffd92c86b97a6ca5a2fc6c2c4693830326b3a009dce9e62
|
data/.gitignore
CHANGED
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:
|
6
|
-
safe_revision:
|
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:
|
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:
|
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:
|
182
|
+
safe_revision: 2154aa7f32e731933ff6091b8f42b2b014028a6a
|
155
183
|
lib/ndr_dev_support/version.rb:
|
156
184
|
comments:
|
157
185
|
reviewed_by: josh.pencheon
|
158
|
-
safe_revision:
|
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:
|
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:
|
199
|
-
safe_revision:
|
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:
|
207
|
-
safe_revision:
|
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:
|
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
|
-
|
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
|
-
|
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'
|
@@ -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
|
@@ -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
|
data/lib/tasks/ci/server.rake
CHANGED
data/lib/tasks/ci/slack.rake
CHANGED
data/ndr_dev_support.gemspec
CHANGED
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.
|
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-
|
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
|