Running a Clojure Script in a Maven BuildClojure, Continuous Integration, and Maven
Detailed explanation of the various ways you can execute a Clojure script within a Maven build, including sample configuration that you can import into your project now.
I recently needed to include some custom functionality in a Maven build and decided to use Clojure to write a little script for it. The process of getting my script running in Maven took me on an interesting journey, so I figured it'd be something that would be more broadly useful - especially to other Clojure newbies like me! Here's a quick run-down of how you can get a Clojure script up & running in a matter of minutes.
There are two Clojure plugins for Maven that I'm aware of: clojure-maven-plugin and Zi . From what I could tell, Zi doesn't provide a goal for executing a Clojure script so that unfortunately went out the window. I say "unfortunately" because it looks like a pretty cool plugin! Fortunately, clojure-maven-plugin provides a run goal for this exact purpose.
One other plugin I decided to investigate is exec-maven-plugin . This obviously hasn't got anything specifically to do with Clojure which means it involves a little more manual effort (if you want to think of it that way), but it gives some really nice features that clojure-maven-plugin doesn't provide.
To show how this works, I've written a trivial script that simply prints out some text:
My first attempt was to use the clojure-maven-plugin, for no other reason than I figured it was built specifically to handle Clojure so would most likely be the best. While this may be true if you're building a Clojure project, it has some idiosyncrasies that make it less than ideal if you're not. Unfortunately this plugin doesn't seem to include plugin dependencies on the classpath when executing the run goal; it only includes compile-scoped dependencies for the project. This means you need to have any requirements of your script (i.e. clojure.jar and any other libraries you might need) declared as compile scope dependencies of your project. This isn't really an ideal solution - particularly if you're only using Clojure for a build script and not as your language of development. In my case, this proved to be a deal-breaker. My project was pure Java (unfortunately) and I wasn't prepared to package up Clojure with my project just for the sake of running a Clojure script at build time. I think it's a valid use case though, so have submitted a request to include this feature in the project. Aside from this issue, the plugin seems pretty good.
Here's an example of how you can configure it to run a script:
Note that we had to declare the dependency on Clojure as a project-level dependency. This is only really suitable if you intend on packaging Clojure with your project. Fortunately the exec-maven-plugin doesn't have this limitation.
The exec-maven-plugin has some really useful features that make it a better choice for this kind of thing - at least, I think it's better. Firstly, it allows you to include plugin dependencies on the classpath. This is absolutely essential if it's to be useful on any kind of Maven project. In my case, this meant that I didn't need to unnecessarily package Clojure in my pure Java project just to get a build script to run. Big win! There are some other nice benefits too. For example, if your script is creating some output that is to be used as source for the project (e.g. code or resource generation), this plugin allows you to specify where the source is being written out and automatically add that directory to the list of source locations for the project (check out the sourceRoot and testSourceRoot configuration properties).
Here's an example of how you can configure this plugin to run the same script as above:
So the only extra configuration required here is mainClass, which we specify as clojure.main. This is really no different to the examples you can find on the Clojure site.
Hopefully that's been helpful to someone. As I said before, I'm a bit of a newbie to Clojure so if there's a better way this can be done, please let me know.
I created an issue in GitHub for the plugin dependencies feature in clojure-maven-plugin and it has subsequently been added to the plugin. I have to say it was an incredibly fast turnaround, so major credit to Mark Derricutt (talios) for that. Since version 1.3.12, you can now specify theĀ
option for all goals (defaults to false) which means it's a lot easier to use for non-Clojure projects.