はじめに
- YUZURIHAの松村です。
- 現在私が担当しているPHPのプロジェクトでは、GitHub ActionsにてPHPStanを実行してコードの静的解析を行っています。
- その中で発生した問題と対応した方法について、ご紹介します。
LibXLの導入
- 私が担当しているプロジェクトでは、Excelを扱うためにPHP拡張モジュールのLibXLを導入しています。
- このLibXLは、composerなどのライブラリ管理ツールではなく、makeコマンドによってLinuxに直接インストールしています。
- ※ 具体的にLibXLをどのようにインストールしてどのように使っているかは、本稿の趣旨からは逸れるため割愛します。
- Dockerで用意しているローカル開発環境でもLibXLを使えるように、Dockerfile上でmakeコマンドによってインストールしています。
GitHub Actionsの設定
- GitHub ActionsでPHPStanを実行するためのワークフローは、以下のように設定しています。
.github/workflows/phpstan.yml
jobs:
phpstan:
runs-on: ubuntu-latest
steps:
# リポジトリにあるソースコードをGitHub Actions Runnerに持ってくる
- name: Checkout code
uses: actions/checkout@v6
# PHPのセットアップ
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
# Composer Install
- name: Composer Install
run: composer install --prefer-dist --no-progress
# PHPStanを実行
- name: Run PHPStan
run: ./vendor/bin/phpstan analyze -c phpstan.neon
※ 実際にはcomposerのキャッシュの設定や各コマンドのオプションなどもありますが、こちらも本稿の趣旨から逸れるため割愛しています。
PHPStan実行時に発生した問題
- このような状態でGitHub ActionsにてPHPStanを実行すると、LibXLで定義している
ExcelBookやExcelFormatといったクラスが存在しないため、エラーが発生してしまいました。
------ ----------------------------------------------------------------------------------------
Line Services/HogeService.php
------ ----------------------------------------------------------------------------------------
XXX Call to method loadFile() on an unknown class ExcelBook.
🪪 class.notFound
💡 Learn more at https://phpstan.org/user-guide/discovering-symbols
XXX Access to constant COLOR_BLACK on an unknown class ExcelFormat.
🪪 class.notFound
💡 Learn more at https://phpstan.org/user-guide/discovering-symbols
- ローカル開発環境にてPHPStanを実行すると、ちゃんとLibXLをインストールしているのでこのエラーは発生しません。
- そのため、GitHub Actionsとローカル開発環境でPHPStan実行時の挙動が異なるという少し困った状況になってしまいました😩
対応した方法
- 以下の方法で対応して、解決することができました😄
- ghcr.io(GitHub Container Registry)に、ローカル開発環境のdockerイメージをbuild & pushする。
- そのdockerイメージを使って、GitHub Actions上でPHPStanを実行する。
- では、具体的にどのように対応したのかを詳しく説明して行きます。
ghcr.ioにdockerイメージをbuild & push
- 新たなワークフロー
image-build-push.ymlを追加します。 - ワークフロー実行のトリガーを指定する
on:は割愛していますが、各々のプロジェクトの運用に応じて設定するのが良いと思います。
.github/workflows/image-build-push.yml
permissions:
# リポジトリのソースコードを読み取る権限を付与
contents: read
# GitHub Actionsの標準トークン(GITHUB_TOKEN)に、ghcr.ioへイメージを書き込む権限を付与
packages: write
jobs:
image-build-and-push:
runs-on: ubuntu-latest
env:
IMAGE_NAME: ghcr.io/${{ github.repository }}/php
IMAGE_TAG: ${{ github.sha }}
steps:
# リポジトリにあるソースコードをGitHub Actions Runnerに持ってくる
- uses: actions/checkout@v6
# GitHub Actions専用の高速キャッシュ(type=gha)を使うために、標準のdocker buildよりも高機能なBuildxを有効にする
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
# ghcr.ioへログイン
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# メタデータの自動生成(手動でタグを管理する手間を省く)
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ env.IMAGE_TAG }}
type=ref,event=branch
type=ref,event=tag
type=raw,value=latest
# ghcr.ioへBuild & Push
- name: Build & Push
uses: docker/build-push-action@v6
with:
# リポジトリ上のDockerfileのパスを指定
file: ./docker/php/Dockerfile
# php.iniなどを配置しているディレクトリパスを指定
context: ./docker/php
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
# GitHub Actionsのキャッシュストレージに保存して高速化する
cache-from: type=gha
cache-to: type=gha,mode=max
ghcr.io上のdockerイメージを使ってPHPStanを実行
- 次に、PHPStan実行のワークフローを以下のように改修します。
.github/workflows/phpstan.yml
jobs:
phpstan:
runs-on: ubuntu-latest
permissions:
# リポジトリのソースコードを読み取る権限を付与
contents: read
# ghcr.ioからイメージをPullする権限を付与
packages: read
# stepsを実行するDockerコンテナを指定
container:
# 最新のイメージを指定
image: ghcr.io/${{ github.repository }}/php:latest
# イメージが保存されているghcr.ioにアクセスするための実行ユーザと一時パスワードを指定
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
# リポジトリにあるソースコードをGitHub Actions Runnerに持ってくる
- name: Checkout code
uses: actions/checkout@v6
# Composer Install
- name: Composer Install
run: composer install --prefer-dist --no-progress
# PHPStanを実行
- name: Run PHPStan
run: ./vendor/bin/phpstan analyze -c phpstan.neon
- PHPのインストールはDockerfile内で行っているため、従来のワークフローで行っていた
Setup PHPは不要になります。
最後に
- 以上の対応を行ってから数ヶ月間チーム内でワークフローを運用していますが、特に問題は起こっていません。
- ghcr.ioからイメージをPullする分ワークフローの実行時間が遅くなることを懸念していましたが、高速キャッシュ(type=gha)を使っているためか遅くなりませんでした。
スタブを使う
- そして、記事を書きながらいろいろ調べていたのですが、スタブを使う方法でも対応できそうです。
- LibXL(php-excel)のための静的解析用スタブパッケージというのがありました。
- このパッケージの各クラスのスタブを
phpstan.neonに指定することで、エラーを回避できそうです。 - というわけで、以下のようなケースではスタブを使う方が良いかもしれません。
- GitHub Packagesでかかる料金が気になる
- GitHub Actionsでは静的解析(PHPStan)を行うだけで、テストは実行しない
- もし他にも「こういう方法が良い」とかあれば、教えていただけると嬉しいです。
