GitHub Actionsを使っていて、並列目的などでジョブを細かく分けたときに依存関係の設定などで記述が重複する箇所が結構発生し、それらの重複をComposite run steps action (Composite actionなどとも表記されるようです)という機能を使って軽減したのでその際の備忘録です。
発生していた問題とやったこと
少し前にPythonの自作ライブラリのLintやテスト・デプロイなどのGitHub Actionsのジョブで依存関係の設定のキャッシュ機能やジョブ分割による並列実行などを対応しました。多くのジョブを走らせても処理時間などは良い感じに気にならない形となりました。
一方でジョブの分割によって依存関係の設定など(Pythonの設定やPythonライブラリのパッケージ設定など)の記述が各ジョブ間で重複している箇所がsteps内で目立ちました。
DRY原則的にもこの辺は重複が多いと結構気になりますし変更する際などに変更漏れなどが発生しそうであまり良くありません。
そこでComposite run steps actionという機能を使ってstepsの重複部分の記述を統一しました。
Composite run steps actionとはどんな機能なのか
- steps内の一部の処理群を別のYAMLファイルに記述することができます。
- 元々のワークフローの各ジョブのsteps内の任意の位置でその別ファイルのYAMLのstepsの処理を呼び出すことができます。
- 別ファイル側で実行されたstepsの処理結果は呼び出し元にも反映されます。つまり依存関係などの設定を別ファイルで設定した際には呼び出し元のジョブ側でもその後その依存関係のものを利用することができます。
- 別ファイルのstepsへは呼び出し元から引数のように任意のパラメーターを渡すことができます。
- この記事を書いている時点では別ファイル側ではifが使えなかったり一部追加の設定などが必要になったりといった制限などがあります。
必要な対応内容の概略
※それぞれ後の節で詳しく触れます。
- 切り出したいstepsの処理を記述した別ファイルのYAMLファイルを設置します。
- そちらの別ファイルに受け付けるパラメーターの設定やstepsなどを記述します。
- 呼び出し元のジョブの任意のstepsの箇所でその別ファイルを指定して処理を呼び出します。
別ファイルのYAMLの設置方法
設置する別ファイルにはフォルダ名やファイル名にルールがあるので注意します。
まずは通常のワークフローのYAMLが設置されているリポジトリの.github
フォルダ以下にactionsというフォルダを追加します。そちらのフォルダ内に切り出したい処理の名前を付けたフォルダを更に追加します。
今回は依存関係などの設定を行うためのstepsを切り出したのでsetup_py_dependencies
という名前のフォルダにしました。<リポジトリパス>/.github/actions/setup_py_dependencies/
といったようなフォルダ構成になっています。
今後別のstepsの処理を追加で切り出したい場合はsetup_py_dependencies
フォルダと同じ階層に別の名前のフォルダを追加します。
追加したsetup_py_dependencies
フォルダ以下にaction.yml
というファイルを追加します。拡張子は.yaml
でも認識してくれるようです。ただしファイル名は別のものにしてしまうと認識してくれなさそう?なので注意します。結果的に今回対応したファイルのパスは<リポジトリパス>/.github/actions/setup_py_dependencies/action.yml
となっています。
切り出したaction.ymlファイルで最低限必要な記述
最低限name, description, runsが必要になります。descriptionなどは省略するとVS Code上で引っかかっていたので基本的には書く形のようです。また、runs内にはusing: composite
という記述が必要になります。後はruns内にstepsを書いていけば対応ができます。
name: Setup the Python dependencies
description: This composite run steps require the dependencies cache before running.
runs:
using: composite
steps:
- name: Set the Python version
...
渡すパラメーターの設定
呼び出し元からなんらか任意のパラメーターを切り出したYAMLの処理に渡したい場合にはinputs
の設定を行う必要があります。以下のようなフォーマットで書きます。
inputs:
<パラメーター名>:
description: <パラメーターの説明>
required: <パラメーターを必須とするかどうかの真偽値>
例えばpython-version
という名前のパラメーターを必須の設定で設定したい場合には以下のように書きます。
name: Setup the Python dependencies
description: This composite run steps require the dependencies cache before running.
inputs:
python-version:
description: Python version to use.
required: true
...
こうすることで、steps内で${{ inputs.<パラメーター名> }}
と記述することで渡されたパラメーターを参照することができます。先ほどのpython-version
というパラメーターの場合は${{ inputs.python-version }}
といったようになります。
記述例 :
name: Setup the Python dependencies
description: This composite run steps require the dependencies cache before running.
inputs:
python-version:
description: Python version to use.
required: true
runs:
using: composite
steps:
- name: Set the Python version
uses: actions/setup-python@v2
with:
python-version: ${{ inputs.python-version }}
...
呼び出し元のsteps内で追加したYAMLの内容を呼び出す方法
呼び出し元となるワークフローの任意のsteps内で追加した別ファイルのYAMLのものを呼び出したい場合にはuses
に./.github/actions/<対象の処理のフォルダ名>
と指定します。今回はsetup_py_dependencies
というフォルダを追加しているのでuses: ./.github/actions/setup_py_dependencies
といった記述になります。action.ymlといったファイル名部分は不要です。また、先頭に./
の記述が無いと動かなかったりする?ようなので注意してください。
記述例 :
...
RunFlake8:
needs: CreateCache
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Set the Python version environment variable
run: echo "python-version=3.6.15" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v2
- name: Setup the Python dependencies
uses: ./.github/actions/setup_py_dependencies
- name: Set the flake8 alias
run: alias flake8=/opt/hostedtoolcache/Python/${{ env.python-version }}/x64/bin/flake8
- name: Run the flake8 command
run: python run_flake8.py
...
パラメーターを指定して呼び出しを行う
呼び出しの際にパラメーターを指定したい場合にはwith
を使って以下のように書きます。
...
with:
<パラメーター名>: <渡すパラメーター>
...
今回はpython-version
というパラメーターを必須として切り出したYAMLファイル側で設定しているのでそちらを指定します。
記述例 :
...
- name: Setup the Python dependencies
uses: ./.github/actions/setup_py_dependencies
with:
python-version: ${{ env.python-version }}
...
runを使うときには追加でshellの指定が必要
注意点となりますが、切り出したYAML内でのrunでのコマンドの実行にはshell
の設定が必要なようです。shell: bash
といったような記述を追加しておく必要があります。
記述例 :
- name: Set the site package path to the environment variables
run: python -c "import site; print(f'site-packages-path={site.getsitepackages()[0]}')" >> $GITHUB_ENV
shell: bash
記述が無いとVS Code上などでエラーが表示されます。試していないですがそのままGitHub上に反映しても弾かれるかもしれません。
今回の記事の内容を反映したYAML
参考用に今回のものを反映したYAMLファイルのリンクを貼っておきます(日々更新しているため記事内容と最新のYAMLファイルの差分などはご容赦ください)。
メインのワークフローのYAML:
Composite run steps actionとして別ファイルに切り出したYAML:
参考サイトまとめ