GitHubActions上にreviewdog🐶を導入して、自動でPRコメント形式でTypescriptのエラーを注釈させよう

# したいこと、やったこと

`Typescript`の型エラーが含まれるコードを`GitHub`の保護ブランチにマージさせないように、`GitHub Actions`を用いて`tsc`に失敗したらチェックを落としたい。さらに、`tsc`が検知した箇所にPRコメントで注釈して欲しい日がある。今回は[reviewdog](https://github.com/reviewdog/reviewdog)を使って、自動で注釈させるようにした。

`reviewdog`が使われている既製の`GitHub Action`に、`eslint`のエラーを自動で注釈してくれる[Run eslint with reviewdog](https://github.com/marketplace/actions/run-eslint-with-reviewdog)が公開されているので、これと同様に`TypeScript`のエラーも自動注釈できるんじゃなかろうかという考え。

**注釈されている様子**
![スクリーンショット 2021-01-11 4.21.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/60cffe40-60bc-41ac-1061-e9f3f6548c52.png)


# 実装したworkflow
## 前提
プロジェクトに`npmパッケージ`の`typescript`が導入されている。

```
yarn add -D typescript
```

## 実装したWorkflow
実装したWorkflowにおけるポイントは以下2点。

1. `Github　Action`の[reviewdog/action-setup@v1](https://github.com/marketplace/actions/setup-reviewdog)を用いることで、`Github　Actions`上で`reviewdog`を使えるようにしている。
2. `Typecheck`ステップ。

```yml:.github/workflows/main.yml
name: Test
on: [pull_request]

jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      # ref: https://github.com/actions/setup-node#v2
      - uses: actions/setup-node@v2
        with:
          node-version: "14"
      # ref: https://github.com/reviewdog/reviewdog#github-action-reviewdogaction-setup
      - uses: reviewdog/action-setup@v1
        with:
          reviewdog_version: latest
      # ref: https://github.com/actions/cache/blob/main/examples.md#node---yarn
      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn cache dir)"
      - uses: actions/cache@v2
        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-
      - name: Install Dependencies
        run: yarn --frozen-lockfile
      # ref: https://github.com/reviewdog/reviewdog#available-pre-defined-errorformat
      - name: Typecheck
        run: tsc --pretty false --noEmit | reviewdog -f=tsc -reporter=github-pr-review -fail-on-error=true
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.github_token }}
```

## それぞれのポイントについて
**reviewdog/action-setup@v1**
[reviewdog/action-setup@v1](https://github.com/marketplace/actions/setup-reviewdog)で`GitHub Actions`上に`reviewdog`をインストールしている。`reviewdog`は種々のチェックツールの出力に対応しており`-list`オプションをつけて実行するとその一覧が見れる。これらチェックツールの出力を受け取り、その結果を`GitHub`のPRにコメントをすることができる。

<details><summary>`reviewdog -list`した結果</summary><div>

```terminal:terminal
 ❯❯❯ reviewdog -list
rdjson          Reviewdog Diagnostic JSON Format (JSON of DiagnosticResult message)                                             - https://github.com/reviewdog/reviewdog
rdjsonl         Reviewdog Diagnostic JSONL Format (JSONL of Diagnostic message)                                                 - https://github.com/reviewdog/reviewdog
diff            Unified Diff Format                                                                                             - https://en.wikipedia.org/wiki/Diff#Unified_format
checkstyle      checkstyle XML format                                                                                           - http://checkstyle.sourceforge.net/
ansible-lint    (ansible-lint -p playbook.yml) Checks playbooks for practices and behaviour that could potentially be improved  - https://github.com/ansible/ansible-lint
brakeman        (brakeman --quiet --format tabs) A static analysis security vulnerability scanner for Ruby on Rails applications- https://github.com/presidentbeef/brakeman
cargo-check     (cargo check -q --message-format=short) Check a local package and all of its dependencies for errors            - https://github.com/rust-lang/cargo
clippy          (cargo clippy -q --message-format=short) A bunch of lints to catch common mistakes and improve your Rust code   - https://github.com/rust-lang/rust-clippy
dotenv-linter   Lightning-fast linter for .env files. Written in Rust                                                           - https://github.com/dotenv-linter/dotenv-linter
dotnet          (dotnet build -clp:NoSummary -p:GenerateFullPaths=true --no-incremental --nologo -v q) .NET Core CLI            - https://docs.microsoft.com/en-us/dotnet/core/tools/
eslint          (eslint [-f stylish]) A fully pluggable tool for identifying and reporting on patterns in JavaScript            - https://github.com/eslint/eslint
eslint-compact  (eslint -f compact) A fully pluggable tool for identifying and reporting on patterns in JavaScript              - https://github.com/eslint/eslint
fasterer        Speed improvements suggester                                                                                    - https://github.com/DamirSvrtan/fasterer
go-consistent   Source code analyzer that helps you to make your Go programs more consistent                                    - https://github.com/quasilyte/go-consistent
golangci-lint   (golangci-lint run --out-format=line-number) GolangCI-Lint is a linters aggregator.                             - https://github.com/golangci/golangci-lint
golint          linter for Go source code                                                                                       - https://github.com/golang/lint
gosec           (gosec -fmt=golint) Golang Security Checker                                                                     - https://github.com/securego/gosec
govet           Vet examines Go source code and reports suspicious problems                                                     - https://golang.org/cmd/vet/
haml-lint       Tool for writing clean and consistent HAML                                                                      - https://github.com/sds/haml-lint
hlint           Linter for Haskell source code                                                                                  - https://github.com/ndmitchell/hlint
msbuild         (msbuild /property:GenerateFullPaths=true /nologo /v:q) Microsoft Build Engine                                  - https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild
pep8            Python style guide checker                                                                                      - https://pypi.python.org/pypi/pep8
phpstan         (phpstan --error-format=raw) PHP Static Analysis Tool - discover bugs in your code without running it!          - https://github.com/phpstan/phpstan
psalm           (psalm --output-format=text) Psalm is a static analysis tool for finding errors in PHP                          - https://github.com/vimeo/psalm
puppet-lint     Check that your Puppet manifests conform to the style guide                                                     - https://github.com/rodjek/puppet-lint
reek            (reek --single-line) Code smell detector for Ruby                                                               - https://github.com/troessner/reek
rubocop         A Ruby static code analyzer, based on the community Ruby style guide                                            - https://github.com/rubocop-hq/rubocop
sbt             the interactive build tool                                                                                      - http://www.scala-sbt.org/
sbt-scalastyle  Scalastyle - SBT plugin                                                                                         - http://www.scalastyle.org/sbt.html
scalac          Scala compiler                                                                                                  - http://www.scala-lang.org/
scalastyle      Scalastyle - Command line                                                                                       - http://www.scalastyle.org/command-line.html
slim-lint       Tool to help keep your Slim files clean and readable                                                            - https://github.com/sds/slim-lint
sorbet          A fast, powerful type checker designed for Ruby                                                                 - https://github.com/sorbet/sorbet
standardjs      (standard) JavaScript style guide, linter, and formatter                                                        - https://github.com/standard/standard
standardrb      (standard) Ruby style guide, linter, and formatter                                                              - https://github.com/testdouble/standard
stylelint       A mighty modern CSS linter                                                                                      - https://github.com/stylelint/stylelint
tsc             TypeScript compiler                                                                                             - https://www.typescriptlang.org/
tslint          An extensible linter for the TypeScript language                                                                - https://github.com/palantir/tslint
```

</div></details>

**TypeCheckステップ**

```yml:.github/workflows/main.yml部分
 - name: Typecheck
        run: tsc --pretty false --noEmit | reviewdog -f=tsc -reporter=github-pr-review -fail-on-error=true
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.github_token }}
```

`TypeScript`のコンパイラである`tsc`は`--pretty false`オプションをつけることでエラー出力が簡略化される。`reviewdog`が受け付ける`tsc`の出力は簡素化された方であるので、このオプションを付与したものをパイプ(`|`)で`reviewdog`に送る。

<details><summary>`tsc --pretty`の有無による違い</summary><div>

```terminal:terminal
❯❯❯ tsc
src/components/IndexPage.tsx:3:7 - error TS2322: Type 'string' is not assignable to type 'number'.

3 const a: number = "hoge";
        ~


Found 1 error.

❯❯❯ tsc --pretty false
src/components/IndexPage.tsx(3,7): error TS2322: Type 'string' is not assignable to type 'number'.
```

</div></details>

`reviewdog`には`-f`オプションでどのチェックツールの出力が入力されているのか伝えている。ここで`-reporter=github-pr-review`オプションと必要な環境変数をつけることで、自動でPRにコメントがされる。必要な環境変数は`$REVIEWDOG_GITHUB_API_TOKEN`であり、`GitHub Actions`の`Workflow`においては上記のような設定をすれば良い。

また`reviewdog`に`-fail-on-error=true`オプションをつけることで、エラーが入力されたら`GitHub`のPRのチェックを失敗させるようにしている。

# 終わりに

最近の私は、たとえ一人で作るものでも、`GitHub Actions`などを整えることを楽しんでやっています。我が我に出すPRにコメントなんざ付かないところ、botにでもコメントされると賑やかで良いものなんですよね。一人で作るプロジェクトこそあれチェックされる必要がないのに、却って、ロボットなり猫なりタコなりに自分の不注意を指摘してもらいたいというのは、なんか作るにあたって縛りプレイに面白みを感じる手合いだからだと思っています。