開発
RuboCop
Rails
個人開発
SonicGarden Gym

【RuboCop】husky + lint-staged で RuboCop を自動実行する際に除外設定が適用されない

created: 2023-01-26 / updated: 2023-01-31
554 views

サマリ

  • husky, lint-staged を用いることで、 git commit 時に自動で RuboCop を実行することができるが、 .rubocop.yml でチェック対象から除外しているファイルにも指摘が入ってしまい困っていた
  • RuboCop はファイルを指定して実行すると .rubocop.yml の除外設定を無視する仕様になっており、これを防ぐには --force-exclusion オプションをつける必要がある

husky と lint-staged

linter を導入しているプロジェクトでは、わざわざ手動で linter を走らせるのではなく、コミット前に自動で linter を走らせておくようにするとスマートです。
これを実現してくれる npm パッケージとして huskylint-staged があります。husky はコミットやプッシュ時に任意のコマンドを実行するライブラリ、 lint-staged は git add されたファイルに限定して linter を走らせてくれるライブラリです。
導入方法はそれぞれのレポジトリの README に譲ります。

.rubocop.yml でチェック対象から除外するファイルを指定する

RuboCop では、 .rubocop.yml でチェック対象から除外するファイルを指定することができます。
自動生成されたファイルについてはチェック対象にしないことで、無用な修正をしなくて済むことになります。
Rails のプロジェクトだったらこんな感じです。

AllCops:
  Exclude:
    - "bin/*"
    - "config/application.rb"
    - "config/backup.rb"
    - "config/boot.rb"
    - "config/environments/*"
    - "config/initializers/*"
    - "config/unicorn.rb"
    - "config/spring.rb"
    - "config/puma.rb"
    - "config.ru"
    - "db/*schema.rb"
    - "deploy/*"
    - "node_modules/**/*"
    - "spec/rails_helper.rb"
    - "spec/spec_helper.rb"
    - "vendor/**/*"

しかし

lint-staged で実行した RuboCop については、 .rubocop.yml の除外設定が適用されないのです。
例えば spec/rails_helper.rb にちょっと変更を加えてコミットすると、チェック対象から外しているはずなのに指摘が入ります。
一方で、コンソールから $ bundle exec rubocop をした場合は指摘が入りません。

なぜなのか・どうしたら良いか

RuboCop は、引数としてファイルやディレクトリを渡すことで、チェックするファイルを限定することができます。これを lint-staged では活用しているわけですが、むしろこれによって、引数として明示的に渡されたファイルが除外指定にも関わらずチェック対象になってしまっているのです。

これを防ぐためのオプションがあります。

--force-exclusion
Force excluding files specified in the configuration Exclude even if they are explicitly passed as arguments.

https://docs.rubocop.org/rubocop/1.44/usage/basic_usage.html

引数として明示的に渡された場合でも、設定の Exclude で指定したファイルが強制的に除外されるようになります。
例えば次のように設定してみましょう。

  "lint-staged": {
    "*.{rb,rake}|Gemfile": [
      "bundle exec rubocop -DES --force-exclusion"
    ]
  }

--force-exclusion をつけたことで、 .rubocop.yml で指定した除外ファイルは変更を加えても指摘が入らないようになりました。