Module: Kettle::Gha::Pins::VersionRubric
- Defined in:
- lib/kettle/gha/pins/version_rubric.rb
Overview
Shared version ordering and upgrade selection rules for GitHub Action pins.
Constant Summary collapse
- VALID_UPGRADE_LEVELS =
%w[major minor patch].freeze
- DEFAULT_UPGRADE_LEVEL =
"major"- RELEASE_TAG_RE =
/\A(?:\d+|\d+\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)\z/
Class Method Summary collapse
- .allowed_by_level?(current_version, current, entry, level) ⇒ Boolean
- .build_release_versions(release_tags:, tag_shas:, release_dates: {}) ⇒ Object
- .canonicalize_equivalent_release_versions(releases) ⇒ Object
- .choose_upgrade_target(current_version, versions, level) ⇒ Object
- .entry(tag:, sha: nil, released_at: nil) ⇒ Object
- .equivalent_release_tag?(left, right) ⇒ Boolean
- .latest_outdated_target(current_version, versions) ⇒ Object
- .major_line?(value) ⇒ Boolean
- .normalize_upgrade_level(level) ⇒ Object
- .parse(value) ⇒ Object
- .sort_key(entry) ⇒ Object
- .sort_versions(versions) ⇒ Object
- .specificity(entry) ⇒ Object
Class Method Details
.allowed_by_level?(current_version, current, entry, level) ⇒ Boolean
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 121 def allowed_by_level?(current_version, current, entry, level) return true if level == "major" return false if major_line?(entry.fetch(:version)) return false if major_line?(current_version) case level when "patch" entry.fetch(:version_obj).segments[0, 2] == current.segments[0, 2] when "minor" entry.fetch(:version_obj).segments[0] == current.segments[0] else true end end |
.build_release_versions(release_tags:, tag_shas:, release_dates: {}) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 40 def build_release_versions(release_tags:, tag_shas:, release_dates: {}) = .each_with_object({}) { |tag, memo| memo[tag.to_s] = true } releases = .each_with_object([]) do |tag, memo| release_entry = entry(tag: tag, sha: tag_shas[tag.to_s], released_at: release_dates[tag.to_s]) memo << release_entry if release_entry end tag_versions = tag_shas.each_with_object([]) do |(tag, sha), memo| next if [tag.to_s] tag_entry = entry(tag: tag, sha: sha) memo << tag_entry if tag_entry end sort_versions(canonicalize_equivalent_release_versions(releases + tag_versions)).reverse end |
.canonicalize_equivalent_release_versions(releases) ⇒ Object
56 57 58 59 60 61 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 56 def canonicalize_equivalent_release_versions(releases) releases.each_with_object([]) do |release, groups| group = groups.find { |entries| equivalent_release_tag?(entries.first, release) } group ? group << release : groups << [release] end.map { |entries| entries.max_by { |entry| sort_key(entry) } } end |
.choose_upgrade_target(current_version, versions, level) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 84 def choose_upgrade_target(current_version, versions, level) normalized_level = normalize_upgrade_level(level) current = parse(current_version) return nil if current.nil? return nil if normalized_level != "major" && major_line?(current_version) versions.select do |entry| entry.fetch(:version_obj, nil).is_a?(Gem::Version) && entry.fetch(:version_obj) > current && (!entry.fetch(:version_obj).prerelease? || current.prerelease?) && allowed_by_level?(current_version, current, entry, normalized_level) end.max_by { |entry| sort_key(entry) } end |
.entry(tag:, sha: nil, released_at: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 27 def entry(tag:, sha: nil, released_at: nil) version_obj = parse(tag) return nil unless version_obj { tag: tag.to_s, version_obj: version_obj, version: version_obj.to_s, sha: sha, released_at: released_at.to_s } end |
.equivalent_release_tag?(left, right) ⇒ Boolean
114 115 116 117 118 119 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 114 def equivalent_release_tag?(left, right) left[:version_obj] == right[:version_obj] && left[:sha] && right[:sha] && left[:sha] == right[:sha] end |
.latest_outdated_target(current_version, versions) ⇒ Object
98 99 100 101 102 103 104 105 106 107 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 98 def latest_outdated_target(current_version, versions) current = parse(current_version) return nil if current.nil? versions.select do |entry| entry.fetch(:version_obj, nil).is_a?(Gem::Version) && entry.fetch(:version_obj) > current && (!entry.fetch(:version_obj).prerelease? || current.prerelease?) end.max_by { |entry| sort_key(entry) } end |
.major_line?(value) ⇒ Boolean
23 24 25 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 23 def major_line?(value) value.to_s.match?(/\A\d+\z/) end |
.normalize_upgrade_level(level) ⇒ Object
109 110 111 112 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 109 def normalize_upgrade_level(level) normalized = level.to_s.downcase VALID_UPGRADE_LEVELS.include?(normalized) ? normalized : DEFAULT_UPGRADE_LEVEL end |
.parse(value) ⇒ Object
14 15 16 17 18 19 20 21 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 14 def parse(value) normalized = value.to_s.sub(/\A[vV]/, "") return nil unless normalized.match?(RELEASE_TAG_RE) Gem::Version.new(normalized) rescue ArgumentError nil end |
.sort_key(entry) ⇒ Object
67 68 69 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 67 def sort_key(entry) [entry.fetch(:version_obj), *specificity(entry)] end |
.sort_versions(versions) ⇒ Object
63 64 65 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 63 def sort_versions(versions) versions.sort_by { |entry| sort_key(entry) } end |
.specificity(entry) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/kettle/gha/pins/version_rubric.rb', line 71 def specificity(entry) text = entry.fetch(:tag).to_s.sub(/\A[vV]/, "") release_text, suffix = text.split(/[-.](?=[A-Za-z])/, 2) numeric_segments = release_text.to_s.split(".").take_while { |part| part.match?(/\A\d+\z/) } [ numeric_segments.length, suffix ? 0 : 1, text.length, entry.fetch(:tag).to_s ] end |