semverve 0.2.1 → 0.4.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 +4 -4
- data/CONTRIBUTING.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +166 -32
- data/UPGRADING.md +78 -0
- data/lib/semverve/adapters.rb +292 -0
- data/lib/semverve/configuration.rb +64 -39
- data/lib/semverve/finding.rb +55 -0
- data/lib/semverve/fix_result.rb +39 -0
- data/lib/semverve/{version_metadata.rb → package_metadata.rb} +36 -116
- data/lib/semverve/presets.rb +4 -100
- data/lib/semverve/project_metadata.rb +8 -5
- data/lib/semverve/rails_config_metadata.rb +176 -0
- data/lib/semverve/railtie.rb +1 -1
- data/lib/semverve/task.rb +166 -114
- data/lib/semverve/version.rb +2 -2
- data/lib/semverve/version_checks.rb +518 -0
- data/lib/semverve/version_code_references.rb +53 -89
- data/lib/semverve/version_literal_rewriter.rb +78 -0
- data/lib/semverve/version_match_policy.rb +62 -0
- data/lib/semverve/version_references.rb +32 -88
- data/lib/semverve.rb +4 -0
- metadata +10 -2
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "error"
|
|
4
|
+
require_relative "package_metadata"
|
|
5
|
+
require_relative "rails_config_metadata"
|
|
6
|
+
require_relative "version_code_references"
|
|
7
|
+
require_relative "version_references"
|
|
8
|
+
|
|
9
|
+
module Semverve
|
|
10
|
+
##
|
|
11
|
+
# Registry and check adapters for version-maintenance surfaces.
|
|
12
|
+
module VersionChecks
|
|
13
|
+
class << self
|
|
14
|
+
##
|
|
15
|
+
# Registers a core version check.
|
|
16
|
+
#
|
|
17
|
+
# @param [#name] check
|
|
18
|
+
#
|
|
19
|
+
# @return [#name]
|
|
20
|
+
def register(check)
|
|
21
|
+
core_checks[check.name] = check
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# All checks available to task dispatch and validation.
|
|
26
|
+
#
|
|
27
|
+
# @param [Array<#name>] extra_checks
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<#name>]
|
|
30
|
+
def all(extra_checks: [])
|
|
31
|
+
(core_checks.values + extra_checks).each_with_object({}) do |check, checks|
|
|
32
|
+
checks[check.name] = check
|
|
33
|
+
end.values
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Fetches a registered check by name.
|
|
38
|
+
#
|
|
39
|
+
# @param [Symbol, String] name
|
|
40
|
+
# @param [Array<#name>] extra_checks
|
|
41
|
+
#
|
|
42
|
+
# @return [#name]
|
|
43
|
+
def fetch(name, extra_checks: [])
|
|
44
|
+
normalized_name = normalize_name(name)
|
|
45
|
+
check = all(extra_checks: extra_checks).find { |candidate| candidate.name == normalized_name }
|
|
46
|
+
return check if check
|
|
47
|
+
|
|
48
|
+
raise Error, unknown_check_message([normalized_name], extra_checks: extra_checks)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Validates and normalizes configured check names.
|
|
53
|
+
#
|
|
54
|
+
# @param [Array<Symbol, String>] checks
|
|
55
|
+
# @param [Array<#name>] extra_checks
|
|
56
|
+
#
|
|
57
|
+
# @return [Array<Symbol>]
|
|
58
|
+
def normalize(checks, extra_checks: [])
|
|
59
|
+
normalized_checks = Array(checks).map { |check| normalize_name(check) }
|
|
60
|
+
valid_names = names(extra_checks: extra_checks)
|
|
61
|
+
return normalized_checks if normalized_checks.all? { |check| valid_names.include?(check) }
|
|
62
|
+
|
|
63
|
+
invalid_checks = normalized_checks.reject { |check| valid_names.include?(check) }
|
|
64
|
+
raise Error, unknown_check_message(invalid_checks, extra_checks: extra_checks)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# Registered check names.
|
|
69
|
+
#
|
|
70
|
+
# @param [Array<#name>] extra_checks
|
|
71
|
+
#
|
|
72
|
+
# @return [Array<Symbol>]
|
|
73
|
+
def names(extra_checks: [])
|
|
74
|
+
all(extra_checks: extra_checks).map(&:name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Default core version-maintenance surfaces for package projects.
|
|
79
|
+
#
|
|
80
|
+
# @return [Array<Symbol>]
|
|
81
|
+
def default_names
|
|
82
|
+
[:doc_references, :code_references, :package_metadata]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Core check registry.
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash<Symbol, #name>]
|
|
91
|
+
def core_checks
|
|
92
|
+
@core_checks ||= {}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Normalizes a check name.
|
|
97
|
+
#
|
|
98
|
+
# @param [Object] name
|
|
99
|
+
#
|
|
100
|
+
# @return [Symbol, Object]
|
|
101
|
+
def normalize_name(name)
|
|
102
|
+
name.respond_to?(:to_sym) ? name.to_sym : name
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# Error message for invalid checks.
|
|
107
|
+
#
|
|
108
|
+
# @param [Array<Symbol>] invalid_checks
|
|
109
|
+
# @param [Array<#name>] extra_checks
|
|
110
|
+
#
|
|
111
|
+
# @return [String]
|
|
112
|
+
def unknown_check_message(invalid_checks, extra_checks:)
|
|
113
|
+
valid_check_names = names(extra_checks: extra_checks).map(&:inspect)
|
|
114
|
+
valid_checks = "#{valid_check_names[0...-1].join(", ")}, or #{valid_check_names.last}"
|
|
115
|
+
"Unknown version check #{invalid_checks.map(&:inspect).join(", ")}. Use #{valid_checks}."
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Base behavior for check adapters. Public check objects must expose name,
|
|
121
|
+
# task_name, descriptions, labels, findings, and fix.
|
|
122
|
+
class Check
|
|
123
|
+
##
|
|
124
|
+
# Whether focused task accepts an exact target version argument.
|
|
125
|
+
#
|
|
126
|
+
# @return [Boolean]
|
|
127
|
+
def targetable?
|
|
128
|
+
false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# Whether findings should print a note when an exact target is already current.
|
|
133
|
+
#
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
def exact_target_fix_noop_notice?
|
|
136
|
+
false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
# Rake task argument names for the focused task.
|
|
141
|
+
#
|
|
142
|
+
# @return [Array<Symbol>]
|
|
143
|
+
def task_arguments
|
|
144
|
+
targetable? ? [:version] : []
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
##
|
|
148
|
+
# Label used when reporting replacement counts.
|
|
149
|
+
#
|
|
150
|
+
# @return [String]
|
|
151
|
+
def fix_label
|
|
152
|
+
finding_label
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
##
|
|
156
|
+
# Finds mismatches.
|
|
157
|
+
#
|
|
158
|
+
# @return [Array]
|
|
159
|
+
def findings(_configuration, _current_version, include_ignored: false, target_version: nil)
|
|
160
|
+
raise NotImplementedError
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Fixes mismatches.
|
|
165
|
+
#
|
|
166
|
+
# @return [#changed_files, #replacement_count]
|
|
167
|
+
def fix(_configuration, _current_version, target_version: nil)
|
|
168
|
+
raise NotImplementedError
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
##
|
|
173
|
+
# Documentation/reference version check.
|
|
174
|
+
class DocReferences < Check
|
|
175
|
+
##
|
|
176
|
+
# Initializes the check.
|
|
177
|
+
#
|
|
178
|
+
# @param [Class] scanner
|
|
179
|
+
#
|
|
180
|
+
# @return [Semverve::VersionChecks::DocReferences]
|
|
181
|
+
def initialize(scanner: VersionReferences)
|
|
182
|
+
@scanner = scanner
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
##
|
|
186
|
+
# Public check name used in +config.version_checks+.
|
|
187
|
+
#
|
|
188
|
+
# @return [Symbol]
|
|
189
|
+
def name
|
|
190
|
+
:doc_references
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
##
|
|
194
|
+
# Focused Rake task suffix.
|
|
195
|
+
#
|
|
196
|
+
# @return [Symbol]
|
|
197
|
+
def task_name
|
|
198
|
+
:references
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
##
|
|
202
|
+
# Focused check task description.
|
|
203
|
+
#
|
|
204
|
+
# @return [String]
|
|
205
|
+
def check_description
|
|
206
|
+
"Check configured files for stale version references"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
##
|
|
210
|
+
# Focused fix task description.
|
|
211
|
+
#
|
|
212
|
+
# @return [String]
|
|
213
|
+
def fix_description
|
|
214
|
+
"Replace stale version references in configured files"
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
##
|
|
218
|
+
# Label printed for findings and replacement counts.
|
|
219
|
+
#
|
|
220
|
+
# @return [String]
|
|
221
|
+
def finding_label
|
|
222
|
+
"version reference"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
##
|
|
226
|
+
# Message printed when no findings or replacements exist.
|
|
227
|
+
#
|
|
228
|
+
# @return [String]
|
|
229
|
+
def clean_message
|
|
230
|
+
"Version references are current."
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def targetable?
|
|
234
|
+
true
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def exact_target_fix_noop_notice?
|
|
238
|
+
true
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def findings(configuration, current_version, include_ignored: false, target_version: nil)
|
|
242
|
+
scanner.new(
|
|
243
|
+
configuration,
|
|
244
|
+
current_version,
|
|
245
|
+
include_ignored: include_ignored,
|
|
246
|
+
target_version: target_version
|
|
247
|
+
).findings
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def fix(configuration, current_version, target_version: nil)
|
|
251
|
+
scanner.new(configuration, current_version, target_version: target_version).fix
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
private
|
|
255
|
+
|
|
256
|
+
##
|
|
257
|
+
# Scanner/fixer class used by the check.
|
|
258
|
+
#
|
|
259
|
+
# @return [Class]
|
|
260
|
+
attr_reader :scanner
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
##
|
|
264
|
+
# Code literal version check.
|
|
265
|
+
class CodeReferences < Check
|
|
266
|
+
##
|
|
267
|
+
# Initializes the check.
|
|
268
|
+
#
|
|
269
|
+
# @param [Class] scanner
|
|
270
|
+
#
|
|
271
|
+
# @return [Semverve::VersionChecks::CodeReferences]
|
|
272
|
+
def initialize(scanner: VersionCodeReferences)
|
|
273
|
+
@scanner = scanner
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
##
|
|
277
|
+
# Public check name used in +config.version_checks+.
|
|
278
|
+
#
|
|
279
|
+
# @return [Symbol]
|
|
280
|
+
def name
|
|
281
|
+
:code_references
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
##
|
|
285
|
+
# Focused Rake task suffix.
|
|
286
|
+
#
|
|
287
|
+
# @return [Symbol]
|
|
288
|
+
def task_name
|
|
289
|
+
:code
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
##
|
|
293
|
+
# Focused check task description.
|
|
294
|
+
#
|
|
295
|
+
# @return [String]
|
|
296
|
+
def check_description
|
|
297
|
+
"Check configured code files for version literals"
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
##
|
|
301
|
+
# Focused fix task description.
|
|
302
|
+
#
|
|
303
|
+
# @return [String]
|
|
304
|
+
def fix_description
|
|
305
|
+
"Replace safe code version literals in configured files"
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
##
|
|
309
|
+
# Label printed for findings and replacement counts.
|
|
310
|
+
#
|
|
311
|
+
# @return [String]
|
|
312
|
+
def finding_label
|
|
313
|
+
"code version literal"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
##
|
|
317
|
+
# Message printed when no findings or replacements exist.
|
|
318
|
+
#
|
|
319
|
+
# @return [String]
|
|
320
|
+
def clean_message
|
|
321
|
+
"Code version literals are current."
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def targetable?
|
|
325
|
+
true
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def exact_target_fix_noop_notice?
|
|
329
|
+
true
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def findings(configuration, current_version, include_ignored: false, target_version: nil)
|
|
333
|
+
scanner.new(
|
|
334
|
+
configuration,
|
|
335
|
+
current_version,
|
|
336
|
+
include_ignored: include_ignored,
|
|
337
|
+
target_version: target_version
|
|
338
|
+
).findings
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def fix(configuration, current_version, target_version: nil)
|
|
342
|
+
scanner.new(configuration, current_version, target_version: target_version).fix
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
private
|
|
346
|
+
|
|
347
|
+
##
|
|
348
|
+
# Scanner/fixer class used by the check.
|
|
349
|
+
#
|
|
350
|
+
# @return [Class]
|
|
351
|
+
attr_reader :scanner
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
##
|
|
355
|
+
# Package metadata version check.
|
|
356
|
+
class PackageMetadataCheck < Check
|
|
357
|
+
##
|
|
358
|
+
# Initializes the check.
|
|
359
|
+
#
|
|
360
|
+
# @param [Class] scanner
|
|
361
|
+
#
|
|
362
|
+
# @return [Semverve::VersionChecks::PackageMetadataCheck]
|
|
363
|
+
def initialize(scanner: PackageMetadata)
|
|
364
|
+
@scanner = scanner
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
##
|
|
368
|
+
# Public check name used in +config.version_checks+.
|
|
369
|
+
#
|
|
370
|
+
# @return [Symbol]
|
|
371
|
+
def name
|
|
372
|
+
:package_metadata
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
##
|
|
376
|
+
# Focused Rake task suffix.
|
|
377
|
+
#
|
|
378
|
+
# @return [Symbol]
|
|
379
|
+
def task_name
|
|
380
|
+
:package_metadata
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
##
|
|
384
|
+
# Focused check task description.
|
|
385
|
+
#
|
|
386
|
+
# @return [String]
|
|
387
|
+
def check_description
|
|
388
|
+
"Check package metadata for version mismatches"
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
##
|
|
392
|
+
# Focused fix task description.
|
|
393
|
+
#
|
|
394
|
+
# @return [String]
|
|
395
|
+
def fix_description
|
|
396
|
+
"Fix safe package metadata version mismatches"
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
##
|
|
400
|
+
# Package findings provide their own labels.
|
|
401
|
+
#
|
|
402
|
+
# @return [nil]
|
|
403
|
+
def finding_label
|
|
404
|
+
nil
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def fix_label
|
|
408
|
+
"package metadata version"
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
##
|
|
412
|
+
# Message printed when no findings or replacements exist.
|
|
413
|
+
#
|
|
414
|
+
# @return [String]
|
|
415
|
+
def clean_message
|
|
416
|
+
"Package metadata is current."
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def findings(configuration, current_version, include_ignored: false, target_version: nil)
|
|
420
|
+
scanner.new(configuration, current_version).findings
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def fix(configuration, current_version, target_version: nil)
|
|
424
|
+
scanner.new(configuration, current_version).fix
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
private
|
|
428
|
+
|
|
429
|
+
##
|
|
430
|
+
# Scanner/fixer class used by the check.
|
|
431
|
+
#
|
|
432
|
+
# @return [Class]
|
|
433
|
+
attr_reader :scanner
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
##
|
|
437
|
+
# Rails config metadata version check.
|
|
438
|
+
class RailsConfigMetadataCheck < Check
|
|
439
|
+
##
|
|
440
|
+
# Initializes the check.
|
|
441
|
+
#
|
|
442
|
+
# @param [Class] scanner
|
|
443
|
+
#
|
|
444
|
+
# @return [Semverve::VersionChecks::RailsConfigMetadataCheck]
|
|
445
|
+
def initialize(scanner: RailsConfigMetadata)
|
|
446
|
+
@scanner = scanner
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
##
|
|
450
|
+
# Public check name used in +config.version_checks+.
|
|
451
|
+
#
|
|
452
|
+
# @return [Symbol]
|
|
453
|
+
def name
|
|
454
|
+
:rails_config_metadata
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
##
|
|
458
|
+
# Focused Rake task suffix.
|
|
459
|
+
#
|
|
460
|
+
# @return [Symbol]
|
|
461
|
+
def task_name
|
|
462
|
+
:rails_config_metadata
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
##
|
|
466
|
+
# Focused check task description.
|
|
467
|
+
#
|
|
468
|
+
# @return [String]
|
|
469
|
+
def check_description
|
|
470
|
+
"Check Rails config metadata for version mismatches"
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
##
|
|
474
|
+
# Focused fix task description.
|
|
475
|
+
#
|
|
476
|
+
# @return [String]
|
|
477
|
+
def fix_description
|
|
478
|
+
"Fix safe Rails config metadata version mismatches"
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
##
|
|
482
|
+
# Label printed for Rails config metadata findings and replacements.
|
|
483
|
+
#
|
|
484
|
+
# @return [String]
|
|
485
|
+
def finding_label
|
|
486
|
+
"Rails config version"
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
##
|
|
490
|
+
# Message printed when no findings or replacements exist.
|
|
491
|
+
#
|
|
492
|
+
# @return [String]
|
|
493
|
+
def clean_message
|
|
494
|
+
"Rails config metadata is current."
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def findings(configuration, current_version, include_ignored: false, target_version: nil)
|
|
498
|
+
scanner.new(configuration, current_version).findings
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def fix(configuration, current_version, target_version: nil)
|
|
502
|
+
scanner.new(configuration, current_version).fix
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
private
|
|
506
|
+
|
|
507
|
+
##
|
|
508
|
+
# Scanner/fixer class used by the check.
|
|
509
|
+
#
|
|
510
|
+
# @return [Class]
|
|
511
|
+
attr_reader :scanner
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
Semverve::VersionChecks.register(Semverve::VersionChecks::DocReferences.new)
|
|
517
|
+
Semverve::VersionChecks.register(Semverve::VersionChecks::CodeReferences.new)
|
|
518
|
+
Semverve::VersionChecks.register(Semverve::VersionChecks::PackageMetadataCheck.new)
|