| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "formula_auditor" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-30 13:50:02 -07:00
										 |  |  | RSpec.describe Homebrew::FormulaAuditor do | 
					
						
							| 
									
										
										
										
											2024-03-30 19:10:56 -07:00
										 |  |  |   include FileUtils | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-30 13:50:02 -07:00
										 |  |  |   let(:dir) { mktmpdir } | 
					
						
							|  |  |  |   let(:foo_version) do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     @count ||= 0
 | 
					
						
							|  |  |  |     @count += 1
 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   let(:formula_subpath) { "Formula/foo#{foo_version}.rb" } | 
					
						
							| 
									
										
										
										
											2024-08-10 13:35:20 -07:00
										 |  |  |   let(:origin_tap_path) { HOMEBREW_TAP_DIRECTORY/"homebrew/homebrew-foo" } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |   let(:origin_formula_path) { origin_tap_path/formula_subpath } | 
					
						
							| 
									
										
										
										
											2024-08-10 13:35:20 -07:00
										 |  |  |   let(:tap_path) { HOMEBREW_TAP_DIRECTORY/"homebrew/homebrew-bar" } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |   let(:formula_path) { tap_path/formula_subpath } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def formula_auditor(name, text, options = {}) | 
					
						
							|  |  |  |     path = Pathname.new "#{dir}/#{name}.rb" | 
					
						
							|  |  |  |     path.open("w") do |f| | 
					
						
							|  |  |  |       f.write text | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     formula = Formulary.factory(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if options.key? :tap_audit_exceptions | 
					
						
							|  |  |  |       tap = Tap.fetch("test/tap") | 
					
						
							|  |  |  |       allow(tap).to receive(:audit_exceptions).and_return(options[:tap_audit_exceptions]) | 
					
						
							|  |  |  |       allow(formula).to receive(:tap).and_return(tap) | 
					
						
							|  |  |  |       options.delete :tap_audit_exceptions | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     described_class.new(formula, options) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def formula_gsub(before, after = "") | 
					
						
							|  |  |  |     text = formula_path.read | 
					
						
							|  |  |  |     text.gsub! before, after | 
					
						
							|  |  |  |     formula_path.unlink | 
					
						
							|  |  |  |     formula_path.write text | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def formula_gsub_origin_commit(before, after = "") | 
					
						
							|  |  |  |     text = origin_formula_path.read | 
					
						
							|  |  |  |     text.gsub!(before, after) | 
					
						
							|  |  |  |     origin_formula_path.unlink | 
					
						
							|  |  |  |     origin_formula_path.write text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     origin_tap_path.cd do | 
					
						
							|  |  |  |       system "git", "commit", "-am", "commit" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tap_path.cd do | 
					
						
							|  |  |  |       system "git", "fetch" | 
					
						
							|  |  |  |       system "git", "reset", "--hard", "origin/HEAD" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#problems" do | 
					
						
							|  |  |  |     it "is empty by default" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_license" do | 
					
						
							|  |  |  |     let(:spdx_license_data) { SPDX.license_data } | 
					
						
							|  |  |  |     let(:spdx_exception_data) { SPDX.exception_data } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let(:deprecated_spdx_id) { "GPL-1.0" } | 
					
						
							|  |  |  |     let(:license_all_custom_id) { 'all_of: ["MIT", "zzz"]' } | 
					
						
							|  |  |  |     let(:deprecated_spdx_exception) { "Nokia-Qt-exception-1.1" } | 
					
						
							|  |  |  |     let(:license_any) { 'any_of: ["0BSD", "GPL-3.0-only"]' } | 
					
						
							|  |  |  |     let(:license_any_with_plus) { 'any_of: ["0BSD+", "GPL-3.0-only"]' } | 
					
						
							|  |  |  |     let(:license_nested_conditions) { 'any_of: ["0BSD", { all_of: ["GPL-3.0-only", "MIT"] }]' } | 
					
						
							|  |  |  |     let(:license_any_mismatch) { 'any_of: ["0BSD", "MIT"]' } | 
					
						
							|  |  |  |     let(:license_any_nonstandard) { 'any_of: ["0BSD", "zzz", "MIT"]' } | 
					
						
							|  |  |  |     let(:license_any_deprecated) { 'any_of: ["0BSD", "GPL-1.0", "MIT"]' } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "does not check if the formula is not a new formula" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, new_formula: false | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects no license info" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true, core_tap: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match "Formulae in homebrew/core must specify a license." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects if license is not a standard spdx-id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license "zzz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match <<~EOS | 
					
						
							|  |  |  |         Formula foo contains non-standard SPDX licenses: ["zzz"]. | 
					
						
							|  |  |  |         For a list of valid licenses check: https://spdx.org/licenses/ | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects if license is a deprecated spdx-id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true, strict: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license "#{deprecated_spdx_id}" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to eq <<~EOS | 
					
						
							|  |  |  |         Formula foo contains deprecated SPDX licenses: ["GPL-1.0"]. | 
					
						
							|  |  |  |         You may need to add `-only` or `-or-later` for GNU licenses (e.g. `GPL`, `LGPL`, `AGPL`, `GFDL`). | 
					
						
							|  |  |  |         For a list of valid licenses check: https://spdx.org/licenses/ | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects if license with AND contains a non-standard spdx-id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_all_custom_id} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match <<~EOS | 
					
						
							|  |  |  |         Formula foo contains non-standard SPDX licenses: ["zzz"]. | 
					
						
							|  |  |  |         For a list of valid licenses check: https://spdx.org/licenses/ | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects if license array contains a non-standard spdx-id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_any_nonstandard} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match <<~EOS | 
					
						
							|  |  |  |         Formula foo contains non-standard SPDX licenses: ["zzz"]. | 
					
						
							|  |  |  |         For a list of valid licenses check: https://spdx.org/licenses/ | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "detects if license array contains a deprecated spdx-id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true, strict: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_any_deprecated} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to eq <<~EOS | 
					
						
							|  |  |  |         Formula foo contains deprecated SPDX licenses: ["GPL-1.0"]. | 
					
						
							|  |  |  |         You may need to add `-only` or `-or-later` for GNU licenses (e.g. `GPL`, `LGPL`, `AGPL`, `GFDL`). | 
					
						
							|  |  |  |         For a list of valid licenses check: https://spdx.org/licenses/ | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license info is a standard spdx id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license "0BSD" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license info with plus is a standard spdx id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license "0BSD+" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows :public_domain license" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license :public_domain | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license info with multiple licenses are standard spdx ids" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license any_of: ["0BSD", "MIT"] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license info with exceptions are standard spdx ids" do | 
					
						
							|  |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license "Apache-2.0" => { with: "LLVM-exception" } | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor("foo", formula_text, new_formula: true, | 
					
						
							|  |  |  |                            spdx_license_data:, spdx_exception_data:) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license array contains only standard spdx id" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_any} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license array contains only standard spdx id with plus" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_any_with_plus} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license array with AND contains only standard spdx ids" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, spdx_license_data:, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           license #{license_nested_conditions} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that a standard license id is the same " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "as what is indicated on its GitHub repo", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-09-04 11:35:28 -04:00
										 |  |  |           license "GPL-3.0-or-later" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that a standard license id with AND is the same " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "as what is indicated on its GitHub repo", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license all_of: ["GPL-3.0-or-later", "MIT"] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that a standard license id with WITH is the same " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "as what is indicated on its GitHub repo", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "GPL-3.0-or-later" => { with: "LLVM-exception" } | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor("cask", formula_text, online: true, core_tap: true, new_formula: true, | 
					
						
							|  |  |  |                            spdx_license_data:, spdx_exception_data:) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license exception has standard spdx ids", :needs_network do | 
					
						
							|  |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "GPL-3.0-or-later" => { with: "zzz" } | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor("cask", formula_text, core_tap: true, new_formula: true, | 
					
						
							|  |  |  |                            spdx_license_data:, spdx_exception_data:) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match <<~EOS | 
					
						
							|  |  |  |         Formula cask contains invalid or deprecated SPDX license exceptions: ["zzz"]. | 
					
						
							|  |  |  |         For a list of valid license exceptions check: | 
					
						
							|  |  |  |           https://spdx.org/licenses/exceptions-index.html | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "verifies that a license exception has non-deprecated spdx ids", :needs_network do | 
					
						
							|  |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "GPL-3.0-or-later" => { with: "#{deprecated_spdx_exception}" } | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor("cask", formula_text, core_tap: true, new_formula: true, | 
					
						
							|  |  |  |                            spdx_license_data:, spdx_exception_data:) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match <<~EOS | 
					
						
							|  |  |  |         Formula cask contains invalid or deprecated SPDX license exceptions: ["#{deprecated_spdx_exception}"]. | 
					
						
							|  |  |  |         For a list of valid license exceptions check: | 
					
						
							|  |  |  |           https://spdx.org/licenses/exceptions-index.html | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that a standard license id is in the same exempted license group " \ | 
					
						
							|  |  |  |        "as what is indicated on its GitHub repo", :needs_network 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" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "GPL-3.0-or-later" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that a standard license array is in the same exempted license group " \ | 
					
						
							|  |  |  |        "as what is indicated on its GitHub repo", :needs_network 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" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license any_of: ["GPL-3.0-or-later", "MIT"] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and detects that a formula-specified license is not " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "the same as what is indicated on its GitHub repository", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "0BSD" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to eq 'Formula license ["0BSD"] does not match GitHub license ["GPL-3.0"].' | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows a formula-specified license that differs from its GitHub " \ | 
					
						
							|  |  |  |        "repository for formulae on the mismatched license allowlist", :needs_network do | 
					
						
							|  |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license "0BSD" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true, | 
					
						
							|  |  |  |                            tap_audit_exceptions: { permitted_formula_license_mismatches: ["cask"] } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and detects that an array of license does not contain " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "what is indicated on its GitHub repository", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license #{license_any_mismatch} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match "Formula license [\"0BSD\", \"MIT\"] " \ | 
					
						
							|  |  |  |                                                    "does not match GitHub license [\"GPL-3.0\"]." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "checks online and verifies that an array of license contains " \ | 
					
						
							| 
									
										
										
										
											2024-06-15 19:08:53 +10:00
										 |  |  |        "what is indicated on its GitHub repository", :needs_network do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       formula_text = <<~RUBY | 
					
						
							|  |  |  |         class Cask < Formula | 
					
						
							|  |  |  |           url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://github.com/cask/cask.git", branch: "main" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |           license #{license_any} | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  |       fa = formula_auditor "cask", formula_text, spdx_license_data:, | 
					
						
							|  |  |  |                            online: true, core_tap: true, new_formula: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_license | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_file" do | 
					
						
							|  |  |  |     specify "no issue" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_file | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 22:08:48 +02:00
										 |  |  |   describe "#audit_name" do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     specify "no issue" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, core_tap: true, strict: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 22:08:48 +02:00
										 |  |  |       fa.audit_name | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "uppercase formula name" do | 
					
						
							|  |  |  |       fa = formula_auditor "Foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/Foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 22:08:48 +02:00
										 |  |  |       fa.audit_name | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       expect(fa.problems.first[:message]).to match "must not contain uppercase letters" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_resource_name_matches_pypi_package_name_in_url" do | 
					
						
							| 
									
										
										
										
											2024-07-14 13:19:36 -04:00
										 |  |  |     it "reports a problem if the resource name does not match the python sdist name" do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "abc123" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           resource "Something" do | 
					
						
							|  |  |  |             url "https://files.pythonhosted.org/packages/FooSomething-1.0.0.tar.gz" | 
					
						
							|  |  |  |             sha256 "def456" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 13:19:36 -04:00
										 |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         .to match("`resource` name should be 'FooSomething' to match the PyPI package name") | 
					
						
							| 
									
										
										
										
											2024-07-14 13:19:36 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "reports a problem if the resource name does not match the python wheel name" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "abc123" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           resource "Something" do | 
					
						
							|  |  |  |             url "https://files.pythonhosted.org/packages/FooSomething-1.0.0-py3-none-any.whl" | 
					
						
							|  |  |  |             sha256 "def456" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         .to match("`resource` name should be 'FooSomething' to match the PyPI package name") | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#check_service_command" do | 
					
						
							|  |  |  |     specify "Not installed" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           service do | 
					
						
							|  |  |  |             run [] | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.check_service_command(fa.formula)).to match nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "No service" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir_p fa.formula.prefix | 
					
						
							|  |  |  |       expect(fa.check_service_command(fa.formula)).to match nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "No command" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           service do | 
					
						
							|  |  |  |             run [] | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir_p fa.formula.prefix | 
					
						
							|  |  |  |       expect(fa.check_service_command(fa.formula)).to match nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "Invalid command" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           service do | 
					
						
							|  |  |  |             run [HOMEBREW_PREFIX/"bin/something"] | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir_p fa.formula.prefix | 
					
						
							|  |  |  |       expect(fa.check_service_command(fa.formula)).to match "Service command does not exist" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_github_repository" do | 
					
						
							|  |  |  |     specify "#audit_github_repository when HOMEBREW_NO_GITHUB_API is set" do | 
					
						
							|  |  |  |       ENV["HOMEBREW_NO_GITHUB_API"] = "1" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, strict: true, online: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           homepage "https://github.com/example/example" | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_github_repository | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_github_repository_archived" do | 
					
						
							|  |  |  |     specify "#audit_github_repository_archived when HOMEBREW_NO_GITHUB_API is set" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, strict: true, online: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           homepage "https://github.com/example/example" | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_github_repository_archived | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_gitlab_repository" do | 
					
						
							|  |  |  |     specify "#audit_gitlab_repository for stars, forks and creation date" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, strict: true, online: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           homepage "https://gitlab.com/libtiff/libtiff" | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_gitlab_repository | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_gitlab_repository_archived" do | 
					
						
							|  |  |  |     specify "#audit gitlab repository for archived status" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, strict: true, online: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           homepage "https://gitlab.com/libtiff/libtiff" | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_gitlab_repository_archived | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_bitbucket_repository" do | 
					
						
							|  |  |  |     specify "#audit_bitbucket_repository for stars, forks and creation date" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, strict: true, online: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           homepage "https://bitbucket.com/libtiff/libtiff" | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_bitbucket_repository | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_specs" do | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |     let(:livecheck_throttle) { "livecheck do\n    throttle 10\n  end" } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     let(:versioned_head_spec_list) { { versioned_head_spec_allowlist: ["foo"] } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "doesn't allow to miss a checksum" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]).to match "Checksum is missing" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows to miss a checksum for git strategy" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo.git", tag: "1.0", revision: "f5e00e485e7aa4c5baa20355b27e3b84a6912790" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows to miss a checksum for HEAD" 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" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |     it "requires `branch:` to be specified for Git head URLs" do | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, online: true | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |           head "https://github.com/Homebrew/homebrew-test-bot.git" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       # This is `.last` because the first problem is the unreachable stable URL. | 
					
						
							|  |  |  |       expect(fa.problems.last[:message]).to match("Git `head` URL must specify a branch name") | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "suggests a detected default branch for Git head URLs" do | 
					
						
							| 
									
										
										
										
											2025-08-26 14:25:39 +02:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, online: true, core_tap: true | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |           head "https://github.com/Homebrew/homebrew-test-bot.git", branch: "master" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-26 14:25:39 +02:00
										 |  |  |       message = "To use a non-default HEAD branch, add the formula to `head_non_default_branch_allowlist.json`." | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       # This is `.last` because the first problem is the unreachable stable URL. | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       expect(fa.problems.last[:message]).to match(message) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-26 14:25:39 +02:00
										 |  |  |     it "can specify a default branch without an allowlist if not in a core tap" do | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       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-test-bot.git", branch: "main" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).not_to match("Git `head` URL must specify a branch name") | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "ignores `branch:` for non-Git head URLs" do | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, online: true | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, online: true | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2025-08-10 21:46:53 +01:00
										 |  |  |       expect(fa.problems).not_to match("Git `head` URL must specify a branch name") | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     it "allows versions with no throttle rate" do | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |       fa = formula_auditor "bar", <<~RUBY, core_tap: true | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         class Bar < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.1.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows major/minor versions with throttle rate" do | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, core_tap: true | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |           #{livecheck_throttle} | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows patch versions to be multiples of the throttle rate" do | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, core_tap: true | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.10.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |           #{livecheck_throttle} | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "doesn't allow patch versions that aren't multiples of the throttle rate" do | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |       fa = formula_auditor "foo", <<~RUBY, core_tap: true | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.1.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2024-04-01 00:54:13 -04:00
										 |  |  |           #{livecheck_throttle} | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							| 
									
										
										
										
											2025-08-15 22:33:23 -04:00
										 |  |  |       expect(fa.problems.first[:message]).to match "Should only be updated every 10 releases on multiples of 10" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows non-versioned formulae to have a `HEAD` spec" do | 
					
						
							|  |  |  |       fa = formula_auditor "bar", <<~RUBY, core_tap: true, tap_audit_exceptions: versioned_head_spec_list | 
					
						
							|  |  |  |         class Bar < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://brew.sh/foo.git", branch: "develop" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "doesn't allow versioned formulae to have a `HEAD` spec" do | 
					
						
							|  |  |  |       fa = formula_auditor "bar@1", <<~RUBY, core_tap: true, tap_audit_exceptions: versioned_head_spec_list | 
					
						
							|  |  |  |         class BarAT1 < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://brew.sh/foo.git", branch: "develop" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |       expect(fa.problems.first[:message]).to match "Versioned formulae should not have a `head` spec" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "allows versioned formulae on the allowlist to have a `HEAD` spec" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, core_tap: true, tap_audit_exceptions: versioned_head_spec_list | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							| 
									
										
										
										
											2025-08-03 22:51:29 +01:00
										 |  |  |           head "https://brew.sh/foo.git", branch: "develop" | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_specs | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_deps" do | 
					
						
							|  |  |  |     describe "a dependency on a macOS-provided keg-only formula" do | 
					
						
							|  |  |  |       describe "which is allowlisted" do | 
					
						
							|  |  |  |         subject(:f_a) { fa } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let(:fa) do | 
					
						
							|  |  |  |           formula_auditor "foo", <<~RUBY, new_formula: true | 
					
						
							|  |  |  |             class Foo < Formula | 
					
						
							|  |  |  |               url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |               homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               depends_on "openssl" | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           RUBY | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let(:f_openssl) do | 
					
						
							|  |  |  |           formula do | 
					
						
							|  |  |  |             url "https://brew.sh/openssl-1.0.tgz" | 
					
						
							|  |  |  |             homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             keg_only :provided_by_macos | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           allow(fa.formula.deps.first) | 
					
						
							|  |  |  |             .to receive(:to_formula).and_return(f_openssl) | 
					
						
							|  |  |  |           fa.audit_deps | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it(:problems) { expect(f_a.problems).to be_empty } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "which is not allowlisted", :needs_macos do | 
					
						
							|  |  |  |         subject(:f_a) { fa } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let(:fa) do | 
					
						
							|  |  |  |           formula_auditor "foo", <<~RUBY, new_formula: true, core_tap: true | 
					
						
							|  |  |  |             class Foo < Formula | 
					
						
							|  |  |  |               url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |               homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               depends_on "bc" | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           RUBY | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let(:f_bc) do | 
					
						
							|  |  |  |           formula do | 
					
						
							|  |  |  |             url "https://brew.sh/bc-1.0.tgz" | 
					
						
							|  |  |  |             homepage "https://brew.sh" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             keg_only :provided_by_macos | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           allow(fa.formula.deps.first) | 
					
						
							|  |  |  |             .to receive(:to_formula).and_return(f_bc) | 
					
						
							|  |  |  |           fa.audit_deps | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it(:new_formula_problems) do | 
					
						
							|  |  |  |           expect(f_a.new_formula_problems) | 
					
						
							|  |  |  |             .to include(a_hash_including(message: a_string_matching(/is provided by macOS/))) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_stable_version" do | 
					
						
							|  |  |  |     subject do | 
					
						
							|  |  |  |       fa = described_class.new(Formulary.factory(formula_path), git: true) | 
					
						
							|  |  |  |       fa.audit_stable_version | 
					
						
							|  |  |  |       fa.problems.first&.fetch(:message) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     before do | 
					
						
							|  |  |  |       origin_formula_path.dirname.mkpath | 
					
						
							|  |  |  |       origin_formula_path.write <<~RUBY | 
					
						
							|  |  |  |         class Foo#{foo_version} < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tar.gz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							|  |  |  |           revision 2
 | 
					
						
							|  |  |  |           version_scheme 1
 | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       origin_tap_path.mkpath | 
					
						
							|  |  |  |       origin_tap_path.cd do | 
					
						
							|  |  |  |         system "git", "init" | 
					
						
							|  |  |  |         system "git", "add", "--all" | 
					
						
							|  |  |  |         system "git", "commit", "-m", "init" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tap_path.mkpath | 
					
						
							|  |  |  |       tap_path.cd do | 
					
						
							|  |  |  |         system "git", "clone", origin_tap_path, "." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "versions" do | 
					
						
							|  |  |  |       context "when uncommitted should not decrease" do | 
					
						
							|  |  |  |         before { formula_gsub "foo-1.0.tar.gz", "foo-0.9.tar.gz" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("Stable: version should not decrease (from 1.0 to 0.9)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       context "when committed can decrease" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-0.9.tar.gz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "can decrease with version_scheme increased" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub "revision 2" | 
					
						
							|  |  |  |           formula_gsub "foo-1.0.tar.gz", "foo-0.9.tar.gz" | 
					
						
							|  |  |  |           formula_gsub "version_scheme 1", "version_scheme 2" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_revision" do | 
					
						
							|  |  |  |     subject do | 
					
						
							|  |  |  |       fa = described_class.new(Formulary.factory(formula_path), git: true) | 
					
						
							|  |  |  |       fa.audit_revision | 
					
						
							|  |  |  |       fa.problems.first&.fetch(:message) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     before do | 
					
						
							|  |  |  |       origin_formula_path.dirname.mkpath | 
					
						
							|  |  |  |       origin_formula_path.write <<~RUBY | 
					
						
							|  |  |  |         class Foo#{foo_version} < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tar.gz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							|  |  |  |           revision 2
 | 
					
						
							|  |  |  |           version_scheme 1
 | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       origin_tap_path.mkpath | 
					
						
							|  |  |  |       origin_tap_path.cd do | 
					
						
							|  |  |  |         system "git", "init" | 
					
						
							|  |  |  |         system "git", "add", "--all" | 
					
						
							|  |  |  |         system "git", "commit", "-m", "init" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tap_path.mkpath | 
					
						
							|  |  |  |       tap_path.cd do | 
					
						
							|  |  |  |         system "git", "clone", origin_tap_path, "." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "new formulae should not have a revision" do | 
					
						
							|  |  |  |       it "doesn't allow new formulae to have a revision" do | 
					
						
							|  |  |  |         fa = formula_auditor "foo", <<~RUBY, new_formula: true | 
					
						
							|  |  |  |           class Foo < Formula | 
					
						
							|  |  |  |             url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |             revision 1
 | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fa.audit_revision | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(fa.new_formula_problems).to include( | 
					
						
							|  |  |  |           a_hash_including(message: a_string_matching(/should not define a revision/)), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "revisions" do | 
					
						
							|  |  |  |       describe "should not be removed when first committed above 0" do | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "with the same version, should not decrease" do | 
					
						
							|  |  |  |         before { formula_gsub_origin_commit "revision 2", "revision 1" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision` should not decrease (from 2 to 1)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not be removed with the same version" do | 
					
						
							|  |  |  |         before { formula_gsub_origin_commit "revision 2" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision` should not decrease (from 2 to 0)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not decrease with the same, uncommitted version" do | 
					
						
							|  |  |  |         before { formula_gsub "revision 2", "revision 1" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision` should not decrease (from 2 to 1)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should be removed with a newer version" do | 
					
						
							|  |  |  |         before { formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision 2` should be removed") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should be removed with a newer local version" do | 
					
						
							|  |  |  |         before { formula_gsub "foo-1.0.tar.gz", "foo-1.1.tar.gz" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision 2` should be removed") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not warn on an newer version revision removal" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2", "" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not warn when revision from previous version matches current revision" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2", "# no revision" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "# no revision", "revision 1" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 1", "revision 2" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should only increment by 1 with an uncommitted version" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub "revision 2", "revision 4" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`revision` should only increment by 1") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not warn on past increment by more than 1" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2", "# no revision" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "# no revision", "revision 3" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_version_scheme" do | 
					
						
							|  |  |  |     subject do | 
					
						
							|  |  |  |       fa = described_class.new(Formulary.factory(formula_path), git: true) | 
					
						
							|  |  |  |       fa.audit_version_scheme | 
					
						
							|  |  |  |       fa.problems.first&.fetch(:message) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     before do | 
					
						
							|  |  |  |       origin_formula_path.dirname.mkpath | 
					
						
							|  |  |  |       origin_formula_path.write <<~RUBY | 
					
						
							|  |  |  |         class Foo#{foo_version} < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tar.gz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							|  |  |  |           revision 2
 | 
					
						
							|  |  |  |           version_scheme 1
 | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       origin_tap_path.mkpath | 
					
						
							|  |  |  |       origin_tap_path.cd do | 
					
						
							|  |  |  |         system "git", "init" | 
					
						
							|  |  |  |         system "git", "add", "--all" | 
					
						
							|  |  |  |         system "git", "commit", "-m", "init" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tap_path.mkpath | 
					
						
							|  |  |  |       tap_path.cd do | 
					
						
							|  |  |  |         system "git", "clone", origin_tap_path, "." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "version_schemes" do | 
					
						
							|  |  |  |       describe "should not decrease with the same version" do | 
					
						
							|  |  |  |         before { formula_gsub_origin_commit "version_scheme 1" } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`version_scheme` should not decrease (from 1 to 0)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not decrease with a new version" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2", "" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "version_scheme 1", "" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`version_scheme` should not decrease (from 1 to 0)") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should only increment by 1" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit "version_scheme 1", "# no version_scheme" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2", "" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "# no version_scheme", "version_scheme 3" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 16:42:32 -04:00
										 |  |  |         it { is_expected.to match("`version_scheme` should only increment by 1") } | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_unconfirmed_checksum_change" do | 
					
						
							|  |  |  |     subject do | 
					
						
							|  |  |  |       fa = described_class.new(Formulary.factory(formula_path), git: true) | 
					
						
							|  |  |  |       fa.audit_unconfirmed_checksum_change | 
					
						
							|  |  |  |       fa.problems.first&.fetch(:message) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     before do | 
					
						
							|  |  |  |       origin_formula_path.dirname.mkpath | 
					
						
							|  |  |  |       origin_formula_path.write <<~RUBY | 
					
						
							|  |  |  |         class Foo#{foo_version} < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tar.gz" | 
					
						
							|  |  |  |           sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e" | 
					
						
							|  |  |  |           revision 2
 | 
					
						
							|  |  |  |           version_scheme 1
 | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       origin_tap_path.mkpath | 
					
						
							|  |  |  |       origin_tap_path.cd do | 
					
						
							|  |  |  |         system "git", "init" | 
					
						
							|  |  |  |         system "git", "add", "--all" | 
					
						
							|  |  |  |         system "git", "commit", "-m", "init" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tap_path.mkpath | 
					
						
							|  |  |  |       tap_path.cd do | 
					
						
							|  |  |  |         system "git", "clone", origin_tap_path, "." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe "checksums" do | 
					
						
							|  |  |  |       describe "should not change with the same version" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub( | 
					
						
							|  |  |  |             'sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e"', | 
					
						
							|  |  |  |             'sha256 "3622d2a53236ed9ca62de0616a7e80fd477a9a3f862ba09d503da188f53ca523"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to match("stable sha256 changed without the url/version also changing") } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "should not change with the same version when not the first commit" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit( | 
					
						
							|  |  |  |             'sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e"', | 
					
						
							|  |  |  |             'sha256 "3622d2a53236ed9ca62de0616a7e80fd477a9a3f862ba09d503da188f53ca523"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |           formula_gsub_origin_commit "revision 2" | 
					
						
							|  |  |  |           formula_gsub_origin_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub( | 
					
						
							|  |  |  |             'sha256 "3622d2a53236ed9ca62de0616a7e80fd477a9a3f862ba09d503da188f53ca523"', | 
					
						
							|  |  |  |             'sha256 "e048c5e6144f5932d8672c2fade81d9073d5b3ca1517b84df006de3d25414fc1"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to match("stable sha256 changed without the url/version also changing") } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "can change with the different version" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit( | 
					
						
							|  |  |  |             'sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e"', | 
					
						
							|  |  |  |             'sha256 "3622d2a53236ed9ca62de0616a7e80fd477a9a3f862ba09d503da188f53ca523"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |           formula_gsub "foo-1.0.tar.gz", "foo-1.1.tar.gz" | 
					
						
							|  |  |  |           formula_gsub_origin_commit( | 
					
						
							|  |  |  |             'sha256 "3622d2a53236ed9ca62de0616a7e80fd477a9a3f862ba09d503da188f53ca523"', | 
					
						
							|  |  |  |             'sha256 "e048c5e6144f5932d8672c2fade81d9073d5b3ca1517b84df006de3d25414fc1"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe "can be removed when switching schemes" do | 
					
						
							|  |  |  |         before do | 
					
						
							|  |  |  |           formula_gsub_origin_commit( | 
					
						
							|  |  |  |             'url "https://brew.sh/foo-1.0.tar.gz"', | 
					
						
							|  |  |  |             'url "https://foo.com/brew/bar.git", tag: "1.0", revision: "f5e00e485e7aa4c5baa20355b27e3b84a6912790"', | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |           formula_gsub_origin_commit('sha256 "31cccfc6630528db1c8e3a06f6decf2a370060b982841cfab2b8677400a5092e"', | 
					
						
							|  |  |  |                                      "") | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it { is_expected.to be_nil } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_versioned_keg_only" do | 
					
						
							|  |  |  |     specify "it warns when a versioned formula is not `keg_only`" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo@1.1", <<~RUBY, core_tap: true | 
					
						
							|  |  |  |         class FooAT11 < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.1.tgz" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_versioned_keg_only | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("Versioned formulae in homebrew/core should use `keg_only :versioned_formula`") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "it warns when a versioned formula has an incorrect `keg_only` reason" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo@1.1", <<~RUBY, core_tap: true | 
					
						
							|  |  |  |         class FooAT11 < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.1.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           keg_only :provided_by_macos | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_versioned_keg_only | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("Versioned formulae in homebrew/core should use `keg_only :versioned_formula`") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "it does not warn when a versioned formula has `keg_only :versioned_formula`" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo@1.1", <<~RUBY, core_tap: true | 
					
						
							|  |  |  |         class FooAT11 < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.1.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           keg_only :versioned_formula | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_versioned_keg_only | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_conflicts" do | 
					
						
							|  |  |  |     before do | 
					
						
							| 
									
										
										
										
											2024-05-04 22:04:04 +01:00
										 |  |  |       # We don't really test the formula text retrieval here | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       allow(File).to receive(:open).and_return("") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-10 14:37:21 +00:00
										 |  |  |     specify "it warns when conflicting with non-existing formula", :no_api do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       foo = formula("foo") do | 
					
						
							|  |  |  |         url "https://brew.sh/bar-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts_with "bar" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa = described_class.new foo | 
					
						
							|  |  |  |       fa.audit_conflicts | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("Can't find conflicting formula \"bar\"") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-10 14:37:21 +00:00
										 |  |  |     specify "it warns when conflicting with itself", :no_api do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       foo = formula("foo") do | 
					
						
							|  |  |  |         url "https://brew.sh/bar-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts_with "foo" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       stub_formula_loader foo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa = described_class.new foo | 
					
						
							|  |  |  |       fa.audit_conflicts | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("Formula should not conflict with itself") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-10 14:37:21 +00:00
										 |  |  |     specify "it warns when another formula does not have a symmetric conflict", :no_api do | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  |       stub_formula_loader formula("gcc") { url "gcc-1.0" } | 
					
						
							|  |  |  |       stub_formula_loader formula("glibc") { url "glibc-1.0" } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       foo = formula("foo") do | 
					
						
							|  |  |  |         url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       stub_formula_loader foo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bar = formula("bar") do | 
					
						
							|  |  |  |         url "https://brew.sh/bar-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts_with "foo" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa = described_class.new bar | 
					
						
							|  |  |  |       fa.audit_conflicts | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("Formula foo should also have a conflict declared with bar") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2024-09-30 23:11:00 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_deprecate_disable" do | 
					
						
							|  |  |  |     specify "it warns when deprecate/disable reason is invalid" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         deprecate! date: "2021-01-01", because: :foobar | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir_p fa.formula.prefix | 
					
						
							|  |  |  |       fa.audit_deprecate_disable | 
					
						
							|  |  |  |       expect(fa.problems.first[:message]) | 
					
						
							|  |  |  |         .to match("foobar is not a valid deprecate! or disable! reason") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     specify "it does not warn when deprecate/disable reason is valid" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         deprecate! date: "2021-01-01", because: :repo_archived | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mkdir_p fa.formula.prefix | 
					
						
							|  |  |  |       fa.audit_deprecate_disable | 
					
						
							|  |  |  |       expect(fa.problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2025-07-16 23:46:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe "#audit_no_autobump" do | 
					
						
							|  |  |  |     it "warns when autobump exclusion reason is not suitable for new formula" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           no_autobump! because: :requires_manual_review | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_no_autobump | 
					
						
							|  |  |  |       expect(fa.new_formula_problems.first[:message]) | 
					
						
							|  |  |  |         .to match("`:requires_manual_review` is a temporary reason intended for existing packages, " \ | 
					
						
							|  |  |  |                   "use a different reason instead.") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it "does not warn when autobump exclusion reason is allowed" do | 
					
						
							|  |  |  |       fa = formula_auditor "foo", <<~RUBY, new_formula: true | 
					
						
							|  |  |  |         class Foo < Formula | 
					
						
							|  |  |  |           url "https://brew.sh/foo-1.0.tgz" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           no_autobump! because: "foo bar" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       RUBY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fa.audit_no_autobump | 
					
						
							|  |  |  |       expect(fa.new_formula_problems).to be_empty | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2024-03-30 11:18:58 -07:00
										 |  |  | end |