Skip to content

Commit

Permalink
Revert "Use new implementation of Maven version standard" (#10647)
Browse files Browse the repository at this point in the history
* Revert "Use new implementation of Maven version standard (#10558)"

This reverts commit 60cfd98.

* Update dependabot branch
  • Loading branch information
amazimbe authored Sep 20, 2024
1 parent 9eb037d commit 10e5c7c
Show file tree
Hide file tree
Showing 8 changed files with 939 additions and 385 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ concurrency:

env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKE_TEST_BRANCH: main
SMOKE_TEST_BRANCH: revert-228-amazimbe/use-new-maven-version
jobs:
discover:
runs-on: ubuntu-latest
Expand Down
71 changes: 71 additions & 0 deletions maven/lib/dependabot/maven/new_version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# typed: strict
# frozen_string_literal: true

require "dependabot/maven/version_parser"
require "dependabot/version"
require "dependabot/utils"

# See https://maven.apache.org/pom.html#Version_Order_Specification for details.

module Dependabot
module Maven
class NewVersion
extend T::Sig
extend T::Helpers

PRERELEASE_QUALIFIERS = T.let([
Dependabot::Maven::VersionParser::ALPHA,
Dependabot::Maven::VersionParser::BETA,
Dependabot::Maven::VersionParser::MILESTONE,
Dependabot::Maven::VersionParser::RC,
Dependabot::Maven::VersionParser::SNAPSHOT
].freeze, T::Array[Integer])

sig { returns(Dependabot::Maven::TokenBucket) }
attr_accessor :token_bucket

sig { params(version: String).returns(T::Boolean) }
def self.correct?(version)
return false if version.empty?

Dependabot::Maven::VersionParser.parse(version.to_s).to_a.any?
rescue Dependabot::BadRequirementError
Dependabot.logger.info("Malformed version string - #{version}")
false
end

sig { params(version: String).void }
def initialize(version)
@version_string = T.let(version, String)
@token_bucket = T.let(Dependabot::Maven::VersionParser.parse(version), Dependabot::Maven::TokenBucket)
end

sig { returns(String) }
def inspect
"#<#{self.class} #{version_string}>"
end

sig { returns(String) }
def to_s
version_string
end

sig { returns(T::Boolean) }
def prerelease?
token_bucket.to_a.flatten.any? do |token|
token.is_a?(Integer) && token.negative?
end
end

sig { params(other: ::Dependabot::Maven::NewVersion).returns(Integer) }
def <=>(other)
T.must(token_bucket <=> other.token_bucket)
end

private

sig { returns(String) }
attr_reader :version_string
end
end
end
18 changes: 16 additions & 2 deletions maven/lib/dependabot/maven/update_checker/requirements_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ def updated_requirements
attr_reader :properties_to_update

def update_requirement(req_string)
# Since range requirements are excluded this must be exact
update_exact_requirement(req_string)
if req_string.include?(".+")
update_dynamic_requirement(req_string)
else
# Since range requirements are excluded this must be exact
update_exact_requirement(req_string)
end
end

def update_exact_requirement(req_string)
Expand All @@ -60,6 +64,16 @@ def update_exact_requirement(req_string)
req_string.gsub(old_version.to_s, latest_version.to_s)
end

# This is really only a Gradle thing, but Gradle relies on this
# RequirementsUpdater too
def update_dynamic_requirement(req_string)
precision = req_string.split(".").take_while { |s| s != "+" }.count

version_parts = latest_version.segments.first(precision)

version_parts.join(".") + ".+"
end

def version_class
Maven::Version
end
Expand Down
190 changes: 151 additions & 39 deletions maven/lib/dependabot/maven/version.rb
Original file line number Diff line number Diff line change
@@ -1,80 +1,192 @@
# typed: strict
# typed: true
# frozen_string_literal: true

require "dependabot/maven/version_parser"
require "dependabot/version"
require "dependabot/utils"

# Java versions use dots and dashes when tokenising their versions.
# Gem::Version converts a "-" to ".pre.", so we override the `to_s` method.
#
# See https://maven.apache.org/pom.html#Version_Order_Specification for details.

module Dependabot
module Maven
class Version < Dependabot::Version
extend T::Sig
extend T::Helpers

PRERELEASE_QUALIFIERS = T.let([
Dependabot::Maven::VersionParser::ALPHA,
Dependabot::Maven::VersionParser::BETA,
Dependabot::Maven::VersionParser::MILESTONE,
Dependabot::Maven::VersionParser::RC,
Dependabot::Maven::VersionParser::SNAPSHOT
].freeze, T::Array[Integer])

NULL_VALUES = %w(0 final ga).freeze
PREFIXED_TOKEN_HIERARCHY = {
"." => { qualifier: 1, number: 4 },
"-" => { qualifier: 2, number: 3 },
"+" => { qualifier: 3, number: 2 }
}.freeze
NAMED_QUALIFIERS_HIERARCHY = {
"a" => 1, "alpha" => 1,
"b" => 2, "beta" => 2,
"m" => 3, "milestone" => 3,
"rc" => 4, "cr" => 4, "pr" => 4, "pre" => 4,
"snapshot" => 5, "dev" => 5,
"ga" => 6, "" => 6, "final" => 6,
"sp" => 7
}.freeze
VERSION_PATTERN =
"[0-9a-zA-Z]+" \
'(?>\.[0-9a-zA-Z]*)*' \
'([_\-\+][0-9A-Za-z_-]*(\.[0-9A-Za-z_-]*)*)?'
ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/

sig { returns(Dependabot::Maven::TokenBucket) }
attr_accessor :token_bucket

sig { override.params(version: VersionParameter).returns(T::Boolean) }
def self.correct?(version)
return false if version.to_s.empty?
return false if version.nil?

Dependabot::Maven::VersionParser.parse(version.to_s).to_a.any?
rescue ArgumentError
Dependabot.logger.info("Malformed version string #{version}")
false
version.to_s.match?(ANCHORED_VERSION_PATTERN)
end

sig { override.params(version: VersionParameter).void }
def initialize(version)
raise BadRequirementError, "Malformed version string - string is nil" if version.nil?

@version_string = T.let(version.to_s, String)
@token_bucket = T.let(Dependabot::Maven::VersionParser.parse(version_string), Dependabot::Maven::TokenBucket)
@version_string = version.to_s
super(version.to_s.tr("_", "-"))
end

sig { returns(String) }
def inspect
"#<#{self.class} #{version_string}>"
"#<#{self.class} #{@version_string}>"
end

sig { returns(String) }
def to_s
version_string
@version_string
end

sig { returns(T::Boolean) }
def prerelease?
token_bucket.to_a.flatten.any? do |token|
token.is_a?(Integer) && token.negative?
tokens.any? do |token|
next true if token == "eap"
next false unless NAMED_QUALIFIERS_HIERARCHY[token]

NAMED_QUALIFIERS_HIERARCHY[token] < 6
end
end

sig { params(other: VersionParameter).returns(Integer) }
def <=>(other)
other = Dependabot::Maven::Version.new(other.to_s) unless other.is_a? Dependabot::Maven::Version
T.must(token_bucket <=> T.cast(other, Dependabot::Maven::Version).token_bucket)
version = stringify_version(@version_string)
version = fill_tokens(version)
version = trim_version(version)

other_version = stringify_version(other)
other_version = fill_tokens(other_version)
other_version = trim_version(other_version)

version, other_version = convert_dates(version, other_version)

prefixed_tokens = split_into_prefixed_tokens(version)
other_prefixed_tokens = split_into_prefixed_tokens(other_version)

prefixed_tokens, other_prefixed_tokens =
pad_for_comparison(prefixed_tokens, other_prefixed_tokens)

prefixed_tokens.count.times.each do |index|
comp = compare_prefixed_token(
prefix: prefixed_tokens[index][0],
token: prefixed_tokens[index][1..-1] || "",
other_prefix: other_prefixed_tokens[index][0],
other_token: other_prefixed_tokens[index][1..-1] || ""
)
return comp unless comp.zero?
end

0
end

private

sig { returns(String) }
attr_reader :version_string
def tokens
@tokens ||=
begin
version = @version_string.to_s.downcase
version = fill_tokens(version)
version = trim_version(version)
split_into_prefixed_tokens(version).map { |t| t[1..-1] }
end
end

def stringify_version(version)
version = version.to_s.downcase

# Not technically correct, but pragmatic
version.gsub(/^v(?=\d)/, "")
end

def fill_tokens(version)
# Add separators when transitioning from digits to characters
version = version.gsub(/(\d)([A-Za-z])/, '\1-\2')
version = version.gsub(/([A-Za-z])(\d)/, '\1-\2')

# Replace empty tokens with 0
version = version.gsub(/([\.\-])([\.\-])/, '\10\2')
version = version.gsub(/^([\.\-])/, '0\1')
version.gsub(/([\.\-])$/, '\10')
end

def trim_version(version)
version.split("-").filter_map do |v|
parts = v.split(".")
parts = parts[0..-2] while NULL_VALUES.include?(parts&.last)
parts&.join(".")
end.reject(&:empty?).join("-")
end

def convert_dates(version, other_version)
default = [version, other_version]
return default unless version.match?(/^\d{4}-?\d{2}-?\d{2}$/)
return default unless other_version.match?(/^\d{4}-?\d{2}-?\d{2}$/)

[version.delete("-"), other_version.delete("-")]
end

def split_into_prefixed_tokens(version)
".#{version}".split(/(?=[\-\.\+])/)
end

def pad_for_comparison(prefixed_tokens, other_prefixed_tokens)
prefixed_tokens = prefixed_tokens.dup
other_prefixed_tokens = other_prefixed_tokens.dup

longest = [prefixed_tokens, other_prefixed_tokens].max_by(&:count)
shortest = [prefixed_tokens, other_prefixed_tokens].min_by(&:count)

longest.count.times do |index|
next unless shortest[index].nil?

shortest[index] = longest[index].start_with?(".") ? ".0" : "-"
end

[prefixed_tokens, other_prefixed_tokens]
end

def compare_prefixed_token(prefix:, token:, other_prefix:, other_token:)
token_type = token.match?(/^\d+$/) ? :number : :qualifier
other_token_type = other_token.match?(/^\d+$/) ? :number : :qualifier

hierarchy = PREFIXED_TOKEN_HIERARCHY.fetch(prefix).fetch(token_type)
other_hierarchy =
PREFIXED_TOKEN_HIERARCHY.fetch(other_prefix).fetch(other_token_type)

hierarchy_comparison = hierarchy <=> other_hierarchy
return hierarchy_comparison unless hierarchy_comparison.zero?

compare_token(token: token, other_token: other_token)
end

def compare_token(token:, other_token:)
if (token_hierarchy = NAMED_QUALIFIERS_HIERARCHY[token])
return -1 unless NAMED_QUALIFIERS_HIERARCHY[other_token]

return token_hierarchy <=> NAMED_QUALIFIERS_HIERARCHY[other_token]
end

return 1 if NAMED_QUALIFIERS_HIERARCHY[other_token]

if token.match?(/\A\d+\z/) && other_token.match?(/\A\d+\z/)
token = token.to_i
other_token = other_token.to_i
end

token <=> other_token
end
end
end
end
Expand Down
Loading

0 comments on commit 10e5c7c

Please sign in to comment.