【PHP】Github Actionsを用いた3つのコードチェッカーの紹介【自動化】

Yuki IwakamiPosted by

この記事は GRIPHONE Advent Calendar 2020 16日目の記事です。

Github Actionsの無料枠はあるけど、チーム開発でどう活かしたらいいんだろうって思っている方に向けて、簡単な導入事例を紹介したいなと思います。

はじめに

前提として、PHPで開発しているチームで導入した例を紹介します。もし別の言語をご使用の場合は、頭の中でその言語に良い感じに置き換えていただけると幸いです。

コードをgitにpushしたら、Github Actions上でそのコードが正しく機能するのかをチェックする。このような、Github Actionsを用いたコードの自動チェッカーについてこの記事で紹介したいと思います。

紹介する3つの例は以下になります。

  1. ユニットテストの自動化
  2. コードフォーマットのチェック
  3. チーム独自のコードチェック

ここで、.github/workflow/code_check.ymlというファイルを作成したとします。上で書いているように、「コードをgitにpushしたら」ということで、トリガーはgitにプッシュなので、code_check.ymlのトリガー(on)は以下のようになります。(ワークフロー名のnameも一緒に定義しちゃいました)

name: CodeCheck

on:
  push:
    branches:
      - 'feature/*'

jobs:
  # これ以降を各チェック項目を書いていく

後は、以下で紹介するようなチェック処理をjobsの項目で定義していきます。
そのため、以下のワークフローの定義ファイルでは上のワークフロー名とトリガーは省略して書いていきます。

ユニットテストの自動化

PHPでテストといえばPHPUnitですね。Github Actions上でphpunitを実行して、全てのテストコードが成功すればOK、一つでも失敗すればNG、とするようなものを作ってみたいと思います。

まず、前提として、チーム開発をしているので、各自のPC上のローカル環境はdockerを使っています。
なので、phpunitを実行するまでの手順としては以下のようになるかなと思います。

  1. docker-compose upをする
  2. composer installをする
  3. phpunitを実行する

これをワークフローで定義します。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: dokcer-compose up
      run: |
        docker-compose build
        docker-compose up -d
    - name: composer install
      run: |
        docker-compose exec -T php bash -c "composer install"
    - name: phpunit
      run: |
        docker-compose exec -T php bash -c "php vendor/bin/phpunit"

もちろんディレクトリが違う場合は別のディレクトリに移動したりする必要があります。

Github Actionsでは、その処理の終了コードが0(正常終了)が返ったときに、そのワークフローが成功になり、0以外が返ったときは失敗となります。

終了コードを使って、アクションのステータスを設定できます。 GitHubは、パスした、あるいは失敗したアクションを示すステータスを表示します。

https://docs.github.com/ja/free-pro-team@latest/actions/creating-actions/setting-exit-codes-for-actions

ちなみにphpunitの終了コードはどうでしょうか?PIPESTATUSという変数で取得できるみたいです。

$ phpunit 
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 2.16 seconds, Memory: 22.00 MB

OK (1 test, 4 assertions)
$ echo  ${PIPESTATUS[@]}
0
$ phpunit
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 3.19 seconds, Memory: 24.00 MB

There was 1 failure:

~~~省略~~~

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
$ echo  ${PIPESTATUS[@]}
1

このことから以下のようなことがわかります。

ユニットテストの結果終了コード
成功0
失敗1

ということは、テストが全てパスすれば正常終了して、一つでも失敗すればエラーとして返るということですね。

これを利用すれば、最悪はローカル環境でユニットテストを実行しなくても、とりあえずpushしておけば、Github Actions側でテストを実行してくれるので、その間はPC上で別の作業ができて効率アップですね!

コードフォーマットのチェック

次にコードフォーマットのチェックです。PHPのコード整形で有名なものの1つであるPHP-CS-Fixerをここでは使いたいと思います。コード整形もしてくれますし、dry-runさせることでコードフォーマットのチェックもしてくれます。

この記事ではdry-runをしてチェックするだけにしますが、コード整形した結果をコミットしてくれるようにするためには、同じサイバーエージェントグループ内のサムザップのアドベントカレンダーの記事で紹介されていますので、リンクを載せておきます。
CIサービスはもういらない!?github actionsでphp-cs-fixerを使ってみる – Qiita

こちらもPHP-CS-Fixerをする流れの説明です。

  1. docker-compose upをする
  2. composer installをする
  3. PHP-CS-Fixerを実行する

こちらもワークフローで定義します。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: dokcer-compose up
      run: |
        docker-compose build
        docker-compose up -d
    - name: composer install
      run: |
        docker-compose exec -T php bash -c "composer install"
    - name: php-cs-fixer
      run: |
        docker-compose exec -T php bash -c "vendor/bin/php-cs-fixer fix --dry-run"

また、PHP-CS-Fixerについても終了コードを調べてみましょう。
同じように、コマンドを実行した後にPIPESTATUSを確認します。

$ vendor/bin/php-cs-fixer fix --dry-run
~~~省略~~~
$ echo  ${PIPESTATUS[@]}
8

いろんな結果のパターンを見てみると以下のようになりました。

PHP-CS-Fixerの結果終了コード
修正すべき項目がない0
修正すべき項目がある8
構文エラーなどがある場合4

ということで、こちらもコードフォーマットのチェックで問題なければ0(正常終了)、なにか問題があればエラーのコードが返ることがわかります。すなわち、このままコマンドを実行してコードチェックをすればGithub Actions側にステータスを伝えることができますね。

チーム独自のコードチェック

さて、終了コードを見て、それがGithub Actionsの実行結果として表示してくれることがわかりましたね。ということは、自分でexit 0だったり、exit 1だったりを実行してあげればそのワークフローを成功させたり失敗させたりすることができます。ここでは、これを利用して、独自のチェッカーを作りたいと思います。

とあるチームでは、yamlの定義ファイルからコマンド一発でいろいろなPHPのクラスを生成するようにしていました。ただ、たまにyamlは定義するのですが、そのコマンドを実行するのを忘れて、PHPクラスを生成し忘れることがあったんですよね。ということで、それをチェックすることをしてみましょう。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: dokcer-compose up
      run: |
        docker-compose build
        docker-compose up -d
    - name: composer install
      run: |
        docker-compose exec -T php bash -c "composer install"
    - name: check code generator
      run: |
        docker-compose exec -T php bash -c "[コード生成のコマンドを入力]"
        git add -N .
        git diff
        line=`git diff | wc -l`
        if [ $line -gt 0 ]; then
          echo "自動生成の漏れがあります"
          git diff
          exit -1
        fi

ちょっと無理やりですが、コードの生成コマンドを実行した後に、git diffを実行してみて、なにか差分が表示されたらexit 1を実行としています。たったこれだけで簡単に独自のチェッカーを作成することができます。できる幅が広がりますね。

3つの手法を結合させる

もちろん、上で紹介した3つを1つのワークフローで定義することができます。

name: CodeCheck

on:
  push:
    branches:
      - 'feature/*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: dokcer-compose up
      run: |
        docker-compose build
        docker-compose up -d
    - name: composer install
      run: |
        docker-compose exec -T php bash -c "composer install"
    - name: phpunit
      run: |
        docker-compose exec -T php bash -c "php vendor/bin/phpunit"
    - name: php-cs-fixer
      run: |
        docker-compose exec -T php bash -c "vendor/bin/php-cs-fixer fix --dry-run"
    - name: check code generator
      run: |
        docker-compose exec -T php bash -c "[コード生成のコマンドを入力]"
        git add -N .
        git diff
        line=`git diff | wc -l`
        if [ $line -gt 0 ]; then
          echo "自動生成の漏れがあります"
          git diff
          exit -1
        fi

このようにして実行することで、何かしらのチェックが失敗したらNGとして結果を返してくれます。

Github上の表示

ということで、Github上でコミットの履歴を確認すると、以下のようにテストが通っていたりコードチェックに問題がなければ緑、エラーが発生していれば赤が付いてくれます。

もちろん、Pull Requestにも表示されるので、それがマージできる状態のものかも確認することができます。

さいごに

このようにして、プッシュするだけでGithub側が勝手にチェックしてくれて、Pull Requestレビューの際には、そのコードがこれらのチェッカーを通してOKかどうかを判断した上でレビュワーはコードのレビューをすることができるようになります。

これを導入する前は、マージしてから「あれ?動かないぞ!」ということが発生していたのですが、導入してからは何度もこれに助けられています。

自動化って便利ですね!