diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 2b17297200..b97a79fbc9 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -330,20 +330,28 @@ module Homebrew def audit_license if formula.license.present? - if @spdx_data["licenses"].any? { |lic| lic["licenseId"] == formula.license } - return unless @online + non_standard_licenses = [] + formula.license.each do |license| + next if @spdx_data["licenses"].any? { |spdx| spdx["licenseId"] == license } - user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula - return if user.blank? - - github_license = GitHub.get_repo_license(user, repo) - return if github_license && [formula.license, "NOASSERTION"].include?(github_license) - - problem "License mismatch - GitHub license is: #{github_license}, "\ - "but Formulae license states: #{formula.license}." - else - problem "#{formula.license} is not a standard SPDX license." + non_standard_licenses << license end + + if non_standard_licenses.present? + problem "Formula #{formula.name} contains non-standard SPDX licenses: #{non_standard_licenses}." + end + + return unless @online + + user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula + return if user.blank? + + github_license = GitHub.get_repo_license(user, repo) + return if github_license && (formula.license + ["NOASSERTION"]).include?(github_license) + + problem "License mismatch - GitHub license is: #{Array(github_license)}, "\ + "but Formulae license states: #{formula.license}." + elsif @new_formula problem "No license specified for package." end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index c1e1fc8f0d..ab4734cf57 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -2208,9 +2208,16 @@ class Formula # @!attribute [w] # The SPDX ID of the open-source license that the formula uses. # Shows when running `brew info`. - # + # Multiple licenses means that the software is licensed under multiple licenses. + # Do not use multiple licenses if e.g. different parts are under different licenses. #
license "BSD-2-Clause"
- attr_rw :license + def license(args = nil) + if args.nil? + @licenses + else + @licenses = Array(args) + end + end # @!attribute [w] homepage # The homepage for the software. Used by users to get more information diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 5ac720ebee..c07d59b976 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1123,18 +1123,18 @@ class FormulaInstaller next if @ignore_deps dep_f = dep.to_formula - next unless forbidden_licenses.include? dep_f.license + next unless dep_f.license.all? { |license| forbidden_licenses.include? license } raise CannotInstallFormulaError, <<~EOS - The installation of #{formula.name} has a dependency on #{dep.name} with a forbidden license #{dep_f.license}. + The installation of #{formula.name} has a dependency on #{dep.name} where all its licenses are forbidden: #{dep_f.license}. EOS end return if @only_deps - return unless forbidden_licenses.include? formula.license + return unless formula.license.all? { |license| forbidden_licenses.include? license } raise CannotInstallFormulaError, <<~EOS - #{formula.name} has a forbidden license #{formula.license}. + #{formula.name}'s licenses are all forbidden: #{formula.license}. EOS end end diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb index 9c78bde60f..87c65925b3 100644 --- a/Library/Homebrew/test/dev-cmd/audit_spec.rb +++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb @@ -86,12 +86,14 @@ module Homebrew let(:custom_spdx_id) { "zzz" } let(:standard_mismatch_spdx_id) { "0BSD" } + let(:license_array) { ["0BSD", "GPL-3.0"] } + let(:license_array_mismatch) { ["0BSD", "MIT"] } + let(:license_array_nonstandard) { ["0BSD", "zzz", "MIT"] } it "does not check if the formula is not a new formula" do fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: false class Foo < Formula url "https://brew.sh/foo-1.0.tgz" - license "" end RUBY @@ -103,7 +105,6 @@ module Homebrew fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: true class Foo < Formula url "https://brew.sh/foo-1.0.tgz" - license "" end RUBY @@ -120,7 +121,19 @@ module Homebrew RUBY fa.audit_license - expect(fa.problems.first).to match "#{custom_spdx_id} is not a standard SPDX license." + expect(fa.problems.first).to match "Formula foo contains non-standard SPDX licenses: [\"zzz\"]." + end + + it "detects if license array contains a non-standard spdx-id" do + fa = formula_auditor "foo", <<~RUBY, spdx_data: spdx_data, new_formula: true + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + license #{license_array_nonstandard} + end + RUBY + + fa.audit_license + expect(fa.problems.first).to match "Formula foo contains non-standard SPDX licenses: [\"zzz\"]." end it "verifies that a license info is a standard spdx id" do @@ -135,6 +148,18 @@ module Homebrew 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_data: spdx_data, new_formula: true + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + license #{license_array} + 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 "\ "as what is indicated on its Github repo" do fa = formula_auditor "cask", <<~RUBY, spdx_data: spdx_data, online: true, core_tap: true, new_formula: true @@ -160,8 +185,37 @@ module Homebrew RUBY fa.audit_license - expect(fa.problems.first).to match "License mismatch - GitHub license is: GPL-3.0, "\ - "but Formulae license states: #{standard_mismatch_spdx_id}." + expect(fa.problems.first).to match "License mismatch - GitHub license is: [\"GPL-3.0\"], "\ + "but Formulae license states: #{Array(standard_mismatch_spdx_id)}." + end + + it "checks online and detects that an array of license does not contain "\ + "what is indicated on its Github repository" do + fa = formula_auditor "cask", <<~RUBY, online: true, spdx_data: spdx_data, core_tap: true, new_formula: true + class Cask < Formula + url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" + head "https://github.com/cask/cask.git" + license #{license_array_mismatch} + end + RUBY + + fa.audit_license + expect(fa.problems.first).to match "License mismatch - GitHub license is: [\"GPL-3.0\"], "\ + "but Formulae license states: #{Array(license_array_mismatch)}." + end + + it "checks online and verifies that an array of license contains "\ + "what is indicated on its Github repository" do + fa = formula_auditor "cask", <<~RUBY, online: true, spdx_data: spdx_data, core_tap: true, new_formula: true + class Cask < Formula + url "https://github.com/cask/cask/archive/v0.8.4.tar.gz" + head "https://github.com/cask/cask.git" + license #{license_array} + end + RUBY + + fa.audit_license + expect(fa.problems).to be_empty end end