in elixir phoenix heroku circleci ~ read. profile image for Erik Reedstrom by Erik Reedstrom
Phoenix, CircleCI, and Heroku walk into a bar…

Phoenix, CircleCI, and Heroku walk into a bar…

There are a couple Elixir/Phoenix and CircleCI configs floating around, and although they provide the necessary foundation to get going, improvements can always be made. The following posts provided the base for this config redux:

Heroku and the Buildpack

For applications running on Heroku using the elixir buildpack, having versions established in both the config file and .tool-versions is a potential maintenance issue. There should be a single source of truth ensuring that what we’re testing is what we end up running. Given we declare our versions in the buildpack config, we can use them to drive asdf later.

elixir_buildpack.config

erlang_version=18.2.1  
elixir_version=1.2.0  

Convert to Bash Script

Circle executes each statement in the yml list, but when we begin to drive complex behaviors, it’s likely best to consolidate into an actionable script.

circle_pre_build.sh

#!/bin/bash
# Ensure exit codes other than 0 fail the build
set -e  
# Check for asdf
if ! asdf | grep version; then  
 git clone https://github.com/HashNuke/asdf.git ~/.asdf;
fi  
# Add plugins for asdf
asdf plugin-add erlang https://github.com/HashNuke/asdf-erlang.git  
asdf plugin-add elixir https://github.com/HashNuke/asdf-elixir.git  

Since the buildpack config is a valid bash script, we can simply run it to
extract the vars we need for asdf versions — no need for awking. Additionally, we’ll generate the .tool-versions file from these values.

# Extract vars from elixir_buildpack.config
. elixir_buildpack.config
# Write .tool-versions
echo “erlang $erlang_version” >> .tool-versions  
echo “elixir $elixir_version” >> .tool-versions  
# Install erlang/elixir
asdf install erlang $erlang_version  
asdf install elixir $elixir_version  
# Get dependencies
yes | mix deps.get  
mix local.rebar  
# Exit successfully
exit 0  

Speed up with Caching

We can get some decent improvements in build time by caching our dependency and build directories between builds. Additionally, we execute the compilation steps as part of the pre to ensure they are run prior to cache collection — it also cleans up the test execution log allowing us to focus on what’s important: failed tests.

circle.yml

machine:  
  environment:
    PATH: "$HOME/.asdf/bin:$HOME/.asdf/shims:$PATH"

dependencies:  
  cache_directories:
    — ~/.asdf
    — deps
    — _build
  pre:
    — ./circle_pre_build.sh
    — mix deps.compile
    — mix compile

test:  
  override:
    — mix test

Wrapping up

The bash script is far from robust, and there are very certainly additional improvements that could be made. However, hopefully this helps hone in on a more complete solution for continuous integration with Phoenix and CircleCI.