How do you force a maven MOJO to be executed only once at the end of a build?

一笑奈何 提交于 2019-12-03 12:59:54

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
Konrad Windszus

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!