简体   繁体   中英

How to use parent pom's profile properties in child pom?

Current scenario:

Parent pom has a distributionManagement section, where two repositories (releases and snapshots) are defined; refer below:

Parent 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>

Based on the 'version' specified in same pom, maven automatically identifies whether to deploy artifacts in releases or snapshots repository in nexus. (I believe this is being done using whether there is any '-SNAPSHOT' suffix to version or not.)

There is a child-pom which has some deploy-file goals defined; refer below:

Child 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/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>

Problem:

As you can see in child pom above that I have to specify the url and repositoryId tags explicitly for each of the configuration tags. Without them, there is an error thrown and deploy-file goal fails.

Now, I do not want to hard-code their values in the child pom. Rather, I want to inherit these values from parent pom conditionally: If the parent uses the releases repository, then child should also use the same. If parent uses the snapshots repository, then child should also use the same. (Note again that there is no condition specified in parent pom to use respective repository, rather it is done automatically by maven as mentioned above)

So how do I make this conditional value population in child pom based on certain condition evaluation in parent/child pom?

Things I have tried:

I added the profiles section in the parent pom as follows:

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

As seen above, there are two profiles, and each of them have same properties with different values. However, I am not able to populate the above properties in either parent or child pom using their IDs. For eg. using ${repositoryUrl} in parent pom or ${parent.repositoryUrl} in child pom does not work. IntelliJ immediately shows this in red color. Despite that, if I still try to use the command 'mvn deploy -P release-enabled', the deployment still fails as maven is not able to substitute values of above properties dynamically. (The reason I do not have activation section in profiles is because I need to build this entire project through TeamCity later, which will not have environment variable. Hence, as part of command line only I shall pass the information of which profile should be used.)

Any suggestions on how to dynamically populate values in parent/child poms? Is there any if-else kind of expression evaluation possible, may be based on some arguments that can be passed while executing 'mvn deploy' command?

you can't have a parametric version in the parent definition, how would you be able to retrieve the correct value, otherwise?

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

What you should do, is to define the correct version in the parent pom:

<groupId>x.y.z</groupId>
<artifactId>abc</artifactId>
<version>0.7</version>
<packaging>pom</packaging>

getting rid of the buildVersion variable and use thepom version plugin to change the versions of all the modules at once:

mvn versions:set -DnewVersion=0.8-SNAPSHOT

From the doc:

The set goal can be used to update the version of the current module. It will automatically climb up local directories to find the aggregation root. It will automatically update explicitly referenced dependencies. You specify the version to update to via the newVersion property

First of all, while you can be defining the version via the command-line, it's not really advisable. The problem is that this breaks the build portability of the code. If I check out your code, I wouldn't know which version this is, or what I should use for it in order to build it. Also, if you do it this way and then tag the code in Git, if somebody checks out the code later, they won't know what version string you used and they will be guessing (unless they're on your team).

Secondly, defining properties this way is very tricky. When you pass the version like this, the parent needs to be installed first, unless it's part of an aggregator as a sub-module.

In your example above, the parent is also an aggregator. I would recommend putting it in a separate module.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM