diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index 8e7b3d447a..549e4251a3 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -58,12 +58,12 @@ GEM mime-types-data (3.2022.0105) mini_portile2 (2.8.0) minitest (5.16.2) - msgpack (1.5.3) + msgpack (1.5.4) mustache (1.1.1) net-http-digest_auth (1.4.1) net-http-persistent (4.0.1) connection_pool (~> 2.2) - nokogiri (1.13.7) + nokogiri (1.13.8) mini_portile2 (~> 2.8.0) racc (~> 1.4) parallel (1.22.1) diff --git a/Library/Homebrew/ast_constants.rb b/Library/Homebrew/ast_constants.rb index 1de605374d..7622f0a2d3 100644 --- a/Library/Homebrew/ast_constants.rb +++ b/Library/Homebrew/ast_constants.rb @@ -29,6 +29,10 @@ FORMULA_COMPONENT_PRECEDENCE_LIST = [ [{ name: :depends_on, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }], [{ name: :on_macos, type: :block_call }], + *MacOSVersions::SYMBOLS.keys.map do |os_name| + [{ name: :"on_#{os_name}", type: :block_call }] + end, + [{ name: :on_system, type: :block_call }], [{ name: :on_linux, type: :block_call }], [{ name: :on_arm, type: :block_call }], [{ name: :on_intel, type: :block_call }], diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh index 0269d73edb..69cb58ccdb 100644 --- a/Library/Homebrew/cmd/update.sh +++ b/Library/Homebrew/cmd/update.sh @@ -603,13 +603,13 @@ EOS # Only try to `git fetch` when the upstream tags have changed # (so the API does not return 304: unmodified). GITHUB_API_ETAG="$(sed -n 's/^ETag: "\([a-f0-9]\{32\}\)".*/\1/p' ".git/GITHUB_HEADERS" 2>/dev/null)" - GITHUB_API_ACCEPT="application/vnd.github.v3+json" + GITHUB_API_ACCEPT="application/vnd.github+json" GITHUB_API_ENDPOINT="tags" else # Only try to `git fetch` when the upstream branch is at a different SHA # (so the API does not return 304: unmodified). GITHUB_API_ETAG="$(git rev-parse "refs/remotes/origin/${UPSTREAM_BRANCH_DIR}")" - GITHUB_API_ACCEPT="application/vnd.github.v3.sha" + GITHUB_API_ACCEPT="application/vnd.github.sha" GITHUB_API_ENDPOINT="commits/${UPSTREAM_BRANCH_DIR}" fi diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 1ad696ceef..fbcc4de792 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -243,8 +243,8 @@ module Homebrew elsif new_tag.present? [ [ - /#{formula_spec.specs[:tag]}(?=")/, - new_tag, + /tag:(\s+")#{formula_spec.specs[:tag]}(?=")/, + "tag:\\1#{new_tag}\\2", ], [ formula_spec.specs[:revision], diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index a11c177654..171e1e252d 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -1034,7 +1034,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy output, _, status = curl_output( "--silent", "--head", "--location", - "-H", "Accept: application/vnd.github.v3.sha", + "-H", "Accept: application/vnd.github.sha", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}" ) @@ -1051,7 +1051,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy output, _, status = curl_output( "--silent", "--head", "--location", - "-H", "Accept: application/vnd.github.v3.sha", + "-H", "Accept: application/vnd.github.sha", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}" ) diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index 094ef0bfce..002ce1f9cf 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -15,7 +15,7 @@ module RuboCop extend AutoCorrector def on_system_methods - @on_system_methods ||= [:intel, :arm, :macos, :linux, *MacOSVersions::SYMBOLS.keys].map do |m| + @on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersions::SYMBOLS.keys].map do |m| :"on_#{m}" end end @@ -116,6 +116,15 @@ module RuboCop end def check_on_system_block_content(component_precedence_list, on_system_block) + if on_system_block.body.block_type? && !on_system_methods.include?(on_system_block.body.method_name) + offending_node(on_system_block) + problem "Nest `#{on_system_block.method_name}` blocks inside `#{on_system_block.body.method_name}` " \ + "blocks when there is only one inner block." do |corrector| + original_source = on_system_block.source.split("\n") + new_source = [original_source.second, original_source.first, *original_source.drop(2)] + corrector.replace(on_system_block.source_range, new_source.join("\n")) + end + end on_system_allowed_methods = %w[ depends_on patch diff --git a/Library/Homebrew/rubocops/lines.rb b/Library/Homebrew/rubocops/lines.rb index cbac0882a0..e8c7a631a3 100644 --- a/Library/Homebrew/rubocops/lines.rb +++ b/Library/Homebrew/rubocops/lines.rb @@ -1,6 +1,7 @@ # typed: true # frozen_string_literal: true +require "macos_versions" require "rubocops/extend/formula" module RuboCop @@ -375,61 +376,171 @@ module RuboCop # This cop makes sure that OS conditionals are consistent. # # @api private - class OSConditionals < FormulaCop + class OnSystemConditionals < FormulaCop extend AutoCorrector + NO_ON_SYSTEM_METHOD_NAMES = [:install, :post_install].freeze + NO_ON_SYSTEM_BLOCK_NAMES = [:service, :test].freeze + + ON_ARCH_OPTIONS = [:intel, :arm].freeze + ON_BASE_OS_OPTIONS = [:macos, :linux].freeze + ON_MACOS_VERSION_OPTIONS = MacOSVersions::SYMBOLS.keys.freeze + ALL_SYSTEM_OPTIONS = [*ON_ARCH_OPTIONS, *ON_BASE_OS_OPTIONS, *ON_MACOS_VERSION_OPTIONS, :system].freeze + + MACOS_VERSION_CONDITIONALS = { + "==" => nil, + "<=" => :or_older, + ">=" => :or_newer, + }.freeze + + ON_SYSTEM_CONDITIONALS = [:<, :<=].freeze + + def on_system_method_info(on_system_option) + info = {} + info[:method] = :"on_#{on_system_option}" + info[:if_module], info[:if_method] = if ON_ARCH_OPTIONS.include?(on_system_option) + ["Hardware::CPU", :"#{on_system_option}?"] + elsif ON_BASE_OS_OPTIONS.include?(on_system_option) + ["OS", on_system_option == :macos ? :mac? : :linux?] + else + ["MacOS", :version] + end + info[:on_system_string] = "on_#{on_system_option}" + info[:if_string] = if on_system_option == :system + "if OS.linux? || MacOS.version" + else + "if #{info[:if_module]}.#{info[:if_method]}" + end + + info + end + def audit_formula(_node, _class_node, _parent_class_node, body_node) - no_on_os_method_names = [:install, :post_install].freeze - no_on_os_block_names = [:service, :test].freeze - [[:on_macos, :mac?], [:on_linux, :linux?]].each do |on_method_name, if_method_name| - if_method_and_class = "if OS.#{if_method_name}" - no_on_os_method_names.each do |formula_method_name| - method_node = find_method_def(body_node, formula_method_name) - next unless method_node - next unless method_called_ever?(method_node, on_method_name) + top_level_nodes_to_check = [] + NO_ON_SYSTEM_METHOD_NAMES.each do |formula_method_name| + method_node = find_method_def(body_node, formula_method_name) + top_level_nodes_to_check << [formula_method_name, method_node] if method_node + end + NO_ON_SYSTEM_BLOCK_NAMES.each do |formula_block_name| + block_node = find_block(body_node, formula_block_name) + top_level_nodes_to_check << [formula_block_name, block_node] if block_node + end - problem "Don't use '#{on_method_name}' in 'def #{formula_method_name}', " \ - "use '#{if_method_and_class}' instead." do |corrector| - block_node = offending_node.parent - next if block_node.type != :block + ALL_SYSTEM_OPTIONS.each do |on_system_option| + method_info = on_system_method_info(on_system_option) - # TODO: could fix corrector to handle this but punting for now. - next if block_node.single_line? + top_level_nodes_to_check.each do |top_level_name, top_level_node| + top_level_node_string = if top_level_node.def_type? + "def #{top_level_name}" + else + "#{top_level_name} do" + end - source_range = offending_node.source_range.join(offending_node.parent.loc.begin) - corrector.replace(source_range, if_method_and_class) + find_every_method_call_by_name(top_level_node, method_info[:method]).each do |method| + if ON_MACOS_VERSION_OPTIONS.include?(on_system_option) + on_macos_version_method_call(method, on_method: method_info[:method]) do |on_method_parameters| + if on_method_parameters.empty? + method_info[:if_string] = "if MacOS.version == :#{on_system_option}" + else + method_info[:on_system_string] = "#{method_info[:method]} :#{on_method_parameters.first}" + if_condition_operator = MACOS_VERSION_CONDITIONALS.key(on_method_parameters.first) + method_info[:if_string] = "if MacOS.version #{if_condition_operator} :#{on_system_option}" + end + end + elsif method_info[:method] == :on_system + on_system_method_call(method) do |macos_symbol| + base_os, condition = macos_symbol.to_s.split(/_(?=or_)/).map(&:to_sym) + method_info[:on_system_string] = if condition.present? + "on_system :linux, macos: :#{base_os}_#{condition}" + else + "on_system :linux, macos: :#{base_os}" + end + if_condition_operator = MACOS_VERSION_CONDITIONALS.key(condition) + method_info[:if_string] = "if OS.linux? || MacOS.version #{if_condition_operator} :#{base_os}" + end + end + + offending_node(method) + + problem "Don't use `#{method_info[:on_system_string]}` in `#{top_level_node_string}`, " \ + "use `#{method_info[:if_string]}` instead." do |corrector| + block_node = offending_node.parent + next if block_node.type != :block + + # TODO: could fix corrector to handle this but punting for now. + next if block_node.single_line? + + source_range = offending_node.source_range.join(offending_node.parent.loc.begin) + corrector.replace(source_range, method_info[:if_string]) + end + end + end + end + + # Don't restrict OS.mac? or OS.linux? usage in taps; they don't care + # as much as we do about e.g. formulae.brew.sh generation, often use + # platform-specific URLs and we don't want to add DSLs to support + # that case. + return if formula_tap != "homebrew-core" + + ALL_SYSTEM_OPTIONS.each do |on_system_option| + method_info = on_system_method_info(on_system_option) + + if_nodes_to_check = [] + + if ON_ARCH_OPTIONS.include?(on_system_option) + if_arch_node_search(body_node, arch: method_info[:if_method]) do |if_node, else_node| + else_info = if else_node.present? + { + can_autocorrect: true, + on_system_method: on_system_option == :intel ? "on_arm" : "on_intel", + node: else_node, + } + end + + if_nodes_to_check << [if_node, else_info] + end + elsif ON_BASE_OS_OPTIONS.include?(on_system_option) + if_base_os_node_search(body_node, base_os: method_info[:if_method]) do |if_node, else_node| + else_info = if else_node.present? + { + can_autocorrect: true, + on_system_method: on_system_option == :macos ? "on_linux" : "on_macos", + node: else_node, + } + end + + if_nodes_to_check << [if_node, else_info] + end + else + if_macos_version_node_search(body_node, os_name: on_system_option) do |if_node, operator, else_node| + if operator == :< + method_info[:on_system_string] = "on_system" + elsif operator == :<= + method_info[:on_system_string] = "on_system :linux, macos: :#{on_system_option}_or_older" + elsif operator != :== && MACOS_VERSION_CONDITIONALS.key?(operator.to_s) + method_info[:on_system_string] = "#{method_info[:method]} " \ + ":#{MACOS_VERSION_CONDITIONALS[operator.to_s]}" + end + method_info[:if_string] = "if #{method_info[:if_module]}.#{method_info[:if_method]} #{operator} " \ + ":#{on_system_option}" + if else_node.present? || !MACOS_VERSION_CONDITIONALS.key?(operator.to_s) + else_info = { can_autocorrect: false } + end + + if_nodes_to_check << [if_node, else_info] end end - no_on_os_block_names.each do |formula_block_name| - block_node = find_block(body_node, formula_block_name) - next unless block_node - next unless block_method_called_in_block?(block_node, on_method_name) - - problem "Don't use '#{on_method_name}' in '#{formula_block_name} do', " \ - "use '#{if_method_and_class}' instead." do |corrector| - # TODO: could fix corrector to handle this but punting for now. - next if offending_node.single_line? - - source_range = offending_node.send_node.source_range.join(offending_node.body.source_range.begin) - corrector.replace(source_range, "#{if_method_and_class}\n") - end - end - - # Don't restrict OS.mac? or OS.linux? usage in taps; they don't care - # as much as we do about e.g. formulae.brew.sh generation, often use - # platform-specific URLs and we don't want to add DSLs to support - # that case. - next if formula_tap != "homebrew-core" - - find_instance_method_call(body_node, "OS", if_method_name) do |method| + if_nodes_to_check.each do |if_node, else_info| + # TODO: check to see if it's legal valid = T.let(false, T::Boolean) - method.each_ancestor do |ancestor| + if_node.each_ancestor do |ancestor| valid_method_names = case ancestor.type when :def - no_on_os_method_names + NO_ON_SYSTEM_METHOD_NAMES when :block - no_on_os_block_names + NO_ON_SYSTEM_BLOCK_NAMES else next end @@ -440,19 +551,47 @@ module RuboCop end next if valid - offending_node(method) - problem "Don't use '#{if_method_and_class}', use '#{on_method_name} do' instead." do |corrector| - if_node = method.parent - next if if_node.type != :if + offending_node(if_node) + problem "Don't use `#{method_info[:if_string]}`, " \ + "use `#{method_info[:on_system_string]} do` instead." do |corrector| # TODO: could fix corrector to handle this but punting for now. next if if_node.unless? - corrector.replace(if_node.source_range, "#{on_method_name} do\n#{if_node.body.source}\nend") + if else_info.present? + next unless else_info[:can_autocorrect] + + corrector.replace(if_node.source_range, + "#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend\n" \ + "#{else_info[:on_system_method]} do\n#{else_info[:node].source}\nend") + else + corrector.replace(if_node.source_range, + "#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend") + end end end end end + + def_node_matcher :on_macos_version_method_call, <<~PATTERN + (send nil? %on_method (sym ${:or_newer :or_older})?) + PATTERN + + def_node_matcher :on_system_method_call, <<~PATTERN + (send nil? :on_system (sym :linux) (hash (pair (sym :macos) (sym $_)))) + PATTERN + + def_node_search :if_arch_node_search, <<~PATTERN + $(if (send (const (const nil? :Hardware) :CPU) %arch) _ $_) + PATTERN + + def_node_search :if_base_os_node_search, <<~PATTERN + $(if (send (const nil? :OS) %base_os) _ $_) + PATTERN + + def_node_search :if_macos_version_node_search, <<~PATTERN + $(if (send (send (const nil? :MacOS) :version) ${:== :<= :< :>= :> :!=} (sym %os_name)) _ $_) + PATTERN end # This cop checks for other miscellaneous style violations. diff --git a/Library/Homebrew/rubocops/lines.rbi b/Library/Homebrew/rubocops/lines.rbi new file mode 100644 index 0000000000..4036b6dd7b --- /dev/null +++ b/Library/Homebrew/rubocops/lines.rbi @@ -0,0 +1,24 @@ +# typed: strict + +module RuboCop + module Cop + module FormulaAudit + class OnSystemConditionals < FormulaCop + sig { params(node: T.any, on_method: Symbol, block: T.proc.params(parameters: T::Array[T.any]).void).void } + def on_macos_version_method_call(node, on_method:, &block); end + + sig { params(node: T.any, block: T.proc.params(macos_symbol: Symbol).void).void } + def on_system_method_call(node, &block); end + + sig { params(node: T.any, arch: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void } + def if_arch_node_search(node, arch:, &block); end + + sig { params(node: T.any, base_os: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void } + def if_base_os_node_search(node, base_os:, &block); end + + sig { params(node: T.any, os_name: Symbol, block: T.proc.params(node: T.any, operator: Symbol, else_node: T.any).void).void } + def if_macos_version_node_search(node, os_name:, &block); end + end + end + end +end diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index 7b8e2a813a..20c6736a55 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -679,6 +679,130 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do RUBY end + it "reports an offense when a single `patch` block is inside the `on_arm` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_arm do + ^^^^^^^^^ Nest `on_arm` blocks inside `patch` blocks when there is only one inner block. + patch do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + patch do + on_arm do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + end + + it "reports an offense when a single `resource` block is inside the `on_linux` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_linux do + ^^^^^^^^^^^ Nest `on_linux` blocks inside `resource` blocks when there is only one inner block. + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + resource do + on_linux do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + end + + it "reports an offense when a single `patch` block is inside the `on_monterey :or_newer` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_monterey :or_newer do + ^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_monterey` blocks inside `patch` blocks when there is only one inner block. + patch do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + patch do + on_monterey :or_newer do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + end + + it "reports an offense when a single `resource` block is inside the `on_system` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_system :linux, macos: :monterey_or_older do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_system` blocks inside `resource` blocks when there is only one inner block. + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + resource do + on_system :linux, macos: :monterey_or_older do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + end + + it "reports no offenses when a single `on_arm` block is inside the `on_macos` block" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_macos do + on_arm do + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + end + RUBY + end + context "when in a resource block" do it "reports no offenses for a valid `on_macos` and `on_linux` block" do expect_no_offenses(<<~RUBY) diff --git a/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb b/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb deleted file mode 100644 index 28f1a41185..0000000000 --- a/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "rubocops/lines" - -describe RuboCop::Cop::FormulaAudit::OSConditionals do - subject(:cop) { described_class.new } - - context "when auditing OS conditionals" do - it "reports an offense when `OS.linux?` is used on Formula class" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - if OS.linux? - ^^^^^^^^^ Don't use 'if OS.linux?', use 'on_linux do' instead. - url 'https://brew.sh/linux-1.0.tgz' - else - url 'https://brew.sh/linux-1.0.tgz' - end - end - RUBY - end - - it "reports an offense when `OS.mac?` is used on Formula class" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - if OS.mac? - ^^^^^^^ Don't use 'if OS.mac?', use 'on_macos do' instead. - url 'https://brew.sh/mac-1.0.tgz' - else - url 'https://brew.sh/linux-1.0.tgz' - end - end - RUBY - end - - it "reports an offense when `on_macos` is used in install method" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - def install - on_macos do - ^^^^^^^^ Don't use 'on_macos' in 'def install', use 'if OS.mac?' instead. - true - end - end - end - RUBY - end - - it "reports an offense when `on_linux` is used in install method" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - def install - on_linux do - ^^^^^^^^ Don't use 'on_linux' in 'def install', use 'if OS.linux?' instead. - true - end - end - end - RUBY - end - - it "reports an offense when `on_macos` is used in test block" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - test do - on_macos do - ^^^^^^^^ Don't use 'on_macos' in 'test do', use 'if OS.mac?' instead. - true - end - end - end - RUBY - end - end -end diff --git a/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb b/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb new file mode 100644 index 0000000000..24ed0a1e86 --- /dev/null +++ b/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb @@ -0,0 +1,546 @@ +# typed: false +# frozen_string_literal: true + +require "rubocops/lines" + +describe RuboCop::Cop::FormulaAudit::OnSystemConditionals do + subject(:cop) { described_class.new } + + context "when auditing OS conditionals" do + it "reports an offense when `OS.linux?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if OS.linux? + ^^^^^^^^^^^^ Don't use `if OS.linux?`, use `on_linux do` instead. + url 'https://brew.sh/linux-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_linux do + url 'https://brew.sh/linux-1.0.tgz' + end + on_macos do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `OS.mac?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if OS.mac? + ^^^^^^^^^^ Don't use `if OS.mac?`, use `on_macos do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_macos do + url 'https://brew.sh/mac-1.0.tgz' + end + on_linux do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_macos` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_macos do + ^^^^^^^^ Don't use `on_macos` in `def install`, use `if OS.mac?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.mac? + true + end + end + end + RUBY + end + + it "reports an offense when `on_linux` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_linux do + ^^^^^^^^ Don't use `on_linux` in `def install`, use `if OS.linux?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.linux? + true + end + end + end + RUBY + end + + it "reports an offense when `on_macos` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_macos do + ^^^^^^^^ Don't use `on_macos` in `test do`, use `if OS.mac?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if OS.mac? + true + end + end + end + RUBY + end + end + + context "when auditing Hardware::CPU conditionals" do + it "reports an offense when `Hardware::CPU.arm?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if Hardware::CPU.arm? + ^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.arm?`, use `on_arm do` instead. + url 'https://brew.sh/linux-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_arm do + url 'https://brew.sh/linux-1.0.tgz' + end + on_intel do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `Hardware::CPU.intel?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if Hardware::CPU.intel? + ^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.intel?`, use `on_intel do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_intel do + url 'https://brew.sh/mac-1.0.tgz' + end + on_arm do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_intel` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_intel do + ^^^^^^^^ Don't use `on_intel` in `def install`, use `if Hardware::CPU.intel?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if Hardware::CPU.intel? + true + end + end + end + RUBY + end + + it "reports an offense when `on_arm` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_arm do + ^^^^^^ Don't use `on_arm` in `def install`, use `if Hardware::CPU.arm?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if Hardware::CPU.arm? + true + end + end + end + RUBY + end + + it "reports an offense when `on_intel` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_intel do + ^^^^^^^^ Don't use `on_intel` in `test do`, use `if Hardware::CPU.intel?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if Hardware::CPU.intel? + true + end + end + end + RUBY + end + end + + context "when auditing MacOS.version conditionals" do + it "reports an offense when `MacOS.version ==` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version == :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version == :monterey`, use `on_monterey do` instead. + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_monterey do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version <=` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version <= :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version <= :monterey`, use `on_system :linux, macos: :monterey_or_older do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_system :linux, macos: :monterey_or_older do + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version <` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version < :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version < :monterey`, use `on_system do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version >=` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version >= :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version >= :monterey`, use `on_monterey :or_newer do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version >` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version > :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version > :monterey`, use `on_monterey do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_monterey` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey do + ^^^^^^^^^^^ Don't use `on_monterey` in `def install`, use `if MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version == :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey :or_older` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey :or_older do + ^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_older` in `def install`, use `if MacOS.version <= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version <= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey :or_newer` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey :or_newer do + ^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_newer` in `def install`, use `if MacOS.version >= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version >= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_system :linux, macos: :monterey_or_newer` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_system :linux, macos: :monterey_or_newer do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey_or_newer` in `def install`, use `if OS.linux? || MacOS.version >= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.linux? || MacOS.version >= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_monterey do + ^^^^^^^^^^^ Don't use `on_monterey` in `test do`, use `if MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if MacOS.version == :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_system :linux, macos: :monterey` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_system :linux, macos: :monterey do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey` in `test do`, use `if OS.linux? || MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if OS.linux? || MacOS.version == :monterey + true + end + end + end + RUBY + end + end +end diff --git a/Library/Homebrew/utils/github/api.rb b/Library/Homebrew/utils/github/api.rb index 8db64eda0c..005f5baf7b 100644 --- a/Library/Homebrew/utils/github/api.rb +++ b/Library/Homebrew/utils/github/api.rb @@ -184,8 +184,7 @@ module GitHub # This is a no-op if the user is opting out of using the GitHub API. return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api? - args = ["--header", "Accept: application/vnd.github.v3+json", "--write-out", "\n%\{http_code}"] - args += ["--header", "Accept: application/vnd.github.antiope-preview+json"] + args = ["--header", "Accept: application/vnd.github+json", "--write-out", "\n%\{http_code}"] token = credentials args += ["--header", "Authorization: token #{token}"] unless credentials_type == :none diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index 54f7c69dc1..7fc5627185 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -13,8 +13,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-4.0.7/l $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.10/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.3" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.3/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.4" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/bootsnap-1.12.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.12.0/lib" $:.unshift "#{path}/" @@ -49,7 +49,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/racc-1.6.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/racc-1.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.7-x86_64-darwin/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.8-x86_64-darwin/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubyntlm-0.6.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrick-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" diff --git a/docs/FAQ.md b/docs/FAQ.md index e9325489a9..6d37d8a629 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -78,10 +78,10 @@ Homebrew provides pre-built binary packages for many formulae. These are referre If available, bottled binaries will be used by default except under the following conditions: -* Options were passed to the install command, i.e. `brew install ` will use a bottled version of the formula, but `brew install --enable-bar ` will trigger a source build. * The `--build-from-source` option is invoked. * No bottle is available for the machine's currently running OS version. (Bottles for macOS are generated only for supported macOS versions.) * Homebrew is installed to a prefix other than the default (although some bottles support this). +* Formula options were passed to the install command. For example, `brew install ` will try to find a bottled binary, but `brew install --with-foo ` will trigger a source build. We aim to bottle everything.