From 33228067adecd8437a1dccfd2a1d458cabaf6171 Mon Sep 17 00:00:00 2001 From: Max Downey Twiss Date: Sat, 6 Dec 2025 14:34:12 +1100 Subject: [PATCH] Split out and refactor github_fallback in tools/version.rb (#13739) --- tests/tools/version.rb | 9 +++-- tools/version.rb | 80 ++++++++++++++---------------------------- 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/tests/tools/version.rb b/tests/tools/version.rb index 3c4881df9..2fb6ce4de 100644 --- a/tests/tools/version.rb +++ b/tests/tools/version.rb @@ -2,6 +2,13 @@ require 'minitest/autorun' require_relative '../../tools/version' class VersionMonitorTest < Minitest::Test + def test_github_fallback + assert_equal('2025-11-03', github_fallback(URI.parse('https://github.com/artichoke/nightly.git'))) + assert_equal('1.0.19', github_fallback(URI.parse('https://github.com/mcxiaoke/android-volley.git'))) + assert_nil(github_fallback(URI.parse('https://github.com/artichoke/artichoke.git'))) + assert_nil(github_fallback(URI.parse('https://github.com/99notreal/99notreal.git'))) + end + def test_gitlab_fallback assert_equal('1.0.0', gitlab_fallback(URI.parse('https://gitlab.com/caseif/fs2sbc.git'))) assert_nil(gitlab_fallback(URI.parse('https://gitlab.com/erikschull/Simple-Camera-Abandoned.git'))) @@ -9,7 +16,6 @@ class VersionMonitorTest < Minitest::Test end def test_sourceforge_fallback - # This repo has been archived for 7 years, so hopefully there won't be any new releases. assert_equal('0.7.1', sourceforge_fallback(URI.parse('http://downloads.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz'))) assert_nil(sourceforge_fallback(URI.parse('https://downloads.sourceforge.net/project/99notreal/99notreal.odz'))) end @@ -17,7 +23,6 @@ class VersionMonitorTest < Minitest::Test def test_pagure_fallback # This repo has been archived for 7 years, so hopefully there won't be any new releases. assert_equal('18.0.0-5', pagure_fallback(URI.parse('https://pagure.io/release-notes'))) - # https://pagure.io/test assert_nil(pagure_fallback(URI.parse('https://pagure.io/test'))) assert_nil(pagure_fallback(URI.parse('https://pagure.io/99notreal'))) end diff --git a/tools/version.rb b/tools/version.rb index 62d8f28eb..f8a8f05cc 100755 --- a/tools/version.rb +++ b/tools/version.rb @@ -1,5 +1,5 @@ #!/usr/bin/env ruby -# version.rb version 3.18 (for Chromebrew) +# version.rb version 3.19 (for Chromebrew) OPTIONS = %w[-h --help -j --json -u --update-package-files -v --verbose -vv] @@ -60,64 +60,14 @@ def get_version(name, homepage, source) puts json if VERY_VERBOSE return json['latest_version'] if json['stable_versions'][0].nil? return json['stable_versions'][0] - elsif source.nil? || %w[Pip].include?(@pkg.superclass.to_s) - return - else - # If anitya has failed, check if the source is a GitHub repository - # as a fallback. - # Note that we only check releases on GitHub since semantic - # version ordering isn't easy to get from tags. - # You can get the last numeric tag using: - # git -c 'versionsort.suffix=-' \ - # ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/#{repo} '*.*.*' \ - # | tail --lines=1 \ - # | cut --delimiter='/' --fields=3 - # However, since that does miss text tags, better to just use - # anitya first. + elsif !source.nil? + # If anitya has failed, we have a variety of fallbacks as a last resort. source.sub!('www.', '') url = URI.parse(source) puts "source_url host is #{url.host}" if VERY_VERBOSE case url.host when 'github.com' - url_parts = url.path.split('/') - unless url_parts.count < 3 - git_hash = nil - repo = "#{url_parts[1]}/#{url_parts[2].gsub(/.git\z/, '')}" - puts "GitHub repo is #{repo}" if VERBOSE - if File.which('gh') - # This allows us to only get non-pre-release versions from - # GitHub if such releases exist. - puts "gh release ls --exclude-pre-releases --exclude-drafts -L 1 -R #{repo} --json tagName -q '.[] | .tagName'" if VERY_VERBOSE - github_ver = `gh release ls --exclude-pre-releases --exclude-drafts -L 1 -R #{repo} --json tagName -q '.[] | .tagName'`.chomp if system 'gh auth status >/dev/null', exception: false - else - puts "curl https://api.github.com/repos/#{repo}/releases/latest -Ls | jq .tag_name -r" if VERY_VERBOSE - rel_status = `curl -fsI https://api.github.com/repos/#{repo}/releases/latest`.lines.first.split[1] - tag_status = `curl -fsI https://api.github.com/repos/#{repo}/tags`.lines.first.split[1] - if rel_status == '404' && tag_status == '404' - puts 'GitHub repo not found or no release/tag available.' if VERBOSE - return - end - # Get the latest release. - github_ver = `curl https://api.github.com/repos/#{repo}/releases/latest -Ls | jq .tag_name -r`.chomp - if github_ver.blank? || github_ver == 'null' - # Get the latest tag. - puts "curl https://api.github.com/repos/#{repo}/tags -Ls | jq '.[0].name' -r" if VERY_VERBOSE - github_ver = `curl https://api.github.com/repos/#{repo}/tags -Ls | jq '.[0].name' -r`.chomp - end - if github_ver.blank? || github_ver == 'null' - # Get the first 6 characters of the latest git hash. - puts "curl https://api.github.com/repos/#{repo}/git/refs -Ls | jq .[0].object.sha -r" if VERY_VERBOSE - github_ver = `curl https://api.github.com/repos/#{repo}/git/refs -Ls | jq .[0].object.sha -r`.chomp[0..5] - git_hash = true - end - end - unless github_ver.blank? || github_ver == 'null' - puts "github_ver = #{github_ver}" if VERY_VERBOSE - # Strip off any leading non-numeric characters. - upstream_version = git_hash.nil? ? github_ver.sub(/.*?(?=[0-9].)/im, '').chomp : github_ver - return upstream_version - end - end + github_fallback(url) when 'gitlab.com' gitlab_fallback(url) when 'downloads.sourceforge.net' @@ -128,6 +78,28 @@ def get_version(name, homepage, source) end end +def github_fallback(url) + url_parts = url.path.split('/') + return if url_parts.count < 3 + + repo = "#{url_parts[1]}/#{url_parts[2].delete_suffix('.git')}" + puts "GitHub repo is #{repo}" if VERBOSE + + releases_json = JSON.parse(Net::HTTP.get(URI("https://api.github.com/repos/#{repo}/releases/latest"))) + tags_json = JSON.parse(Net::HTTP.get(URI("https://api.github.com/repos/#{repo}/tags"))) + + # We check for the prescence of a message here because this will also gracefully handle rate limiting. + if releases_json.include?('message') && (tags_json.empty? || tags_json.include?('message')) + puts 'GitHub repo not found or no release/tag available.' if VERBOSE + return + end + + github_ver = releases_json['tag_name'].nil? ? tags_json[0]['name'] : releases_json['tag_name'] + puts "github_ver = #{github_ver}" if VERY_VERBOSE + # Strip off any leading non-numeric characters. + return github_ver.sub(/.*?(?=[0-9].)/im, '') +end + def gitlab_fallback(url) url_parts = url.path.split('/') return if url_parts.count < 3