I have a MOJO I would like executed once, and once only after the test phase of the last project in the reactor to run.
Using:
if (!getProject().isExecutionRoot()) {
return ;
}
at the start of the execute() method means my mojo gets executed once, however at the very beginning of the build - before all other child modules.
The best solution I have found for this is:
/**
* The projects in the reactor.
*
* @parameter expression="${reactorProjects}"
* @readonly
*/
private List reactorProjects;
public void execute() throws MojoExecutionException {
// only execute this mojo once, on the very last project in the reactor
final int size = reactorProjects.size();
MavenProject lastProject = (MavenProject) reactorProjects.get(size - 1);
if (lastProject != getProject()) {
return;
}
// do work
...
}
This appears to work on the small build hierarchies I've tested with.
The best solution is relying on a lifecycle extension by extending your class from org.apache.maven.AbstractMavenLifecycleParticipant
(see also https://maven.apache.org/examples/maven-3-lifecycle-extensions.html) which got a method afterSessionEnd
added with https://issues.apache.org/jira/browse/MNG-5640 (fixed in Maven 3.2.2).
There is a Sonatype blog entry that describes how to do this. The last project to be run will be the root project as it will contain module references to the rest. Thereforec you need a test in your mojo to check if the current project's directory is the same as the directory from where Maven was launched:
boolean result = mavenSession.getExecutionRootDirectory().equalsIgnoreCase(basedir.toString());
In the referenced entry there is a pretty comprehensive example of how to use this in your mojo.
I think you might get what you need if you use the @aggregator tag and bind your mojo to one of the following lifecycle phases:
- prepare-package
- package
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install
- deploy
The solution with using session.getEventDispatcher() no longer works since Maven 3.x. The whole eventing has been removed in this commit: https://github.com/apache/maven/commit/505423e666b9a8814e1c1aa5d50f4e73b8d710f4
Check out maven-monitor API
You can add an EventMonitor to the dispatcher, and then trap the END of the 'reactor-execute' event: this is dispatched after everything is completed, i.e. even after you see the BUILD SUCCESSFUL/FAILED output.
Here's how I used it recently to print a summary right at the end:
/**
* The Maven Project Object
*
* @parameter expression="${project}"
* @required
* @readonly
*/
protected MavenProject project;
/**
* The Maven Session.
*
* @parameter expression="${session}"
* @required
* @readonly
*/
protected MavenSession session;
...
@Override
public void execute() throws MojoExecutionException, MojoFailureException
{
//Register the event handler right at the start only
if (project.isExecutionRoot())
registerEventMonitor();
...
}
/**
* Register an {@link EventMonitor} with Maven so that we can respond to certain lifecycle events
*/
protected void registerEventMonitor()
{
session.getEventDispatcher().addEventMonitor(
new EventMonitor() {
@Override
public void endEvent(String eventName, String target, long arg2) {
if (eventName.equals("reactor-execute"))
printSummary();
}
@Override
public void startEvent(String eventName, String target, long arg2) {}
@Override
public void errorEvent(String eventName, String target, long arg2, Throwable arg3) {}
}
);
}
/**
* Print summary at end
*/
protected void printSummary()
{
...
}
Normally, this is a matter of configuration. You might have to setup a project just for the mojo and make it dependent on all of the other projects. Or you could force one of the child projects to be last by making it dependent on all of the other children.