Rubocopを一応入れているのに、滅多に動かしてなくてあんまり意味を成していなかった。issueにずっとあったCIにRubocopを取り入れるというやつに着手しようと思ってようやく取り組み始めた。
reviewdogを知る
CircleCIのワークフローにRubocopのチェックを入れて、自動的にコメントをしてもらいたいなぁと思って調べていたら、reviewdogを知った。
自分がやりたかったことはまさにこれだったので、これを参考にすることに。
reviewdogのインストールは本家を参考にした。
バイナリで配布もされているが、goenv
でgoを入れているので、go getを使って入れた。
$ go get -u github.com/haya14busa/reviewdog/cmd/reviewdog
reviewdogが実行できない場合はパスが通ってないってことなので、パスを通しましょう。
その前にrubocopのルールを決めたい
Rubocopのルールをよく把握してなかったので、チームで以前に作ったルールを実行してみたら、かなりの量で怒られたので、たぶんプロジェクトにルールがまだ合ってないなと思ったので、一から作り直そうと思った。
とはいえ、ルールの数も途方もないだろうし、有名な指針があればいいかなと思って調べ始めたら、onkさんのRubocopの記事を見つけた。
スモールスタートする
スモールスタートの仕方が書いてあったので、まずはそれを検証することに。
- 現在の.rubocop.ymlを.rubocop.old.ymlに変更
bundle exec rubocop --auto-gen-config
を実行して.rubocop.ymlと.rubocop_todo.ymlを生成するbundle exec rubocop --parallel
を実行して指摘がないことを確認する- 一旦コミットする
- ローカルでreviewdogを実行してみる
- CircleCIでreviewdogを実行してみる
という方針を立てた。
reviewdogが動かない(俺の勘違い)
とりあえず、rubocop.old.ymlで怒られていたルールを実行してみると、たくさん指摘された。
それをreviewdogに食わせてみることに。
$ bundle exec rubocop --parallel --only Layout/SpaceAroundEqualsInParameterDefault | reviewdog -f=rubocop -diff="git diff"
何も表示されない!
しかしこれは当然の話で、reviewdogは変更のあった行でrubocopの指摘がある場合のみ通知してくる。まだコード自体は一切変えていなかったからだ。そこで、敢えてコードをルールに違反するコードに変えたところ、ちゃんと指摘された。
CircleCIでreviewdogを動かす
reviewdogを実行するワークフローを定義する
上のほうで参考にしたサイトの通りにすれば動くので、特に書くことはない…んだけど、一応書く。ちなみにcircle.ymlのフォーマットはCircleCI 2.1なのであしからず。
executorsのrubyのdocker imageの環境変数に、reviewdogのバージョンを指定する。
executors: default: docker: - image: patorash/circle_ci_ruby:2.5.3-node-browsers-pg11 environment: RAILS_ENV: test REVIEWDOG_VERSION: 0.9.11 # ここ
次に、reviewdogを実行するcommandsを定義する。
commands: # 他のコマンドは略 run_reviewdog: steps: - run: name: Install reviewdog command: | curl -fSL https://github.com/haya14busa/reviewdog/releases/download/$REVIEWDOG_VERSION/reviewdog_linux_amd64 -o reviewdog chmod +x ./reviewdog - run: bundle exec rubocop | ./reviewdog -f=rubocop -reporter=github-pr-review
次に、workflowを定義。テストが実行される前にrobocopで検査して、問題があればそこで止めるようにする。まだジョブの定義はしていないが、とりあえずワークフローを先に書く。
workflows: build: jobs: - prepare_test - reviewdog: requires: - prepare_test - retry_failed_test: requires: - reviewdog - test: requires: - retry_failed_test
しかしこれだとreviewdogが通らないとテストすら実行されないので、緊急時とかにうざいかもしれない…。そのときは、retry_failed_testのrequiresをprepare_testに変えてしまうほうがいいかも…とこの記事を書きながら思った。
さて、reviewdogジョブを定義する。もうcommandsを定義しているので、それを呼び出すだけである。一応prepare_testも載せておくが、やってることはcommand名から想像してほしい。
jobs: prepare_test: parallelism: 1 executor: default steps: - checkout - restore_node_module_cache - restore_bootsnap_cache - ruby-orbs/bundle-install - yarn_install - save_node_module_cache - save_code_cache reviewdog: parallelism: 1 executor: default steps: - restore_code_cache - run: bundle --path vendor/bundle - run_reviewdog # 他のジョブは略
これでcircle.ymlは完成。
環境変数を設定する
あとはgithubでreviewdogでコメントさせるユーザーのトークンを環境変数REVIEWDOG_GITHUB_API_TOKEN
に定義しなくてはならない。
この時、もし自分のアカウントで取得すると、reviewdogのコメントをしてくるのが自分のアカウントになる。別に問題ない人はそれでいいが、個人アカウントで機械的にであっても個人のアイコンがある状態でコメントされると、なんか殺伐としそう…。なので、bot用の別アカウントを作るなりして、そいつにコメントしてもらうほうがいいと思う。onkさんの記事でも、カーチャンに指摘してもらうみたいに書いてた。
話を元に戻すが、repoにチェックを入れてアクセストークンを発行する。
発行したアクセストークンは、CircleCIのプロジェクト毎の環境変数に保存しておく。
これで完了。
あとは、先ほど設定したcircle.ymlを含むbranchをpushして、PRにしてreviewdogがコメントするのを確認すればよし。ちゃんとCIのワークフローがそこで止まることも確認する。
そして、指摘された点を修正し直して、ワークフローが全部通ることを確認する。
オーケー、完成だ。
今後の方針
CircleCIのworkflowにreviewdogを入れられたのは一歩前進。とはいえ、rubocopはスモールスタートの設定をしただけなので、ルールを決めていく必要がある。onkさんが公開しているonkcopが参考になりそうなので、それを読みながら一部を自分のルールで上書きしていこうと思う。