Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Library/Homebrew/style.rb
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,15 @@ def self.run_rubocop(files, output_type,
args << "--config" << (HOMEBREW_REPOSITORY/"docs/docs_rubocop_style.yml")
elsif files.any? { |f| f.to_s.start_with? HOMEBREW_LIBRARY_PATH }
base_dir = HOMEBREW_LIBRARY_PATH
elsif (tap = single_tap(files))
# RuboCop roots its project index at the working directory for this
# config (see `tap_rubocop_style.yml`). A tap has to be indexed on its
# own: rooted at `Library`, the index spans every installed tap and the
# cross-file cops pair one tap's constants and methods with another's as
# reassignments and duplicates. The paths stay as given, so the shared
# config's `Taps/...` exclusions keep matching a symlinked tap.
args << "--config" << (HOMEBREW_LIBRARY/"tap_rubocop_style.yml")
base_dir = tap.path
else
args << "--config" << (HOMEBREW_LIBRARY/".rubocop.yml")
base_dir = HOMEBREW_LIBRARY if files.any? { |f| f.to_s.start_with? HOMEBREW_LIBRARY }
Expand Down Expand Up @@ -282,6 +291,15 @@ def self.run_rubocop(files, output_type,
end
end

sig { params(files: T::Array[Pathname]).returns(T.nilable(Tap)) }
def self.single_tap(files)
taps = files.filter_map { |file| Tap.from_path(file) }
return if taps.empty? || taps.length != files.length
return unless taps.map(&:name).uniq.one?
Comment thread
MikeMcQuaid marked this conversation as resolved.

taps.first
end

sig {
params(
files: T::Array[Pathname],
Expand Down
32 changes: 32 additions & 0 deletions Library/Homebrew/test/style_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,37 @@ class Test

described_class.run_rubocop([ruby_file], :json, fix: true, todo: true)
end

it "roots RuboCop at the tap when every file is in one tap" do
tap_path = HOMEBREW_TAP_DIRECTORY/"homebrew/homebrew-foo"
script = tap_path/"cmd/foo.rb"
script.dirname.mkpath
script.write "# frozen_string_literal: true\n"
result = double(status: double(exitstatus: 0), stdout: '{"files":[]}')

expect(described_class).to receive(:system_command).with(
anything,
hash_including(args: include("--config", HOMEBREW_LIBRARY/"tap_rubocop_style.yml", script), chdir: tap_path),
).and_return(result)

described_class.run_rubocop([script], :json)
end

it "uses the shared config when files span multiple taps" do
scripts = %w[foo bar].map do |name|
script = HOMEBREW_TAP_DIRECTORY/"homebrew/homebrew-#{name}/cmd/#{name}.rb"
script.dirname.mkpath
script.write "# frozen_string_literal: true\n"
script
end
result = double(status: double(exitstatus: 0), stdout: '{"files":[]}')

expect(described_class).to receive(:system_command).with(
anything,
hash_including(args: include("--config", HOMEBREW_LIBRARY/".rubocop.yml"), chdir: HOMEBREW_LIBRARY),
).and_return(result)

described_class.run_rubocop(scripts, :json)
end
end
end
7 changes: 7 additions & 0 deletions Library/tap_rubocop_style.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# `brew style` passes this file as `--config` when every target is inside one
# tap. RuboCop roots its project index at the directory of a `.rubocop*` config
# file and at the working directory for any other name, so this file lets
# `brew style` root the index at the tap it is checking instead of at every
# tap under `Library/Taps`.
inherit_from: .rubocop.yml
Loading