你如何强制一个 maven MOJO 在构建结束时只执行一次?

Posted

技术标签:

【中文标题】你如何强制一个 maven MOJO 在构建结束时只执行一次?【英文标题】:How do you force a maven MOJO to be executed only once at the end of a build? 【发布时间】:2010-09-13 01:49:45 【问题描述】:

我有一个 MOJO,我想执行一次,并且仅在反应堆中最后一个项目的测试阶段之后运行一次。

使用:

if (!getProject().isExecutionRoot()) 
        return ;

在 execute() 方法的开头意味着我的 mojo 被执行一次,但是在构建的最开始 - 在所有其他子模块之前。

【问题讨论】:

让我确定我理解你。您有一个父项目和一些子项目。您希望此 mojo 在最后一个子项目中的测试后运行。对吗? 另外,你需要保证它运行吗? ~9 年后...对于 Maven 3x,请参阅@Konrad Windszus 回复:org.apache.maven.AbstractMavenLifecycleParticipant 【参考方案1】:

我为此找到的最佳解决方案是:

/**
 * 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
   ...

这似乎适用于我测试过的小型构建层次结构。

【讨论】:

+1 这确实有效,但对我来说似乎是一种解决方法。 Mojo 仍然为 maven 报告的每个项目执行。当你有 5 个项目时,这是一个很小的细节,但当你有很多项目时,这就是一个缺陷。 我认为真正的解决方案是像@KonradWindszus 在另一个答案中建议的那样做一个 Maven 扩展【参考方案2】:

最好的解决方案是依赖生命周期扩展,方法是从 org.apache.maven.AbstractMavenLifecycleParticipant 扩展您的类(另请参阅 https://maven.apache.org/examples/maven-3-lifecycle-extensions.html),该类添加了一个方法 afterSessionEnd 和 https://issues.apache.org/jira/browse/MNG-5640(在 Maven 3.2.2 中修复)。

【讨论】:

【参考方案3】:

有一个Sonatype blog entry 描述了如何执行此操作。最后一个要运行的项目将是根项目,因为它将包含对其余项目的模块引用。因此,您需要在 mojo 中进行测试,以检查当前项目的目录是否与启动 Maven 的目录相同:

boolean result = mavenSession.getExecutionRootDirectory().equalsIgnoreCase(basedir.toString());

在引用的条目中有一个非常全面的示例,说明如何在你的 mojo 中使用它。

【讨论】:

【参考方案4】:

如果您使用 @aggregator 标签并将您的 mojo 绑定到以下生命周期阶段之一,我认为您可能会得到您需要的东西:

准备包 包 预集成测试 集成测试 集成后测试 验证 安装 部署

【讨论】:

这可能行得通,但是,MOJO 需要在测试阶段之后执行。即: mvn test 应该运行所有子模块中的所有测试,然后运行执行根的MOJO。 另外,在绑定到生命周期阶段时要注意@aggregator。 “当绑定到生命周期时,聚合器 mojo 可能会产生一些令人讨厌的副作用。它可以强制执行 ... 生命周期阶段提前执行,并可能导致构建最终执行 ... 阶段两次。” ref +1 您的回答实际上为我节省了很多时间。感谢您提及@aggregator 标签。【参考方案5】:

使用 session.getEventDispatcher() 的解决方案自 Maven 3.x 起不再有效。整个事件已在此提交中删除:https://github.com/apache/maven/commit/505423e666b9a8814e1c1aa5d50f4e73b8d710f4

【讨论】:

赞成,但这不是答案-应该是评论或编辑或@Konrad Windszus 其他答案(这是我多年来一直试图找到的,并且在 Maven 3.5.0 中有效)【参考方案6】:

查看maven-monitor API

您可以将 EventMonitor 添加到调度程序,然后捕获“reactor-execute”事件的 END:这会在一切完成后调度,即即使在您看到 BUILD SUCCESSFUL/FAILED 输出之后。

这是我最近使用它在最后打印摘要的方式:

/**
 * 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()

    ...

【讨论】:

我在调用 session.getEventDispatcher() 时得到一个空指针【参考方案7】:

你可以使用mavensession来解决这个问题

public boolean isThisTheLastProject() 
        return session.getProjectDependencyGraph().getSortedProjects().
                get(session.getProjectDependencyGraph().getSortedProjects().size()-1).getArtifactId().equalsIgnoreCase(project.getArtifactId());
    

【讨论】:

【参考方案8】:

通常,这是配置问题。您可能必须为 mojo 设置一个项目,并使其依赖于所有其他项目。或者,您可以通过使其依赖于所有其他子项目来强制其中一个子项目位于最后。

【讨论】:

以上是关于你如何强制一个 maven MOJO 在构建结束时只执行一次?的主要内容,如果未能解决你的问题,请参考以下文章

从自定义 mojo 访问 maven 插件的运行时配置的最佳方式?

用于读取应用程序类和生成 java 的 maven mojo

maven codehaus.mojo 无法解决

执行 Maven 安装时构建 Maven 项目时出错

Maven:我的 mojo 如何访问自己的资源?

jenkins Error while storing the mojo status