TL;DR
GitHub Actionsで多くのジョブを定義した際に、定数値(使うPythonバージョンやバッジの色だったりなど)などの定義を各ジョブで使いまわしたい(記述を統一したい)と思い色々調べて調整したのでその備忘録です。
発生していた問題点
少し前にGitHub Actionsでジョブを細かく分割・キャッシュ・並列化などしたのですが、その影響で各ジョブで重複する値の指定の部分が結構発生していました。
同一のジョブ内であれば環境変数など設定すれば問題ないのですが、ジョブをまたいだ場合には環境変数が反映されません。しかし記述が重複しているとDRY原則的に少々気になってしまいます。
できれば各ジョブの前に定数定義的なことができると良いな・・・という状態でした。
定数的に他のジョブの値を参照する方法
定数的に値を設定してその値を他のジョブで参照するには以下のような手順が必要になります。
- 必要な定数値などを設定するためのジョブでoutputsの定義を行う。
- その定数値などを参照したいジョブではneedsでそのジョブを指定する。
- needsが指定されていると
needs.<ジョブ名>.outputs.<定数などの名前>
という書き方でアクセスができる。
それぞれ順番にみていきます。
必要な定数値などを設定するためのジョブでoutputsの定義を行う
必要な定数値などを他のジョブで参照するために設定する場合にはoutputsの定義をジョブに加えます。
例えばSetGlobalConstants
というジョブ名でPYTHON_38_VERSION
といったようなPythonバージョンの定義であったりPASSING_BADGE_COLOR
といったようなバッジ用の色の定義などをしたい場合には以下のような感じになります。
jobs:
...
SetGlobalConstants:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
PYTHON_36_VERSION: 3.6.15
PYTHON_37_VERSION: 3.7.12
PYTHON_38_VERSION: 3.8.12
PYTHON_39_VERSION: 3.9.9
PYTHON_310_VERSION: 3.10.0
CHECKING_BADGE_COLOR: FFAA00
PASSING_BADGE_COLOR: 0088FF
steps:
- run: echo 'Setting constans.'
...
※steps部分は必須なので最低限の出力だけしています。他の処理と一緒のジョブ内で設定する場合などにはこの辺の出力はスキップ可です。
他のジョブでneedsの指定や設定した定数値などを参照する
定義した値を他のジョブから参照したい場合にはまずneeds部分にその定数などを定義したジョブを含めます。
例えば定数定義をSetGlobalConstants
というジョブでやっていれば以下のような感じになります。
...
RunFlake8:
needs: [CreateCache, SetGlobalConstants]
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
...
このようにneedsの指定をしたジョブ内ではneeds.<ジョブ名>.outputs.<定数などの名前>
といった記述でoutputsで指定していた定数にアクセスすることができます。
たとえばSetGlobalConstants
というジョブ名で定数名がPYTHON_36_VERSION
という名前であれば以下のように書くことで対象の定数にアクセスすることができます。
RunFlake8:
needs: [CreateCache, SetGlobalConstants]
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup the Python dependencies
uses: ./.github/actions/setup_py_dependencies
with:
python-version: '${{ needs.SetGlobalConstants.outputs.PYTHON_36_VERSION }}'
なお、ジョブ1 -> ジョブ2 -> ジョブ3...といったようにジョブのフローが流れるようにしていてジョブ1で定数などを定義してジョブ3でそれらを扱いたい・・・といった場合でもneedsにはジョブ1を指定しないとエラーになります(ジョブ2のneedsでジョブ1が指定されている場合でもneedsの参照は引き継がれません)。
つまりジョブ3をスタートがジョブ2の次としていて、且つジョブ1の定数値を参照したいような場合にはジョブ3のneedsにはジョブ1とジョブ2を両方含める必要があります。
定数値をそのジョブ内の値で設定したい場合
定数値が固定ではなくジョブの実行結果次第で変わるようなケースでは、outputs内でsteps.<対象のstepのid>.outputs.<対象の値の名称>
とすることでジョブのsteps内の値にアクセスができるのでそれをoutputsの箇所で指定すれば対応ができます。
例えば値を設定するstepでset-coverage
というidを付け、且つcoverage
という名前で値が設定されている場合には以下のようにoutputsには書きます(定数名はCOVERAGE
としています)。
...
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
COVERAGE: ${{ steps.set-coverage.outputs.coverage }}
対象のstep部分では以下のように書いています。::set-output name=<値の名前>::<設定する値>
という書き方で値が設定できるようです。
...
- name: Set the coverage to outputs value
id: set-coverage
run: echo '::set-output name=coverage::${{ env.COVERAGE }}'
...
サンプルとして該当のジョブ全体では以下のような感じになっています。
RunTestsOnPython36AndSaveCoverageAndPassedNum:
needs: [CreateCache, SetGlobalConstants]
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
COVERAGE: ${{ steps.set-coverage.outputs.coverage }}
PASSED_TESTS_NUM: ${{ steps.set-passed-tests-num.outputs.passed-tests-num }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup the Python dependencies
uses: ./.github/actions/setup_py_dependencies
with:
python-version: ${{ needs.SetGlobalConstants.outputs.PYTHON_36_VERSION }}
- name: Set the pytest alias
run: alias pytest=/opt/hostedtoolcache/Python/${{ needs.SetGlobalConstants.outputs.PYTHON_36_VERSION }}/x64/bin/pytest
- name: Run the test runner command
run: python run_tests_and_save_coverage_and_num.py
- name: Set the environment variables from .env file
uses: c-py/action-dotenv-to-setenv@v3
with:
env-file: .env
- name: Set the coverage to outputs value
id: set-coverage
run: echo '::set-output name=coverage::${{ env.COVERAGE }}'
- name: Set the passed tests number to outputs value
id: set-passed-tests-num
run: echo '::set-output name=passed-tests-num::${{ env.PASSED_TESTS_NUM }}'
実際のYAMLファイル
※今回の定数値などを利用する形にしたPythonプロジェクト用のワークフローのYAMLファイルのリンクを貼っておきます。日々更新を入れているので記事の内容と将来ずれてくるとは思いますがご了承ください。
参考サイト