version_boss 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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