Class: Kettle::Dev::VersionBump
- Inherits:
-
Object
- Object
- Kettle::Dev::VersionBump
- Defined in:
- lib/kettle/dev/version_bump.rb
Overview
Reusable engine behind kettle-bump.
Constant Summary collapse
- BUMP_TYPES =
%w[major minor patch pre].freeze
Instance Attribute Summary collapse
-
#current_version ⇒ Object
readonly
Returns the value of attribute current_version.
-
#from_version ⇒ Object
readonly
Returns the value of attribute from_version.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
-
#target_version ⇒ Object
readonly
Returns the value of attribute target_version.
Class Method Summary collapse
- .bumped_prerelease_version(current_version) ⇒ Object
- .bumped_version(type, current_version) ⇒ Object
- .each_node(root) ⇒ Object
- .file_edit(path, source, start_offset, end_offset, replacement) ⇒ Object
- .parse_source(source, path) ⇒ Object
- .prerelease_suffix_for(current_version, release_core) ⇒ Object
- .quote_like(original, value) ⇒ Object
- .released_patch_version(segments) ⇒ Object
- .replace_byte_range(source, start_offset, end_offset, replacement) ⇒ Object
- .require_prism ⇒ Object
- .resolve_target_version(target, current_version) ⇒ Object
- .string_tail(value, offset) ⇒ Object
- .validate_version(version) ⇒ Object
- .version_string_node(source, path) ⇒ Object
- .write_edits(edits) ⇒ Object
Instance Method Summary collapse
- #edits ⇒ Object
-
#initialize(root:, target_version:, current_version: nil, from_version: nil) ⇒ VersionBump
constructor
A new instance of VersionBump.
- #write! ⇒ Object
Constructor Details
#initialize(root:, target_version:, current_version: nil, from_version: nil) ⇒ VersionBump
Returns a new instance of VersionBump.
148 149 150 151 152 153 |
# File 'lib/kettle/dev/version_bump.rb', line 148 def initialize(root:, target_version:, current_version: nil, from_version: nil) @root = root @current_version = current_version || Kettle::Dev::Versioning.detect_version(root) @target_version = self.class.resolve_target_version(target_version, @current_version) @from_version = self.class.validate_version(from_version) if from_version end |
Instance Attribute Details
#current_version ⇒ Object (readonly)
Returns the value of attribute current_version.
155 156 157 |
# File 'lib/kettle/dev/version_bump.rb', line 155 def current_version @current_version end |
#from_version ⇒ Object (readonly)
Returns the value of attribute from_version.
155 156 157 |
# File 'lib/kettle/dev/version_bump.rb', line 155 def from_version @from_version end |
#root ⇒ Object (readonly)
Returns the value of attribute root.
155 156 157 |
# File 'lib/kettle/dev/version_bump.rb', line 155 def root @root end |
#target_version ⇒ Object (readonly)
Returns the value of attribute target_version.
155 156 157 |
# File 'lib/kettle/dev/version_bump.rb', line 155 def target_version @target_version end |
Class Method Details
.bumped_prerelease_version(current_version) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/kettle/dev/version_bump.rb', line 53 def bumped_prerelease_version(current_version) version = Gem::Version.new(current_version) segments = version.segments prerelease_index = segments.index { |segment| !segment.is_a?(Integer) } unless prerelease_index raise Kettle::Dev::Error, "cannot pre-bump version without prerelease segment #{current_version.inspect}" end release_core = segments[0...prerelease_index].join(".") prerelease_suffix = prerelease_suffix_for(current_version, release_core) "#{release_core}.#{prerelease_suffix.next}" end |
.bumped_version(type, current_version) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/kettle/dev/version_bump.rb', line 25 def bumped_version(type, current_version) return bumped_prerelease_version(current_version) if type == "pre" version = Gem::Version.new(current_version) segments = version.segments return released_patch_version(segments) if type == "patch" && segments.any? { |segment| !segment.is_a?(Integer) } unless segments.all? { |segment| segment.is_a?(Integer) } raise Kettle::Dev::Error, "cannot #{type}-bump non-numeric version #{current_version.inspect}" end major, minor, patch = (segments + [0, 0, 0])[0, 3] case type when "major" "#{major + 1}.0.0" when "minor" "#{major}.#{minor + 1}.0" when "patch" "#{major}.#{minor}.#{patch + 1}" end end |
.each_node(root) ⇒ Object
106 107 108 109 110 111 112 113 114 115 |
# File 'lib/kettle/dev/version_bump.rb', line 106 def each_node(root) return enum_for(__method__, root) unless block_given? queue = [root] until queue.empty? node = queue.shift yield node queue.concat(node.child_nodes.compact) if node.respond_to?(:child_nodes) end end |
.file_edit(path, source, start_offset, end_offset, replacement) ⇒ Object
117 118 119 |
# File 'lib/kettle/dev/version_bump.rb', line 117 def file_edit(path, source, start_offset, end_offset, replacement) {path: path, source: source, start_offset: start_offset, end_offset: end_offset, replacement: replacement} end |
.parse_source(source, path) ⇒ Object
90 91 92 93 94 95 96 |
# File 'lib/kettle/dev/version_bump.rb', line 90 def parse_source(source, path) require_prism parse_result = Prism.parse(source) raise Kettle::Dev::Error, "could not parse #{path}" unless parse_result.success? parse_result end |
.prerelease_suffix_for(current_version, release_core) ⇒ Object
66 67 68 69 70 71 72 73 74 |
# File 'lib/kettle/dev/version_bump.rb', line 66 def prerelease_suffix_for(current_version, release_core) prefix = "#{release_core}." return string_tail(current_version, prefix.length) if current_version.start_with?(prefix) canonical_version = Gem::Version.new(current_version).to_s return string_tail(canonical_version, prefix.length) if canonical_version.start_with?(prefix) raise Kettle::Dev::Error, "cannot find prerelease segment in version #{current_version.inspect}" end |
.quote_like(original, value) ⇒ Object
121 122 123 124 |
# File 'lib/kettle/dev/version_bump.rb', line 121 def quote_like(original, value) quote = original.start_with?("'") ? "'" : '"' "#{quote}#{value}#{quote}" end |
.released_patch_version(segments) ⇒ Object
47 48 49 50 51 |
# File 'lib/kettle/dev/version_bump.rb', line 47 def released_patch_version(segments) release_segments = segments.take_while { |segment| segment.is_a?(Integer) } major, minor, patch = (release_segments + [0, 0, 0])[0, 3] "#{major}.#{minor}.#{patch}" end |
.replace_byte_range(source, start_offset, end_offset, replacement) ⇒ Object
141 142 143 144 145 |
# File 'lib/kettle/dev/version_bump.rb', line 141 def replace_byte_range(source, start_offset, end_offset, replacement) before = source.byteslice(0, start_offset) || +"" after = source.byteslice(end_offset, source.bytesize - end_offset) || +"" "#{before}#{replacement}#{after}" end |
.require_prism ⇒ Object
98 99 100 101 102 103 104 |
# File 'lib/kettle/dev/version_bump.rb', line 98 def require_prism return if defined?(Prism) require "prism" rescue LoadError => error raise Kettle::Dev::Error, "kettle-bump requires Prism; install the prism gem or run on Ruby 3.3+ (#{error.})" end |
.resolve_target_version(target, current_version) ⇒ Object
10 11 12 13 14 15 16 17 |
# File 'lib/kettle/dev/version_bump.rb', line 10 def resolve_target_version(target, current_version) target = target.to_s if BUMP_TYPES.include?(target) bumped_version(target, current_version) else validate_version(target) end end |
.string_tail(value, offset) ⇒ Object
76 77 78 |
# File 'lib/kettle/dev/version_bump.rb', line 76 def string_tail(value, offset) value[offset, value.length - offset] end |
.validate_version(version) ⇒ Object
19 20 21 22 23 |
# File 'lib/kettle/dev/version_bump.rb', line 19 def validate_version(version) Gem::Version.new(version).to_s rescue ArgumentError => error raise Kettle::Dev::Error, "invalid version #{version.inspect}: #{error.}" end |
.version_string_node(source, path) ⇒ Object
80 81 82 83 84 85 86 87 88 |
# File 'lib/kettle/dev/version_bump.rb', line 80 def version_string_node(source, path) parse_result = parse_source(source, path) constant = each_node(parse_result.value).find do |node| node.is_a?(Prism::ConstantWriteNode) && node.name == :VERSION && node.value.is_a?(Prism::StringNode) end raise Kettle::Dev::Error, "could not find string VERSION constant in #{path}" unless constant constant.value end |
.write_edits(edits) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/kettle/dev/version_bump.rb', line 126 def write_edits(edits) edits.group_by { |edit| edit.fetch(:path) }.each_value do |file_edits| source = file_edits.first.fetch(:source) file_edits.sort_by { |edit| -edit.fetch(:start_offset) }.each do |edit| source = replace_byte_range( source, edit.fetch(:start_offset), edit.fetch(:end_offset), edit.fetch(:replacement) ) end File.write(file_edits.first.fetch(:path), source) end end |
Instance Method Details
#edits ⇒ Object
157 158 159 160 |
# File 'lib/kettle/dev/version_bump.rb', line 157 def edits validate_from_version version_file_edits + gemspec_version_edits end |
#write! ⇒ Object
162 163 164 |
# File 'lib/kettle/dev/version_bump.rb', line 162 def write! self.class.write_edits(edits) end |