4

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?

Vaibhav Shah
  • 93
  • 1
  • 10
  • 1
    is it actually configured as the parent pom? – Stultuske Mar 01 '18 at 07:18
  • It's just the snippet of parent pom. I shall post the whole parent pom for clarity. – Vaibhav Shah Mar 01 '18 at 08:32
  • whether it is a parent pom, is actually configured in the child pom, where you declare what the parent is – Stultuske Mar 01 '18 at 09:03
  • Added whole child pom now. It refers to the parent pom using the parent xml node. The entire project works fine with parent-child configuration, but I need to dynamically set values in both parent and child pomx, that part is not working. – Vaibhav Shah Mar 01 '18 at 09:09

2 Answers2

1

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

senape
  • 342
  • 2
  • 12
  • Hello @senape, the reason I have used buildVersion property is because I have many child modules, which all can refer to the buildVersion in their parent tag declaration. If I don't do that, then I have to update all child poms' parent tag with explicit version number before deploying new version of project in maven, which makes my task cumbersome. Above poms work perfectly fine, and there is no problem with them as far as versions are concerned. The problem is with populating other profile properties dynamically in both parent/child poms. You may read question again to get the context. – Vaibhav Shah Mar 02 '18 at 10:54
  • I'm sorry, but I honestly can't understand how `...${buildVersion}` works. – senape Mar 02 '18 at 13:36
  • It really does work :) at least I am able to build and push artifacts to nexus with that using both IntelliJ and TeamCity. Though I am still stuck on dynamically populating profile properties part. – Vaibhav Shah Mar 02 '18 at 16:13
0

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.

carlspring
  • 31,231
  • 29
  • 115
  • 197