Larastanで静的解析したエラーをreviewdogでプルリクにコメントさせるよ

## はじめに
[アドベントカレンダー](https://qiita.com/advent-calendar/2021/arsaga)
この記事ではGitHubへのプルリクエストに対して、Larastanを利用して静的解析して出たエラーをreviewdogがコメントしてくれる方法を紹介します。

**Larastan**はPHPの静的解析ツールであるPHPstanをLaravel用に最適化したラッパーのパッケージです。
https://github.com/nunomaduro/larastan

**reviewdog**はlinterなどを使ってソースコードレビューを行ってくれる補助ツールです。
linterの実行結果を自動でGitHubのプルリクエストにコメントしたりしてくれます。
https://github.com/reviewdog/reviewdog

環境
Laravel 8.*
Larastan 1.0
reviewdog 0.13.0

作成したソースコード
https://github.com/ryofutebol/laravel_reviewdog
## Larastan設定
#### インストール
```bash
composer require nunomaduro/larastan --dev
```
LarastanはPHPが7.2以上、Laravelが6.0以上である必要があります。

#### phpstan.neonファイル設定
phpstan自体の設定はphpstan.neonファイルに記述します。

```
includes:
    - ./vendor/nunomaduro/larastan/extension.neon

parameters:
    paths:
        - app
    level: 0
    ignoreErrors:
        - '#Call to an undefined method .*badMethod\(\)#'
```
最初に2行でLarastanの設定を読み込んでいます。

`parameters`に必要な設定をしていきます。

- `paths`にどのパスを解析対象のディレクトリを指定
- `level`はPHPstanでどのくらい厳格に解析するかのレベルを指定  
0~9まであるので今回は最も緩い解析である`0`を指定します。
-  `ignoreErrors`で無視するエラーを指定
エラー分をそのまま指定してもいいですし、上記コードのように正規表現で指定することも可能です。

#### 動作確認
実際に静的解析を行ってくれているのかをローカルで確認してみます。
Laravelをインストールした初期状態で`UserContorller`のみを作成します。
そこに下記のようなわざとエラーが出るようなメソッドを記述します。

```php
namespace App\Http\Controllers;

use App\Models\User;

class UserController extends Controller
{
    public function getUserName(): string
    {
        $user = Admin::query()->findOrFail(1);
        return $user->name;
    }
}
```
本来やりたいことはIDが`1`のユーザー名を取得することですが、わざと存在しない`Admin`モデルを指定したメソッドを用意しました。
この状態で静的解析を実行します。

```bash
./vendor/bin/phpstan analyse
```

```bash
Note: Using configuration file /laravel_reviewdog/phpstan.neon.
 19/19 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ ------------------------------------------------------------------------------- 
  Line   Http/Controllers/UserController.php                                            
 ------ ------------------------------------------------------------------------------- 
  15     Call to static method query() on an unknown class App\Http\Controllers\Admin.  
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols             
 ------ ------------------------------------------------------------------------------- 
                                                                                                                        
 [ERROR] Found 1 error                                                                                                    
```
存在しないクラスなのでしっかりエラーが出てくれました。

試しに`ignoreErrors`で上記エラーが出ないように正規表現で指定してみます。

```
ignoreErrors:
    - '#Call to static method .*\(\)#'
```

```bash
Note: Using configuration file /laravel_reviewdog/phpstan.neon.
 19/19 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
                                                                                                                        
 [OK] No errors                                                                                                                                                                                                                        
```
今回はエラーが出ず正常に静的解析が実行されました。

## reviewdog設定
reviewdogが静的解析のエラーをプルリクにコメントしてくれるようにGitHub Actionsの設定をしていきます。
`.github/workflow/reviewdog.yml`を作成します。

```yml
name: reviewdog
on:
  pull_request:
    branches:
      - master
jobs:
  analyse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: reviewdog/action-setup@v1
        with:
          reviewdog_version: latest
      - name: Setup PHP
        uses: shivammathur/setup-php@v2 
        with:
          php-version: '8.0'
          tools: composer:v2
      - name: Resolve dependencies
        run: composer install --no-progress --prefer-dist --optimize-autoloader
      - name: Run PHPstan
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: ./vendor/bin/phpstan analyse --error-format=raw --no-progress | reviewdog -reporter=github-pr-review -f=phpstan
```
- `name`でワークフロー名を指定

- `on`でワークフローファイルを自動的にトリガーするイベントを指定
今回だとmasterブランチにプルリクを上げたタイミングでこのワークフローが実行されます。

- `jobs`の中にLarastanを実行してエラーが出た際にreviewdogがコメントしてくれるための実行ジョブを指定
中身を簡単に説明すると
①reviewdogを導入
②PHPとComposerのセットアップ
③PHPstan実行して結果を出力
注意点としては`REVIEWDOG_GITHUB_API_TOKEN`にGitHubのトークンを設定していますが、Personal Access Tokensの権限スコープの`workflow`にチェックが入っていないとうまく動いてくれません。
![スクリーンショット 2021-11-28 16.28.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/570ad9b2-839e-ee04-b6ee-3a58dc766d18.png)

これでreviewdogの設定は終了です。

## reviewdogにコメントしてもらう
試しに先程エラーが出たコードをプルリクにあげてみます。
![スクリーンショット 2021-11-28 16.34.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/54b0f1ce-90b2-7e8f-473d-513a6d6d7f65.png)
そうすると先程ローカルで実行したときと同じエラーがコメントとして表示されます。

##最後に
今回はLaravelで静的解析ツールを使いましたが、構文チェックしてくれるPHP_CodeSnifferでも同じことは可能です。
レビュワーからすると細かく構文などをチェックしている時間はないと思うので、こういった自動ツールを導入することで実装タスク以外のコストが削減できることはメリットかなと思います。
そもそもプルリク上げる前に構文エラーがあったら自動整形してくれるようなツールもあるみたいなので調べたいみたいですね。