Have you ever tried to use the lein-release plugin to release an artifact into Clojars? It works by automatically updating version information in your
project.clj and adding commits to your source control system. Those commits can then be used with your build system to drive new builds and push a final artifact into Clojars.
I always found this approach unpalatable.
- It’s complicated – there are nine actions that the plugin takes by default. Nine!
- Version details are updated twice – the
-SNAPSHOTsuffix is removed, committed, then updated again to update the version and add
-SNAPSHOTback on before committing again – but that needs me to say what kind of update the next release is going to be!
- I don’t like having to run automation on my local machine (or give my build system write credentials to my source control system!).
There are other irritations with this approach but rather than rant, I’ll share what I think is a better way. This is the approach I’ve been using with Crucible for a few months now and it’s been working well.
A Simpler Way
If you set the version to be looked up from an environment variable, you don’t need the actual source code to have the version details you intend to deploy hard-coded into a git commit. That’s really easy to do with Leiningen because the
project.clj gets evaluated when you run Leiningen. Here’s an example from the Crucible project.
(defproject crucible (or (System/getenv "PROJECT_VERSION") "0.0.0-SNAPSHOT") :description "AWS Cloudformation templates in Clojure" ...)
I’m setting a default version of
0.0.0-SNAPSHOT here, so when I’m working locally I get something I’ll recognise. The version resolves to the value of the
PROJECT_VERSION environment variable when it’s set.
As Crucible builds on Travis I can trigger a build when I apply a git tag, and I can see the label of the tag in the build environment, as
TRAVIS_TAG. I have a small script that inspects the value of the
TRAVIS_TAG environment variable and sets
PROJECT_VERSION appropriately before running
This release process is as simple as tagging an existing commit with the label you want to release as, which you can do after you see a green build. No extra commits. No extra builds where there have been changes in source control. No write access for your build system. Nothing to merge with your next changes. Just a tag. The final release is done by your build system, in Crucible’s case Travis, using Leiningen’s standard Clojars deployment capabilities.
Once you’ve made your project.clj version dynamic, added your deploy script and told your build system when and how to deploy your code, you only have two actions (that aren’t waiting) to do each actual release:
- commit/merge to your production branch
- wait for green light on build
- tag the commit with your release version
- wait for build to deploy your new version to Clojars
Taking this process and Github releases, it’s so simple I can perform a release on my phone while I’m standing on the train. That can genuinely be useful if I get a great PR in!
3 thoughts on “Easier Clojure Releases without Commits”
That’s a neat simple strategy for getting dynamic versions. Also checkout `lein-v` which is way of deriving versions from git tags & bumping versions without writing to project.clj!
Forgot the link: https://github.com/roomkey/lein-v
Thanks @rymndhng, I will check out `lein-v`, it might just be the Leiningen plugin that I need to perform this process without code in my `project.clj` or a special deploy script!