如何在子POM中使用父POM的配置文件属性?

4

当前情况:

父POM文件中有一个distributionManagement部分,其中定义了两个仓库(releases和snapshots);请参见下面的内容:

父POM文件:

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <properties>
        <buildVersion>0.7</buildVersion>
    </properties>

    <groupId>x.y.z</groupId>
    <artifactId>abc</artifactId>
    <version>${buildVersion}</version>
    <packaging>pom</packaging>

    <modules>
        <module>moduleA</module>
        <module>moduleB</module>
        <module>moduleC</module>
    </modules>

    <dependencies>

    </dependencies>

    <distributionManagement>
        <repository>
            <id>releases</id>
            <url>http://xyz/nexus/content/repositories/releases/</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <url>http://xyz/nexus/content/repositories/snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

    <profiles>
    <profile>
        <id>snapshots-enabled</id>
        <properties>
            <repositoryUrl>http://xyz/nexus/content/repositories/snapshots/</repositoryUrl>
            <repositoryId>snapshots</repositoryId>
        </properties>
    </profile>
    <profile>
        <id>release-enabled</id>
        <properties>
            <repositoryUrl>http://xyz/nexus/content/repositories/releases/</repositoryUrl>
            <repositoryId>releases</repositoryId>
        </properties>
    </profile>
</profiles>

</project>

基于在同一pom文件中指定的“版本”,Maven会自动识别是否在Nexus的发布版或快照版存储库中部署构件。(我认为这是通过检查版本号是否有“-SNAPSHOT”后缀来完成的。)
存在一个子模块,其中定义了一些deploy-file目标,请参见下文: 子模块:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>x.y.z</groupId>
        <artifactId>abc</artifactId>
        <version>${buildVersion}</version>
    </parent>

    <groupId>${parent.groupId}</groupId>
    <artifactId>childArtifactId</artifactId>
    <version>${parent.version}</version>
    <packaging>war</packaging>
    <name>MyChildProject</name>    

    <build>
        <sourceDirectory>src</sourceDirectory>

        <plugins>
            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-deploy-plugin</artifactId>
            <version>2.8.2</version>
            <executions>
                <execution>
                    <id>deploy-TA</id>
                    <configuration>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>TA</artifactId>
                        <version>${project.version}</version>
                        <url>http://xyz/nexus/content/repositories/releases/</url>
                        <repositoryId>releases</repositoryId>
                        <file>${basedir}/target/TA.war</file>
                    </configuration>
                    <phase>deploy</phase>
                    <goals>
                        <goal>deploy-file</goal>
                    </goals>
                </execution>
                <execution>
                    <id>deploy-OA</id>
                    <configuration>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>OA</artifactId>
                        <version>${project.version}</version>
                        <url>http://xyz/nexus/content/repositories/releases/</url>
                        <repositoryId>releases</repositoryId>
                        <file>${basedir}/target/OA.war</file>
                    </configuration>
                    <phase>deploy</phase>
                    <goals>
                        <goal>deploy-file</goal>
                    </goals>
                </execution>
                <execution>
                    <id>deploy-CSA</id>
                    <configuration>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>CSA</artifactId>
                        <version>${project.version}</version>
                        <url>http://xyz/nexus/content/repositories/releases/</url>
                        <repositoryId>releases</repositoryId>
                        <file>${basedir}/target/CSA.war</file>
                    </configuration>
                    <phase>deploy</phase>
                    <goals>
                        <goal>deploy-file</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        </plugins>

    </build>

</project>

问题:

如上所示,我在子POM中必须为每个配置标签显式指定url和repositoryId标签。如果没有这些标签,将会抛出错误并且deploy-file目标会失败。

现在,我不想在子POM中硬编码它们的值。相反,我希望根据条件从父POM继承这些值:如果父POM使用发布存储库,则子POM也应该使用相同的存储库。如果父POM使用快照存储库,则子POM也应该使用相同的存储库。(再次注意,父POM中没有指定使用相应存储库的条件,而是由maven自动完成,如上所述)

那么,如何基于父/子POM中的某些条件评估,在子POM中进行有条件的值填充?

我尝试过的方法:

我在父POM中添加了以下配置段:

<profiles>
    <profile>
        <id>snapshots-enabled</id>
        <properties>
            <repositoryUrl>http://xyz/nexus/content/repositories/snapshots/</repositoryUrl>
            <repositoryId>snapshots</repositoryId>
        </properties>
    </profile>
    <profile>
        <id>release-enabled</id>
        <properties>
            <repositoryUrl>http://xyz/nexus/content/repositories/releases/</repositoryUrl>
            <repositoryId>releases</repositoryId>
        </properties>
    </profile>
</profiles>

如上所示,有两个配置文件,它们各自具有相同的属性但值不同。然而,我无法在父POM或子POM中使用它们的ID来填充上述属性。例如,在父POM中使用${repositoryUrl} 或在子POM中使用${parent.repositoryUrl}都不起作用。IntelliJ会立即以红色显示。尽管如此,如果我仍然尝试使用“mvn deploy -P release-enabled”命令,则部署仍将失败,因为Maven无法动态替换上述属性的值。(我没有在配置文件中添加activation部分是因为我需要通过TeamCity构建整个项目,后者将没有环境变量。因此,我只能通过命令行传递应该使用哪个配置文件的信息。)
是否有任何关于如何在父/子POM中动态填充值的建议?是否可能进行if-else类似的表达式评估,可能基于执行“mvn deploy”命令时可以传递的一些参数?

1
它实际上被配置为父POM了吗? - Stultuske
这只是父POM的片段。为了清晰起见,我将发布整个父POM。 - Vaibhav Shah
无论它是一个父POM还是子POM实际上都在子POM中配置,你可以在其中声明其父级。 - Stultuske
现在已经添加了整个子pom,它使用parent xml节点引用父pom。整个项目在父子配置中运行正常,但我需要动态设置父pom和子pom中的值,但这一部分还没有实现。 - Vaibhav Shah
2个回答

1
您不能在父定义中使用参数版本,否则您将无法检索正确的值。
<parent>
    <groupId>x.y.z</groupId>
    <artifactId>abc</artifactId>
    <version>${buildVersion}</version>
</parent>

你需要做的是在父POM中定义正确的版本号:
<groupId>x.y.z</groupId>
<artifactId>abc</artifactId>
<version>0.7</version>
<packaging>pom</packaging>

摆脱buildVersion变量,并使用pom版本插件一次性更改所有模块的版本:
mvn versions:set -DnewVersion=0.8-SNAPSHOT

来自文档:

设置目标可以用于更新当前模块的版本。它会自动向上爬取本地目录以查找聚合根。它将自动更新明确引用的依赖项。您可以通过newVersion属性指定要更新到的版本


你好 @senape,我使用 buildVersion 属性的原因是因为我有很多子模块,它们都可以在其父标签声明中引用 buildVersion。如果我不这样做,那么在将项目的新版本部署到 Maven 中之前,我必须更新所有子 POM 的父标签以显式版本号,这使得我的任务繁琐。上述 POM 工作得非常好,就版本而言没有任何问题。问题在于在父/子 POM 中动态填充其他配置文件属性。您可以再次阅读问题以获取上下文。 - Vaibhav Shah
很抱歉,但我真的不明白 <parent>...<version>${buildVersion}</version> 是如何工作的。 - senape
它真的有效 :) 至少我能够使用IntelliJ和TeamCity构建和推送工件到nexus。虽然我仍然卡在动态填充配置文件属性部分。 - Vaibhav Shah

0
首先,虽然你可以通过命令行定义版本号,但这并不是明智的做法。问题在于这会破坏代码的构建可移植性。如果我检出你的代码,我就不知道这是哪个版本,或者我应该用什么来构建它。此外,如果你以这种方式进行操作,然后在 Git 中标记代码,如果以后有人检出代码,他们就不知道你使用了什么版本字符串,他们就要猜测(除非他们在你的团队中)。
其次,以这种方式定义属性非常棘手。当你像这样传递版本时,父级需要先安装,除非它作为聚合器的子模块之一。
在你上面的例子中,父级也是一个聚合器。我建议将其放在一个单独的模块中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接