GitHub Actions
概要
- GitHub Actionsのビルドマトリクスは動的に生成することが出来る
- 動的に生成したビルドマトリクスを使ってジョブを並列実行する
ビルドマトリクスとは
公式より
マトリックス戦略を使うと、単一のジョブ定義中で変数を使って、変数の組み合わせに基づく複数のジョブの実行を自動的に生成できます。 たとえばマトリックス戦略を使って、コードを言語の複数のバージョンや、複数のオペレーティングシステムでテストできます。
https://docs.github.com/ja/actions/using-jobs/using-a-matrix-for-your-jobs
本題
GitHub Actionsのコード
dynamic-build-matrix.yml
name: 'Dynamic Build Matrix Actions'
on:
workflow_dispatch:
inputs:
zeus:
description: 'zeus'
type: boolean
required: true
default: false
athena:
description: 'athena'
type: boolean
required: true
default: false
hades:
description: 'hades'
type: boolean
required: true
default: false
jobs:
setup:
runs-on: ubuntu-latest
timeout-minutes: 3
outputs:
targets: ${{ steps.build-matrix.outputs.targets }}
steps:
- name: Setup Dynamic Build Matrix
id: build-matrix
run: |
TARGETS=()
if [ "${{ github.event.inputs.zeus }}" = "true" ]; then
TARGETS+=("zeus")
fi
if [ "${{ github.event.inputs.athena }}" = "true" ]; then
TARGETS+=("athena")
fi
if [ "${{ github.event.inputs.hades }}" = "true" ]; then
TARGETS+=("hades")
fi
targets=$(printf '%s\n' "${TARGETS[@]}" | jq -R . | jq -s -c .)
echo "::set-output name=targets::$targets"
execute:
runs-on: ubuntu-latest
timeout-minutes: 5
needs:
- setup
strategy:
fail-fast: true
max-parallel: 3
matrix:
targets: ${{ fromJSON(needs.setup.outputs.targets) }}
steps:
- uses: actions/checkout@v3
- name: Install Figlet
run: sudo apt-get install -y figlet
- name: Execute Script
working-directory: scripts
run: ./${{ matrix.targets }}.sh
解説
ポイントは3つ。
workflow_dispatch
なワークフローを定義し、入力値として実行するスクリプトのon / offを選択させるsetup
ジョブでワークフローの入力値からビルドマトリクスに必要な値を動的に生成し、ジョブのoutputs
に出力する- 並列実行する後続のジョブでGitHub Actionsの組み込み関数である
fromJSON()
を使い、ビルドマトリクスとして定義する
workflow_dispatch
なワークフローの定義
type: boolean
とすることでチェックボックスの入力項目が定義出来る。
入力値はチェックボックスがONであれば true
、OFFであれば false
となる。
入力値の解析とビルドマトリクスの必要な値の動的な生成
ワークフローの入力値からBashの配列を生成し、jqコマンドを組み合わせて文字列のJSON配列を生成する。
生成したJSON配列を echo "::setoutput name=xxx::$yyy"
でステップの結果として出力、さらにジョブの outputs
に伝搬させることでジョブ間での値の共有を図る。
setup:
runs-on: ubuntu-latest
timeout-minutes: 3
outputs:
targets: ${{ steps.build-matrix.outputs.targets }}
steps:
- name: Setup Dynamic Build Matrix
id: build-matrix
run: |
TARGETS=()
if [ "${{ github.event.inputs.zeus }}" = "true" ]; then
TARGETS+=("zeus")
fi
if [ "${{ github.event.inputs.athena }}" = "true" ]; then
TARGETS+=("athena")
fi
if [ "${{ github.event.inputs.hades }}" = "true" ]; then
TARGETS+=("hades")
fi
targets=$(printf '%s\n' "${TARGETS[@]}" | jq -R . | jq -s -c .)
echo "::set-output name=targets::$targets"
動的なビルドマトリクスを設定してジョブを並列実行する
needs
でジョブの依存関係を定義し、さらに先行ジョブである setup
の出力値をGitHub Actionsの組み込み関数である fromJSON()
に食わせることでJSON配列の出力値から動的にビルドマトリクスが設定される。
あとは ${{ matrix.targets }}
を必要な箇所で使えばジョブが並列実行される。
ビルドマトリクスが動的生成されるのも面白いが、このビルドマトリクス自体がただの文字列でしかないので、これを使ってさらにコマンドを組み立てるようなことも可能なのが面白い。
今回の例ではあらかじめ実行するスクリプトを用意しておき、そのスクリプトとビルドマトリクスの文字列を一致させるようにすることで複数のスクリプトを並列実行させている。
execute:
runs-on: ubuntu-latest
timeout-minutes: 5
needs:
- setup
strategy:
fail-fast: true
max-parallel: 3
matrix:
targets: ${{ fromJSON(needs.setup.outputs.targets) }}
steps:
- uses: actions/checkout@v3
- name: Install Figlet
run: sudo apt-get install -y figlet
- name: Execute Script
working-directory: scripts
run: ./${{ matrix.targets }}.sh
実行結果
athena
/ hades
/ zeus
の全てをチェックしてワークフローを実行した場合。
それぞれ別のスクリプトが実行されていることが分かる。
おわりに
今回のデモコードは以下。