首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在多模块项目中执行单个maven插件目标

在多模块项目中执行单个maven插件目标
EN

Stack Overflow用户
提问于 2022-08-05 22:29:07
回答 2查看 294关注 0票数 1

我正试图克服众所周知的maven问题,在各种SO问题中都有描述,例如:

在此之前,我熟悉以下解决办法:

  • mvn install -这正是我想要避免的
  • 涉及<skip>/<properties>/<profiles>的极其全面的项目配置
  • 使用maven-dependency-plugin将依赖项复制到模块文件夹中,同时打包和安装classpath

从我的角度来看,所有这些解决方案看起来都很糟糕。

今天我读到了关于根-反应堆感知子文件夹生成 in maven-4的文章,但是maven-4还没有发布,我很有兴趣为maven-3找到一个解决方案。我进行了一些研究,并在maven-3中找到了几个有用的扩展点。

DefaultArtifactResolver.java

代码语言:javascript
复制
if ( workspace != null )
{
    File file = workspace.findArtifact( artifact );
    if ( file != null )
    {
        artifact = artifact.setFile( file );
        result.setArtifact( artifact );
        result.setRepository( workspace.getRepository() );
        artifactResolved( session, trace, artifact, result.getRepository(), null );
        continue;
    }
}

DefaultProjectDependenciesResolver.java

代码语言:javascript
复制
for ( RepositorySessionDecorator decorator : decorators )
{
    RepositorySystemSession decorated = decorator.decorate( project, session );
    if ( decorated != null )
    {
        session = decorated;
    }
}

最后,我实现了一个非常简单的maven扩展(github上的完整源代码):

代码语言:javascript
复制
@Component(role = RepositorySessionDecorator.class)
public class FakeRepositorySessionDecorator implements RepositorySessionDecorator {

    @Requirement
    protected ArtifactHandlerManager artifactHandlerManager;

    @Override
    public RepositorySystemSession decorate(MavenProject project, RepositorySystemSession session) {
        String enabled = session.getUserProperties().get("fakerepo");
        if (!"true".equalsIgnoreCase(enabled)) {
            return null;
        }
        MavenProject root = project;
        while (root != null && !root.isExecutionRoot()) {
            root = root.getParent();
        }
        if (root != null) {
            WorkspaceReader workspaceReader = session.getWorkspaceReader();
            workspaceReader = new FakeWorkspaceReader(workspaceReader, root, artifactHandlerManager);
            return new DefaultRepositorySystemSession(session)
                    .setWorkspaceReader(workspaceReader);
        }
        return null;
    }

}

这样做的想法是,如果开发人员在执行maven插件目标时指定了-Dfakeroot,那么我的扩展将workspace范围从single module扩展到project root,并且当请求新的扩展工作区时,尝试在子模块文件夹中查找打包的工件,因此命令的顺序如下:

代码语言:javascript
复制
mvn clean package
mvn exec:exec -pl submodule -Dfakeroot

引导开发人员达到预期的结果。

问题是:如果我删除了指定-Dfakerepo的要求并在默认情况下启用了上述行为(即为所有maven目标和生命周期阶段应用新行为),我可以刹车什么?在我看来,在子模块文件夹中查找打包的工件总是比在本地存储库中更合理。还是我漏掉了什么?

UPD。

当我的扩展可能不像“预期”那样工作时,我发现了以下假设情况:

  • 在多模块项目中有两个子模块ABB依赖于A
  • 开发人员至少修改了A并发布了类似于mvn -am test -pl B的内容。

在这种情况下,如果A是以前打包的,那么我的扩展强制maven使用陈旧的工件,但是默认实现会使用A/target/classes作为类路径条目,另一方面,A/target/classes可能包含陈旧的类(我们没有发出clean),因此在这种情况下,“默认实现”的行为也是不理想的。

UPD2。

似乎有必要解释一下为什么这个问题困扰着我。实际上,有几种“典型的”情况:

  1. 开发人员希望维护他们自己的基础设施(特别是主要是DB),即:启动和停止多个实例,执行DB迁移,调试等等--因此我们希望避免CI问题,比如“CI管道中出了问题--猜猜是什么”。目标是使其尽可能简单,例如,我们在dev子模块中有一个特殊的dev目标,它执行DB迁移:
代码语言:javascript
复制
<dependencies>

    <dependency>
        <groupId>tld.project</groupId>
        <artifactId>another-submodule</artifactId>
    </dependency>
    
</dependencies>

<execution>
    <id>liquibase-update-primary</id>
    <phase>install</phase>
    <goals>
        <goal>exec</goal>
    </goals>
    <configuration>
        <executable>java</executable>
        <arguments>
            <argument>-classpath</argument>
            <!-- expecting to get module dependencies there -->
            <classpath/>
            <!-- main class -->
            <argument>liquibase.integration.commandline.Main</argument>
            <!-- covered by project properties -->
            <argument>--changeLogFile=${primary.changeLogFile}</argument>
            <!-- covered by profile properties -->
            <argument>--url=${jdbc.url}</argument>
            <argument>--driver=${jdbc.driver}</argument>
            <argument>--username=${jdbc.username}</argument>
            <argument>--password=${jdbc.password}</argument>
            <argument>--logLevel=info</argument>
            <argument>update</argument>
        </arguments>
    </configuration>
</execution>

这在maven-3中显然不起作用,因为它希望在本地存储库中找到tld.project-another-submodule工件,但是可以使用maven-dependency-plugin执行以下技巧

代码语言:javascript
复制
<execution>
    <id>liquibase-dependencies</id>
    <phase>package</phase>
    <goals>
        <goal>copy</goal>
    </goals>
    <configuration>
        <artifactItems>
            <artifactItem>
                <!-- 
                    now we may tell liquibase to load extra jars
                    from  ${project.build.directory}/liquibase
                -->
                <groupId>tld.project</groupId>
                <artifactId>another-submodule</artifactId>
                <type>jar</type>
                <destFileName>another-submodule.jar</destFileName>
                <outputDirectory>${project.build.directory}/liquibase</outputDirectory>
            </artifactItem>
        </artifactItems>
    </configuration>
</execution>
  1. 我们希望单独运行集成测试,而不重新编译/打包整个项目,即发布类似于mvn verify -pl it-submodule的内容,这从开发人员和CI的角度都是有用的:
代码语言:javascript
复制
- Developers and DevOps may perform infrastructure-related steps somewhere between `package` and `verify` phases
- CI may run `verify` multiple times (yep, someone may think about how is it possible to reiterate failed tests in CI pipeline, however our goal is to run `verify` phase multiple times in a row to make sure there are no flapping tests)
  1. 在大型项目的情况下,每一个额外的生命周期步骤都需要大量的时间。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-14 21:15:05

最后,我得出以下结论:

  1. 我怀疑这个特性将在可见的将来在maven中实现,因此实现我自己的maven扩展是有意义的,如下所示:GitHubMaven Central
  2. 实现了两种模式:
    • 将反应堆构件安装到“临时本地存储库”--通过这样做,我们不会毒害local repository,并且执行mvn install现在是“安全的”。-Dimh.repository系统属性启用此模式
    • maven-4一样,将反应堆工作空间扩展到整个项目,但也要注意补充工件,在这种情况下不需要mvn installmvn package就足够了。-Dimh.workspace系统属性启用此模式

下面的示例基于MNG-7527项目

-Dimh.repository模式:

代码语言:javascript
复制
% mvn clean install -Dimh.repository| grep Installing
[INFO] Installing MNG-7527/pom.xml to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527/0.0.1-SNAPSHOT/mng7527-0.0.1-SNAPSHOT.pom
[INFO] Installing MNG-7527/mng7527-war/target/mng7527-war-0.0.1-SNAPSHOT.war to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-war/0.0.1-SNAPSHOT/mng7527-war-0.0.1-SNAPSHOT.war
[INFO] Installing MNG-7527/mng7527-war/pom.xml to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-war/0.0.1-SNAPSHOT/mng7527-war-0.0.1-SNAPSHOT.pom
[INFO] Installing MNG-7527/mng7527-war/target/mng7527-war-0.0.1-SNAPSHOT-classes.jar to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-war/0.0.1-SNAPSHOT/mng7527-war-0.0.1-SNAPSHOT-classes.jar
[INFO] Installing MNG-7527/mng7527-dep1/target/mng7527-dep1-0.0.1-SNAPSHOT.jar to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-dep1/0.0.1-SNAPSHOT/mng7527-dep1-0.0.1-SNAPSHOT.jar
[INFO] Installing MNG-7527/mng7527-dep1/pom.xml to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-dep1/0.0.1-SNAPSHOT/mng7527-dep1-0.0.1-SNAPSHOT.pom
[INFO] Installing MNG-7527/mng7527-dep2/target/mng7527-dep2-0.0.1-SNAPSHOT.jar to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-dep2/0.0.1-SNAPSHOT/mng7527-dep2-0.0.1-SNAPSHOT.jar
[INFO] Installing MNG-7527/mng7527-dep2/pom.xml to /Users/apanfilov/.m2/repository/../../work/gh/MNG-7527/target/local-repo/tel/panfilov/maven/mng7527-dep2/0.0.1-SNAPSHOT/mng7527-dep2-0.0.1-SNAPSHOT.pom

% mvn clean package -f mng7527-dep1 -Dimh.repository
[INFO] [IMH] workspace extension disabled
[INFO] [IMH] setting up overlay repository
[INFO] [IMH] using root project target folder as overlay repository: MNG-7527/target/local-repo
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< tel.panfilov.maven:mng7527-dep1 >-------------------
[INFO] Building mng7527-dep1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mng7527-dep1 ---
[INFO] Deleting MNG-7527/mng7527-dep1/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ mng7527-dep1 ---
[INFO] skip non existing resourceDirectory MNG-7527/mng7527-dep1/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ mng7527-dep1 ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ mng7527-dep1 ---
[INFO] skip non existing resourceDirectory MNG-7527/mng7527-dep1/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ mng7527-dep1 ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ mng7527-dep1 ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ mng7527-dep1 ---
[INFO] Building jar: MNG-7527/mng7527-dep1/target/mng7527-dep1-0.0.1-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

-Dimh.workspace模式:

代码语言:javascript
复制
% mvn clean package -f mng7527-dep1 -Dimh.workspace 
[INFO] [IMH] repository extension disabled
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< tel.panfilov.maven:mng7527-dep1 >-------------------
[INFO] Building mng7527-dep1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mng7527-dep1 ---
[INFO] Deleting MNG-7527/mng7527-dep1/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ mng7527-dep1 ---
[INFO] skip non existing resourceDirectory MNG-7527/mng7527-dep1/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ mng7527-dep1 ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ mng7527-dep1 ---
[INFO] skip non existing resourceDirectory MNG-7527/mng7527-dep1/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ mng7527-dep1 ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ mng7527-dep1 ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ mng7527-dep1 ---
[INFO] Building jar: MNG-7527/mng7527-dep1/target/mng7527-dep1-0.0.1-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
票数 0
EN

Stack Overflow用户

发布于 2022-08-07 01:27:23

井,

我查看了这是如何实现的maven-4中的内容,并得出了一个结论,即它不能像预期的那样工作:

  1. maven团队已经扩展了反应堆工作区的范围,现在反应堆工作区的范围是一个完整的项目,不管是指定了-f还是-pl --与我所做的完全相同。
  2. maven团队添加了一些启发式方法来确定打包工件是否陈旧(简单地比较target/classes中打包工件和类的修改日期,但与源代码无关)--这实际上是我Q的答案。
  3. 有一个问题使得“根-反应堆感知子文件夹构建”功能完全无用且危险:不支持分类器- maven-4试图获取主工件,而不管指定了什么分类器,如果失败,则返回到~/.m2/repository - filed MNG-7527
  4. 如果maven未能发现主工件,它将尝试target/classestarget/test-classes -在大多数情况下导致异常的情况下,“Arti实物尚未打包。当用于反应堆工件时,应在打包后执行副本:请参阅MDEP-187”。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73255826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档