From fcdaa271e3b97f297169bbd5dfd8df7f08b544b8 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 8 Mar 2025 02:01:13 +0900 Subject: [PATCH] Pluginfy RuboCop Airbnb This PR adds support for RuboCop's Plugin feature. It replaces the ad-hoc `Inject` hack with the RuboCop plugin system introduced in RuboCop 1.72. - https://github.com/rubocop/rubocop/pull/13792 - https://docs.rubocop.org/rubocop/plugin_migration_guide.html Accordingly, rubocop-airbnb has been updated to require specific versions of the following RuboCop extension plugins it depends on - rubocop-performance (`~> 1.24`) - rubocop-rails (`~> 2.30`) - rubocop-rspec (`~> 3.5`) The most significant change is that rubocop-rspec has been updated from version 2 to version 3. As a result, `RSpec/Capybara` and `RSpec/FactoryBot` have been extracted into the following extension gems: - rubocop-capybara - rubocop-factory_bot This PR adds dependencies on both rubocop-capybara and rubocop-rspec extensions to maintain the previous rubocop-rspec configuration. `RSpec/FilePath` has been split into `RSpec/SpecFilePathFormat` and `RSpec/SpecFilePathSuffix`, so the original disabling has been retained in the configuration. Similarly, `RSpec/Capybara/FeatureMethods` remains disabled as `RSpec/Dialect`. https://github.com/rubocop/rubocop-rspec/blob/v3.5.0/config/obsoletion.yml Resolves https://github.com/rubocop/rubocop-factory_bot/issues/147. --- rubocop-airbnb/.rubocop.yml | 4 +- rubocop-airbnb/README.md | 8 ++-- rubocop-airbnb/config/default.yml | 4 +- rubocop-airbnb/config/rubocop-capybara.yml | 6 +++ rubocop-airbnb/config/rubocop-factory_bot.yml | 10 +++++ rubocop-airbnb/config/rubocop-performance.yml | 3 +- rubocop-airbnb/config/rubocop-rails.yml | 2 +- rubocop-airbnb/config/rubocop-rspec.yml | 40 ++++++++----------- rubocop-airbnb/lib/rubocop-airbnb.rb | 8 ++-- rubocop-airbnb/lib/rubocop/airbnb/inject.rb | 20 ---------- rubocop-airbnb/lib/rubocop/airbnb/plugin.rb | 31 ++++++++++++++ rubocop-airbnb/rubocop-airbnb.gemspec | 13 ++++-- 12 files changed, 88 insertions(+), 61 deletions(-) create mode 100644 rubocop-airbnb/config/rubocop-capybara.yml create mode 100644 rubocop-airbnb/config/rubocop-factory_bot.yml delete mode 100644 rubocop-airbnb/lib/rubocop/airbnb/inject.rb create mode 100644 rubocop-airbnb/lib/rubocop/airbnb/plugin.rb diff --git a/rubocop-airbnb/.rubocop.yml b/rubocop-airbnb/.rubocop.yml index e72544e..e8c37e3 100644 --- a/rubocop-airbnb/.rubocop.yml +++ b/rubocop-airbnb/.rubocop.yml @@ -1,6 +1,8 @@ inherit_from: - .rubocop_airbnb.yml - - ./config/default.yml + +plugins: + - rubocop-airbnb AllCops: CacheRootDirectory: tmp/rubocop diff --git a/rubocop-airbnb/README.md b/rubocop-airbnb/README.md index 9a3cbe5..c579f3c 100644 --- a/rubocop-airbnb/README.md +++ b/rubocop-airbnb/README.md @@ -29,7 +29,7 @@ ways to do this: First Create a new file `.rubocop_airbnb.yml` in the same directory as your `.rubocop.yml` this file should contain ``` -require: +plugins: - rubocop-airbnb ``` @@ -50,10 +50,13 @@ you could potentially experience a bunch of warnings from `.rubocop_todo.yml` fo Now you can run `rubocop` and it will automatically load the RuboCop Airbnb cops together with the standard cops. +> [!NOTE] +> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`. + ### Command line ```bash -rubocop --require rubocop-airbnb +rubocop --plugin rubocop-airbnb ``` ## The Cops @@ -70,4 +73,3 @@ Airbnb/PhraseBundleKeys: Exclude: - spec/my_poorly_named_spec_file.rb ``` - diff --git a/rubocop-airbnb/config/default.yml b/rubocop-airbnb/config/default.yml index a8a9f79..7c13102 100644 --- a/rubocop-airbnb/config/default.yml +++ b/rubocop-airbnb/config/default.yml @@ -29,7 +29,7 @@ RSpec: Include: - _spec.rb - "(?:^|/)spec/" -RSpec/FactoryBot: +FactoryBot: Include: - spec/factories/**/*.rb - features/support/factories/**/*.rb @@ -37,6 +37,8 @@ RSpec/FactoryBot: inherit_from: - './rubocop-airbnb.yml' - './rubocop-bundler.yml' + - './rubocop-capybara.yml' + - './rubocop-factory_bot.yml' - './rubocop-gemspec.yml' - './rubocop-layout.yml' - './rubocop-lint.yml' diff --git a/rubocop-airbnb/config/rubocop-capybara.yml b/rubocop-airbnb/config/rubocop-capybara.yml new file mode 100644 index 0000000..208feba --- /dev/null +++ b/rubocop-airbnb/config/rubocop-capybara.yml @@ -0,0 +1,6 @@ +plugins: + - rubocop-capybara + +Capybara/CurrentPathExpectation: + Description: Checks that no expectations are set on Capybara's `current_path`. + Enabled: false diff --git a/rubocop-airbnb/config/rubocop-factory_bot.yml b/rubocop-airbnb/config/rubocop-factory_bot.yml new file mode 100644 index 0000000..41a4a7b --- /dev/null +++ b/rubocop-airbnb/config/rubocop-factory_bot.yml @@ -0,0 +1,10 @@ +plugins: + - rubocop-factory_bot + +FactoryBot/AttributeDefinedStatically: + Description: Always declare attribute values as blocks. + Enabled: false + +FactoryBot/CreateList: + Description: Checks for create_list usage. + Enabled: true diff --git a/rubocop-airbnb/config/rubocop-performance.yml b/rubocop-airbnb/config/rubocop-performance.yml index 3300633..3dbae27 100644 --- a/rubocop-airbnb/config/rubocop-performance.yml +++ b/rubocop-airbnb/config/rubocop-performance.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-performance Performance/Caller: @@ -122,4 +122,3 @@ Performance/UnfreezeString: Performance/UriDefaultParser: Enabled: false - diff --git a/rubocop-airbnb/config/rubocop-rails.yml b/rubocop-airbnb/config/rubocop-rails.yml index 7ee5a1e..ddd4980 100644 --- a/rubocop-airbnb/config/rubocop-rails.yml +++ b/rubocop-airbnb/config/rubocop-rails.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-rails # before_action doesn't seem to exist, so this doesn't make sense. diff --git a/rubocop-airbnb/config/rubocop-rspec.yml b/rubocop-airbnb/config/rubocop-rspec.yml index 0503b7d..e0cc01f 100644 --- a/rubocop-airbnb/config/rubocop-rspec.yml +++ b/rubocop-airbnb/config/rubocop-rspec.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-rspec RSpec/AlignLeftLetBrace: @@ -53,6 +53,10 @@ RSpec/DescribedClass: Description: 'Use `described_class` for tested class / module' Enabled: false +RSpec/Dialect: + Description: Enforces custom RSpec dialects. + Enabled: false + RSpec/EmptyExampleGroup: Description: Checks if an example group does not include any tests. Enabled: true @@ -110,13 +114,6 @@ RSpec/ExpectOutput: Description: Checks for opportunities to use `expect { ... }.to output`. Enabled: false -RSpec/FilePath: - Description: 'Checks the file and folder naming of the spec file.' - Enabled: false - CustomTransform: - RuboCop: rubocop - RSpec: rspec - RSpec/Focus: Description: Checks if examples are focused. Enabled: false @@ -293,6 +290,17 @@ RSpec/SingleArgumentMessageChain: Description: Checks that chains of messages contain more than one element. Enabled: true +RSpec/SpecFilePathFormat: + Description: Checks that spec file paths are consistent and well-formed. + Enabled: false + CustomTransform: + RuboCop: rubocop + RSpec: rspec + +RSpec/SpecFilePathSuffix: + Description: Checks that spec file paths suffix are consistent and well-formed. + Enabled: false + RSpec/SubjectStub: Description: Checks for stubbed test subjects. Enabled: false @@ -308,19 +316,3 @@ RSpec/VerifiedDoubles: RSpec/VoidExpect: Description: This cop checks void `expect()`. Enabled: false - -RSpec/Capybara/CurrentPathExpectation: - Description: Checks that no expectations are set on Capybara's `current_path`. - Enabled: false - -RSpec/Capybara/FeatureMethods: - Description: Checks for consistent method usage in feature specs. - Enabled: false - -RSpec/FactoryBot/AttributeDefinedStatically: - Description: Always declare attribute values as blocks. - Enabled: false - -RSpec/FactoryBot/CreateList: - Description: Checks for create_list usage. - Enabled: true diff --git a/rubocop-airbnb/lib/rubocop-airbnb.rb b/rubocop-airbnb/lib/rubocop-airbnb.rb index 6edf6cb..d7cc81b 100644 --- a/rubocop-airbnb/lib/rubocop-airbnb.rb +++ b/rubocop-airbnb/lib/rubocop-airbnb.rb @@ -7,8 +7,6 @@ require 'rubocop-performance' require 'rubocop-rails' -require 'rubocop/airbnb' -require 'rubocop/airbnb/inject' -require 'rubocop/airbnb/version' - -RuboCop::Airbnb::Inject.defaults! +require_relative 'rubocop/airbnb' +require_relative 'rubocop/airbnb/plugin' +require_relative 'rubocop/airbnb/version' diff --git a/rubocop-airbnb/lib/rubocop/airbnb/inject.rb b/rubocop-airbnb/lib/rubocop/airbnb/inject.rb deleted file mode 100644 index d636f27..0000000 --- a/rubocop-airbnb/lib/rubocop/airbnb/inject.rb +++ /dev/null @@ -1,20 +0,0 @@ -# Straight up ripped from the custom Rspec rubocop -# https://github.com/nevir/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb -require 'yaml' - -module RuboCop - module Airbnb - # Because RuboCop doesn't yet support plugins, we have to monkey patch in a - # bit of our configuration. - module Inject - def self.defaults! - path = CONFIG_DEFAULT.to_s - hash = ConfigLoader.load_file(path).to_hash - config = Config.new(hash, path) - puts "configuration from #{path}" if ConfigLoader.debug? - config = ConfigLoader.merge_with_default(config, path) - ConfigLoader.instance_variable_set(:@default_configuration, config) - end - end - end -end diff --git a/rubocop-airbnb/lib/rubocop/airbnb/plugin.rb b/rubocop-airbnb/lib/rubocop/airbnb/plugin.rb new file mode 100644 index 0000000..6406024 --- /dev/null +++ b/rubocop-airbnb/lib/rubocop/airbnb/plugin.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'lint_roller' + +module RuboCop + module Airbnb + # A plugin that integrates RuboCop Airbnb with RuboCop's plugin system. + class Plugin < LintRoller::Plugin + def about + LintRoller::About.new( + name: 'rubocop-airbnb', + version: VERSION, + homepage: 'https://github.com/airbnb/ruby', + description: 'A plugin for RuboCop code style enforcing & linting tool.' + ) + end + + def supported?(context) + context.engine == :rubocop + end + + def rules(_context) + LintRoller::Rules.new( + type: :path, + config_format: :rubocop, + value: Pathname.new(__dir__).join('../../../config/default.yml'), + ) + end + end + end +end diff --git a/rubocop-airbnb/rubocop-airbnb.gemspec b/rubocop-airbnb/rubocop-airbnb.gemspec index f68f14a..049d577 100644 --- a/rubocop-airbnb/rubocop-airbnb.gemspec +++ b/rubocop-airbnb/rubocop-airbnb.gemspec @@ -25,9 +25,14 @@ Gem::Specification.new do |spec| 'Gemfile', ] - spec.add_dependency('rubocop', '~> 1.61') - spec.add_dependency('rubocop-performance', '~> 1.20') - spec.add_dependency('rubocop-rails', '~> 2.24') - spec.add_dependency('rubocop-rspec', '~> 2.26') + spec.metadata['default_lint_roller_plugin'] = 'RuboCop::Airbnb::Plugin' + + spec.add_dependency('lint_roller', '~> 1.1') + spec.add_dependency('rubocop', '~> 1.72') + spec.add_dependency('rubocop-capybara', '~> 2.22') + spec.add_dependency('rubocop-factory_bot', '~> 2.27') + spec.add_dependency('rubocop-performance', '~> 1.24') + spec.add_dependency('rubocop-rails', '~> 2.30') + spec.add_dependency('rubocop-rspec', '~> 3.5') spec.add_development_dependency('rspec', '~> 3.5') end