前提
今回はMatrixを使用する例としてDjangoとMySQLとPytestを使用します
DjangoとMySQLのサービスコンテナを使ってPytestを実行する方法について
本記事では解説しないので詳細に知りたい方は以下の記事を参照してください
Matrixとは
同じワークフローを複数の
- 実行環境(Node.jsなど)
- runnerOS (Ubuntuなど)
- 言語(Pythonなど)
のバージョンで実行できる仕組みです
Matrixを使うと例えばバージョンをアップデートする際の検証やトラブルシューティングに役立つかと思います
デフォルトでは全てのバージョンを以下のように並列で実行できます
また、Matrixを使用する際は一つのJobsが失敗すると他のJobsが実行されないのも特徴です
(ただし、continue-on-errorを追加した場合は除く)
Matrixの設定方法
Matrixを設定する際は以下の例のようにstrategy
を定義し、その下にmatrix
を定義します
matrixの下に任意の変数を定義し、テストしたいバージョンの一覧を配列に入れます
jobs:
Setup:
name: Run Test Code
# 実行したいバッケージ等のバージョンを配列内にstrategyとmatrixに指定
strategy:
matrix:
python-version: [3.10.5, 3.10.6, 3.10.7]
os: [ubuntu-latest, ubuntu-20.04]
Job内でMatrixで定義したバージョンを適用させたい処理には以下のように記載します
例えばOSのバージョンを適用させたいときは以下のように記載します
${{ matrix.os }}
実際に実行してみよう!
以上を踏まえてMatrixを適用させると以下の例のようになります
ディレクトリ構成
❯ tree
.
├── .github
│ └── workflows
│ └── test.yml
└── application # Djangoのプロジェクトファイルおよびpyproject.tomlが入ったディレクトリ
├── project
│ └── settings.py
├── manage.py
├── poetry.lock
└── pyproject.toml
ワークフロー
name: Run Pytest Using Matrix
# ワークフローのイベントは任意です
# 今回は検証用なので手動でワークフローを実行するようにします
on: workflow_dispatch
env:
SECRET_KEY: test
DJANGO_SETTINGS_MODULE: project.settings
ALLOWED_HOSTS: 127.0.0.1
DEBUG: "True"
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test-db
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3306
MYSQL_USER: test
MYSQL_PASSWORD: test
jobs:
Setup:
name: Run Test Code
# 実行したいバッケージ等のバージョンを配列内にstrategyとmatrixに指定
strategy:
matrix:
python-version: [3.10.5, 3.10.6, 3.10.7]
os: [ubuntu-latest, ubuntu-20.04]
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: application
services:
db:
image: mysql:8.0
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: ${{ env.MYSQL_ROOT_PASSWORD }}
MYSQL_DATABASE: ${{ env.MYSQL_DATABASE }}
MYSQL_USER: ${{ env.MYSQL_USER }}
MYSQL_PASSWORD: ${{ env.MYSQL_PASSWORD }}
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Chekcout code
uses: actions/checkout@v3
- name: Grant privileges to user
run: mysql --protocol=tcp -h 127.0.0.1 -P 3306 -u root -p$MYSQL_ROOT_PASSWORD -e "GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'%'; FLUSH PRIVILEGES;"
- name: Install poetry
run: pipx install poetry
- name: Use cache dependencies
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- name: Install Packages
run: poetry install
- name: Run migration
run: |
poetry run python manage.py makemigrations
poetry run python manage.py migrate
- name: Run Pytest
run: poetry run pytest -x -n auto --cov --no-cov-on-fail --suppress-no-test-exit-code
Django側の設定
import os
SECRET_KEY = os.environ.get("SECRET_KEY")
DEBUG = os.environ.get("DEBUG") == "True"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS").split(" ")
# データベースの設定を行う
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.environ.get("MYSQL_DATABASE"),
"USER": os.environ.get("MYSQL_USER"),
"PASSWORD": os.environ.get("MYSQL_PASSWORD"),
"HOST": os.environ.get("MYSQL_HOST", "db"),
"PORT": os.environ.get("MYSQL_PORT", 3306),
}
}
前述の通り、各Jobが並列で実行され、成功すると以下のようになります
特定のバージョンのみ追加したいとき
例えば
- Python 3.10.8
- Ubuntu 18.04
だけ追加で検証したいときはinclude
を使用します
2つとも配列に入れてしまうと
- Python 3.10.8
- Ubuntu 20.04 と latest
など、実行しなくてもいいバージョンのJobまで実行されてしまいます
そのため、今回みたいなケースではinclude
を使用します
strategy:
matrix:
python-version: [3.10.5, 3.10.6, 3.10.7]
os: [ubuntu-latest, ubuntu-20.04]
# includeを使って python-version: 3.10.8 と ubuntu-18.04 のみ追加
include:
- python-version: 3.10.8
os: ubuntu-18.04
以下のように
- Python 3.10.8
- Ubuntu 18.04
のJobのみ追加されていることが確認できました
特定のバージョンのみ除外したいとき
特定のバージョンのみ除外するときはincludeとは逆にexcludeを使用します
今回は
- Python 3.10.5
- Ubuntu 20.04
のJobのみ実行しないようにします
strategy:
matrix:
python-version: [3.10.5, 3.10.6, 3.10.7]
os: [ubuntu-latest, ubuntu-20.04]
# includeを使って python-version: 3.10.5 と ubuntu-20.04 のみ除外
exclude:
- python-version: 3.10.5
os: ubuntu-20.04
以下のように
- Python 3.10.5
- Ubuntu 20.04
参考