TIL

Today I learned something interesting,
and now it's saved here forever.

  • Learned on

    Elixir cache busting in GitHub actions

    Most blogs will show a simple Elixir GitHub action workflow with these cache busting settings:

    steps:
      - name: Checkout
        uses: actions/[email protected]
    
      - name: Install (Elixir)
        uses: erlef/[email protected]
        with:
          otp-version: 24
          elixir-version: 1.12
    
      - name: Cache
        uses: actions/[email protected]
        id: cache
        with:
          key: elixir-1.12-${{ hashFiles('mix.lock') }}
          restore-keys: |
            elixir-1.12-
          path: |
            _build
            deps
            priv/plts
    
      - name: Install (Mix)
        if: steps.cache.outputs.cache-hit != 'true'
        run: mix deps.get
    
      - name: Dialyzer
        run: mix dialyzer
    

    However, the Elixir version might change from 1.12.1 to 1.12.2 out from under you. This can cause Dialyzer errors like so:

    :dialyzer.run error: Old PLT file /home/runner/work/test-app/priv/plts/dialyzer.plt
    

    To solve it, use the output of the setup action for the cache keys like so:

    steps:
      - name: Checkout
        uses: actions/[email protected]
    
      - name: Install (Elixir)
        id: beam
        uses: erlef/[email protected]
        with:
          otp-version: 24
          elixir-version: 1.12
    
      - name: Cache
        uses: actions/[email protected]
        id: cache
        with:
          key: elixir-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-${{ hashFiles('mix.lock') }}
          restore-keys: |
            elixir-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-
          path: |
            _build
            deps
            priv/plts
    
      - name: Install (Mix)
        if: steps.cache.outputs.cache-hit != 'true'
        run: mix deps.get
    
      - name: Dialyzer
        run: mix dialyzer
    

    While this is more verbose, it ensures that the cache doesn't cause issues with Dialyzer and Elixir versions changing out from under you.