Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eproxus/d74315864fd6897bb47741e8de5bc980 to your computer and use it in GitHub Desktop.
Save eproxus/d74315864fd6897bb47741e8de5bc980 to your computer and use it in GitHub Desktop.
How to Setup Erlang GitHub Actions With setup-beam and Caching

Erlang GitHub Actions With setup-beam and Caching

To build and test Erlang projects on GitHub actions with Rebar it is fastest to use the setup-beam action and use caching.

To get started, create a workflow file in .github/workflows in your repository. For this example we use a file called .github/workflows/continuous_integration.yml.

Basics

The basic pre-amble is a name for the actions and the events that should trigger the job:

name: Continous Integration

on:
  - push
  - pull_request
  - workflow_dispatch

The event workflow_dispatch enables a button on the workflow page that lets you manually trigger the workflow.

Build Matrix

Next, we add a job called ci that will run our tasks:

jobs:
  ci:
    runs-on: ubuntu-latest
    name: Erlang ${{matrix.otp}} / rebar ${{matrix.rebar3}}
    strategy:
      matrix:
        otp: ['24', '25', '26']
        rebar3: ['3']
    ...

Here we specify the OS, the name and a build matrix strategy to use. In this example, we want to build on the versions of OTP 24, 25 and 26 together with the latest version of Rebar 3.

⚠️ Warning
To avoid surprises, it is usually a good idea to specify full version numbers (e.g '24.0.2'). This is so that your jobs do not break on newer, possibly incompatible versions. It is also better if you rely on deployed artifacts produced by the jobs.

The following steps checks out the project and installs Erlang and Rebar:

      - uses: actions/checkout@v2

      - uses: erlef/setup-beam@v1
        with:
          otp-version: ${{matrix.otp}}
          rebar3-version: ${{matrix.rebar3}}

We have selected the current matrix version of OTP and Rebar as input to the setup-beam task.

Cache

To make the builds faster we use the cache action to save these folders:

  • The global Rebar cache folder (~/.cache/rebar3)
  • The project _build folder

The global Rebar cache folder is saved because that is where cached Hex packages, plugins and Dialyzer PLT files live. We cache the _build folder to avoid recompiling dependencies on every build.

      - name: Cache Rebar 3
        uses: actions/cache@v2
        env:
          cache-name: rebar3
        with:
          path: |
            ~/.cache/rebar3
            _build
          key: ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}-rebar_${{matrix.rebar3}}-${{hashFiles('rebar.lock')}}
          restore-keys: |
            ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}-rebar_${{matrix.rebar3}}
            ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}

We use a complex cache key that is a combination of the following things:

  • OS name
  • OTP version
  • Rebar version
  • A hash of the currently locked dependencies

If any of these change, the cache will not be used. Items are evicted from the cache after 7 days or when the cache is larger than 5 Gb.

In a project where these steps with caching was used, the build time went from 2 minutes to about 15 seconds!

Steps

Now we are ready to add some normal build steps:

      - name: Clean & Compile
        run: rebar3 do clean, compile

      - name: Analyze
        run: rebar3 do xref, dialyzer

      - name: Test
        run: rebar3 do eunit, ct

The reason we both clean and compile, is because the _build folder is cached, including the compiled project files from the last run. The clean task will delete the compiled project files, but not the compiled dependencies. This speeds up job times by avoiding to compile dependencies every time.

For the full example, see continuous_integration.yaml.

name: Continuous Integration
on:
- push
- pull_request
- workflow_dispatch
jobs:
ci:
runs-on: ubuntu-latest
name: Erlang ${{matrix.otp}} / rebar ${{matrix.rebar3}}
strategy:
matrix:
otp: ['24', '25', '26']
rebar3: ['3']
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
rebar3-version: ${{matrix.rebar3}}
- uses: actions/cache@v2
env:
cache-name: rebar3
with:
path: |
~/.cache/rebar3
_build
key: ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}-rebar_${{matrix.rebar3}}-${{hashFiles('rebar.lock')}}
restore-keys: |
ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}-rebar_${{matrix.rebar3}}
ci-${{runner.os}}-${{env.cache-name}}-otp_${{matrix.otp}}
- name: Compile
run: rebar3 do clean, compile
- name: Analyze
run: rebar3 do xref, dialyzer
- name: Test
run: rebar3 do eunit, ct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment