diff --git a/Library/Homebrew/formula_creator.rb b/Library/Homebrew/formula_creator.rb index db44f2ea4e..15d295597b 100644 --- a/Library/Homebrew/formula_creator.rb +++ b/Library/Homebrew/formula_creator.rb @@ -23,31 +23,9 @@ module Homebrew } def initialize(url:, name: nil, version: nil, tap: nil, mode: nil, license: nil, fetch: false, head: false) @url = url - - if name.blank? - stem = Pathname.new(url).stem - name = if stem.start_with?("index.cgi") && stem.include?("=") - # special cases first - # gitweb URLs e.g. http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary - stem.rpartition("=").last - elsif url =~ %r{github\.com/\S+/(\S+)/(archive|releases)/} - # e.g. https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz - T.must(Regexp.last_match(1)) - else - # e.g. http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz - pathver = Version.parse(stem).to_s - stem.sub(/[-_.]?#{Regexp.escape(pathver)}$/, "") - end - odebug "name from url: #{name}" - end - @name = T.let(name, String) - - version = if version.present? - Version.new(version) - else - Version.detect(url) - end - @version = T.let(version, Version) + @mode = mode + @license = license + @fetch = fetch tap = if tap.blank? CoreTap.instance @@ -56,23 +34,58 @@ module Homebrew end @tap = T.let(tap, Tap) - @mode = T.let(mode.presence, T.nilable(Symbol)) - @license = T.let(license.presence, T.nilable(String)) - @fetch = fetch - - case url - when %r{github\.com/(\S+)/(\S+)\.git} - head = true - user = Regexp.last_match(1) - repository = Regexp.last_match(2) - github = GitHub.repository(user, repository) if fetch - when %r{github\.com/(\S+)/(\S+)/(archive|releases)/} - user = Regexp.last_match(1) - repository = Regexp.last_match(2) - github = GitHub.repository(user, repository) if fetch + if (match_github = url.match %r{github\.com/(?[^/]+)/(?[^/]+).*}) + user = T.must(match_github[:user]) + repository = T.must(match_github[:repo]) + if repository.end_with?(".git") + # e.g. https://github.com/Homebrew/brew.git + repository.delete_suffix!(".git") + head = true + end + odebug "github: #{user} #{repository} head:#{head}" + if name.blank? + name = repository + odebug "name from github: #{name}" + end + elsif name.blank? + stem = Pathname.new(url).stem + name = if stem.start_with?("index.cgi") && stem.include?("=") + # special cases first + # gitweb URLs e.g. http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary + stem.rpartition("=").last + else + # e.g. http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz + pathver = Version.parse(stem).to_s + stem.sub(/[-_.]?#{Regexp.escape(pathver)}$/, "") + end + odebug "name from url: #{name}" end + @name = T.let(name, String) @head = head + + if version.present? + version = Version.new(version) + odebug "version from user: #{version}" + else + version = Version.detect(url) + odebug "version from url: #{version}" + end + + if fetch && user && repository + github = GitHub.repository(user, repository) + + if version.null? && !head + begin + latest_release = GitHub.get_latest_release(user, repository) + version = Version.new(latest_release.fetch("tag_name")) + odebug "github: version from latest_release: #{version}" + rescue GitHub::API::HTTPNotFoundError + odebug "github: latest_release lookup failed: #{url}" + end + end + end @github = T.let(github, T.untyped) + @version = T.let(version, Version) @sha256 = T.let(nil, T.nilable(String)) @desc = T.let(nil, T.nilable(String)) diff --git a/Library/Homebrew/test/formula_creator_spec.rb b/Library/Homebrew/test/formula_creator_spec.rb index a5844829b1..b7d6d20077 100644 --- a/Library/Homebrew/test/formula_creator_spec.rb +++ b/Library/Homebrew/test/formula_creator_spec.rb @@ -5,55 +5,71 @@ require "formula_creator" RSpec.describe Homebrew::FormulaCreator do describe ".new" do tests = { - "generic tarball URL": { - url: "http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz", - name: "synscan", - version: "5.02", + "generic tarball URL": { + url: "http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz", + expected_name: "synscan", + expected_version: "5.02", }, - "gitweb URL": { - url: "http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary", - name: "libzipper", + "gitweb URL": { + url: "http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary", + expected_name: "libzipper", }, - "GitHub repo URL with .git": { - url: "https://github.com/Homebrew/brew.git", - name: "brew", - head: true, - fetch: true, - github_user: "Homebrew", - github_repo: "brew", + "GitHub repository URL with .git": { + url: "https://github.com/Homebrew/brew.git", + fetch: true, + github_user_repository: ["Homebrew", "brew"], + expected_name: "brew", + expected_head: true, }, - "GitHub archive URL": { - url: "https://github.com/Homebrew/brew/archive/4.5.7.tar.gz", - name: "brew", - version: "4.5.7", - fetch: true, - github_user: "Homebrew", - github_repo: "brew", + "GitHub archive URL": { + url: "https://github.com/Homebrew/brew/archive/4.5.7.tar.gz", + fetch: true, + github_user_repository: ["Homebrew", "brew"], + expected_name: "brew", + expected_version: "4.5.7", }, - "GitHub releases URL": { - url: "https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz", - name: "stella", - version: "6.7", - fetch: true, - github_user: "stella-emu", - github_repo: "stella", + "GitHub releases URL": { + url: "https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz", + fetch: true, + github_user_repository: ["stella-emu", "stella"], + expected_name: "stella", + expected_version: "6.7", + }, + "GitHub latest release": { + url: "https://github.com/buildpacks/pack", + fetch: true, + github_user_repository: ["buildpacks", "pack"], + latest_release: { "tag_name" => "v0.37.0" }, + expected_name: "pack", + expected_version: "v0.37.0", + }, + "GitHub URL with name override": { + url: "https://github.com/RooVetGit/Roo-Code", + name: "roo", + expected_name: "roo", }, } tests.each do |description, test| it "parses #{description}" do fetch = test.fetch(:fetch, false) - allow(GitHub).to receive(:repository).with(test.fetch(:github_user), test.fetch(:github_repo)) if fetch + if fetch + github_user_repository = test.fetch(:github_user_repository) + allow(GitHub).to receive(:repository).with(*github_user_repository) + if (latest_release = test[:latest_release]) + expect(GitHub).to receive(:get_latest_release).with(*github_user_repository).and_return(latest_release) + end + end - formula_creator = described_class.new(url: test.fetch(:url), fetch:) + formula_creator = described_class.new(url: test.fetch(:url), name: test[:name], fetch:) - expect(formula_creator.name).to eq(test.fetch(:name)) - if (version = test[:version]) - expect(formula_creator.version).to eq(version) + expect(formula_creator.name).to eq(test.fetch(:expected_name)) + if (expected_version = test[:expected_version]) + expect(formula_creator.version).to eq(expected_version) else expect(formula_creator.version).to be_null end - expect(formula_creator.head).to eq(test.fetch(:head, false)) + expect(formula_creator.head).to eq(test.fetch(:expected_head, false)) end end end