Home > Back-end >  How to get the version tags from a Github repository URL with Ruby and return the latest one
How to get the version tags from a Github repository URL with Ruby and return the latest one

Time:01-21

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")
  • Related