Jenkinsfile and POM version - maven

After we fetch POM model like described in Krzysztof KrasoĊ„'s answer in extract pom version in a jenkins pipeline. Call to pom.version returns the fully qualified name of the artifact and not just the version.
For example
#NonCPS
def version() {
pom = readMavenPom file: 'pom.xml'
pom.version
}
for
<groupId>com.test.app</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
will produce
com.test.app:app:pom:1.0.0-SNAPSHOT
Is there a way to return just the version part from returned Model without doing any String manipulation?

You should not call regular (CPS-transformed) methods, or Pipeline steps inside #NonCPS methods because they requires CPS-transformation.
See more in README.md.

Related

Call hierachy of properties in pom.xml

I have a maven project with multiple nested projects. All of them do always have the same version. Untill now, if I want to increase the version, I went through all pom.xml files and changed the version number.
Now, I wanted to outsource the version to the properties tag of the parent pom.xml file. It works, for all nested projects, but not for the parent pom itself.
In which order are the attributes in the pom.xml called? I can not reference
the project version in the parent pom.xml file.
The code snippet shows the parent pom.xml
<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">
<groupId>com.my.project</groupId>
<artifactId>my.project</artifactId>
<packaging>pom</packaging>
<version>${projectVersion}</version>
<properties>
<projectVersion>1.0.0</projectVersion>
...
</properties>
<modules>
<module>my.project.service</module>
<module>my.project.db</module>
...
</modules>
I expect the pom to take the version number defined in the properties. But it failes building with the error invalid reference format
I expect the pom to take the version number defined in the properties.
But it failes building with the error invalid reference format
By running a maven goal from the parent project, maven first binds the artifact/group/version in the current build process, so it uses the version defined here :
<version>${projectVersion}</version>
I can not reference the project version in the parent pom.xml file.
In this case, you could "cheat" by creating an aggregator/multimodule project that defines a not used/fake version (1.0-NOT-USED for example) that has as unique module the parent pom. When you build the aggregator/multimodule project, you can now pass as parameter the version to use in the parent project and all its modules.
As a side note, to use a central version for a set of projects, you should use the flatten maven plugin that relieves you from the hell version management.

Generate the maven artifact path

Maven install knows all the artifacts generated by a build, and will push them locally.
Installs the project's main artifact, and any other artifacts attached by other plugins in the lifecycle, to the local repository.
the help plugin probably supports this, but not sure of right expression
# has all the pieces (artifact, version, type) but is it fair to assume filename will always be that combo?
mvn help:evaluate -Dexpression=project.artifact
Is there any way to get that list of paths from a maven command?
I want to generate a list of specific artifacts to persist as artifact results in a build process, without publishing to a maven repo.
Artifact paths in Maven repository will follow the following formula by default:
groupId is broken into folders using the full stops as delimiter, then artifactId and version form the last two folders
filename of the artifact consists of artifactId and version, type is defined by packaging
So, let's say you have a multi-module project with main pom.xml:
<groupId>com.foobar.my.business</group>
<artifactId>myApp</artifactId>
<version>1.0-SNAPSHOT</version>
And it has two submodules, first is web module that creates a REST endpoint:
<parent>
<groupId>com.foobar.my.business</group>
<artifactId>myApp</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>myApp-web</artifactId>
<packaging>war</packaging>
Second one is persistence layer:
<parent>
<groupId>com.foobar.my.business</group>
<artifactId>myApp</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>myApp-persistence</artifactId>
<packaging>jar</packaging>
Let's say your local repository is found from ~/.m2/repository. Then your artifacts will be saved in local repository at:
~/.m2/repository/com/foobar/my/business/myapp/1.0-SNAPSHOT/myapp-1.0-SNAPSHOT.pom
~/.m2/repository/com/foobar/my/business/myapp-web/1.0-SNAPSHOT/myapp-web-1.0-SNAPSHOT.pom
~/.m2/repository/com/foobar/my/business/myapp-web/1.0-SNAPSHOT/myapp-web-1.0-SNAPSHOT.war
~/.m2/repository/com/foobar/my/business/myapp-persistence/1.0-SNAPSHOT/myapp-persistence-1.0-SNAPSHOT.pom
~/.m2/repository/com/foobar/my/business/myapp-persistence/1.0-SNAPSHOT/myapp-persistence-1.0-SNAPSHOT.jar
An artifact's final build name and the local repository location can be tinkered with. But you can use the following expressions to check those:
${settings.localRepository} will return path to local repository.
${project.build.finalName} will return final build artifact name.
To get this list in almost the correct format, you can run:
On Windows mvn -q exec:exec -Dexec.executable="cmd" -Dexec.args="/C echo ${settings.localRepository}\${project.groupId}\${project.artifactId}\${project.version}\${project.build.finalName}.${project.packaging}"
On POSIX mvn -q exec:exec -Dexec.executable='echo' -Dexec.args='${settings.localRepository}/${project.groupId}/${project.artifactId}/${project.version}/${project.build.finalName}.${project.packaging}'
Then you just have to fix the full stops in groupId.
There is also a mvn dependency:build-classpath command which will show the location of each dependency on the file system that can come in handy sometimes.

Maven "conditional" parent POM?

What's the best structure for a (multi-module) Maven project which should build "in the wild" without any Maven repository manager and can easily build within my organization where deployments should happen to my Maven repository manager?
Ideally, I would have two different paren POMs for each situation.
But unfortunately, I can't use a Maven property to pass the correct value for each situation, because the property expression in the parent POM reference doesn't get interpolated, if I try something like
<parent>
<groupId>org.example</groupId>
<artifactId>${root.pom}</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/>
</parent>
...
<properties>
<root.pom>wild-parent</root.pom>
</properties>
Added a minimalistic project which shows a crude approach to solve this by patching the parent POM via sed.
This response on the maven-users mailing list pointed me in the direction to use Maven properties to pass in the in-house specifics.
I updated the example project.

Override sonar projectKey when using maven

I want to group 25 modules under a single project key so I can get a consolidated view of code duplication. However the sonar maven plugin uses the <groupId>:<artifactId> so each project is separate.
I've tried overriding the sonar.projectKey but the maven plugin doesn't consider it.
Is there a way of grouping modules together under a single name so that you can have an aggregate view?
Or is there some other in the sonarqube server to get that aggregate view?
As far as I can tell, and contrary to some other forum posts, with at least v3.2 of the maven-sonar-plugin (maybe earlier) the sonar.projectKey property is respected and overrides the default of ${project.groupId}:${project.artifactId}.
Checking the source code also confirms it first looks for the property before defaulting it.
org.sonarsource.scanner.maven.bootstrap.MavenSonarRunner.java
private static void defineProjectKey(MavenProject pom, Properties props) {
String key;
if (pom.getModel().getProperties().containsKey(ScanProperties.PROJECT_KEY)) {
key = pom.getModel().getProperties().getProperty(ScanProperties.PROJECT_KEY);
} else {
key = getSonarKey(pom);
}
props.setProperty(MODULE_KEY, key);
}
private static String getSonarKey(MavenProject pom) {
return new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()).toString();
}
org.sonarsource.scanner.api.ScanProperties
String PROJECT_KEY = "sonar.projectKey";
So by setting the following in the POM, for example, the projectKey can be overriden:
<properties>
<sonar.projectKey>myprefix:${project.groupId}:${project.artifactId}</sonar.projectKey>
</properties>
Tested on Maven 3.3.9. In case this helps anyone!
Link to original GitHub Source:
https://github.com/SonarSource/sonar-scanner-maven/blob/master/src/main/java/org/sonarsource/scanner/maven/bootstrap/MavenProjectConverter.java
I have a similar setup and use a multi modules / aggregator project for that http://maven.apache.org/pom.html#Aggregation.
Just pass the aggregator pom that contains the modules to the sonar build and it should group all modules together. The grouping name is taken from the aggregator artifact-property (and can be overwritten by its name-property).
<groupId>...</groupId>
<artifactId>aggregator-project</artifactId>
<version>...</version>
<packaging>pom</packaging>
<name>Group name overrites artifactId</name>
<modules>
<module>my-project</module>
<module>another-project</module>
</modules>

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

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

Resources