[GitHub Actions]actions/cache&pipenv&pytestの組み合わせを正常動作するまで検証&修正した記録
はじめに
GitHub ActionsのWorkflowにて、pipenvを使いつつcache化させて効率よく動かす、ということをされている方は多いと思われます。私自身、担当プロジェクトにて効率よく動かしている、と思っていました。一応キャッシュはしていたものの、キャッシュを無視して毎回インストールするフローになっていたのは不覚の極みでした。
正常にキャッシュされているかどうかの見極めと、pipenvとactions/cacheを併用したpytestの動作例をまとめました。
正常にキャッシュされているかどうかを見極める
セルフホストしていない限りは、ActionsのWorkflowログが確認の全てです。
キャッシュキーが意図した通りになっているか確認する
actions/cacheにて生成を想定するキーは恐らく次のような構成でしょう。
Linux-pipenv-8772fa24c3defb28f6eee443046fa57808f73961c10022ed9c7af06182663622 > ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
ですが、指定を間違えている場合は以下のようになります。
Linux-pipenv- > ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }}
詳しくは公式ドキュメントの 「Context and expression syntax for GitHub Actions - GitHub Docs」を参照してみましょう。
actions/cacheでのサンプルがマッチ例と異なっているのも意図しない状況になる要因かもしれません。
- uses: actions/cache@v2 with: path: ~/.local/share/virtualenvs key: ${{ runner.os }}-pipenv-${{ hashFiles('Pipfile.lock') }} restore-keys: | ${{ runner.os }}-pipenv-
なお、restore-keys
の指定によっては復元するキャッシュ候補の範囲を広げることもできますが、厳密に復元候補をしばりたい場合は下のような完全マッチがおすすめです。
- uses: actions/cache@v2 with: path: ~/.local/share/virtualenvs key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} restore-keys: | ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
キャッシュ保存時のフラグを利用する
action/cacheを使うことで、その後の処理が復元したキャッシュ前提で進むかというとそんなことはありません。if
によるチェックを挟む必要があります。
- uses: actions/cache@v2 with: path: ~/.local/share/virtualenvs key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} restore-keys: | ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} - name: Install dependencies if: steps.pipenv-cache.outputs.cache-hit != 'true' run: | pipenv sync --dev
キャッシュが効いている場合はaction/cacheの実行ログに以下のような出力がなされています。
Cache restored from key: Linux-pipenv-8772fa24c3defb28f6eee443046fa57808f73961c10022ed9c7af06182663622
キャッシュ復元後のテスト実行
以下のようなログを見かけた場合はPipfileに追記が必要です。PATHに入れる手もありますが、ローカルとActionsの双方で同じコマンド実行ができる点でもPipfileがおすすめです。
Error: the command pytest could not be found within PATH or Pipfile's [scripts].
警告の通り、Pipfileのscriptsセクションにpytestを指定しましょう。セクションがない場合はセクション自体を追加してください。
[scripts] test = "pytest --flake8 --cache-clear"
flake8によるチェックとキャッシュクリアも兼ねています。Workflow上には以下のように記載します。
- name: Test run: pipenv run test
実際のworkflow例
Workflowでpipenvをactions/cache併用時にはまった部分を挙げてきました。通しての設計は以下のようになります。
name: test on: workflow_dispatch: jobs: build: runs-on: ubuntu-18.04 timeout-minutes: 30 steps: - uses: actions/checkout@v2 - name: Set up Python 3.7 uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install pipenv run: | python -m pip install --upgrade pip python -m pip install pipenv - id: install-aws-cli uses: unfor19/install-aws-cli-action@v1 with: version: 2 - name: Cache uses: actions/cache@v2 id: pipenv-cache with: path: ~/.local/share/virtualenvs key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} restore-keys: | ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} - name: Install dependencies if: steps.pipenv-cache.outputs.cache-hit != 'true' run: pipenv sync --dev - name: Test run: pipenv run test
TestのステップはPipfileのscriptsセクション設定が前提なところだけ注意します。また、必要に応じて
あとがき
全くの想定外動作になっていることに気が付き、修正しては動作させることを繰り返していました。個々の修正点については検索してみると対処例が多く出てきますが、複合した例となると中々見当たらないものです。
Workflowの動作は前提として、各種Actionがどのように動いているのかも把握する必要があり、手間はかかりますが実現できれば楽になることも確かです。イマイチ上手くいかずに放置した方等の参考になれば幸いです。