Github actions for Elixir & Phoenix app with cache

Pierre-Louis Gottfrois
3 min readDec 22, 2020

--

Photo by Glenn Carstens-Peters on Unsplash

You can already find some samples on how to configure Github actions for an Elixir/Phoenix project but I couldn’t find one which shows the full picture with cached dependencies to avoid losing time re-compiling your whole project deps on every push.

I’ll show you how to configure Github action to run the following tasks:

  • Install & compile your project’s dependencies
  • Run static code analysis such as mix formatand credo and dialyzer
  • Run your unit tests
  • BONUS! Deploy to Gigalixir

Let’s dive in!

TL; DR: Skip toward the end to get the complete Github action manifest file ;)

Let’s start with a brand new Elixir app to play around with:

mix new my_app
cd my_app

Open the app with your favorite editor and let’s start to add our Github action steps one by one under .github/workflows/elixir.yml. Our first goal is to install our project dependencies and compile them. We’ll talk about caching later.

Install and compile your project’s dependencies

Next, let’s run a simple static code analysis tool like mix format by adding the following step next to the deps one:

Running static code analysis tool such as mix format

Notice that this step depends on the one above. We first need to install our project dependencies to be able to run mix format .

Finally, let’s add a step to run our unit tests:

Running unit tests and display 10 slowest

If you run this pipeline multiple times, you’ll notice that we are always re-installing and re-compiling our project’s dependencies. It’s time to add caching my friend.

Github action cache works by specifying a list of directories (v2) of files to cache using a given cache key. We’ll compute a hash based on the mix.lock file to automatically invalidate the cache when our project’s dependencies change.

Since we’ve spread our pipeline into multiple jobs, you’ll need to fetch the cached directories at the beginning of each job.

Finally, if a cached version of our dependencies already exists, we’ll simply skip the job completely. Time is money!

Add the following cache steps after each setup steps of our existing jobs:

Caching our project dependencies and more

Notice that we are also using the runner.os matrix.otp and matrix.elixir built-in variables to generate a cache key which is unique across the OS, Erlang, and Elixir versions we use.

Don’t mind the priv/plts folder for now.

Try to run our new pipeline a few times and you’ll notice that the deps step is skipped completely when there are no dependency changes.

It’s time to run even more static code analyzers such as credo and dialyzer. Let’s add the following dev and test dependencies to our project in mix.exs :

Adding static code analyzer tools

Don’t forget to run mix deps.get . Let’s now add the commands to our CI pipeline under the static_code_analysis step:

Adding mix commands to run static code analyzers

There is one final step for dialyzer before we can run this new pipeline. We need to generate the PLT files, which can take a while and also needs to be invalidated when we update our project’s dependencies. PLT files are generated using the mix dialyzer —-plt command and located under priv/plts folder. This is why I made you add this folder to our cached directory list as well earlier.

Now, simply add the following commands to our “Install Dependencies” task in our deps step:

Give our new pipeline a try!

Maybe you have noticed that old pipelines don’t stop automatically when you have a new one scheduled for your branch. You can use the following bonus step to cancel previous pipelines. You’ll have to add that step at the beginning of each job:

Cancel previous pipelines

Finally, it’s time for the bonus step to deploy your app on Gigalixir! Simply add the following job at the end of the file:

Bonus job to deploy to Gigalixir

Don’t forget to set up your Github action secrets and feel free to tune the env variables the way you want.

You can find here the complete CI pipeline using Github action for Elixir and Phoenix projects using Github action cache. I hope you’ve enjoyed reading this article as much as I deed writing it. Happy coding!

--

--

Pierre-Louis Gottfrois

Enthusiasts software engineer who loves to write about Ruby on Rails, Elixir and DevOps related subjects.