Prontoを実行するGithub Actionを作った

Ruby でコードを書くときに [Rubocop](https://github.com/rubocop-hq/rubocop) などでコードチェックするのは品質向上に役立つと思う。
[Pronto](https://github.com/prontolabs/pronto) を使って Rubocop を実行すると Github のプルリクエストにコメントとしてエラーを指摘してくれる。
あんまりいい例でないけどこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32533/60610d38-0f2d-d104-e206-21c47865cdb7.png)

チーム開発するときには「不要な改行は取ってください」とかレビューでコメントしなくて良くなるし、１人で開発するときにもうっかりミスを防げて良い（私は１人でも実装中のメモを残すためにプルリクエストを作ったりする）。

自動で実行されないと結局使わなくなっていくので、CIサービスなどで実行していたのだけど、Github Workflow で実行できればそれが一番手軽なのでやってみた。

最初は Pronto の README に記載されている[GitHub Actions Integration](https://github.com/prontolabs/pronto#github-actions-integration) を見ながらワークフローを定義して使っていたのだけど、pronto 等の gem インストールだけで１分以上かかっていた。
予め、 pronto 関連 gem をインストールしたDockerイメージを利用すれば時間短縮できるのでは？ と思い立ち、 Github Actionを作った[^pronto-ruby]。結果としてイメージのPullにかかる時間は10秒少々なので時間短縮できた。

[^pronto-ruby]: [Pronto Ruby](https://github.com/marketplace/actions/pronto-ruby)というActionも公開されているが、いろいろと依存関係が解決できてなくて特定のプロジェクトには合うだろうけど、汎用的に使えそうになかったので自作することにした。

作ったものは次で公開している。

- [Pronto Action · Actions · GitHub Marketplace](https://github.com/marketplace/actions/pronto-action)

以下、公開している Pronto Action について紹介する。

## サポートしている Pronto runners

次のPronto Runnerを使えるようにしている。

- [pronto\-brakeman](https://github.com/prontolabs/pronto-brakeman)
- [pronto\-eslint\_npm](https://github.com/doits/pronto-eslint_npm)
- [pronto\-rails\_best\_practices](https://github.com/prontolabs/pronto-rails_best_practices)
- [pronto\-rubocop](https://github.com/prontolabs/pronto-rubocop)
- [pronto\-scss](https://github.com/prontolabs/pronto-scss)
- [pronto\-slim\_lint](https://github.com/ibrahima/pronto-slim_lint)
- [pronto\-sorbet](https://github.com/teamsimplepay/pronto-sorbet)

Runnerはもっとたくさんあるが、Ruby（Rails）でなにか作るときにこれくらいが使えればさしあたって私には事足りると思う。

## サポートしている Rubocop extentions

Rubocop は徐々にチェック内容ごとにExtentionとして分割されているが、こちらはできる限り含めるようにした。

- [rubocop\-i18n](https://github.com/puppetlabs/rubocop-i18n)
- [rubocop\-md](https://github.com/rubocop-hq/rubocop-md)
- [rubocop\-minitest](https://github.com/rubocop-hq/rubocop-minitest)
- [rubocop\-performance](https://github.com/rubocop-hq/rubocop-performance)
- [rubocop\-rails](https://github.com/rubocop-hq/rubocop-rails)
- [rubocop\-rake](https://github.com/rubocop-hq/rubocop-rake)
- [rubocop\-require\_tools](https://github.com/milch/rubocop-require_tools)
- [rubocop\-rspec](https://github.com/rubocop-hq/rubocop-rspec)
- [rubocop\-sequel](https://github.com/rubocop-hq/rubocop-sequel)
- [rubocop\-thread\_safety](https://github.com/covermymeds/rubocop-thread_safety)

上記以外に [cookstyle](https://github.com/chef/cookstyle)もあるのだけど、インストールでエラーが起ったので除外した[^cookstyle]。

[^cookstyle]: 個人的に今後、Chefを使うことはないと思うので、調べる気にもならなかった。

## 設定項目

ワークフローを定義するときに Pronto Action に設定できる項目は次の通り。

| name | reqire | default |
|---|---|---|
| github_token | true | -- |
| commit | false | `origin/master` |
| runner | false | `rubocop` |
| formatters | false | `github_status github_pr` |
| path | false | `'.'` |

基本的に Pronto の [Usage](https://github.com/prontolabs/pronto#usage)に記載されているOptionと同じ[^options]。

[^options]: プルリクエストに対して実行するので、コミット前の変更をチェックするためのオプションである `--staged`、`--unstaged`は不要と思い、除外した。

## 設定例

ワークフローの設定例を紹介する。

### Rubocop を実行する

シンプルに Rubocop を実行するワークフローの定義は次の通り。

The followoing yaml is a simplest workflow difinition of using pronto-action.

```yaml:.github/workflows/pronto-rubocop.yaml
name: Pronto
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  pronto:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: HeRoMo/pronto-action@v1.4.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
```

指摘をコメントする場所が必要なので ワークフローをトリガーするイベントは`pull_request`にしておくのがポイント。
あと、Pronto の実行には git の履歴が必要なので `actions/checkout@v1` でチェックアウトする[^v2]。

[^v2]: `actions/checkout@v2` がリリースされているがこれはデフォルト `fetch-depth:1` でチェックアウトするので、prontoが動けない。動くようにしようとすると設定項目が増えてちょっと面倒。

### ESLintを実行する

Actionで利用するDockerイメージには ESLint は含めていないのでセットアップしてから実行する必要がある[^eslint]。
それらを含めたワークフローの設定例は次の通り。

[^eslint]: Dockerイメージに含めることもできるのだけど、ESLint周りはアップデートが速すぎて、Actionとして最新を保つのが大変だし、ワークフローで利用する側としてもそれに追随するのは辛いと思うのでプロジェクトの *package.json* からインストールして利用するようにした。

```yaml:.github/workflows/pronto-eslint_npm.yaml
name: Pronto
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  eslint_npm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: '12.18.x'
      - name: yarn install
        run: yarn install
      - name: pronto run
        uses: HeRoMo/pronto-action@v1.4.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          runner: eslint_npm
```

多分、これだけだと 「`eslint` が見つからない」とかエラーが出ると思う。
そうなったら。*.pronto_eslint_npm.yml*というファイルを作って、eslint_npm を設定する[^eslint_npm_config]。

[^eslint_npm_config]: https://github.com/doits/pronto-eslint_npm#configuration-of-eslintnpm

その設定例は次の通り。

```yaml:.pronto_eslint_npm.yml
eslint_executable: './node_modules/.bin/eslint'
files_to_lint: '(\.js|\.ts)$'  # TypeScriptをチェックしたいときには指定しておく
cmd_line_opts: './src/**/* ./__tests__/**/*' # eslint のコマンドラインオプション
```

## まとめ

- Github workflow で Pronto を実行するための Github Action を公開した。
- 時間的なオーバヘッド少なくPronto実行を自動化できる。
- リポジトリのソースにProntoを含めなくても（Gemfileに記述しなくても）、Prontoを実行できる。