Deploying a Clojure application from Gitlab CI to Heroku

Now that we have our Clojure application tested every time we push it to Gitlab, let’s configure another stage to deploy it to Heroku.

This assumes that:

  • Anything you merge to master is ready to deploy,
  • You have your Heroku API key handy, and
  • You already have a Heroku app configured, with all the necessary environment variables.

There’s two ways we can do this.

Configuring your secret variables

You’ll need your Heroku API key to deploy from Gitlab.

When talking about Gitlab CI, I mentioned that it supported secret environment variables. We don’t want our API key to be on our .gitlab-ci.yml file, so before going any further, make sure you go to Settings > Variables and add it.

The configuration below assumes you’ll call it HEROKU_PRODUCTION_API_KEY.

The lein way

Heroku provides a leiningen plugin which allows for easy deployment. To use it, you’ll need to add the reference to your plugin vector and add a :heroku section to your project.clj:

1
2
:heroku {:app-name "the-app-name"
:include-files ["target/uberjar/practicum.jar"]}

You’ll then need to add a new production section to your CI configuration. You’ll find mine below, where I:

  • Configure it to allow snapshots in release (since otherwise lein uberjar refuses to build if there’s a reference to a snapshot anywhere),
  • Build the uberjar, and
  • Use the lein-heroku plugin to deploy it.
1
2
3
4
5
6
7
8
9
10
11
production:
type: deploy
script:
- export LEIN_SNAPSHOTS_IN_RELEASE=true
- lein uberjar
- HEROKU_API_KEY=$HEROKU_PRODUCTION_API_KEY lein heroku deploy
artifacts:
paths:
- target/uberjar/practicum.jar
only:
- master

You’ll see there’s an artifacts section. This tells Gitlab CI to save a copy of the generated uberjar artifact, in case I need to review it. You can find these on the Pipelines for your project.

Gitlab artifacts

The only drawback to using lein-heroku is that it’s one year old and has some outdated dependencies. It’s possible some of these will clash with your project’s, or that by the time you read this, it’ll be entirely unsupported.

If so, you can try the second option below.

The gem path

If the plugin above breaks for you, there’s an alternate path. You can use dpl, which is written in Ruby and supports not only Heroku but also other providers.

Since we’re working off a Docker image for Clojure, we don’t have Ruby or Gem installed. We’ll need to install them.

1
2
3
4
5
6
7
8
production:
type: deploy
script:
- apt-get install ruby -y
- gem install dpl
- dpl --provider=heroku --app=the-app-name --api-key=$HEROKU_PRODUCTION_API_KEY
only:
- master

In this case, we don’t build a uberjar, and just use dpl to send our repository directly to Heroku for building.

That’s it!

Author

...
Ricardo J. Méndez