もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

Github Actionsで並列実行させたphpunitを codecovにあげる

はじめに

こんばんは。

前回の記事の続きみたいな感じです。

kojirooooocks.hatenablog.com

前回の記事から、coverageをとって、codecovへあげるようにしてみました。

本題

前提

  1. codecovのtokenをsecretsに登録する

1. ymlの修正

.github/workflows/unittest.yml

name: unit test
on:
  push:

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        parallelism: [5]
        id: [0,1,2,3,4]

    steps:
      - name: Checkout
        uses: actions/checkout@master

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.0
          coverage: pcov

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Execute Test
        run: |
          find src/ -name '*Test.php' | sort | awk "NR % ${{ matrix.parallelism }} == ${{ matrix.id }}" | xargs php ./bin/create_ci_phpunit_xml.php
          XDEBUG_MODE=coverage ./vendor/bin/phpunit --configuration /tmp/ci_phpunit.xml --coverage-php /tmp/phpunit-${{ matrix.id }}.cov

      - name: Archive Artifacts
        uses: actions/upload-artifact@v2
        with:
          name: phpunit-coverage
          path: /tmp/phpunit-${{ matrix.id }}.cov

  coverage:
    runs-on: ubuntu-20.04
    needs: test
    steps:
      - name: Checkout
        uses: actions/checkout@master

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.0
          coverage: pcov

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Download Coverage File
        uses: actions/download-artifact@v2
        with:
          name: phpunit-coverage
          path: ./tmp/

      - name: Merge Coverage Files
        run: ./vendor/bin/phpcov merge --clover coverage.xml ./tmp/

      - name: Upload Coverage to Codecov
        uses: codecov/codecov-action@v1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage.xml
          flags: unittests
          fail_ci_if_error: true
          verbose: true

追加/変更したところ

Install PHP with extensions
      - name: Install PHP with extensions
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.0
          coverage: pcov

こちらを使わずに coverage を取ろうとすると Warning: xdebug.mode=coverage has to be set in php.ini という警告が出て、正しく取れませんでした。

ローカルではなかったので、うーん。悩んでいたのですが、以下のスクリプトをみて、もしやと思い真似してみたらいけました。

github.com

pcovって知らなかったんですが、coverage を計測するドライバ?だそうです。

デフォルトがxdebug??なのかな?

それを pcovに変更したという感じだと思います。

github.com

Execute Test
        run: |
          find src/ -name '*Test.php' | sort | awk "NR % ${{ matrix.parallelism }} == ${{ matrix.id }}" | xargs php ./bin/create_ci_phpunit_xml.php
          ./vendor/bin/phpunit --configuration /tmp/ci_phpunit.xml --coverage-php /tmp/phpunit-${{ matrix.id }}.cov

例の awk のところは変わらず、最終的にphpunitを実行する箇所で --coverage-php /tmp/phpunit-${{ matrix.id }}.covカバレッジを取るようにしています。

Archive Artifacts
      - name: Archive Artifacts
        uses: actions/upload-artifact@v2
        with:
          name: phpunit-coverage
          path: /tmp/phpunit-${{ matrix.id }}.cov

codecovに上げる際に、各jobで実行してとった計測結果をマージしないといけません。

そのために、各jobでの計測結果を次のステップまでどこかに保存しておきたいわけです。

そのためにCIrcleCIでもある artifactsに保存するようにしました。

CoverageStep
  coverage:
    runs-on: ubuntu-20.04
    needs: test
    steps:
      - name: Checkout
        uses: actions/checkout@master

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@v2
        with:
          php-version: 8.0
          coverage: pcov

      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Download Coverage File
        uses: actions/download-artifact@v2
        with:
          name: phpunit-coverage
          path: ./tmp/

      - name: Merge Coverage Files
        run: ./vendor/bin/phpcov merge --clover coverage.xml ./tmp/

      - name: Upload Coverage to Codecov
        uses: codecov/codecov-action@v1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage.xml
          flags: unittests
          fail_ci_if_error: true
          verbose: true

最初の方は一緒ですが、重要なところは、 Download Coverage File Merge Coverage Files Upload Coverage to Codecov になります。

Download Coverage File でartifactにアップロードした各計測結果をダウンロードします。

Merge Coverage Files でダウンロードした各計測結果をマージします。

そして

Upload Coverage to Codecov でマージして生成された coverage.xmlを code covにアップロードします。

2. generateXMLスクリプトの編集

bin/create_ci_phpunit_xml.php

<?php

$baseDir = realpath('./');
$files   = array_slice($argv, 1);
$xmlFileStringData = [];
foreach ($files as $file) {
    $xmlFileStringData[] = "<file>{$baseDir}/{$file}</file>";
}
$testFileString = implode("\n", $xmlFileStringData);
$template = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="{$baseDir}/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
  <coverage processUncoveredFiles="true">
    <include>
      <directory suffix=".php">{$baseDir}/src/Kojirock5260/*/src</directory>
    </include>
  </coverage>
  <testsuites>
    <testsuite name="Test Case">
      {$testFileString}
    </testsuite>
  </testsuites>
</phpunit>
XML;

file_put_contents("/tmp/ci_phpunit.xml", $template);

こちらはそこまで大幅に変わっていませんが、一点、前のままでやった場合、以下のような警告が出ました。

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

スキーマが非推奨になってるっぽいです。

実際に、指定されているオプションをつけて実行してみると、上記のようなxmlが生成されました。

結果

f:id:kojirooooocks:20210303045859p:plain

f:id:kojirooooocks:20210303045915p:plain

マージされた xmlで codecovにアップロードされていました!!!!

終わりに

思ったとおりに、出来て安心しました。

一点だけ、ちょっと。ん?と思ったのが、 codecovの xmlを指定する files という部分ですが、どうやら複数指定できるようでした。

もしかしたらマージしなくてもいいのかも?

とか思って、チャレンジしようかな?と思いましたが、ちょっとめんどくさいのでやめました...

現場からは以上です。