How to Setup Elixir for CircleCI Success

Zachary Porter, Former Senior Developer

Article Category: #Code

Posted on

CircleCI doesn't provide official support for Elixir applications. This tutorial provides the steps to fix that.

At Viget, we enjoy using CircleCI for our automated test suites and deployment. It's easy to use and customize for our various application needs. I recently went through the process of setting up an Elixir application on CircleCI, which, as of this writing, still does not have official support. This post by Erik Reedstrom over at Parent Co. gave me a good start, but there were some tweaks that I had to make in order for the build process to consistently run smoothly.

Managing Versions #

First up, I liked Erik's approach to managing Elixir and Erlang versions in the Heroku buildpack's config, then simply copying them to the .tool_versions file for the asdf version manager. To get started with this approach, add an elixir_buildpack.config file to your project with the following contents:

erlang_version=19.0
elixir_version=1.3.0

If you're not using Heroku for hosting, then simply add a .tool-versions file with the following contents:

erlang 19.0
elixir 1.3.0

Please note that the rest of this post will assume an elixir_buildpack.config file is present in the project. Feel free to customize based on your project's setup.

CircleCI Config #

Next up, add a circle.yml file to the project with the following contents:

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

dependencies:
  cache_directories:
    - ~/.asdf
    - deps
    - _build
  pre:
    - cp config/dev.secret.exs{.sample,}
    - cp config/test.secret.exs{.sample,}
    - ./circle_pre_build.sh
    - mix deps.compile
    - mix compile
test:
  override:
    - mix test

Let's walk through this file because there's a lot going on.

  1. Since we'll be using asdf to manage our Erlang and Elixir versions, we set the PATH variable within the environment to load the relevant binary and shims directories (line 3).
  2. We specify a few directories to cache in order to speed up future builds (lines 7-9).
  3. Commands are executed before the build (lines 10-15). The first commands copy some sample secret config files (lines 11 and 12). Our secret config files usually contain environment-specific database configuration, but they could easily contain other bits of configuration that you don't want stored in the Git repository. A pre-build executable file is invoked (line 13), which we'll get into in the next section. We wrap up the pre-build process with compiling dependencies (line 14) and the project (line 15).
  4. To round out this config file, the test method is overridden with mix test (line 18). This could also be mix test --cover if you're evaluating code coverage, which we recommend.

That covers the CircleCI config. Now, let's take a look at the pre-build executable that was mentioned above.

Pre-build commands #

Managing the pre-build commands in a separate executable file keeps our CircleCI config clean and allows us to use some more robust bash functionality. Here are the contents of our circle_pre_build.sh file complete with comments:

#!/bin/bash

# Ensure exit codes other than 0 fail the build
set -e

# Check for asdf
if ! asdf | grep version; then
  # Install asdf into ~/.asdf if not previously installed
  git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.1.0
fi

# Add plugins (Erlang and Elixir) for asdf

# Check to see if asdf's Erlang plugin is installed
if ! asdf plugin-list | grep erlang; then
  # Install the Erlang plugin
  asdf plugin-add erlang https://github.com/asdf-vm/asdf-erlang.git
else
  # Update the Erlang plugin
  asdf plugin-update erlang
fi

# Check to see if asdf's Elixir plugin is installed
if ! asdf plugin-list | grep elixir; then
  # Install the Elixir plugin
  asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
else
  # Update the Elixir plugin
  asdf plugin-update elixir
fi

# Extract versions from elixir_buildpack.config into variables
. elixir_buildpack.config

# Write .tool-versions for asdf
echo "erlang $erlang_version" >> .tool-versions
echo "elixir $elixir_version" >> .tool-versions

# Install erlang/elixir
echo "Installing Erlang..."
asdf install erlang $erlang_version

echo "Installing Elixir..."
asdf install elixir $elixir_version

# Get dependencies
yes | mix deps.get
yes | mix local.rebar

# Exit successfully
exit 0

To summarize:

  1. Install asdf
  2. Install or update the Erlang and Elixir plugins
  3. Install Erlang and Elixir
  4. Fetch our project's dependencies
  5. Install rebar, which is Erlang's build tool for compiling and testing your applications
  6. Exit 0 for success

Ensure the file is executable by running chmod +x circle_pre_build.sh before committing.

And There You Have It #

Congratulations! You now have all the pieces in place for a good CircleCI time. This is by no means a robust solution, but it should provide a fantastic start to building your Elixir applications on CircleCI.

Related Articles