rubocop + pre-commitで規約違反のコードをコミットできないようにする


rubocopはrubyの静的コード解析を実行してくれる便利なgem。例えば、ソースコード内の残念なメソッド名を発見してくれたり、1メソッドの行数を制限できたりする。解析内容は多岐にわたるので、ぜひ公式ドキュメントを参照あれ。

一方pre-commitとは、gitコミットをフックして何らかのアクションを実行してくれるgem。末尾の空白を検知したり、Javascriptのconsole.logや、pryのbinding.pryがソース内に残っていないかなどチェックできる。こいつが標準でrubocopもサポートしているので、これらを組み合わせると、規約違反のコードが含まれている場合にgit commitできないようにすることができる。

セットアップ

bundle + railsという環境を想定すると、Gemfileは以下のようになる。

📄Gemfile
group :development do
  gem 'rubocop', require: false
  gem 'pre-commit', require: false
end

bundle installした後に、pre-commitをインストールする必要がある。

📄config/pre_commit.yml
$ bundle exec pre-commit install

git-hookは新しいshプロセスで動くので、pre-commitはbundler経由で実行させるよう、gitの設定を施してやる必要があります。

$ git config pre-commit.ruby "bundle exec ruby"

これにて導入は完了。

pre-commit

pre-commit listコマンドで各checkの利用状況が確認できる。

$ bundle exec pre-commit list
Available providers: default(0) git(10) git_old(11) yaml(20) env(30)
Available checks   : before_all ci closure coffeelint common console_log csslint debugger gemfile_path go jshint jslint json local merge_conflict migration nb_space pry rails rspec_focus rubocop ruby ruby_symbol_hashrockets scss_lint tabs whitespace yaml
Default   checks   : common rails
Enabled   checks   : common rails
Evaluated checks   : tabs nb_space whitespace merge_conflict debugger pry local jshint console_log migration
Default   warnings : 
Enabled   warnings : 
Evaluated warnings :

Available checksが利用できるチェックの一覧。Enabledが現在利用しているチェックである。上記ではcommonとrailsというチェックがなされている。この2つのチェックに含まれる個々のチェックはEvaluated checksに記述されている。要するに、これらが実際に実行されるチェック。このあたりは公式サイトとかこのあたりを参考にしてほしい。

デフォルトではrubocopを利用するようにはなっていないので、設定を変更しよう。

$ bundle exec pre-commit enable yaml checks rubocop

yamlと指定しているのは、設定をyamlファイルに書き出すということ。railsディレクトリ内で実行すると、config/pre_commit.ymlというファイルが出来上がっているはずだ。

---
:checks_remove: []
:checks_add:
- :rubocop

今後はこのファイルを直接編集してもよい。ちなみに、先のyamlと指定をgit にするとgitのグルーバル設定にすることができる。プロジェクトで配布する場合はyamlにしておいた方がよい。またrubocopチェックに引っ掛かってもエラーではなく警告にとどめておきたい場合は、checksではなくwarningsを指定する。

rubocop

rubocopでチェックできる内容は多岐に渡り、中には「こんなんもんいらねー」的なチェックもある。何をどうチェックするかの設定をyamlファイルに記述しておくことができる。ルートディレクトリに.rubocop.ymlというファイルを作成すればよい。以下は私が使用している設定。

📄.rubocop.yml
AllCops:
  RunRailsCops: true
  Exclude:
    - bin/**/*
    - config/boot.rb
    - db/schema.rb
    - script/**/*
    - tmp/**/*
    - vendor/**/*

# 1クラスの行数を200行以下に制限する
Metrics/ClassLength:
  Max: 200

# 1行の文字数を制限しない
Metrics/LineLength:
  Enabled: false

# 1メソッドの行数を制限しない
Metrics/MethodLength:
  Enabled: false

# 日本語コメントを許す
Style/AsciiComments:
  Enabled: false

# ファイル冒頭にコメントを書かなくてもよい
Style/Documentation:
  Enabled: false

# class Hoge::Fooのような記述を許す
Style/ClassAndModuleChildren:
  Enabled: false

どんなチェックがあって何を意味しているのかはenabled.ymlのソースを見ればよい。ruby-style-guideへのリンクも記述されているので辞書として利用できる。

手動でrubocopを実行するにはコマンドを叩けばよい。-Dオプションを付けると、引っ掛かったチェック名を表示してくれるのでお勧め。

📄.git/hooks/pre-commit
$ bundle exec rubocop -D

これにてgit commitする度にチェックが走り、エラーがあったらコミットさせてくれないという理想的自虐的環境ができあがった。

既存のプロジェクトに適用させる場合

おそらくデフォルトのルールでrubocopを実行するとエラーまみれになると思う。rubocopでは、必要なチェックなのか吟味しながら少しずつエラーを無くしていくというアプローチが取れるようになっている。このサイトが詳しい。

zsh + rbenvな環境でpre-commitが動かない場合

2016/07/19 追記:現在では公式githubに載っているように、次のコマンドを実行すれば動くようになっています。

$ git config pre-commit.ruby "bundle exec ruby"

—–

pre-commit installした際に自動生成される.git/hooks/pre-commitではzsh+rbenvという環境上では動かない(少なくとも私の環境ではgit commit時にエラーになった)。思いっきり書き換えてしまうことにする。

#!/bin/zsh
source ~/.zshrc

bundle exec ruby -rrubygems -e '
  begin
    require "pre-commit"
    true
  rescue LoadError => e
    $stderr.puts <<-MESSAGE
pre-commit: WARNING: Skipping checks because: #{e}
pre-commit: Did you set your Ruby version?
MESSAGE
  false
  end and PreCommit.run
'

参考

関連する記事


コメントする

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください