RuboCopのバージョンを最新に保つための技術
はじめに
この記事は Ruby Advent Calendar 2022 の 19 日目の記事です。
本記事では RuboCop のバージョンアップに追従するために使える補助ツールや RuboCop の新機能の紹介をしたいと思います。
RuboCop を最新に保つということはとても良い点があります。
それは誤検知が発生するケースや、誤った自動修正をするケースが最新版であれば修正されている場合があります。
新しい cop(= RuboCop のルール)をすぐに使わない方針だったとしても非常に嬉しい点だと思います。
例を挙げると最新の RuboCop 1.40 でも以下のように沢山の Bug fixes の対応が入っています。
RuboCop とは?
ご存知だとは思いますが、紹介させていただきます。
RuboCop は、Ruby の静的解析ツール(Linter)及びコードフォーマッターです。
デフォルトでは、RuboCop チームが管理しているRuby Style Guideで概説されているガイドラインの多くが適用されます。
コードを解析して発見された問題を報告するだけでなく、RuboCop はそれらの問題を自動的に修正することもできます。
https://github.com/rubocop/rubocop
RuboCop のバージョンを最新に保つための技術
ここからは RuboCop のバージョンを最新に保つために作成した補助ツールを紹介したいと思います。
もし、便利そう!と思っていただければご活用いただけると嬉しく思います。
もし何か問題があった場合はお気兼ねなくお知らせください。
rubocop-updater
https://github.com/ydah/rubocop-updater
RuboCop を更新して.rubocop_todo.yml
を再生成し、新しく追加された cop のすべての違反を除外したコミットを追加した、Pull Request を作成するカスタムアクションです。
このカスタムアクションを起動すると、以下のコマンド実行後ごとにコミットを積んで Pull Request を作成します。
- bundle exec rubocop --auto-gen-config
- bundle update --conservative rubocop
- bundle exec rubocop --auto-gen-config
使い方
手動でワークフローを実行する場合のワークフローの例は以下の通りです。
# .github/workflows/rubocop-updater.yml
name: rubocop-updater
on:
workflow_dispatch:
inputs:
update_target:
type: choice
description: Name of the RuboCop (or extension) to be updated
options:
- rubocop
- rubocop-performance
- rubocop-rails
- rubocop-rspec
required: true
conservative_update:
type: boolean
description: Is conservative update?
default: true
required: true
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: ydah/rubocop-updater@v0
with:
label: rubocop-update
update_target: ${{ github.event.inputs.update_target }}
conservative_update: ${{ github.event.inputs.conservative_update }}
この例だと Actions > rubocop-updater を選択して、Run workflow から以下のように実行することができます。
すると、以下のような Pull Request が作成されます。
rubocop-todo-regenerator
https://github.com/ydah/rubocop-todo-regenerator
特定のラベルを PR につけると .rubocop_todo.yml
を再生成したコミットを積んでくれるカスタムアクションです。
RuboCop のバージョンを上げる時には新規に追加された違反はひとまず .rubocop_todo.yml
に追加してバージョンアップのみを実施することが多いと思います。
ただ、大きなプロジェクトだと .rubocop_todo.yml
の再生成に時間がかかることがあります。
そこで、 bundle update rubocop
だけをしたコミットを積んだ Pull Request を作ってしまって、このワークフローを起動します。
そうすることで GitHub Actions に.rubocop_todo.yml
の再生成のコミットを積むのを任せることができます。
ワークフローの例は以下の通りです。
# .github/workflows/rubocop-todo-regenerator.yml
name: rubocop-todo-regenerator
on:
pull_request:
types:
- labeled
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: ydah/rubocop-todo-regenerator@main
with:
github_token: ${{ secrets.WRITABLE_GITHUB_TOKEN }}
RuboCop 1.40 で追加したオプションについて
ここまでは作ってきた RuboCop のバージョンを上げるための補助的なツールを紹介しましたが、RuboCop 1.40 で追加した RuboCop のバージョンアップに使える機能を紹介します。
Add --[no-]auto-gen-enforced-style
CLI option #11205
https://github.com/rubocop/rubocop/pull/11205
このパッチでは --[no-]auto-gen-enforced-style
という CLI オプションを追加しています。
一部の cop は EnforcedStyle
を設定可能なオプションとして持っています。
例えば、Style/AccessModifierDeclarations が該当します。
auto-gen-config
を実行して、.rubocop-todo.yml
を作成する場合、以下のどちらかの通りに違反を抑制します。
- ファイル単位で該当の cop の違反の抑制
- cop そのものを無効化する設定を追加して抑制 (規定の違反ファイル数を超過した場合1)
ですが、EnforcedStyle
を持つ cop については動作が異なります。
.rubocop_todo.yml
を生成する際に、そのスタイルの設定を追加することによって違反を抑制する場合があります。
例を挙げると Style/ClassAndModuleChildren の場合、以下の二つのスタイルがあります。
EnforcedStyle: nested (default)
# good
# have each child on its own line
class Foo
class Bar
end
end
EnforcedStyle: compact
# good
# combine definitions as much as possible
class Foo::Bar
end
全てが compact のスタイルで書かれていた場合には auto-gen-config
を実行した場合に .rubocop_todo.yml
は以下のように生成します。
Style/ClassAndModuleChildren:
EnforcedStyle: compact
通常の場合には、既に統一されているスタイルがあった場合に、それを知ることができるため便利な機能です。
しかし、--auto-gen-config
しても違反が残ってしまうケースがありました。
それは Layout/SpaceInsideHashLiteralBraces の以下のようなケースです。
# test.rb
a = {
}
この場合に bundle exec rubocop --auto-gen-config
を実行すると .rubocop_todo.yml
は以下のように生成します。
# .rubocop_todo.yml
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleForEmptyBraces.
# SupportedStyles: space, no_space, compact
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideHashLiteralBraces:
EnforcedStyle: space
この状態で再度 bundle exec rubocop
を実行すると、以下の違反が残っていることがわかります。
test.rb:1:6: C: [Correctable] Layout/SpaceInsideHashLiteralBraces: Space inside empty hash literal braces detected.
a = { ...
これは確かに全てのファイルで EnforcedStyle: space
というスタイルに適合したコードなので、EnforcedStyle: space
を設定することで違反を抑制しようとします。
しかし、この cop には以下の設定オプションも存在しています。
EnforcedStyleForEmptyBraces: no_space (default)
# The `no_space` EnforcedStyleForEmptyBraces style enforces that
# empty hash braces do not contain spaces.
# bad
foo = { }
bar = { }
baz = {
}
# good
foo = {}
bar = {}
baz = {}
なので、実際には違反が残り続けるという現象が発生していました。
そのため、--no-auto-gen-enforced-style
オプションを追加しました。
auto-gen-config
実行時に指定することで、たとえ全てのファイルで同じスタイルで書かれていたとしても EnforcedStyle
を持たない他の cop と同様の動作となります。
是非、同様のケースでバージョンだけを上げて後でゆっくりと TODO を解消したい場合にはご活用ください。
今回紹介したオプション以外にも便利なオプションはありますので詳細は以下をご確認ください。
https://docs.rubocop.org/rubocop/configuration.html#automatically-generated-configuration
- デフォルトは 15 ファイルです↩