Blazing fast CI suite for Elixir on Circle CI 2.0
I’ve been frustrated for so many times on waiting. Whether it is waiting for a test to run, the last season of Game of Thrones to arrive or simply to go to sleep while lying in bed.
While it is quite hard to make Game of Thrones arrive sooner there are things that we actually can make more effective. This is how I got my CI suite to run a lot faster with the help of Circle CI 2.0 and their new workflows.
Reusable defaults
Since the best way to achieve a lot of different stuff in the shortest manner possible is to run jobs in parallel when possible that’s what we’re gonna do. So to make sure we’re gonna have an easy time changing versions and so on we’ll create some default settings that will be used in every job
version: 2
defaults: &defaults
working_directory: ~/metatags
docker:
- image: elixir:1.6.5
environment:
MIX_ENV: test
jobs:
Prerequisites
As circle will run all jobs inside a container we need to do things like checking out the code, fetch dependencies and compilation. We’re going to use some caching so that we do not have to do time consuming tasks when we don’t need to. At the end we’re going to persist the workspace which is basically a cache that can be used between multiple jobs in a workflow
jobs:
build:
<<: *defaults
steps:
- checkout
- restore_cache:
keys:
- v2-deps-cache-{{ checksum "mix.lock" }}
- v2-deps-cache
- run: mix local.hex --force
- run: mix local.rebar --force
- run: mix deps.get
- run: mix deps.compile
- run: mix compile
- save_cache:
key: v2-deps-cache-{{ checksum "mix.lock" }}
paths:
- _build
- deps
- ~/.mix
- persist_to_workspace:
root: ~/
paths:
- metatags
- .mix
Running the tests
To run the test all we have to do is to add the test job (which we’ll attach to the workspace) and setup the workflow to know that the test job requires build to be run first.
jobs:
# ...
test:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- run:
name: Run tests
command: mix test
workflows:
version: 2
continuous_integration:
jobs:
- build
- test:
requires:
- build
Adding other tools to pipeline
In order to add more tools to the pipeline we’ll just have to add the job, make sure it uses the persisted workspace and it to the workflow with proper requirements.
Below you can see my full configuration that is currently being used for my metatags library.
version: 2
defaults: &defaults
working_directory: ~/metatags
docker:
- image: elixir:1.6.5
environment:
MIX_ENV: test
jobs:
build:
<<: *defaults
steps:
- checkout
- restore_cache:
keys:
- v2-deps-cache-{{ checksum "mix.lock" }}
- v2-deps-cache
- run: mix local.hex --force
- run: mix local.rebar --force
- run: mix deps.get
- run: mix deps.compile
- run: mix compile
- save_cache:
key: v2-deps-cache-{{ checksum "mix.lock" }}
paths:
- _build
- deps
- ~/.mix
- persist_to_workspace:
root: ~/
paths:
- metatags
- .mix
test:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- run:
name: Run tests
command: mix test
credo:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- run:
name: Run credo
command: mix credo
check_formatted:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- run:
name: Verify formatted
command: mix format --check-formatted
dialyzer:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- restore_cache:
keys:
- v1-plt-cache-{{ checksum "mix.lock" }}
- v1-plt-cache
- run: mix dialyzer --plt
- save_cache:
key: v1-plt-cache-{{ checksum "mix.lock" }}
paths:
- _build
- ~/.mix
- run:
name: Run dialyzer
command: mix dialyzer
coverage:
<<: *defaults
steps:
- attach_workspace:
at: ~/
- run:
name: Analyze coverage
command: mix coveralls.circle
workflows:
version: 2
continuous_integration:
jobs:
- build
- test:
requires:
- build
- test:
requires:
- build
- credo:
requires:
- build
- dialyzer:
requires:
- build
- coverage:
requires:
- build
Since metatags is only a library there is no use in adding deployment steps to the process. However there’s different opinions on how you should deploy your elixir application around the community so I’ll leave those steps out for now.