先日、GitHub Actionにcacheが追加されました!

リポジトリはこちら

https://github.com/actions/cache

このリポジトリでは色々な言語での使用例も公開されていて、ちゃんとElixirの例も公開されてます!ありがたい!

https://github.com/actions/cache/blob/master/examples.md

このcacheを利用すると、depsのinstallをテストのたびにやらなくて済むようになります!素晴らしい!

どんな感じで書くか、設定ファイルを紹介しておきます。

workflow.yml

早速結論ですが、ymlファイルを次のように記述します。

name: Elixir CI

on: push

jobs:
  build:

    runs-on: ubuntu-latest

    container:
      image: elixir:1.9.1-slim

    steps:
    - uses: actions/checkout@v1
    - name: Cache deps
      uses: actions/cache@v1
      id: cache-deps        ・・・(1) idを指定
      with:
        path: deps
        key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} ・・・(2) lockファイルを参照してcaching
        restore-keys: |
          ${{ runner.os }}-mix-
    - name: Install hex
      run: |
        mix local.rebar --force
        mix local.hex --force
    - name: Install Dependencies
      if: steps.cache-deps.outputs.cache-hit != 'true' ・・・(3) cacheがあればdeps.getしない
      run: |
        mix deps.get
    - name: Run Tests
      run: mix test

(1)でstepに対してidを指定します。このidは後続のcacheに存在するか判定するsteps.<id>.outputs.cache-hitの記述で利用します。

(2)でmix.lockファイルの変更をみてcachingしています。depsが変わる=lockファイルが変わるということなので、これで良さそうです。また、restore-keysを記述しておくと、restore-keysに指定した値を過去のcacheから部分一致で探し、一致すれば採用するという挙動のようです。

すでにcacheが

- Linux-mix-xxxxxx

のように存在する状況で、lockファイルを変更して ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} の値が Linux-mix-yyyyyy となった場合、

  1. Linux-mix-xxxxxx完全一致しないのでskip
  2. restore-keysに ${{ runner.os }}-mix- が指定されているので、Linux-mix-部分一致するcacheを検索 → Linux-mix-xxxxxxにHitするのでLinux-mix-xxxxxxのkeyで保存されたcacheを採用し、depsを復元する

といった流れですね(多分。。)

詳細は公式ドキュメントのcacheアクションの利用 を参照してください。

(3)で、cacheが存在しないときだけdeps.getをするようにifを記述します。言い換えると、cacheが見つかればInstall Dependenciesのstepをスキップします。

これで、lockファイルが変更されたときだけdeps.getが走るようになります。

試してみる

mix.newしただけのリポジトリに対して、actionを動かした結果です。

変更内容commitaction
1lockファイルがない状態でpushcommitaction
2lockファイルをpushcommitaction
3lockファイルを変更せずにpushcommitaction

1はただworkflowのymlをpushしただけで、まだlockファイルがない状態です。この場合、「cacheできないよ!」とエラーが発生します。

no_mix_lock

2でlockファイルを追加してあげると、初回のactionなのでcacheが存在せず、deps.getが走りました。

deps_get

3でlockファイルは変更しないコード修正を加えると、cacheが存在し、Install Dependenciesがskipされました。

skip_deps_get

まとめ

cacheが搭載されたことで効率よくCIを回せるようになりました。ぜひお試しください!