Apache Commons logo

Help with Maven Mojos

The best sources of information are Developing Java Plugins for Maven 3.x and Maven: The Definitive Guide: Chapter 11 Writing Plugins.

New Mojos

Each Mojo is a java file that extends AbstractMojo that contains an annotation specifying the goal name for the mojo and the maven lifecycle phase that it executes under by default. For, example

package org.apache.commons.release.plugin.mojos;

@Mojo(name = "detach-distributions", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true)
public class CommonsDistributionDetachmentMojo extends AbstractMojo {
  .....
}
specifies the goal commons-release:detach-distributions that is to occur during the VERIFY maven lifecycle.

The variables in the mojo that are declared as private with the annotations @Parameter get imported to the Mojo by the existent maven variables or the declared <configuration>. For example, we have a boolean variable named dryRun declared as:

@Parameter(property = "commons.release.dryRun", defaultValue = "false")
private Boolean dryRun;
that can be configured by
<plugin>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-release-plugin</artifactId>
  <version>1.8.0</version>
  <configuration>
    <dryRun>true</dryRun>
  </configuration>
</plugin>
And, because we've set the property here (as in the 1.1 release), you can, on the command line, use the following -Dcommons.release.dryRun=true.

Unit testing

We've declared mock maven poms in the resources directory of the src/test folder, under which we've stored in subdirectories corresponding to the names of the mojos that they are testing. All variables that you wish to be available to your mojo must be specifically declared in the mock pom file. For example, we need to use the already existent MavenProject in the maven runtime by instead, in a test package declaring a class extending MavenProjectStub that returns values we wish to be used in testing. We then add this to our pom in the following declaration of the plugin:

<plugin>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-release-plugin</artifactId>
  <configuration>
    <project implementation="org.apache.commons.release.plugin.stubs.DistributionDetachmentProjectStub" />
    <workingDirectory>target/commons-release-plugin</workingDirectory>
    <distSvnStagingUrl>mockDistSvnStagingUrl</distSvnStagingUrl>
  </configuration>
</plugin>
Also note here we are declaring other values that we are using in the testing of the plugin. We then retrieve our instantiated mojo by declaring a MojoRule in our test class,
@Rule
public MojoRule rule = new MojoRule() {
    @Override
    protected void before() throws Throwable {
    }

    @Override
    protected void after() {
    }
};
and then retrieve the mojo by newing up a File pointed to the path of the mock pom, and then making the following call:
mojo = (CommonsSiteCompressionMojo) rule.lookupMojo("compress-site", testPom);
where we are trying to get the mojo with the compress-site goal.

Debugging

Maven ships with a debugger under the hood. It is suggested that you have a sandbox project in which you can run the goals or the plugin configuration. Once you have that set up you can run something like

mvnDebug commons-release:detach-distributions
which exposes a remote debugger on port 8000 and halts the maven process until you attach a remote debugger to that port. Once you have a remote debugger attached the maven process continues and stops at any breakpoints that you have set up in your project.