version_boss 0.1.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.
@@ -0,0 +1,443 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module VersionBoss
6
+ module Gem
7
+ # rubocop:disable Metrics/ClassLength
8
+
9
+ # The version_boss cli
10
+ #
11
+ # @example
12
+ # require 'version_boss'
13
+ #
14
+ # VersionBoss::CommandLine.start(ARGV)
15
+ #
16
+ # @api private
17
+ #
18
+ class CommandLine < Thor
19
+ # Tell Thor to exit with a non-zero status code if a command fails
20
+ def self.exit_on_failure? = true
21
+
22
+ desc 'current [-q]', 'Show the current gem version'
23
+
24
+ long_desc <<-LONG_DESC
25
+ Output the current gem version from the file that stores the gem version.
26
+
27
+ The command fails if the gem version could not be found or is invalid.
28
+
29
+ Use `--quiet` to ensure that a gem version could be found and is valid without producing any output.
30
+ LONG_DESC
31
+
32
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the current version to stdout'
33
+
34
+ # Show the current gem version
35
+ # @return [void]
36
+ def current
37
+ version_file = VersionBoss::Gem::VersionFileFactory.find
38
+
39
+ if version_file.nil?
40
+ warn 'version file not found or is not valid' unless options[:quiet]
41
+ exit 1
42
+ end
43
+
44
+ puts version_file.version unless options[:quiet]
45
+ end
46
+
47
+ desc 'file [-q]', 'Show the path to the file containing the gem version'
48
+
49
+ long_desc <<-LONG_DESC
50
+ Output the relative path to the file that stores the gem version.
51
+
52
+ The command fails if the gem version could not be found.
53
+
54
+ Use `--quiet` to ensure that a gem version could be found without producing any output.
55
+ LONG_DESC
56
+
57
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the version file path to stdout'
58
+
59
+ # Show the gem's version file
60
+ # @return [void]
61
+ def file
62
+ version_file = VersionBoss::Gem::VersionFileFactory.find
63
+
64
+ if version_file.nil?
65
+ warn 'version file not found or is not valid' unless options[:quiet]
66
+ exit 1
67
+ end
68
+
69
+ puts version_file.path unless options[:quiet]
70
+ end
71
+
72
+ desc 'next-major [VERSION] [-p [-t TYPE]] [-n] [-q]', "Increment the version's major part"
73
+
74
+ long_desc <<-LONG_DESC
75
+ Increase the current gem version to the next major version, update the
76
+ file that stores the version, and output the resulting version to stdout.
77
+
78
+ Increments 1.x.y to 2.0.0.
79
+
80
+ The command fails if the current gem version file could not be found or
81
+ if the version is not valid.
82
+
83
+ If VERSION is given, use that instead of the current gem version. Giving
84
+ VERSION implies --dry-run. The command fails if VERSION is not valid.
85
+
86
+ --pre can be used to specify that the version should be incremented AND
87
+ given a pre-release part. For instance:
88
+
89
+ $ version_boss next-major --pre
90
+
91
+ increments '1.2.3' to '2.0.0.pre.1'.
92
+
93
+ By default, the pre-release type is 'pre'. --pre-type=TYPE can be used with
94
+ --pre to specify a different pre-release type such as alpha, beta, rc, etc.
95
+ For instance:
96
+
97
+ $ version_boss next-major --pre --pre-type=alpha
98
+
99
+ increments '1.2.3' to '2.0.0-alpha.1'.
100
+
101
+ The command fails if the existing pre-release type is not lexically less than or
102
+ equal to TYPE. For example, it the current version is '1.2.3-beta.1' and TYPE
103
+ is 'alpha', the the command will fail since the new version would sort before the
104
+ existing version ('beta' is not less than or equal to 'alpha').
105
+
106
+ Use --dry-run to run this command without updating the version file.
107
+
108
+ Use --quiet to increment the version without producing any output.
109
+ LONG_DESC
110
+
111
+ option :pre, type: :boolean, aliases: '-p', desc: 'Create a pre-release version'
112
+ option :'pre-type', type: :string, aliases: '-t', default: 'pre', banner: 'TYPE',
113
+ desc: 'The type of pre-release version (alpha, beta, etc.)'
114
+ option :'dry-run', type: :boolean, aliases: '-n', desc: 'Do not write the new version to the version file'
115
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the new version to stdout'
116
+
117
+ # Increment the gem version's major part
118
+ # @param version [String, nil] The version to increment or nil to use the version
119
+ # from the gem's version file
120
+ # @return [void]
121
+ def next_major(version = nil)
122
+ increment_core_version(:next_major, version)
123
+ end
124
+
125
+ desc 'next-minor [VERSION] [-p [-t TYPE]] [-n] [-q]', "Increment the version's minor part"
126
+
127
+ long_desc <<-LONG_DESC
128
+ Increase the current gem version to the next minor version, update the
129
+ file that stores the version, and output the resulting version to stdout.
130
+
131
+ Increments 1.2.y to 1.3.0.
132
+
133
+ The command fails if the current gem version file could not be found or
134
+ if the version is not valid.
135
+
136
+ If VERSION is given, use that instead of the current gem version. Giving
137
+ VERSION implies --dry-run. The command fails if VERSION is not valid.
138
+
139
+ --pre can be used to specify that the version should be incremented AND
140
+ given a pre-release part. For instance:
141
+
142
+ $ version_boss next-minor --pre
143
+
144
+ increments '1.2.3' to '2.0.0.pre.1'.
145
+
146
+ By default, the pre-release type is 'pre'. --pre-type=TYPE can be used with
147
+ --pre to specify a different pre-release type such as alpha, beta, rc, etc.
148
+ For instance:
149
+
150
+ $ version_boss next-patch --pre --pre-type=alpha
151
+
152
+ increments '1.2.3' to '1.2.4-alpha.1'.
153
+
154
+ The command fails if the existing pre-release type is not lexically less than or
155
+ equal to TYPE. For example, it the current version is '1.2.3-beta.1' and TYPE
156
+ is 'alpha', the the command will fail since the new version would sort before the
157
+ existing version ('beta' is not less than or equal to 'alpha').
158
+
159
+ Use --dry-run to run this command without updating the version file.
160
+
161
+ Use --quiet to increment the version without producing any output.
162
+ LONG_DESC
163
+
164
+ option :pre, type: :boolean, aliases: '-p', desc: 'Create a pre-release version'
165
+ option :'pre-type', type: :string, aliases: '-t', default: 'pre', banner: 'TYPE',
166
+ desc: 'The type of pre-release version (alpha, beta, etc.)'
167
+ option :'dry-run', type: :boolean, aliases: '-n', desc: 'Do not write the new version to the version file'
168
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the new version to stdout'
169
+
170
+ # Increment the gem version's minor part
171
+ # @param version [String, nil] The version to increment or nil to use the version
172
+ # from the gem's version file
173
+ # @return [void]
174
+ def next_minor(version = nil)
175
+ increment_core_version(:next_minor, version)
176
+ end
177
+
178
+ desc 'next-patch [VERSION] [-p [-t TYPE]] [-n] [-q]', "Increment the version's patch part"
179
+
180
+ long_desc <<-LONG_DESC
181
+ Increase the current gem version to the next patch version, update the
182
+ file that stores the version, and output the resulting version to stdout.
183
+
184
+ Increments 1.2.3 to 1.2.4.
185
+
186
+ The command fails if the current gem version file could not be found or
187
+ if the version is not valid.
188
+
189
+ If VERSION is given, use that instead of the current gem version. Giving
190
+ VERSION implies --dry-run. The command fails if VERSION is not valid.
191
+
192
+ --pre can be used to specify that the version should be incremented AND
193
+ given a pre-release part. For instance:
194
+
195
+ $ version_boss next-patch --pre
196
+
197
+ increments '1.2.3' to '1.2.4.pre.1'.
198
+
199
+ By default, the pre-release type is 'pre'. --pre-type=TYPE can be used with
200
+ --pre to specify a different pre-release type such as alpha, beta, rc, etc.
201
+ For instance:
202
+
203
+ $ version_boss next-patch --pre --pre-type=alpha
204
+
205
+ increments '1.2.3' to '1.2.4-alpha.1'.
206
+
207
+ The command fails if the existing pre-release type is not lexically less than or
208
+ equal to TYPE. For example, it the current version is '1.2.3-beta.1' and TYPE
209
+ is 'alpha', the the command will fail since the new version would sort before the
210
+ existing version ('beta' is not less than or equal to 'alpha').
211
+
212
+ Use --dry-run to run this command without updating the version file.
213
+
214
+ Use --quiet to increment the version without producing any output.
215
+ LONG_DESC
216
+
217
+ option :pre, type: :boolean, aliases: '-p', desc: 'Create a pre-release version'
218
+ option :'pre-type', type: :string, aliases: '-t', default: 'pre', banner: 'TYPE',
219
+ desc: 'The type of pre-release version (alpha, beta, etc.)'
220
+ option :'dry-run', type: :boolean, aliases: '-n', desc: 'Do not write the new version to the version file'
221
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the new version to stdout'
222
+
223
+ # Increment the gem version's patch part
224
+ # @param version [String, nil] The version to increment or nil to use the version
225
+ # from the gem's version file
226
+ # @return [void]
227
+ def next_patch(version = nil)
228
+ increment_core_version(:next_patch, version)
229
+ end
230
+
231
+ desc 'next-pre [VERSION] [-t TYPE] [-n] [-q]', "Increment the version's pre-release part"
232
+
233
+ long_desc <<-LONG_DESC
234
+ Increase the current gem version to the next pre-release version, update the
235
+ file that stores the version, and output the resulting version to stdout.
236
+
237
+ The command fails if the current gem version file could not be found or
238
+ the version is not a valid pre-release version.
239
+
240
+ If VERSION is given, use that instead of the current gem version. Giving
241
+ VERSION implies --dry-run. The command fails if VERSION is not a valid
242
+ pre-release version.
243
+
244
+ By default, the existing pre-release type is preserved. For instance:
245
+
246
+ $ version_boss next-pre
247
+
248
+ Increments 1.2.3-alpha.1 to 1.2.3-alpha.2.
249
+
250
+ --pre-type=TYPE can be used to change the pre-release type to TYPE (typical
251
+ examples include alpha, beta, rc, etc.). If the pre-release type is changed,
252
+ the pre-release number is reset to 1.
253
+
254
+ For example, if the version starts as 1.2.3-alpha.4, then:
255
+
256
+ $ version_boss current
257
+ 1.2.3-alpha.4
258
+ $ semver next-pre --pre-type=beta
259
+ 1.2.3-beta.1
260
+ $ semver next-pre --pre-type=beta
261
+ 1.2.3-beta.2
262
+ $ semver next-pre --pre-type=rc
263
+ 1.2.3-rc.1
264
+ $ version_boss next-release
265
+ 1.2.3
266
+
267
+ The command fails if the existing pre-release type is not lexically less than or
268
+ equal to TYPE. For example, it the current version is '1.2.3-beta.1' and the TYPE
269
+ given type is 'alpha', then the command will fail since the new version would sort
270
+ before the existing version (since 'beta' is not <= 'alpha').
271
+
272
+ Use --dry-run to run this command without updating the version file.
273
+
274
+ Use --quiet to increment the version without producing any output.
275
+ LONG_DESC
276
+
277
+ option :'pre-type', type: :string, aliases: '-t', banner: 'TYPE',
278
+ desc: 'The type of pre-release version (alpha, beta, etc.)'
279
+ option :'dry-run', type: :boolean, aliases: '-n', desc: 'Do not write the new version to the version file'
280
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the new version to stdout'
281
+
282
+ # Increment the gem version's pre-release part
283
+ # @param version [String, nil] The version to increment or nil to use the version
284
+ # from the gem's version file
285
+ # @return [void]
286
+ def next_pre(version = nil)
287
+ args = {}
288
+ args[:pre_type] = options[:'pre-type'] if options[:'pre-type']
289
+
290
+ new_version = increment_version(:next_pre, args, version)
291
+
292
+ puts new_version unless options[:quiet]
293
+ end
294
+
295
+ desc 'next-release [VERSION] [-n] [-q]', 'Increment a pre-release version to the release version'
296
+
297
+ long_desc <<-LONG_DESC
298
+ Increase the current gem version to the next release version, update the
299
+ file that stores the version, and output the resulting version to stdout.
300
+
301
+ Increments 1.2.3-rc.4 to 1.2.3.
302
+
303
+ The command fails if the current gem version file could not be found or
304
+ the version is not a valid pre-release version.
305
+
306
+ If VERSION is given, use that instead of the current gem version. Giving
307
+ VERSION implies --dry-run. The command fails if VERSION is not a valid
308
+ pre-release version.
309
+
310
+ Use --dry-run to run this command without updating the version file.
311
+
312
+ Use --quiet to increment the version without producing any output.
313
+ LONG_DESC
314
+
315
+ option :'dry-run', type: :boolean, aliases: '-n', desc: 'Do not write the new version to the version file'
316
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the new version to stdout'
317
+
318
+ # Increment the gem's pre-release version to a release version
319
+ # @param version [String, nil] The version to increment or nil to use the version
320
+ # from the gem's version file
321
+ # @return [void]
322
+ def next_release(version = nil)
323
+ args = {}
324
+ new_version = increment_version(:next_release, args, version)
325
+
326
+ puts new_version unless options[:quiet]
327
+ end
328
+
329
+ desc 'validate VERSION [-q]', 'Validate the given version'
330
+
331
+ long_desc <<-LONG_DESC
332
+ Validate and output the given gem version.
333
+
334
+ The command fails if the gem version is not valid.
335
+
336
+ Use `--quiet` to validate the gem version without producing any output.
337
+ LONG_DESC
338
+
339
+ option :quiet, type: :boolean, aliases: '-q', desc: 'Do not print the given version to stdout'
340
+
341
+ # Validate that the give version is a valid IncrementableSemver version
342
+ # @param version [String] The version to validate
343
+ # @return [void]
344
+ #
345
+ def validate(version)
346
+ VersionBoss::Gem::IncrementableVersion.new(version)
347
+ rescue VersionBoss::Error => e
348
+ warn e.message unless options[:quiet]
349
+ exit 1
350
+ else
351
+ puts version unless options[:quiet]
352
+ end
353
+
354
+ private
355
+
356
+ # Build a hash of arguments to pass to the IncrementableSemver methods
357
+ #
358
+ # These arguments are specificly for the #next_major, #next_minor, and
359
+ # #next_patch method.
360
+ #
361
+ # @return [Hash]
362
+ #
363
+ def core_args
364
+ {}.tap do |args|
365
+ args[:pre] = options[:pre] if options[:pre]
366
+ args[:pre_type] = options[:'pre-type'] if options[:'pre-type']
367
+ end
368
+ end
369
+
370
+ # Increment the gem's major, minor, or patch version
371
+ #
372
+ # @param method [Symbol] The method to call on the IncrementableSemver object
373
+ # @param version [String, nil] The version to increment or nil to use the version
374
+ # from the gem's version file
375
+ #
376
+ # @return [Void]
377
+ #
378
+ def increment_core_version(method, version)
379
+ new_version = increment_version(method, core_args, version)
380
+
381
+ puts new_version unless options[:quiet]
382
+ end
383
+
384
+ # Increment the gem's version
385
+ #
386
+ # @param method [Symbol] The method to call on the IncrementableSemver object
387
+ #
388
+ # The method can bee one of: :next_major, :next_minor, :next_patch, :next_pre, :next_release
389
+ #
390
+ # @param args [Hash] The arguments to pass to the method
391
+ #
392
+ # @param version [String, nil] The version to increment or nil to use the version
393
+ #
394
+ # @return [Void]
395
+ #
396
+ def increment_version(method, args, version)
397
+ if version
398
+ increment_literal_version(method, args, version)
399
+ else
400
+ increment_gem_version(method, args)
401
+ end
402
+ rescue VersionBoss::Error => e
403
+ warn e.message unless options[:quiet]
404
+ exit 1
405
+ end
406
+
407
+ # Increment a literal version from a string
408
+ #
409
+ # @param method [Symbol] The method to call on the IncrementableSemver object
410
+ # @param args [Hash] The arguments to pass to the method
411
+ # @param version [String] The version to increment
412
+ #
413
+ # @return [VersionBoss::IncrementableRubyVersion] the incremented version
414
+ # @raise [VersionBoss::Error] if the version is not a valid IncrementableSemver version
415
+ #
416
+ def increment_literal_version(method, args, version)
417
+ VersionBoss::Gem::IncrementableVersion.new(version).send(method, **args)
418
+ end
419
+
420
+ # Increment the gem's version from the gem's version file
421
+ #
422
+ # @param method [Symbol] The method to call on the IncrementableSemver object
423
+ # @param args [Hash] The arguments to pass to the method
424
+ #
425
+ # @return [VersionBoss::IncrementableRubyVersion] the incremented version
426
+ # @raise [VersionBoss::Error] if the version is not a valid IncrementableSemver version
427
+ #
428
+ def increment_gem_version(method, args)
429
+ version_file = VersionBoss::Gem::VersionFileFactory.find
430
+
431
+ if version_file.nil?
432
+ warn 'version file not found or is not valid' unless options[:quiet]
433
+ exit 1
434
+ end
435
+
436
+ version_file&.version.send(method, **args).tap do |new_version|
437
+ version_file.version = new_version unless options[:'dry-run']
438
+ end
439
+ end
440
+ end
441
+ # rubocop:enable Metrics/ClassLength
442
+ end
443
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version'
4
+
5
+ module VersionBoss
6
+ module Gem
7
+ # A VersionBoss::Semver with additional constraints on the pre-release part of the version
8
+ #
9
+ # A IncrementableVersion is valid if one of the two following conditions is met:
10
+ # 1. The pre-release part is empty
11
+ # 2. The pre-release part is composed of two dot-separated identifiers:
12
+ # * the first being a String representing the pre-release type (e.g. 'alpha',
13
+ # 'beta', etc.). The default pre-release type is 'pre'
14
+ # * the second being an Integer representing the pre-release sequence number
15
+ # (starting at 1)
16
+ #
17
+ # Valid versions with pre-release parts: `1.2.3.alpha.1`, `1.2.3.beta.2`, `1.2.3.pre.3`
18
+ #
19
+ # @api public
20
+ #
21
+ class IncrementableVersion < Version
22
+ # Create a new IncrementableVersion object
23
+ #
24
+ # @example
25
+ # VersionBoss::Semver.new('1.2.3').valid? # => true
26
+ # VersionBoss::Semver.new('1.2.3-alpha.1+build.001').valid? # => true
27
+ # VersionBoss::Semver.new('1.2.3-alpha').valid? # => raise VersionBoss::Error
28
+ # VersionBoss::Semver.new('1.2.3-alpha.1.2').valid? # => raise VersionBoss::Error
29
+ # VersionBoss::Semver.new('1.2.3-alpha.one').valid? # => raise VersionBoss::Error
30
+ #
31
+ # @return [Boolean] true if the version string is a valid semver and meets the conditions above
32
+ #
33
+ def valid?
34
+ super && (
35
+ pre_release.empty? ||
36
+ (
37
+ pre_release_identifiers.size == 2 &&
38
+ pre_type.is_a?(String) &&
39
+ pre_number.is_a?(Integer)
40
+ )
41
+ )
42
+ end
43
+
44
+ # The default pre-release identifier
45
+ DEFAULT_PRE_TYPE = 'pre'
46
+
47
+ # Increment the major version
48
+ #
49
+ # @example
50
+ # VersionBoss::IncrementableVersion.new('1.2.3').next_major # =>
51
+ # VersionBoss::IncrementableVersion.new('2.0.0')
52
+ #
53
+ # @return [IncrementableVersion] a new IncrementableVersion object with the major version incremented
54
+ #
55
+ def next_major(pre: false, pre_type: DEFAULT_PRE_TYPE)
56
+ version_string = "#{major.to_i + 1}.0.0"
57
+ version_string += ".#{pre_type}1" if pre
58
+ IncrementableVersion.new(version_string)
59
+ end
60
+
61
+ # Increment the minor version
62
+ #
63
+ # @example
64
+ # VersionBoss::IncrementableVersion.new('1.2.3').next_minor # =>
65
+ # VersionBoss::IncrementableVersion.new('1.3.0')
66
+ #
67
+ # @return [IncrementableVersion] a new IncrementableVersion object with the major version incremented
68
+ #
69
+ def next_minor(pre: false, pre_type: DEFAULT_PRE_TYPE)
70
+ version_string = "#{major}.#{minor.to_i + 1}.0"
71
+ version_string += ".#{pre_type}1" if pre
72
+ IncrementableVersion.new(version_string)
73
+ end
74
+
75
+ # Increment the patch version
76
+ #
77
+ # @example
78
+ # VersionBoss::IncrementableVersion.new('1.2.3').next_patch # =>
79
+ # VersionBoss::IncrementableVersion.new('1.2.1')
80
+ #
81
+ # @return [IncrementableVersion] a new IncrementableVersion object with the patch part incremented
82
+ #
83
+ def next_patch(pre: false, pre_type: DEFAULT_PRE_TYPE)
84
+ version_string = "#{major}.#{minor}.#{patch.to_i + 1}"
85
+ version_string += ".#{pre_type}1" if pre
86
+ IncrementableVersion.new(version_string)
87
+ end
88
+
89
+ # Increment the pre_release part of the version
90
+ #
91
+ # @example
92
+ # VersionBoss::IncrementableVersion.new('1.2.3.pre.1').next_patch.to_s # => '1.2.3.pre.2'
93
+ #
94
+ # @return [IncrementableVersion] a new object with the pre_release part incremented
95
+ #
96
+ def next_pre(pre_type: nil)
97
+ assert_is_a_pre_release_version
98
+ version_string = "#{major}.#{minor}.#{patch}"
99
+ version_string += next_pre_part(pre_type)
100
+ IncrementableVersion.new(version_string)
101
+ end
102
+
103
+ # Drop the pre-release part of the version
104
+ #
105
+ # @example
106
+ # VersionBoss::IncrementableVersion.new('1.2.3.pre.1').next_release.to_s # => '1.2.3'
107
+ #
108
+ # @return [IncrementableVersion] a new IncrementableVersion object with the pre_release part dropped
109
+ # @raise [VersionBoss::Error] if the version is not a pre-release version
110
+ #
111
+ def next_release
112
+ assert_is_a_pre_release_version
113
+ version_string = "#{major}.#{minor}.#{patch}"
114
+ IncrementableVersion.new(version_string)
115
+ end
116
+
117
+ # The pre-release type (for example, 'alpha', 'beta', 'pre', etc.)
118
+ #
119
+ # @example
120
+ # VersionBoss::IncrementableVersion.new('1.2.3.pre1').pre_type # => 'pre'
121
+ #
122
+ # @return [String]
123
+ #
124
+ def pre_type
125
+ pre_release_identifiers[0].identifier
126
+ end
127
+
128
+ # Returns the prefix of the pre-release type
129
+ #
130
+ # Ruby Gem versions can optionally prefix the pre-release type with a period.
131
+ #
132
+ # @example
133
+ # VersionBoss::GemVersion.new('1.2.3.pre1').pre_type_prefix # => '-'
134
+ # Semver requires a hyphen prefix.
135
+ #
136
+ # @example
137
+ # VersionBoss::IncrementableVersion.new('1.2.3.pre1').pre_type # => 'pre'
138
+ #
139
+ # @return ['.', '']
140
+ #
141
+ def pre_type_prefix
142
+ pre_release_identifiers[0].prefix
143
+ end
144
+
145
+ # The pre-release sequence number
146
+ #
147
+ # The pre-release sequence number starts at 1 for each pre-release type.
148
+ #
149
+ # @example
150
+ # IncrementableVersion.new('1.2.3.pre.1').pre_number # => 1
151
+ #
152
+ # @return [Integer]
153
+ #
154
+ def pre_number
155
+ pre_release_identifiers[1].identifier
156
+ end
157
+
158
+ # The pre-release sequence number
159
+ #
160
+ # The pre-release identifier can optionally prefix the pre-release sequence number with a period.
161
+ #
162
+ # @example
163
+ # IncrementableVersion.new('1.2.3.pre.1').pre_number_prefix # => '.'
164
+ # IncrementableVersion.new('1.2.3.pre1').pre_number_prefix # => ''
165
+ #
166
+ # @return [String]
167
+ #
168
+ def pre_number_prefix
169
+ pre_release_identifiers[1].prefix
170
+ end
171
+
172
+ private
173
+
174
+ # Raise an error if the version is not a pre-release version
175
+ #
176
+ # @return [void]
177
+ # @raise [VersionBoss::Error] if the version is not a pre-release version
178
+ # @api private
179
+ def assert_is_a_pre_release_version
180
+ return unless pre_release.empty?
181
+
182
+ raise VersionBoss::Error, 'Cannot increment the pre-release part of a release version'
183
+ end
184
+
185
+ # Raise an error if new pre-release type is less than the old pre-release type
186
+ #
187
+ # If the new pre-release type is lexically less than the old pre-release type,
188
+ # then raise an error because the resulting error would sort before the existing
189
+ # version.
190
+ #
191
+ # @return [void]
192
+ # @raise [VersionBoss::Error] if the pre-release type is not valid
193
+ # @api private
194
+ def assert_pre_type_is_valid(pre_type)
195
+ return if self.pre_type <= pre_type
196
+
197
+ message = 'Cannot increment the pre-release identifier ' \
198
+ "from '#{self.pre_type}' to '#{pre_type}' " \
199
+ "because '#{self.pre_type}' is lexically less than '#{pre_type}'"
200
+
201
+ raise VersionBoss::Error, message
202
+ end
203
+
204
+ # Return the next pre-release part
205
+ # @param pre_type [String, nil] the given pre-release type or nil to use the existing pre-release type
206
+ # @return [String]
207
+ # @api private
208
+ def next_pre_part(pre_type)
209
+ pre_type ||= self.pre_type
210
+ assert_pre_type_is_valid(pre_type)
211
+ next_pre_number = self.pre_type == pre_type ? (pre_number + 1) : 1
212
+ "#{pre_type_prefix}#{pre_type}#{pre_number_prefix}#{next_pre_number}"
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VersionBoss
4
+ module Gem
5
+ # Match a gem_version within a string
6
+ REGEXP = /
7
+ (?<gem_version>
8
+ (?<major>0|[1-9]\d*)
9
+ \.
10
+ (?<minor>0|[1-9]\d*)
11
+ \.
12
+ (?<patch>0|[1-9]\d*)
13
+ (?<pre_release>
14
+ (?:
15
+ \.?
16
+ [a-z]+
17
+ (?:
18
+ \.?
19
+ (?:[a-z]+|\d+)
20
+ )*
21
+ )?
22
+ )
23
+ )
24
+ /x
25
+
26
+ # Match a gem_version to the full string
27
+ REGEXP_FULL = /\A#{REGEXP.source}\z/x
28
+ end
29
+ end