I am using Ruby for the first time and am writing a script that should return the latest version available by checking the tags in a Github repository. The script should take into consideration only the tags with format 0.0.0
, 0.0
or v0.0.0
, exclude all the others, remove the v
if present, and return just the most recent tag. So far this is the code I worked on and there is either something off in my regex or in the way I am sorting the version (or likely both). What should I change to achieve the expected result?
def find_latest_version(package_url)
latest_version = ""
version = `git ls-remote --tags --refs #{package_url} "*\.*\.*"`
regex = /[vV]?[0-9][0-9.]*$|\/[0-9][0-9.]*$/
split = version.split("\n")
split.map {|s|
a = s.split("/").last
b = a.scan(regex).map {|a| a.gsub(/[vV]/, '')}
latest_version = b.max_by{ |s| Gem::Version.new(s) }
}
latest_version
end
CodePudding user response:
split
is an array of multiple values. You then call split.map
which will iterate over the array and perform operations on every element.
One of those operations is latest_version = ...
. That means that for every element in the array you are resetting the value of latest_version
. Whatever element is the last element in the array will end up defining the final value of latest_version
which is not what you want.
You can probably use something like this to accomplish your goal:
# Set a regex that looks for:
# 1. v or V, optionally
# 2. one or more digits (e.g., 1 or 55)
# 3. a literal period and then one or more digits (e.g., 2 or 66)
# 4. a literal period and then one or more digits (e.g., 3 or 77), optionally
# This will match v1.2.3 or v1.2 or 1.2.3 or 1.2 or v10.1.2 or v10.1 or v10.1.20, etc.
# This will not match v1.2.3-alpha, for example
regex = /^[vV]?[0-9] \.[0-9] (\.[0-9] )?$/
# Use the Rails repo as the sample as they have a ton of tags and a lot of variety
package_url = "https://github.com/rails/rails"
# Use a semantic variable name
git_versions = `git ls-remote --tags --refs #{package_url} "*\.*\.*"`
# Split the string by newlines
versions = git_versions.split("\n")
# Split each element by refs/tags/ and select the last element so that we get something like "v7.0.4" only
versions = versions.map { |s| s.split('refs/tags/').last }
# Grab only the versions that match the regex, excluding things like "v6.0.2.rc2"
versions = versions.select { |s| s =~ regex }
# Remove all the v and Vs from the start of the version strings
versions = versions.map { |s| s.sub(/^[vV]/, '') }
# Convert all the strings to Gem::Version values
versions = versions.map { |s| Gem::Version.new(s) }
# Get the largest version
latest_version = versions.max
This can be shrunk down quite a bit and limited to three iterations of the array, but from a readability standpoint this code isn't great:
regex = /^[vV]?[0-9] \.[0-9] (\.[0-9] )?$/
package_url = "https://github.com/rails/rails"
git_versions = `git ls-remote --tags --refs #{package_url} "*\.*\.*"`
latest_version = git_versions.split("\n").map { |v| Gem::Version.create(v.split('refs/tags/').last.match(regex)&.[](0)&.sub(/^[vV]/, '')) }.compact.max
=> Gem::Version.new("7.0.4")