Run Your CI Steps Locally

Adjacent traffic lights with one red and one green
Nathan Long

Engineer

Nathan Long

CI just failed your pull request again. You ran the tests locally, and they passed. What's the problem?

After clicking through the logs, you see it: you forgot to format the code. Code formatting is one of the checks specified in your CI's .yml configuration file, and it's one you often forget. There's also that static security check and the opinionated style linter.

Sighing, you go through the list, running each command locally and fixing the issues. Wouldn't it be nice if you could run your CI locally and see the failures before making a PR?

Write a script

While it doesn't fully replicate the CI environment, a simple solution to this is to write a shell script which runs all the automated checks a PR could need.

First, start by creating a script called ./run_ci.

$ touch run_ci $ chmod a+x run_ci

Next, find all the commands your CI is configured to run and update ./run_ci to run them.

Finally, remove those steps from the CI configuration and have it ./run_ci instead.

Now, before you make a PR, you can ./run_ci locally to ensure you checked everything that CI will check.

What /.run_ci looks like

Here's a generic template that your script could follow, which applies to any programming language:

#!/bin/bash

Script to be run in CI and also locally, to simulate what CI will do, as a

pre-PR final check

Ensure that any failing command will exit this script

set -e

export CODE_ENV=test

Run this first to fail fast, before bothering to install dependencies

./check_code_formatting

If actually running in CI (most CI servers set this ENV var)

if [ "$CI" == "true" ] then ./install_dependencies ./setup_database else echo "Skipping CI setup; not needed in local dev environments" fi

Other checks, from fastest to slowest

./run_linter ./run_tests ./run_static_security_analysis

On an Elixir Phoenix project, the specifics might be something like this:

#!/bin/bash

Script to be run in CI and also locally, to simulate what CI will do, as a

pre-PR final check

Ensure that any failing command will exit this script

set -e

export MIX_ENV=test

Run this first to fail fast

echo "Checking formatting" mix format --check-formatted

If actually running in CI

if [ "$CI" == "true" ] then mix local.hex --force mix local.rebar --force mix deps.get mix ecto.create mix ecto.migrate else echo "Skipping CI setup" fi

Other checks, from fastest to slowest

echo "Linting" mix lint echo "Security check" mix sobelow echo "Checking for warnings" mix compile --force --warnings-as-errors echo "Running tests and checking coverage" mix test --cover

Voila! Add this to your workflow and you'll have a lot fewer surprises when opening PRs.

DockYard is a digital product agency offering custom software, mobile, and web application development consulting. We provide exceptional professional services in strategy, user experience, design, and full stack engineering using Ember.js, React.js, Ruby, and Elixir. With a nationwide staff, we've got consultants in key markets across the United States, including San Francisco, Los Angeles, Denver, Chicago, Austin, New York, and Boston.

Newsletter

Stay in the Know

Get the latest news and insights on Elixir, Phoenix, machine learning, product strategy, and more—delivered straight to your inbox.

Narwin holding a press release sheet while opening the DockYard brand kit box