patorashのブログ

方向性はまだない

CircleCIにreviewdogを飼うことにした。

Rubocopを一応入れているのに、滅多に動かしてなくてあんまり意味を成していなかった。issueにずっとあったCIにRubocopを取り入れるというやつに着手しようと思ってようやく取り組み始めた。

reviewdogを知る

CircleCIのワークフローにRubocopのチェックを入れて、自動的にコメントをしてもらいたいなぁと思って調べていたら、reviewdogを知った。

blog.toshimaru.net

自分がやりたかったことはまさにこれだったので、これを参考にすることに。

reviewdogのインストールは本家を参考にした。

github.com

バイナリで配布もされているが、goenvでgoを入れているので、go getを使って入れた。

$ go get -u github.com/haya14busa/reviewdog/cmd/reviewdog

reviewdogが実行できない場合はパスが通ってないってことなので、パスを通しましょう。

その前にrubocopのルールを決めたい

Rubocopのルールをよく把握してなかったので、チームで以前に作ったルールを実行してみたら、かなりの量で怒られたので、たぶんプロジェクトにルールがまだ合ってないなと思ったので、一から作り直そうと思った。

とはいえ、ルールの数も途方もないだろうし、有名な指針があればいいかなと思って調べ始めたら、onkさんのRubocopの記事を見つけた。

blog.onk.ninja

スモールスタートする

スモールスタートの仕方が書いてあったので、まずはそれを検証することに。

  1. 現在の.rubocop.ymlを.rubocop.old.ymlに変更
  2. bundle exec rubocop --auto-gen-configを実行して.rubocop.ymlと.rubocop_todo.ymlを生成する
  3. bundle exec rubocop --parallelを実行して指摘がないことを確認する
  4. 一旦コミットする
  5. ローカルでreviewdogを実行してみる
  6. 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に定義しなくてはならない。

githubのアクセストークンの取得ページに行く。

この時、もし自分のアカウントで取得すると、reviewdogのコメントをしてくるのが自分のアカウントになる。別に問題ない人はそれでいいが、個人アカウントで機械的にであっても個人のアイコンがある状態でコメントされると、なんか殺伐としそう…。なので、bot用の別アカウントを作るなりして、そいつにコメントしてもらうほうがいいと思う。onkさんの記事でも、カーチャンに指摘してもらうみたいに書いてた。

話を元に戻すが、repoにチェックを入れてアクセストークンを発行する。

f:id:patorash:20190312004123p:plain
githubのアクセストークンを発行する。repoにチェックを入れる。

発行したアクセストークンは、CircleCIのプロジェクト毎の環境変数に保存しておく。

f:id:patorash:20190312004858p:plain
CircleCIの設定画面から環境変数を設定する

これで完了。

あとは、先ほど設定したcircle.ymlを含むbranchをpushして、PRにしてreviewdogがコメントするのを確認すればよし。ちゃんとCIのワークフローがそこで止まることも確認する。

f:id:patorash:20190312005703p:plain
reviewdogによってworkflowが停止していることを確認

そして、指摘された点を修正し直して、ワークフローが全部通ることを確認する。

f:id:patorash:20190312010004p:plain
reviewdogの指摘を修正してワークフローが通ることを確認

オーケー、完成だ。

今後の方針

CircleCIのworkflowにreviewdogを入れられたのは一歩前進。とはいえ、rubocopはスモールスタートの設定をしただけなので、ルールを決めていく必要がある。onkさんが公開しているonkcopが参考になりそうなので、それを読みながら一部を自分のルールで上書きしていこうと思う。

github.com