The Smart Reactor Maven Extension is a simple addition to any Maven build/installation that solves many challenges with two behavioral changes - only build SNAPSHOTs and perform release transformation before the build begins. This page walks through how this extension came to be, and describes how it solves common difficulties using Maven.
While working on a fork of dhutils, I noticed that the root POM, as well as the “API” and “Fallback” modules, had dummy <version> values. It appears that the original author’s motivation was to avoid having to re-version these infrequently-changing and non-public-facing modules.
I believe that every Maven module should have a version that concisely communicates how the code’s API has evolved as a result of the changes introduced into the code. I think this holds true even if a module exists solely to facilitate the development of other modules in the same codebase, which is clearly the case with the dhutils codebase.
The problem is that Maven’s history of selective module builds has been sketchy at best. The Maven Reactor Plugin has been retired for quite some time, and Maven’s advanced reactor options require one to specify which projects should be built. The latter fact prevents Maven from making any sort of selective module building behavior as its default behavior. When one considers that Maven’s concept of SNAPSHOTs concisely identifies “code under development”, the simplest default behavior would be to select every SNAPSHOT project in the reactor.
While some people might try to engineer a CLI-based solution to this problem, most people will follow the path of least resistance and just re-release unchanged modules…but this violates common sense - if you didn’t make any changes, why bump the version number? Bumping the version number with no changes actually violates SemVer as well.
Maven’s repository design also betrays the approach of rebuilding an entire multi-module project. Once a Maven project gets installed/deployed to a local/remote repository, it is accessible as a <dependency> for anyone, even if it’s intended only as a <dependency> for another module in the same reactor. Because previously-released modules can be found in a remote repository, it makes perfect sense for those modules to be reused by the same project from which they originated - the alternative is to rebuild code that has not changed, which wastes time and opens the door for human error.
When using Jenkins CI, SCM credentials are managed by the Jenkins Credentials Plugin. When performing a Maven release using the Maven Release Plugin, however, the command-line SCM client also needs credentials for authentication. There are several ways to do this:
These solutions are either not DRY, not secure or unacceptably brittle. These challenges exist regardless of which CI engine is used, because the demands of the Maven Release Plugin do not change.
The real issue is that it doesn’t make sense for a build tool to be performing SCM activity when CI engines are already performing SCM activity. If any commits need to be pushed back to SCM, the CI engine should be responsible for that. Adopting this approach simplifies the management of SCM credentials, as well as the architecture of the software development pipeline.
Because it is impractical for a plugin to modify the reactor - the build has already started by the time any plugin is being invoked - the only option that the Maven Release Plugin has is to trigger another build after it has transformed the POM files. This has two negative effects:
Another strange design choice in the Maven Release Plugin is the tagging of code in SCM prior to the release build occurring. This is undesirable for two reasons:
Maven doesn’t have any default behavior for building only what has changed in a multi-module project. This makes code management of such projects difficult. The two primary solutions are:
Additionally, the design of the Maven Release Plugin is highly presumptuous - it implies that Maven is the “center of the universe” in the software development pipeline. The reality is that Maven is far too deep in the build process to be orchestrating the entire process. It also precludes the possibility of augmenting the behavior of a release build outside the context of Maven, which may be impractical or impossible depending on what types of testing have to be performed during a release build.
The Smart Reactor Maven Extension solves all of these issues in two ways:
These two simple changes have multiple benefits: