diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 525fc58f9c..0da5baec21 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -3797,12 +3797,12 @@ class Formula # If called as a method this provides just the {url} for the {SoftwareSpec}. # If a block is provided you can also add {.depends_on} and {Patch}es just to the {.head} {SoftwareSpec}. # The download strategies (e.g. `:using =>`) are the same as for {url}. - # `master` is the default branch for Git and doesn't need stating with a `branch:` parameter. + # Git repositories must always specify `branch:`. # # ### Example # # ```ruby - # head "https://we.prefer.https.over.git.example.com/.git" + # head "https://we.prefer.https.over.git.example.com/.git", branch: "main" # ``` # # ```ruby diff --git a/Library/Homebrew/resource_auditor.rb b/Library/Homebrew/resource_auditor.rb index 8f20881f21..b3f2663f1c 100644 --- a/Library/Homebrew/resource_auditor.rb +++ b/Library/Homebrew/resource_auditor.rb @@ -178,18 +178,23 @@ module Homebrew end def audit_head_branch - return unless @online - return unless @strict return if spec_name != :head - return unless Utils::Git.remote_exists?(url) return if specs[:tag].present? return if specs[:revision].present? + # Skip `resource` URLs as they use SHAs instead of branch specifiers. + return if name != owner.name + return unless url.end_with?(".git") - branch = Utils.popen_read("git", "ls-remote", "--symref", url, "HEAD") - .match(%r{ref: refs/heads/(.*?)\s+HEAD})&.to_a&.second - return if branch.blank? || branch == specs[:branch] + problem "Git `head` URL must specify a branch name" if specs[:branch].blank? - problem "Specify the default branch as `branch: \"#{branch}\"`" + return unless @online + return unless Utils::Git.remote_exists?(url) + + detected_branch = Utils.popen_read("git", "ls-remote", "--symref", url, "HEAD") + .match(%r{ref: refs/heads/(.*?)\s+HEAD})&.to_a&.second + return if detected_branch.blank? || detected_branch == specs[:branch] + + problem "Detected a default branch \"#{detected_branch}\", not \"#{specs[:branch]}\"" end def problem(text) diff --git a/Library/Homebrew/test/dev-cmd/bump_spec.rb b/Library/Homebrew/test/dev-cmd/bump_spec.rb index 31e7447e23..abfaf735f8 100644 --- a/Library/Homebrew/test/dev-cmd/bump_spec.rb +++ b/Library/Homebrew/test/dev-cmd/bump_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Homebrew::DevCmd::Bump do content = <<~RUBY desc "HEAD-only test formula" homepage "https://brew.sh" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" RUBY setup_test_formula("headonly", content) diff --git a/Library/Homebrew/test/formula_auditor_spec.rb b/Library/Homebrew/test/formula_auditor_spec.rb index a442e03d42..5b5124891d 100644 --- a/Library/Homebrew/test/formula_auditor_spec.rb +++ b/Library/Homebrew/test/formula_auditor_spec.rb @@ -285,7 +285,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "GPL-3.0-or-later" end RUBY @@ -301,7 +301,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license all_of: ["GPL-3.0-or-later", "MIT"] end RUBY @@ -317,7 +317,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "GPL-3.0-or-later" => { with: "LLVM-exception" } end RUBY @@ -332,7 +332,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "GPL-3.0-or-later" => { with: "zzz" } end RUBY @@ -351,7 +351,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "GPL-3.0-or-later" => { with: "#{deprecated_spdx_exception}" } end RUBY @@ -371,7 +371,7 @@ RSpec.describe Homebrew::FormulaAuditor do fa = formula_auditor "cask", <<~RUBY, spdx_license_data:, online: true, new_formula: true class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "GPL-3.0-or-later" end RUBY @@ -385,7 +385,7 @@ RSpec.describe Homebrew::FormulaAuditor do fa = formula_auditor "cask", <<~RUBY, spdx_license_data:, online: true, new_formula: true class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license any_of: ["GPL-3.0-or-later", "MIT"] end RUBY @@ -399,7 +399,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "0BSD" end RUBY @@ -416,7 +416,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license "0BSD" end RUBY @@ -433,7 +433,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license #{license_any_mismatch} end RUBY @@ -450,7 +450,7 @@ RSpec.describe Homebrew::FormulaAuditor do formula_text = <<~RUBY class Cask < Formula url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" - head "https://github.com/cask/cask.git" + head "https://github.com/cask/cask.git", branch: "main" license #{license_any} end RUBY @@ -714,6 +714,63 @@ RSpec.describe Homebrew::FormulaAuditor do expect(fa.problems).to be_empty end + it "requires `branch:` to be specified for Git head URLs" do + fa = formula_auditor "foo", <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" + head "https://github.com/example/foo.git" + end + RUBY + + fa.audit_specs + expect(fa.problems.first[:message]).to match("Git `head` URL must specify a branch name") + end + + it "suggests a detected default branch for Git head URLs" do + fa = formula_auditor "foo", <<~RUBY, online: true + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" + head "https://github.com/Homebrew/homebrew-core.git", branch: "master" + end + RUBY + + fa.audit_specs + # This is `.last` because the first problem is the unreachable stable URL. + expect(fa.problems.last[:message]).to match('Detected a default branch "main", not "master"') + end + + it "ignores `branch:` for non-Git head URLs" do + fa = formula_auditor "foo", <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" + head "https://brew.sh/foo.tgz", branch: "develop" + end + RUBY + + fa.audit_specs + expect(fa.problems).not_to match("Git `head` URL must specify a branch name") + end + + it "ignores `branch:` for `resource` URLs" do + fa = formula_auditor "foo", <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" + + resource "bar" do + url "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/bar.rb" + sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" + end + end + RUBY + + fa.audit_specs + expect(fa.problems).to be_empty + end + it "allows versions with no throttle rate" do fa = formula_auditor "bar", <<~RUBY, core_tap: true class Bar < Formula @@ -770,7 +827,7 @@ RSpec.describe Homebrew::FormulaAuditor do class Bar < Formula url "https://brew.sh/foo-1.0.tgz" sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" end RUBY @@ -783,7 +840,7 @@ RSpec.describe Homebrew::FormulaAuditor do class BarAT1 < Formula url "https://brew.sh/foo-1.0.tgz" sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" end RUBY @@ -796,7 +853,7 @@ RSpec.describe Homebrew::FormulaAuditor do class Foo < Formula url "https://brew.sh/foo-1.0.tgz" sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" end RUBY diff --git a/Library/Homebrew/test/livecheck/livecheck_spec.rb b/Library/Homebrew/test/livecheck/livecheck_spec.rb index eab430f208..2371b1358d 100644 --- a/Library/Homebrew/test/livecheck/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck/livecheck_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Homebrew::Livecheck do desc "Test formula" homepage "https://brew.sh" url "https://brew.sh/test-0.0.1.tgz" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" livecheck do url "https://formulae.brew.sh/api/formula/ruby.json" @@ -252,7 +252,7 @@ RSpec.describe Homebrew::Livecheck do desc "Test formula with a duplicate URL" homepage "https://github.com/Homebrew/brew.git" url "https://brew.sh/test-0.0.1.tgz" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" end end diff --git a/Library/Homebrew/test/livecheck/skip_conditions_spec.rb b/Library/Homebrew/test/livecheck/skip_conditions_spec.rb index 94859b9404..eeb755d1cb 100644 --- a/Library/Homebrew/test/livecheck/skip_conditions_spec.rb +++ b/Library/Homebrew/test/livecheck/skip_conditions_spec.rb @@ -12,7 +12,7 @@ RSpec.describe Homebrew::Livecheck::SkipConditions do desc "Test formula" homepage "https://brew.sh" url "https://brew.sh/test-0.0.1.tgz" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" livecheck do url "https://formulae.brew.sh/api/formula/ruby.json" @@ -34,7 +34,7 @@ RSpec.describe Homebrew::Livecheck::SkipConditions do head_only: formula("test_head_only") do desc "HEAD-only test formula" homepage "https://brew.sh" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" end, gist: formula("test_gist") do desc "Gist test formula" diff --git a/Library/Homebrew/test/livecheck_spec.rb b/Library/Homebrew/test/livecheck_spec.rb index 2a4b4b333c..6813ddcd25 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Livecheck do formula do homepage "https://brew.sh" url "https://brew.sh/test-0.0.1.tgz" - head "https://github.com/Homebrew/brew.git" + head "https://github.com/Homebrew/brew.git", branch: "main" end end let(:livecheck_f) { described_class.new(f.class) } diff --git a/Library/Homebrew/test/rubocops/components_redundancy_spec.rb b/Library/Homebrew/test/rubocops/components_redundancy_spec.rb index e65e31ae80..8e2b5076e6 100644 --- a/Library/Homebrew/test/rubocops/components_redundancy_spec.rb +++ b/Library/Homebrew/test/rubocops/components_redundancy_spec.rb @@ -25,7 +25,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::ComponentsRedundancy do it "reports an offense if both `head` and `head do` are present" do expect_offense(<<~RUBY) class Foo < Formula - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" head do ^^^^^^^ FormulaAudit/ComponentsRedundancy: `head` and `head do` should not be simultaneously present # stuff @@ -50,7 +50,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::ComponentsRedundancy do it "reports no offenses if `stable do` is present with a `head` method" do expect_no_offenses(<<~RUBY) class Foo < Formula - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" stable do # stuff @@ -92,7 +92,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::ComponentsRedundancy do it "reports no offenses if `stable do` is present with `url` and `depends_on`" do expect_no_offenses(<<~RUBY) class Foo < Formula - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "trunk" stable do url "https://brew.sh/foo-1.0.tgz" @@ -109,6 +109,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::ComponentsRedundancy do head do url "https://brew.sh/foo.git" + branch "develop" depends_on "bar" end end diff --git a/Library/Homebrew/test/utils/ast/formula_ast_spec.rb b/Library/Homebrew/test/utils/ast/formula_ast_spec.rb index e97a307364..09492ac1a2 100644 --- a/Library/Homebrew/test/utils/ast/formula_ast_spec.rb +++ b/Library/Homebrew/test/utils/ast/formula_ast_spec.rb @@ -193,6 +193,7 @@ RSpec.describe Utils::AST::FormulaAST do head do url "https://brew.sh/foo.git" + branch "develop" end end RUBY @@ -205,6 +206,7 @@ RSpec.describe Utils::AST::FormulaAST do head do url "https://brew.sh/foo.git" + branch "develop" end end RUBY @@ -355,7 +357,7 @@ RSpec.describe Utils::AST::FormulaAST do described_class.new <<~RUBY.chomp class Foo < Formula url "https://brew.sh/foo-1.0.tar.gz" - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" end RUBY end @@ -364,7 +366,7 @@ RSpec.describe Utils::AST::FormulaAST do <<~RUBY.chomp class Foo < Formula url "https://brew.sh/foo-1.0.tar.gz" - head "https://brew.sh/foo.git" + head "https://brew.sh/foo.git", branch: "develop" bottle do sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra @@ -387,6 +389,7 @@ RSpec.describe Utils::AST::FormulaAST do head do url "https://brew.sh/foo.git" + branch "develop" end end RUBY @@ -403,6 +406,7 @@ RSpec.describe Utils::AST::FormulaAST do head do url "https://brew.sh/foo.git" + branch "develop" end end RUBY diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md index 37f7a4b252..cc2f2feb88 100644 --- a/docs/Formula-Cookbook.md +++ b/docs/Formula-Cookbook.md @@ -841,7 +841,7 @@ end Formulae can specify an alternate download for the upstream project's development/cutting-edge source (e.g. `master`/`main`/`trunk`) using [`head`](https://rubydoc.brew.sh/Formula#head-class_method), which can be activated by passing `--HEAD` when installing. Specifying it is done in the same manner as [`url`](https://rubydoc.brew.sh/Formula#url-class_method), with added conventions for fetching from version control repositories: -* Git repositories need `branch:` specified to fetch a branch other than "master". If the repository is very large, specify `only_path` to [limit the checkout to one path](Cask-Cookbook.md#git-urls). +* Git repositories **must always** specify `branch:`. If the repository is very large, specify `only_path` to [limit the checkout to one path](Cask-Cookbook.md#git-urls). ```sh head "https://github.com/some/package.git", branch: "main"