${project.artifactId} in parent pom.xml resolves odd - maven

I have a bulk full of projects which have the same URLs in their pom.xml:
<url>https://github.com/malkusch/${project.artifactId}</url>
<scm>
<connection>scm:git:git://github.com/malkusch/${project.artifactId}.git</connection>
<developerConnection>scm:git:git#github.com:malkusch/${project.artifactId}.git</developerConnection>
<url>https://github.com/malkusch/${project.artifactId}</url>
</scm>
<issueManagement>
<system>github</system>
<url>https://github.com/malkusch/${project.artifactId}/issues</url>
</issueManagement>
So I thought it's a great idea to put that into a parent pom.xml. But the effective pom produces odd ${project.artifactId}:
<parent>
<groupId>de.malkusch.parent</groupId>
<artifactId>oss-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<groupId>de.malkusch.localized</groupId>
<artifactId>localized</artifactId>
<url>https://github.com/malkusch/localized/localized</url>
<scm>
<connection>scm:git:git://github.com/malkusch/localized.git/localized</connection>
<developerConnection>scm:git:git#github.com:malkusch/localized.git/localized</developerConnection>
<url>https://github.com/malkusch/localized/localized</url>
</scm>
<issueManagement>
<system>github</system>
<url>https://github.com/malkusch/localized/issues</url>
</issueManagement>
You notice that only issueManagement.url was resolved correctly. The others are totally strange, especially ${project.artifactId}.git -> localized.git/localized. I'm using Maven 3.0.4. Am I using some undefined feature? Is it a bug?

Yes, this behaviour is confusing.
Perhaps the easiest way to understand this is to consider how Maven itself is built. It's in Subversion, and the reactor poms (the poms with <modules> sections) tend to also be the parent poms of the modules themselves.
project/pom.xml (artifactId: parent)
|-+ module1/pom.xml (artifactId: module1, inherits parent)
|-+ module2/pom.xml (artifactId: module2, inherits parent)
Here, the parent pom (project/pom.xml) contains a <modules> section, and is also inherited by module1 and module2.
Now suppose the SCM URL for parent is svn://host/path/project/: what should maven do so that you don't have to specify the SCM URL again in the two modules?
Well, the SCM URL for module1 is svn://host/path/project/module1, and Maven can compute that by adding the artifactId to the SCM URL it inherits from the parent pom. It simply needs to append the artifactId to the SCM URL. So that's exactly what it does.
So that's the behaviour you're seeing:
${project.artifactId}.git becomes localized.git/localized as follows:
localized -> from ${project.artifactId} in the inherited SCM URL
.git -> from the the inherited SCM URL
/localized -> from adding the artifactId to the inherited SCM URL
You will see this behaviour in the SCM URLs, and (I think) for project.url and the URL in distributionMangement.site.url. However, Maven doesn't assume that the issueManagement URL structure follows your directory structure, which is why you see it inherited correctly.

Since Maven 3.6.1, inheritance can avoid appending any path to parent value by setting model attribute value to false for each url
src : maven-model-builder
You need to append following properties to SCM tag in your POM :
<scm child.scm.connection.inherit.append.path="false" child.scm.developerConnection.inherit.append.path="false" child.scm.url.inherit.append.path="false">...</scm>
It seems IntelliJ shows error, but at then end, it does the job perfect.

Adding to the already great background information given, in order to still deploy with a valid scm url, since Maven 3.5 you can correct the "module" name that gets appended per the project.directory property:
<properties>
<project.directory>${project.artifactId}</project.directory>
</properties>
And then you just simplify your developerConnection to not include the artifactId anymore since it will be appended as the project.directory:
<scm>
<developerConnection>scm:git:git#server:</developerConnection>
</scm>
Assuming this doesn't conflict with any other goals, that should allow a deploy goal to do its job with the correct git url for a non-multi-module Maven project where you've defined the scm.developerConnection in the parent pom.
When I run a deploy, I see maven doing a correct push like:
[INFO] Executing: /bin/sh -c cd /projectDir/proj && git push git#server:proj master:master

Related

Using Maven scm:checkin to commit changes to module projects

I have a multi-module POM file:
...
<modules>
<module>../project1</module>
<module>../project2</module>
<module>../project3</module>
...
</modules>
...
Each of the modules is itself a Maven project with its own POM. Inside each of these POMs I have the scm tag defined with the developerConnection specified like this:
<scm>
<developerConnection>scm:svn:svn://hostname:port/path/to/trunk</developerConnection>
</scm>
My goal is to run the following Maven goals/options:
versions:update-parent versions:commit scm:checkin \
-Dmessage="automated commit" -Dusername=user -Dpassword=pass
My expected results are:
The parent of each module's POM is updated to the latest released version.
The changes to each POM would be checked in to the SVN path specified in the POM for the module. E.g. project1 POM checked in using project1 <scm>/<developerConnection> path, project2 checked in using project2 path, etc.
Actual Results:
The parent of each module's POM is updated to latest released version. This works as expected.
Only the multi-module POM is checked in to SVN, none of the module POMs are checked in. This is the problem.
Is there a way to achieve the expected results above or is this something that the SCM plugin simply was not designed to do? If it is possible, how would I modify what I have in order to get the results I want?
Note: I can't change the project structure - I can't put the modules inside of the parent project, they have to remain separate.
Not sure if it's relevant but I'm using Maven 3.3.9.

Maven how set absolute path for parent pom

with maven 3 i have a parent project at 'C:/travail/parent'.
I have several child-projects who, for various reasons, can change locations.
To make a war, the relativePath tag must be set.
<parent>
<groupId>framework.parent</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>C:/Travail/parent/pom.xml</relativePath>
</parent>
Question: How can I put an absolute path for the parent? The following doesn't work.
<relativePath>/C:/Travail/parent/pom.xml</relativePath>
You cannot use an absolute path for your parent pom, the name itself of the configuration entry is quite self explanatory (relative path).
From the official Maven model documentation for this element:
The relative path of the parent pom.xml file within the check out. If not specified, it defaults to ../pom.xml. Maven looks for the parent POM first in this location on the filesystem, then the local repository, and lastly in the remote repo. relativePath allows you to select a different location, for example when your structure is flat, or deeper without an intermediate parent POM. However, the group ID, artifact ID and version are still required, and must match the file in the location given or it will revert to the repository for the POM. This feature is only for enhancing the development in a local checkout of that project. Set the value to an empty string in case you want to disable the feature and always resolve the parent POM from the repositories.
Default value is: ../pom.xml.
You can't even use a shortcut or symbolic link for the same, distributed together with each and every module and pointing at the absolute file location, it would not work (and you shouldn't use such a trick anyway, even if it was going to work).
You can't even use a property as value placeholder of the relativePath element. Something like:
<parent>
<groupId>framework.parent</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>${path.to.parent}</relativePath>
</parent>
And try to inject it at build time like:
mvn clean install -Dpath.to.parent=C:/somewhere/pom.xml
Would simply not work, as also documented by the following Maven tickets:
MNG-2569: Expressions not evaluated inside
MNG-624: automatic parent versioning
The only reasonable use case for this configuration entry is, as mentioned in the official documentation, for flat-structured multi-module projects, where modules and parent project are located at the same directory level.
Otherwise, and more suitable for your use case, you should provide the parent pom as part of the shared Maven repository (if any) or require a maven install (so that it will be available in the local maven cache) of the parent project upfront for any new version before any required maven action on the children/module projects.

Duplicate artifactId in child pom

I want a parent pom to define some properties for numerous child poms to inherit. However when I try and use the artifactId within one of these properties in the parent pom, it duplicates in the child's effective pom. Very basic example below. Assume I have all the valid fields needed for poms (groupId, version, packaging etc).
The parent pom's effective pom has a scm connection value of www.mysite.com/parent-pom. But the child's effective pom has a scm connection value of www.mysite.com/child-pom/child-pom. How do I gain this inheritance of the property and general structure of the connection url, without the duplicate artifactId. I want the child pom to have a scm connection of www.mysite.com/child-pom.
Parent:
<project>
<artifactId>parent-pom</artifactId>
<properties>
<scmurl>www.mysite.com</scmurl>
</properties>
<scm>
<connection>${scmurl}/${artifactId}</connection>
</scm>
</project>
Child:
<project>
<parent>
<artifactId>parent-pom</artifactId>
</parent>
<artifactId>child-pom</artifactId>
</project>
edwardmlyte,
There are 2 solutions to what you're trying to do, but neither of them are optimal.
Fundamental Problem
If Maven SCM plugin detects that <scm> block has been defined in your parent but NOT in your child, then it will reason that your child's SCM path is simply the subdir of the parent. In your case there's an additional wrinkle that your parent's url itself contains ${project.artifactId} which gets interpolated at the child level prior to tacking on the artifactId again.
Basically, it's doing the following:
project.scm.connection=${parent.scm.connection}/${project.artifactId}
project.scm.connection=${scmurl}/${project.artifactId}/${project.artifactId}
project.scm.connection=www.mysite.com/child-pom/child-pom
The fact that your parent's url contains ${artifactId} compounds the confusion, but even if you hardcode the url to www.mysite.com/parent-pom/ you won't be able to get around the fact that SCM plugin thinks child-pom is a subdir of the parent's url and so will simply tack it onto the end of the path.
Your 2 options are:
Redundant but Simple
Put the following into every child's pom.xml file:
<scm>
<connection>${scmurl}/${artifactId}</connection>
</scm>
It's annoying but relatively straightforward.
Efficient but Dodgy
Have parent-pom contain the following:
<scm>
<connection>${scmurl}/</connection>
</scm>
That will result in each child will have correct url, but the parent itself will be messed up.
You can get around that problem by putting the parent's correct url into a profile:
<profile>
<id>parent-profile</id>
<scm>
<connection>${scmurl}/parent-pom</connection>
</scm>
</profile>
$ mvn -Pparent-profile ...
It's less obvious and prone to manual error, but it'll avoid the need to edit each child's pom file.
Hope that helps.
My answer is not all that dissimilar to #333kenshin and was in fact derived from it, but I think that it results in a slightly terser paste.
In my parent pom I have added the following to <properties>
<git.account>xenworks</git.account>
<git.base>bitbucket.org/${git.account}/${project.artifactId}</git.base>
<git.conn>scm:git:https://${git.base}.git</git.conn>
<git.devConn>scm:git:ssh://git#${git.base}.git</git.devConn>
<git.url>https://${git.base}</git.url>
Now in the children and parent I can define scm as follows.
<scm>
<connection>${git.conn}</connection>
<developerConnection>${git.devConn}</developerConnection>
<url>${git.url}</url>
<tag>HEAD</tag>
</scm>
the final contribution I'd like to make is there is an open bug on this in the Maven Jira
Where does ${scmurl} come from? The property is called url.
If one adapts parent-pom accordingly:
<scmurl>www.mysite.com</scmurl>
... the behavior is as described in the OQ:
/parent-pom$ mvn help:effective-pom
...
<scm>
<connection>www.mysite.com/parent-pom</connection>
</scm>
...
<relativePath>../parent-pom</relativePath> (assuming they are siblings in the file system) has to be added to child-pom if parent-pom has not been installed into the local Maven repo (yet). Otherwise the following will fail:
/child-pom$ mvn help:effective-pom
...
<scm>
<connection>www.mysite.com/child-pom/child-pom</connection>
</scm>
...
This looks strange to me at first sight, too. I'm still scouring the docs to find a (logical) explanation for this.
Replacing ${artifactId} with ${project.artifactId} – as suggested in the comments – does not help.
Repeating <scm><connection>${scmurl}/${artifactId}</connection></scm> in child-pom helps:
/child-pom$ mvn help:effective-pom
...
<scm>
<connection>www.mysite.com/child-pom</connection>
</scm>
...
However, I'd consider khmarbaise's comments to the question.

Tell Maven to look in repos for parent pom before looking in file system

Per Maven documentation Maven will only look in local and remote repos for a parent pom after it fails to find it locally. The best solution I've found to dummy this out is by adding
<relativePath>.</relativePath>
which is obviously a kludge and produces warnings (as it well should). Maven seems to be like file-system coupling when dealing with parent modules and multi-module projects so this is the only way I see to have both of those co-exist without something that feels obviously wrong (e.g. inheriting from a filesystem child).
You reference the parent pom using the tag:
<parent>
<groupId>com.mycompany</groupId>
<artifactId>my-parentpom</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
You must install the parent pom into your local repo using the mvn install -N command from the directory that contains the parent POM.

What does the parent tag in Maven pom represent?

E.g.:
<parent>
<groupId>mycompany.trade.com</groupId>
<artifactId>mycompany.trade.</artifactId>
<version>1.1.1.0-SNAPSHOT</version>
</parent>
Does it mean that Maven will search for parent pom?
If yes, where, in which order? May be in folder up 1 level? Or in local repository or in repo?
Yes, maven reads the parent POM from your local repository (or proxies like nexus) and creates an 'effective POM' by merging the information from parent and module POM.
See also Introduction to the POM
One reason to use a parent is that you have a central place to store information about versions
of artifacts, compiler-settings etc. that should be used in all modules.
The common dependencies,Properties,constants etc can be definded in central parent project pom.xml
The main important thing is the parent project cannot be distributed and it looks quite similar to a regular "pom.xml" except that it also has a packaging tag
<groupId>com.company.demo</groupId>
<artifactId>MavenInheritance</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
The child now able to inherit this using
<parent>
<groupId>com.company.demo</groupId>
<artifactId>MavenInheritance</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
As the name suggests, we can point out a parent pom.xml file for the current pom.xml file. Doing so, dependencies, properties, constants and many more defined at the parent pom.xml file also get merged with the current pom.xml (child pom.xml) file. Say you have a parent tag in your projects pom.xml that looks like below:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
Then maven reads that parent POM from your local repository (or from repository managers like sonatype, jfrog, etc that you have configured) and creates a Resultant POM by combining the parent POM and your module’s POM.
To see the combined result use the following mvn command:
mvn help:effective-pom
This is the practice that is used in multi-modules projects where we need to inherit the dependencies from the parent projects.

Resources