EC-CUBE の CI/CD を GitHub Actions で実装してみたので、メモ程度に知見をまとめてみます。
該当の Pull Request はこちら
2019年12月現在、 EC-CUBE organization アカウントが利用している契約プランの関係 で、 EC-CUBEオフィシャルリポジトリで GitHub Actions は利用できなくなっています。 ご利用の際は、 fork した個人アカウントでお願いします
実現したいこと
- 以下の環境をマトリクスで実行したい
- Linux, Windows
- PHP5.4〜7.3
- PostgreSQL/MySQL/SQLite3
- PHPUnit によるユニットテスト
- Codeception による E2Eテスト
EC-CUBE は、Travis CI 及び AppVeyor で CI を実行しており、これを GitHub Actions へ移植することにします
直面した課題
GitHub Actions にインストールされている PHP バージョン
- ubuntu-18.04 は PHP7.1〜7.3
- ubuntu-16.04 は PHP5.6〜7.3
- windows-2019, windows-2016 は PHP7.3
上記のような状況ですので、 PHP5.4, 5.5 の環境は自力で構築する必要があります。
GitHub Actions は、独自の Actions を作成できますので、 PHP5.4〜7.3 を Linux, Windows でマトリクス実行する Actions を作成しました。
以下のような感じで実行できます
jobs:
build:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ ubuntu-18.04, windows-2019 ]
php: [ '5.4', '5.5', '5.6', '7.1', '7.2', '7.3', '7.3.3' ]
name: PHP ${{ matrix.php }} sample
steps:
- uses: actions/checkout@master
- name: Setup PHP
uses: nanasess/setup-php@master
with:
php-version: ${{ matrix.php }}
- run: php my_script.php
- Linux で apt の利用可能なバージョンは apt を使用
- apt が利用できない場合は phpenv でビルド
- Windows 環境は chocolatey を利用
- ubuntu-16.04 は標準パッケージと小々異なる構成(OpenSSL1.1 がインストールされている)のため、 OpenSSL1.0 と libpq.so をソースから構築している
独自の Actions を作りたい場合は、 JavaScript または Docker コンテナを使用する必要があります。 actions/typescript-action テンプレートや actions/javascript-action, actions/hello-world-docker-action が利用できます。
Windows 環境は Composer がインストールされていない
こちらも独自の Actions を作成しました
Composer installer of Github Actions
ChromeDriver の実行
Codeception を実行するために ChromeDriver を設定する必要があります。
以下のような step を作成しました
- name: Setup chromedriver
run: |
sudo apt-fast install -y xvfb debconf-utils screen google-chrome-stable
wget -c -nc --retry-connrefused --tries=0 http://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip
unzip -o -q chromedriver_linux64.zip
export DISPLAY=:99
./chromedriver --url-base=/wd/hub &
echo ">>> Started chrome-driver"
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
ここで注意する必要があるのが、環境変数 DISPLAY の設定です。
jobs.<job_id>.steps.env
で設定しても、 ChromeDriver が動きません。
export
で設定する必要があります。
ちなみに、ファイルダウンロードのテストをする必要があるため、ヘッドレスモードは使用しません。
2019年10月3日追記 Actions を作成しました
nanasess/setup-chromedriver
こんな感じで記述できます
- name: setup-chromedriver
uses: nanasess/setup-chromedriver@master
with:
chromedriver-version: '77.0.3865.40'
- name: Run chromedriver
run: |
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
echo ">>> Started chrome-driver"
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
echo ">>> Started xvfb"
Windows 環境での MySQL のテスト
Linux 環境では MySQL Server が動いているのですが、 Windows 環境ではクライアントしかインストールされてないため、自前でインストールします
- name: Setup to database
run: |
choco install -y mysql --version 5.7.18
mysql --user=root -e "CREATE DATABASE `myapp_test`;"
mysql --user=root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';FLUSH PRIVILEGES;"
mysql --user=root --password=password -h 127.0.0.1 -e "SELECT version();"
PostgreSQL のテスト
Linux では jobs.<job_id>.services
で PostgreSQL を実行できます
services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
参考 https://github.com/actions/example-services/blob/master/.github/workflows/postgres-service.yml
MailCatcher を使用したテスト
Linux では jobs.<job_id>.services
で Docker コンテナを実行します
services:
mailcatcher:
image: schickling/mailcatcher
ports:
- 1080:1080
- 1025:1025
Windows は gem でインストールします。
shell: bash
を指定するのがポイント。デフォルトの cmd ではバックグラウンドで実行できません。。。
- name: Setup MailCatcher
run: gem install -N mailcatcher -v 0.6.5
shell: bash
- name: Run to MailCatcher
run: mailcatcher &
shell: bash
マイクロサービスの実行
EC-CUBE の E2E テストでは、 EC-CUBEオーナーズストア をエミュレートした Docker コンテナを実行し、プラグインインストールなどのテストをしています。
これを jobs.<job_id>.services
で動かしたかったのですが、、 Volume マウントするディレクトリが services を初期化する段階では生成できないため、 docker run コマンドで実行するしかないようです
## $ {PWD}/repos does not exist so service cannot be started
- name: Run package-api
run: docker run -d --rm -v ${PWD}/repos:/repos -e MOCK_REPO_DIR=/repos -p 8080:8080 eccube/mock-package-api
本当は以下のように書きたい
services:
package-api:
image: eccube/mock-package-api
env:
MOCK_REPO_DIR: '/repos'
ports:
- 8080:8080
volumes:
- $GITHUB_WORKSPACE/repos:/repos
イベントのフィルタリング
- Pull Request を master にマージした場合にワークフローが2つ走らないようにしたい
-
*.md
ファイルのみの修正はワークフローを実行しないようにしたい - リリースを発行した時にワークフローを実行する
- tag を打った時にワークフローを実行する
- 基本的に直接 push しない
以下のようにすることで、うまく動作しています
on:
push:
branches:
- master
tags:
- '*'
paths:
- '**'
- '!*.md'
pull_request:
paths:
- '**'
- '!*.md'
release:
types: [ published ]
デプロイする
GitHub Actions には AWS CLI や Azure CLI コマンドもインストールされているため、各種クラウドへのデプロイも柔軟にできます。
ここでは、 GitHub にて release の発行をすると、自動的に ZIP 及び tar.gz のパッケージを生成し、 Assets にアップロードするようにしました。
コードは長いので こちら を参照してください。
ポイントは、以下のようにすることで、タグ名をパッケージのファイル名にできます
- name: Packaging
working-directory: ../
env:
TAG_NAME: ${{ github.event.release.tag_name }}
REPOSITORY_NAME: ${{ github.event.repository.name }}
run: |
tar czfp eccube-$TAG_NAME.tar.gz $REPOSITORY_NAME
zip -ry eccube-$TAG_NAME.zip $REPOSITORY_NAME 1> /dev/null
github.event
オブジェクトには、多くの情報が格納されています。
以下のようにして参照できます
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Dump job context
env:
JOB_CONTEXT: ${{ toJson(job) }}
run: echo "$JOB_CONTEXT"
- name: Dump steps context
env:
STEPS_CONTEXT: ${{ toJson(steps) }}
run: echo "$STEPS_CONTEXT"
- name: Dump runner context
env:
RUNNER_CONTEXT: ${{ toJson(runner) }}
run: echo "$RUNNER_CONTEXT"
- name: Dump strategy context
env:
STRATEGY_CONTEXT: ${{ toJson(strategy) }}
run: echo "$STRATEGY_CONTEXT"
- name: Dump matrix context
env:
MATRIX_CONTEXT: ${{ toJson(matrix) }}
run: echo "$MATRIX_CONTEXT"
カバレッジを計測する
GITHUB_TOKEN
でカバレッジも連携できたら便利ですよね。
Coveralls GitHub Action は LCOV 型式のみのサポートの模様。
PHPUnit から LCOV 形式のレポートは出力できないため、 PHP のプロジェクトを secrets.GITHUB_TOKEN
で連携するのは今のところ難しそうです。
(Coveralls.io の token を登録すれば、 php-coveralls で連携できます)
codecov も GITHUB_TOKEN
での連携はサポートされてない模様
まとめ
まだ始まったばかりのサービスですし、 PHP で CI/CD をする環境が充実しているとは言い難い感じですが、いろいろ頑張れば柔軟に対応できそうです。
またナレッジがたまったら追記します