16 January 2010

Maven Reactor Plugin Examples

Turns out you can be a lot more selective about which modules are built when you run a Maven ractor build.

From Maven Reactor Plugin - Examples
Consider an ordinary multi-module reactor build:

|-- pom.xml
|-- fooUI
| `-- pom.xml
|-- barBusinessLogic
| `-- pom.xml
`-- bazDataAccess
`-- pom.xml

Suppose project "fooUI" depends on project "barBusinessLogic", which depends on project "bazDataAccess".
fooUI --> barBusinessLogic --> bazDataAccess

mvn reactor:resume -Dfrom=barBusinessLogic

Suppose you're working on your code and you attempt to build your code
with mvn install from my-root-project, and suppose you get a test
failure in barBusinessLogic. You make additional changes to
barBusinessLogic without changing bazDataAccess; you know that
bazDataAccess is fine, so there's no need to rebuild/test it.  That will skip over bazDataAccess and pick up the build where you left off in barBusinessLogic. If barBusinessLogic succeeds, it will go on to build fooUI.

mvn reactor:make -Dmake.folders=barBusinessLogic

reactor:make will examine barBusinessLogic and walk down its dependency tree, finding all of the projects that it needs to build. In this case, it will automatically build bazDataAccess and then barBusinessLogic, without building fooUI.

mvn reactor:make-dependents -Dmake.folders=barBusinessLogic

reactor:make-dependents will examine all of the projects in your
reactor to find projects that depend on barBusinessLogic, and
automatically build those and nothing else. In this case, it will
automatically build barBusinessLogic and then fooUI.  Suppose you've made a change to barBusinessLogic; you want to make sure
you didn't break any of the projects that depend on you. (In this case,
you want to make sure that you didn't break fooUI, but in a more
complex reactor that might not be so obvious.) You also want to avoid
rebuilding/testing projects that you know you haven't changed. In this
case, you want to avoid building bazDataAccess.

mvn reactor:make-scm-changes

reactor:make-scm-changes determines which files have changed using your SCM (Source Configuration Management) tool, e.g. Subversion, Perforce, Git, etc. To use it, you'll need to configure an SCM connection in your root project POM file:

mvn reactor:make -Dmake.folders=barBusinesslogic -Dmake.printOnly

All of the reactor plugin goals take in an argument -Dmake.printOnly
that you can use to see what the goal would have done without actually
doing it. For example:

Running a different goal/lifecycle ("test", "package", "eclipse:eclipse", "clean", etc.)

By default, all of the reactor plugin goals will run mvn install on the appropriate projects. That's a pretty reasonable default, but sometimes you want to run a different command on a bunch of projects. All of the reactor plugin goals will accept a -Dmake.goals argument that will let you run other goals instead. You can separate multiple goals with commas:

mvn reactor:make -Dmake.folders=barBusinessLogic -Dmake.goals=eclipse:eclipse
mvn reactor:make-dependents -Dmake.folders=barBusinessLogic -Dmake.goals=package,clean
mvn reactor:resume -Dmake.folders=barBusinessLogic -Dmake.goals=test
mvn reactor:resume -Dmake.folders=barBusinessLogic -Dmake.goals=install,-DskipTests

In other words, the "goals" are just extra command-line parameters passed to the spawned Maven; they don't necessarily have to be "goals."

mvn reactor:make -Dmake.folders=fooUI -Dfrom=barBusinessLogic

When you use reactor:make, you run a subset of projects, but that doesn't mean stuff won't fail halfway through the build. You can resume a reactor:make build from the project that stopped the build by passing -Dfrom to the reactor:make goal.  The -Dfrom argument also works with reactor:make-dependents and reactor:make-scm-changes.

Nested directories

Let's consider a more complex project:

|-- pom.xml
|-- fooUI
| `-- pom.xml
|-- barBusinessLogic
| `-- pom.xml
|-- quz
| |-- pom.xml
| |-- quzAdditionalLogic
| | `-- pom.xml
| `-- quzUI
| `-- pom.xml
`-- bazDataAccess
`-- pom.xml

Again suppose project "fooUI" depends on project "barBusinessLogic", which depends on project "bazDataAccess".

fooUI --> barBusinessLogic --> bazDataAccess

But furthermore, suppose "quzUI" depends on "quzAdditionalLogic", which depends on "barBusinessLogic."

quzUI --> quzAdditionalLogic --> barBusinessLogic --> bazDataAccess

If you try to run mvn reactor:make -Dmake.folders=quzUI, you'll get an error:

mvn reactor:make -Dmake.folders=quzUI
[INFO] Folder doesn't exist: /home/person/svn/trunk/quzUI

Naturally, you'll have to specify the complete relative path to quzUI, like this:

mvn reactor:make -Dmake.folders=quz/quzUI