2026年8月5日

2026年8月5日

GitHub Actionsのマトリックスビルド設定(strategy.matrixの書き方と使い分け)

GitHub Actions のマトリックスビルドは、strategy.matrix に並べた値の組み合わせごとにジョブを自動で複製して並列実行する仕組みです。この記事では、WordPress プラグインを複数の PHP・WordPress バージョンでテストする例を通して、include / exclude の挙動、失敗時の制御、ブランチ保護との付き合い方まで、実際に運用できる形で設定できるようになることを目指します。

マトリックスビルドで何が解決するのか

プラグインやテーマを配布していると、「PHP 8.3 では動くが 7.4 で構文エラー」「最新の WordPress では非推奨警告が出る」といった、手元の 1 環境では見つからない不具合に出会います。ジョブをバージョンごとにコピーして書くと、設定の修正漏れが起きやすくなります。

マトリックスを使うと、ジョブ定義は 1 つのまま、php と wp のような変数の直積(全組み合わせ)を GitHub が展開してくれます。2 種類の PHP と 2 種類の WordPress なら 4 ジョブ、3 × 2 なら 6 ジョブです。各ジョブは独立したランナーで動くので、実行時間は「一番遅い組み合わせ」程度に収まります。

一方で、組み合わせを増やすほど実行分数(課金・無料枠の消費)が増えます。macOS や Windows のランナーは Linux より分数の消費が大きく数えられる仕組みなので、OS を軸に加えるときは本当に必要か考えてからにしてください。上限や消費の計算方法は変わることがあるため、GitHub のドキュメントで最新の扱いを確認してください(2026年10月現在)。

基本の書き方

まずは最小構成です。.github/workflows/test.yml に置きます。

name: Test

on:
  push:
    branches: [main]
  pull_request:

jobs:
  phpunit:
    name: PHP ${{ matrix.php }} / WP ${{ matrix.wp }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ['7.4', '8.1', '8.3']
        wp: ['latest', '6.5']
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          tools: composer
      - run: composer install --no-progress
      - run: echo "WordPress ${{ matrix.wp }} でテストします"

ポイントは 3 つあります。

1 つ目は、バージョン番号を文字列としてクォートすることです。YAML では 8.10 と書くと数値の 8.1 と解釈されるため、意図しないバージョンが指定されます。'8.1' のように引用符で囲む習慣をつけておくと安全です。

2 つ目は、name にマトリックスの値を入れることです。省略すると「phpunit (7.4, latest)」のような表示になり、どの軸の値か分かりにくくなります。

3 つ目は、アクションのバージョン指定です。actions/checkout などは定期的にメジャーバージョンが上がります。例では @v4 としていますが、採用時点の最新メジャーを公式リポジトリで確認してください。サードパーティのアクションは、信頼性を重視するならコミット SHA で固定する方法もあります。

WordPress のテスト環境と組み合わせる

実際に WordPress のテストスイートを使う場合は、MySQL をサービスコンテナとして立ち上げ、WP-CLI の wp scaffold plugin-tests が生成する bin/install-wp-tests.sh でテスト用の WordPress を取得します。

jobs:
  phpunit:
    name: PHP ${{ matrix.php }} / WP ${{ matrix.wp }}
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: wordpress_test
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=5
    strategy:
      fail-fast: false
      matrix:
        php: ['7.4', '8.1', '8.3']
        wp: ['latest', '6.5']
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: mysqli
          tools: composer
      - run: sudo apt-get update && sudo apt-get install -y subversion
      - run: composer install --no-progress
      - run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp }} true
      - run: vendor/bin/phpunit

ここでの root / root は、CI の使い捨てコンテナ内だけで使うテスト用の値です。本番や共有サーバーの認証情報をワークフローに直接書くのは避け、必要な秘密情報はリポジトリの Secrets に登録して ${{ secrets.NAME }} で参照します。

つまずきやすいのは PHPUnit のバージョンです。WordPress のテストスイートが対応する PHPUnit のバージョンは WordPress 側のバージョンによって異なり、古い PHP では新しい PHPUnit が動きません。yoast/phpunit-polyfills を使って差を吸収するのが一般的ですが、組み合わせによっては PHPUnit のバージョンもマトリックスの軸に入れるか、後述の include で個別に指定する必要があります。install-wp-tests.sh は内部で svn を使うため、ランナーに subversion が無い場合はインストールのステップが要ります。

include と exclude で組み合わせを調整する

直積のままでは「サポート対象外の組み合わせ」まで実行されます。exclude で特定の組み合わせを外し、include で追加や上書きができます。

strategy:
  fail-fast: false
  matrix:
    php: ['7.4', '8.1', '8.3']
    wp: ['latest', '6.5']
    exclude:
      - php: '7.4'
        wp: 'latest'
    include:
      - php: '8.4'
        wp: 'trunk'
        experimental: true

exclude は書いた値がすべて一致する組み合わせを取り除きます。上の例では「PHP 7.4 × 最新 WordPress」だけが外れます。どのバージョン同士が公式にサポートされるかは WordPress の PHP 互換表(make.wordpress.org)で確認してから決めてください。例の組み合わせは書き方の説明用です。

include の挙動は少し分かりにくいので整理しておきます。

  • include の要素が、既存の組み合わせの元の値を上書きせずに追加できる場合は、その組み合わせに変数が足されます。
  • どの組み合わせにも足せない場合(元の値と食い違う場合)は、新しい組み合わせとして 1 ジョブ増えます。

上の例の php: '8.4', wp: 'trunk' は元の値に無い組み合わせなので、新しいジョブとして追加され、そのジョブにだけ matrix.experimental が true で入ります。

失敗したときの挙動を決める

fail-fast は既定で true です。どれか 1 つのジョブが失敗すると、実行中・待機中の他のジョブがキャンセルされます。分数の節約にはなりますが、「どの組み合わせで落ちるか」を一覧したいテスト用途では false にしておく方が原因を絞り込みやすくなります。

開発版の WordPress や次期 PHP のように、落ちても全体を失敗扱いにしたくない組み合わせには、ジョブ単位の continue-on-error を使います。

jobs:
  phpunit:
    runs-on: ubuntu-latest
    continue-on-error: ${{ matrix.experimental == true }}

max-parallel で同時実行数を絞ることもできます。外部 API やステージング環境に負荷をかけるジョブでは、並列数を抑えておくとトラブルを避けられます。

同じブランチに連続でプッシュしたときに古い実行を止めたい場合は、ワークフローの最上位に concurrency を置きます。

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

ブランチ保護の必須チェックとの関係

マトリックスで展開されたジョブは、組み合わせごとに別のチェックとして扱われます。ブランチ保護(またはルールセット)で必須チェックを指定する場合、展開後の個々のジョブ名を指定することになるため、マトリックスの値やジョブの name を変えると、必須チェックが「待機中のまま」になってマージできなくなることがあります。

対策としてよく使われるのは、全マトリックスジョブの完了を待つ集約ジョブを 1 つ作り、それだけを必須チェックにする方法です。

  all-tests:
    if: always()
    needs: phpunit
    runs-on: ubuntu-latest
    steps:
      - run: test "${{ needs.phpunit.result }}" = "success"

if: always() を付けないと、マトリックスの一部が失敗したときに集約ジョブ自体がスキップされ、スキップが成功として扱われる設定だと意図せずマージできてしまいます。needs.<job>.result で結果を明示的に確認するのがポイントです。

動的マトリックスと上限

組み合わせを別のジョブで計算したい場合は、前のジョブの出力を JSON で渡して fromJSON() で読み込めます。対応バージョン一覧をファイルで管理しているときに便利です。

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set.outputs.matrix }}
    steps:
      - id: set
        run: echo 'matrix={"php":["8.1","8.3"]}' >> "$GITHUB_OUTPUT"
  test:
    needs: prepare
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
    steps:
      - run: echo "PHP ${{ matrix.php }}"

1 回のワークフロー実行で生成できるマトリックスのジョブ数には上限があります(ドキュメント上は 256 ジョブ)。動的に生成する場合は、想定外に組み合わせが膨らまないよう入力を確認してください。

確認とデバッグのコツ

  • Actions タブの実行結果で、各組み合わせが期待どおりに展開されているかを最初に確認します。exclude の書き間違いは、ジョブ数を数えるとすぐ気づけます。
  • 失敗したジョブだけを再実行する機能があるので、ネットワーク起因の一時的な失敗は全体をやり直す前に試せます。
  • 値の受け渡しが怪しいときは、run: echo '${{ toJSON(matrix) }}' で各ジョブのマトリックス変数を出力すると早く原因が分かります。

まとめ

  • strategy.matrix は変数の直積を自動展開し、1 つのジョブ定義で複数環境を並列テストできます。
  • バージョンは文字列でクォートし、name に値を入れて結果を読みやすくします。
  • exclude で不要な組み合わせを外し、include で追加や変数の付与を行います。include の上書きルールは事前に確認しておきます。
  • テスト用途では fail-fast: false、実験的な組み合わせには continue-on-error が便利です。
  • ブランチ保護は集約ジョブを必須チェックにすると、マトリックスの変更に強くなります。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲