前置き
GitHub Actionsではworkflowのyamlファイルに下記のように jobs.<job-id>.strategy.matrix
を書くことでmatrix buildを作ることができます。 *1
# .github/workflows/build.yml jobs: test: name: test (Ruby ${{ matrix.ruby }}, Go ${{ matrix.go }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: - "3.3" - "3.4" go: - "1.23"
しかし、このmatrixの組み合わせを別のworkflowでも使いたくなった時に、普通にやると全く同じものを別ファイルにコピペする必要が出てきます。
このエントリでは複数のworkflowで利用するmatrixを共通化する小ネタを紹介します
tl;dr;
適当なjsonファイルから読み込んだ値をmatrixの値として利用するサンプル
# .github/workflows/build.yml jobs: generate-matrix: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v4 - id: set-matrix run: echo "matrix=$(cat matrix.json | jq -c)" >> $GITHUB_OUTPUT working-directory: .github/workflows/ test: name: test (Go ${{ matrix.go }}, Ruby ${{ matrix.ruby }}) needs: - generate-matrix runs-on: ubuntu-latest strategy: fail-fast: false matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
.github/workflows/matrix.json
の中身は下記のような形式を想定。
{ "go": [ "1.23" ], "ruby": [ "3.3", "3.4" ] }
解説
動的にmatrixを生成する
GitHub Actionsでmatrixを動的に生成する方法は下記で紹介されているので参考になります。
要は別のjobで生成したmatrix(json文字列)をoutputs経由で後続のjobに引き回すという方法です。
.github/workflows/matrix.json
の値をworkflowのmatrixとして引き回す準備をしてるのが下記です。
generate-matrix: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v4 - id: set-matrix run: echo "matrix=$(cat matrix.json | jq -c)" >> $GITHUB_OUTPUT working-directory: .github/workflows/
jsonファイルの置き場所はどこでもいいですが、自分はCI関係のスクリプトを .github/workflows/
に置くことが多いです。
ここでのポイントは jq -c
してるところ。
matrixの値(json文字列)は環境変数経由で渡す必要があるんですが、json文字列が複数行だと環境変数にそのままセットすると環境変数には1行目しかセットされないし、かといって複数行文字列を頑張って環境変数としてセットするのも割と面倒なので jq -c
で1行jsonになるようにしてます。
$ cat matrix.json { "go": [ "1.23" ], "ruby": [ "3.3", "3.4" ] } $ cat matrix.json | jq -c {"go":["1.23"],"ruby":["3.3","3.4"]}
元のjsonファイルを最初から1行にしていてもいいけどリポジトリにコミットする場合はdiffの見やすさから複数行の方が嬉しいんですよね、、、(好みの問題)
自分でスクリプトを書けばjsonファイル以外をmatrixのソースにすることもできるけどこれが一番シンプルだと思います。
working-directory
を削って
- id: set-matrix run: echo "matrix=$(cat .github/workflows/matrix.json | jq -c)" >> $GITHUB_OUTPUT
でもいいですが、そうするとworkflowファイル内で defaults.run.working-directory
を書いてた場合 *2 にそこだけちょっと変える必要が出てくる(完全にコピペできない)のでコピペビリティ重視でset-matrix側で working-directory
を書く方法に落ち着きました。
JSON文字列からmatrixを生成する
generate-matrix jobのoutputsからJSON文字列を取り出してfromJSONでオブジェクトに変換してセット
test: needs: - generate-matrix strategy: fail-fast: false matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
上記はさっきの例でいうと
test: strategy: fail-fast: false matrix: ruby: - "3.3" - "3.4" go: - "1.23"
と同じになります。
ちなみにmatrix.jsonの中の単一のkeyだけをmatrixの値として利用したい(全部のkeyをmatrixに利用したくない)時は必要なkeyだけ取り出せばいいです。
例)*3
test: strategy: fail-fast: false matrix: ruby: ${{ fromJSON(needs.generate-matrix.outputs.matrix).ruby }}
*1:https://github.com/sue445/funnel_http/blob/111b406e33618384fa71e824e4d92869b317171f/.github/workflows/build.yml#L17-L30
*2:具体的には https://github.com/ruby-go-gem/go-gem-wrapper/blob/ae7f410e2de86881bf83984134963f8a950dd45b/.github/workflows/patch_for_go_gem.yml#L18-L34
*3:https://github.com/ruby-go-gem/go-gem-wrapper/blob/ae7f410e2de86881bf83984134963f8a950dd45b/.github/workflows/build.yml#L215