shivers 0.6.0.pre.2 → 0.6.0.pre.3
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/Gemfile +2 -0
- data/Gemfile.lock +77 -43
- data/Rakefile +70 -47
- data/bin/console +1 -0
- data/lib/shivers/format.rb +21 -0
- data/lib/shivers/library_version.rb +3 -0
- data/lib/shivers/matchers/child.rb +21 -0
- data/lib/shivers/matchers/parent.rb +21 -0
- data/lib/shivers/matchers/recursive.rb +21 -0
- data/lib/shivers/matchers.rb +10 -0
- data/lib/shivers/parts/alphanumeric.rb +43 -0
- data/lib/shivers/parts/alphanumeric_or_hyphen.rb +43 -0
- data/lib/shivers/parts/mixins/multivaluable.rb +29 -0
- data/lib/shivers/parts/numeric.rb +41 -0
- data/lib/shivers/parts/static.rb +39 -0
- data/lib/shivers/parts.rb +11 -0
- data/lib/shivers/value_equality.rb +15 -0
- data/lib/shivers/version.rb +29 -1
- data/lib/shivers/version2.rb +17 -0
- data/lib/shivers/version_definition.rb +45 -0
- data/lib/shivers/visitors/extract_visitor.rb +121 -0
- data/lib/shivers/visitors/matcher_visitor.rb +122 -0
- data/lib/shivers/visitors.rb +9 -0
- data/lib/shivers.rb +7 -27
- data/shivers.gemspec +32 -17
- metadata +108 -48
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../value_equality'
|
4
|
+
|
5
|
+
module Shivers
|
6
|
+
module Parts
|
7
|
+
class Static
|
8
|
+
include ValueEquality
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@value = data[:value]
|
12
|
+
end
|
13
|
+
|
14
|
+
def matcher
|
15
|
+
/#{Regexp.quote(@value)}/
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert(value)
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
def merge(_, second)
|
23
|
+
second
|
24
|
+
end
|
25
|
+
|
26
|
+
def capturable?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def multivalued?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def state
|
35
|
+
[@value]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/shivers/version.rb
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Shivers
|
2
|
-
|
4
|
+
class Version
|
5
|
+
def self.from_file(path)
|
6
|
+
git_sha = ENV['GIT_SHA'] || 'LOCAL'
|
7
|
+
metadata = git_sha.to_s
|
8
|
+
|
9
|
+
base_version =
|
10
|
+
if File.exist?(path)
|
11
|
+
File.open(path) { |file| file.read.strip }
|
12
|
+
else
|
13
|
+
'0.0.0'
|
14
|
+
end
|
15
|
+
|
16
|
+
Version.new("#{base_version}+#{metadata}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(version_string)
|
20
|
+
@version = Semantic::Version.new(version_string)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_docker_tag
|
24
|
+
to_s.gsub(/\+/, '_').downcase
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
@version.to_s
|
29
|
+
end
|
30
|
+
end
|
3
31
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
require_relative 'parts'
|
6
|
+
require_relative 'format'
|
7
|
+
require_relative 'visitors'
|
8
|
+
require_relative 'value_equality'
|
9
|
+
|
10
|
+
module Shivers
|
11
|
+
class VersionDefinition
|
12
|
+
PART_TYPES = {
|
13
|
+
numeric: Parts::Numeric,
|
14
|
+
alphanumeric: Parts::Alphanumeric,
|
15
|
+
alphanumeric_or_hyphen: Parts::AlphanumericOrHyphen,
|
16
|
+
static: Parts::Static
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
include ValueEquality
|
20
|
+
|
21
|
+
attr_reader :parts, :format
|
22
|
+
|
23
|
+
def initialize(definition)
|
24
|
+
@parts =
|
25
|
+
definition[:parts]
|
26
|
+
.transform_values { |part| PART_TYPES[part[:type]].new(part) }
|
27
|
+
@format = Format.new(definition[:formatter])
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse(value)
|
31
|
+
extract_visitor = Visitors::ExtractVisitor.new(@parts, value)
|
32
|
+
|
33
|
+
@format.visit(extract_visitor)
|
34
|
+
|
35
|
+
Version2.new(
|
36
|
+
parts: @parts, format: @format,
|
37
|
+
values: extract_visitor.result
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def state
|
42
|
+
[@parts, @format]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Shivers
|
6
|
+
module Visitors
|
7
|
+
class ExtractVisitor
|
8
|
+
def initialize(parts, value, _options = {})
|
9
|
+
@parts = parts
|
10
|
+
@value = value
|
11
|
+
@delegate = MatcherVisitor.new(parts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def optionally(&block)
|
15
|
+
@delegate.optionally(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def recursively(name, &block)
|
19
|
+
@delegate.recursively(name, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(symbol, *args, &block)
|
23
|
+
@delegate.send(symbol, *args, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(symbol, include_private = false)
|
27
|
+
@delegate.respond_to_missing?(symbol, include_private) || super
|
28
|
+
end
|
29
|
+
|
30
|
+
def result
|
31
|
+
matchers = @delegate.result
|
32
|
+
|
33
|
+
parent_captures = match_parent(matchers)
|
34
|
+
total_captures = match_children(matchers, parent_captures)
|
35
|
+
|
36
|
+
convert_values(total_captures)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def match_parent(matchers)
|
42
|
+
standard_captures(/\A#{matchers.capturer.source}\z/, @value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def match_children(matchers, captures)
|
46
|
+
matchers.children.reduce(captures) do |caps, child|
|
47
|
+
value = caps[child.capture_group]
|
48
|
+
first_captures = standard_captures(child.first, value)
|
49
|
+
|
50
|
+
next caps unless first_captures
|
51
|
+
|
52
|
+
rest_captures = recursive_captures(first_captures[:rest], child.rest)
|
53
|
+
|
54
|
+
caps = merge_captures(caps, first_captures)
|
55
|
+
caps = merge_captures(caps, rest_captures)
|
56
|
+
|
57
|
+
caps
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def recursive_captures(value, matcher)
|
62
|
+
match_recursively(value, matcher)
|
63
|
+
.reduce({}) do |all_rest_captures, rest_captures|
|
64
|
+
all_rest_captures.merge(rest_captures) do |name, existing, new|
|
65
|
+
merge_capture_value(name, existing, new)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def match_recursively(value, matcher)
|
71
|
+
rest_matches = value.scan(matcher)
|
72
|
+
rest_capture_names = matcher.names.map(&:to_sym)
|
73
|
+
rest_matches.map do |rest_match|
|
74
|
+
rest_capture_names.zip(rest_match).to_h
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def merge_captures(existing, new)
|
79
|
+
new.reduce(existing) do |captures, capture|
|
80
|
+
name, value = capture
|
81
|
+
captures.merge(
|
82
|
+
name =>
|
83
|
+
merge_capture_value(name, captures[name], value)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def merge_capture_value(name, existing, new)
|
89
|
+
@parts[name]&.merge(existing, new)
|
90
|
+
end
|
91
|
+
|
92
|
+
def standard_captures(matcher, value)
|
93
|
+
return unless value
|
94
|
+
|
95
|
+
ensure_match(matcher.match(value))
|
96
|
+
.named_captures
|
97
|
+
.transform_keys(&:to_sym)
|
98
|
+
end
|
99
|
+
|
100
|
+
def convert_values(captures)
|
101
|
+
capturable_parts
|
102
|
+
.to_h { |name, part| [name, part&.convert(captures[name])] }
|
103
|
+
end
|
104
|
+
|
105
|
+
def ensure_match(match)
|
106
|
+
unless match
|
107
|
+
raise(
|
108
|
+
ArgumentError,
|
109
|
+
"Version string: '#{@value}' does not satisfy expected format."
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
match
|
114
|
+
end
|
115
|
+
|
116
|
+
def capturable_parts
|
117
|
+
@parts.select { |_, part| part.capturable? }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
require_relative '../matchers'
|
6
|
+
require_relative '../value_equality'
|
7
|
+
|
8
|
+
module Shivers
|
9
|
+
module Visitors
|
10
|
+
class MatcherVisitor
|
11
|
+
class RecursiveMatcherVisitor
|
12
|
+
def initialize(name, parts)
|
13
|
+
@name = name
|
14
|
+
@parts = parts
|
15
|
+
end
|
16
|
+
|
17
|
+
def first(&block)
|
18
|
+
@first_block = block
|
19
|
+
end
|
20
|
+
|
21
|
+
def rest(&block)
|
22
|
+
@rest_block = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def result
|
26
|
+
first = visit(@first_block, MatcherVisitor.new(@parts))
|
27
|
+
rest = visit(@rest_block, MatcherVisitor.new(@parts))
|
28
|
+
|
29
|
+
Matchers::Child.new(
|
30
|
+
parent_matcher(first, rest), parent_capturer(first, rest),
|
31
|
+
Matchers::Recursive.new(
|
32
|
+
@name, first_capturer(first, rest), rest_capturer(first, rest)
|
33
|
+
)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def visit(block, visitor)
|
40
|
+
block.call(visitor)
|
41
|
+
visitor.result
|
42
|
+
end
|
43
|
+
|
44
|
+
def parent_matcher(first, rest)
|
45
|
+
/#{first.matcher.source}(?:#{rest.matcher.source})*/
|
46
|
+
end
|
47
|
+
|
48
|
+
def parent_capturer(first, rest)
|
49
|
+
/(?<#{@name}>#{first.matcher.source}(?:#{rest.matcher.source})*)/
|
50
|
+
end
|
51
|
+
|
52
|
+
def first_capturer(first, rest)
|
53
|
+
/#{first.capturer.source}(?<rest>(?:#{rest.matcher.source})*)?/
|
54
|
+
end
|
55
|
+
|
56
|
+
def rest_capturer(_, rest)
|
57
|
+
/#{rest.capturer.source}/
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(parts)
|
62
|
+
@parts = parts
|
63
|
+
@matching_regexps = []
|
64
|
+
@capturing_regexps = []
|
65
|
+
@children = []
|
66
|
+
end
|
67
|
+
|
68
|
+
def optionally(&block)
|
69
|
+
sub_visitor = MatcherVisitor.new(@parts)
|
70
|
+
block.call(sub_visitor)
|
71
|
+
result = sub_visitor.result
|
72
|
+
@matching_regexps << /(?:#{result.matcher.source})?/
|
73
|
+
@capturing_regexps << /(?:#{result.capturer.source})?/
|
74
|
+
@children.concat(result.children)
|
75
|
+
end
|
76
|
+
|
77
|
+
def recursively(name, &block)
|
78
|
+
sub_visitor = RecursiveMatcherVisitor.new(name, @parts)
|
79
|
+
block.call(sub_visitor)
|
80
|
+
result = sub_visitor.result
|
81
|
+
@matching_regexps << result.matcher
|
82
|
+
@capturing_regexps << result.capturer
|
83
|
+
@children << result.child
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_missing(symbol, *_)
|
87
|
+
raise no_dsl_element_error(symbol) unless respond_to_missing?(symbol)
|
88
|
+
|
89
|
+
part = @parts[symbol]
|
90
|
+
|
91
|
+
@matching_regexps << part.matcher
|
92
|
+
@capturing_regexps << if part.capturable?
|
93
|
+
/(?<#{symbol}>#{part.matcher.source})/
|
94
|
+
else
|
95
|
+
part.matcher
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def respond_to_missing?(symbol, _ = false)
|
100
|
+
@parts.include?(symbol) || super
|
101
|
+
end
|
102
|
+
|
103
|
+
def result
|
104
|
+
Matchers::Parent.new(
|
105
|
+
/#{@matching_regexps.collect(&:source).join}/,
|
106
|
+
/#{@capturing_regexps.collect(&:source).join}/,
|
107
|
+
@children
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def no_dsl_element_error(symbol)
|
114
|
+
NoMethodError.new(
|
115
|
+
"DSL does not include an element with name: '#{symbol}'. "\
|
116
|
+
'Check usage.',
|
117
|
+
symbol
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/shivers.rb
CHANGED
@@ -1,30 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'shivers/library_version'
|
4
|
+
require 'shivers/value_equality'
|
5
|
+
require 'shivers/matchers'
|
1
6
|
require 'shivers/version'
|
7
|
+
require 'shivers/version2'
|
8
|
+
require 'shivers/version_definition'
|
2
9
|
|
3
10
|
require 'semantic'
|
4
|
-
|
5
|
-
module Shivers
|
6
|
-
class Version
|
7
|
-
def self.from_file(path)
|
8
|
-
git_sha = ENV['GIT_SHA'] || 'LOCAL'
|
9
|
-
metadata = "#{git_sha}"
|
10
|
-
|
11
|
-
base_version = File.exist?(path) ?
|
12
|
-
File.open(path) { |file| file.read.strip } :
|
13
|
-
'0.0.0'
|
14
|
-
|
15
|
-
Version.new("#{base_version}+#{metadata}")
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(version_string)
|
19
|
-
@version = Semantic::Version.new(version_string)
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_docker_tag
|
23
|
-
to_s.gsub(/[\+]/, '_').downcase
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s
|
27
|
-
@version.to_s
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/shivers.gemspec
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
5
|
+
require_relative 'lib/shivers/library_version'
|
6
|
+
|
7
|
+
files = %w[
|
8
|
+
bin
|
9
|
+
lib
|
10
|
+
CODE_OF_CONDUCT.md
|
11
|
+
shivers.gemspec
|
12
|
+
Gemfile
|
13
|
+
LICENSE.txt
|
14
|
+
Rakefile
|
15
|
+
README.md
|
16
|
+
]
|
5
17
|
|
6
18
|
Gem::Specification.new do |spec|
|
7
19
|
spec.name = 'shivers'
|
@@ -9,31 +21,34 @@ Gem::Specification.new do |spec|
|
|
9
21
|
spec.authors = ['InfraBlocks Maintainers']
|
10
22
|
spec.email = ['maintainers@infrablocks.io']
|
11
23
|
|
12
|
-
spec.date = '2021-01-11'
|
13
24
|
spec.summary = 'Semantic version numbers for CI pipelines.'
|
14
|
-
spec.description = 'Semantic version number management, by file and
|
25
|
+
spec.description = 'Semantic version number management, by file and '\
|
26
|
+
'environment, for CI pipelines.'
|
15
27
|
spec.homepage = 'https://github.com/infrablocks/shivers'
|
16
28
|
spec.license = 'MIT'
|
17
29
|
|
18
30
|
spec.files = `git ls-files -z`.split("\x0").select do |f|
|
19
|
-
f.match(
|
31
|
+
f.match(/^(#{files.map { |g| Regexp.escape(g) }.join('|')})/)
|
20
32
|
end
|
21
33
|
spec.bindir = 'exe'
|
22
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
35
|
spec.require_paths = ['lib']
|
24
36
|
|
25
|
-
spec.required_ruby_version = '>= 2.
|
37
|
+
spec.required_ruby_version = '>= 2.7'
|
26
38
|
|
27
39
|
spec.add_dependency 'semantic', '~> 1.6'
|
28
40
|
|
29
|
-
spec.add_development_dependency 'bundler'
|
30
|
-
spec.add_development_dependency '
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency '
|
33
|
-
spec.add_development_dependency '
|
34
|
-
spec.add_development_dependency '
|
35
|
-
spec.add_development_dependency '
|
36
|
-
spec.add_development_dependency '
|
37
|
-
spec.add_development_dependency '
|
38
|
-
spec.add_development_dependency '
|
41
|
+
spec.add_development_dependency 'bundler'
|
42
|
+
spec.add_development_dependency 'fakefs'
|
43
|
+
spec.add_development_dependency 'gem-release'
|
44
|
+
spec.add_development_dependency 'rake'
|
45
|
+
spec.add_development_dependency 'rake_circle_ci'
|
46
|
+
spec.add_development_dependency 'rake_github'
|
47
|
+
spec.add_development_dependency 'rake_gpg'
|
48
|
+
spec.add_development_dependency 'rake_ssh'
|
49
|
+
spec.add_development_dependency 'rspec'
|
50
|
+
spec.add_development_dependency 'rubocop'
|
51
|
+
spec.add_development_dependency 'rubocop-rake'
|
52
|
+
spec.add_development_dependency 'rubocop-rspec'
|
53
|
+
spec.add_development_dependency 'simplecov'
|
39
54
|
end
|