How to get Maven project version to the bash command line - bash

Previous I issued a question on how to change Maven project vesion from command line which lead me to a new issue.
Previously I was able to get the version number since the version was stored as a property that was easy to grep and parse from the command line (bash). Now that the pom.xml <version> element is used for this, it no longer is unique since all the dependencies and maybe some others too use this. I think there is no way to get the current version number with a bash script without external tools for parsing XML or some very context-aware sed command.
The most clean solution in my opinion would be for Maven to hand out this version information. I was thinking of writing a custom maven plugin for retrieving different properties but I thought I'd ask here first.
So, is there any easy way to get the value of ${project.version} to the command line?
Solution
I had to cd to the directory manually but that can be done easily. In my bash script I have:
version=`cd $project_loc && mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | sed -n -e '/^\[.*\]/ !{ /^[0-9]/ { p; q } }'`
Which gives me the current version that I can then advance. Grepping might be simpler but I thought I'd like as robust as possible, so I'm satisfied with the first line that starts with a number and try to handle this as a version number.
# Advances the last number of the given version string by one.
function advance_version () {
local v=$1
# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=`echo $v | sed -e 's/[^0-9][^0-9]*$//'`
local last_num=`echo $cleaned | sed -e 's/[0-9]*\.//g'`
local next_num=$(($last_num+1))
# Finally replace the last number in version string with the new one.
echo $v | sed -e "s/[0-9][0-9]*\([^0-9]*\)$/$next_num/"
}
And I use this by simply calling:
new_version=$(advance_version $version)

The Maven Help Plugin is somehow already proposing something for this:
help:evaluate evaluates Maven expressions given by the user in an interactive mode.
Here is how you would invoke it on the command line to get the ${project.version}:
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version
As noted in the comments by Seb T, to only print the version without the maven INFO logs, additionally use -q -DforceStdout:
mvn help:evaluate -Dexpression=project.version -q -DforceStdout

Tom's solution with the Exec Maven Plugin is much better, but still more complicated than it needs to be. For me it's as simple as:
MVN_VERSION=$(mvn -q \
-Dexec.executable=echo \
-Dexec.args='${project.version}' \
--non-recursive \
exec:exec)

After doing some research I found the following:
Maven has been blamed because integration with DevOps tools is not easy due to the fact that it does not follow some good practices regarding CLI tools, i.e:
http://www.faqs.org/docs/artu/ch01s06.html (not available anymore)
"The Unix Way"
(ii) Expect the output of every program to become the input of another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.
What does it actually mean?
Your output should be:
"grepable": (One "record" per line)
"cutable": (Delimited "fields")
exit codes: 0 for success, nonzero for failure.
messaging (stderr) vs. output (stdout)
(ref: Make awesome command line apps with ruby by Dave Copeland Jan 18, 2012 https://youtu.be/1ILEw6Qca3U?t=372)
Honesty I think Dave Copeland was right when he said that maven does't play fairly with others. So I decided to give a look to maven's source code as well as to maven-help-plugin's source code as well. It seems that they have fixed a little bit the maven's -q switch (I was using version 3.5.3 at that time), so now if you pass it, you won't get all the annoying non-sense logging stuff that prevents maven from being used within automated scripts. So you should be able to use something like this:
mvn help:evaluate -Dexpression=project.version -q
The problem is that this command prints nothing because by default the help plugin outputs through the logger which has been silenced by the -q switch. (latest available version of the plugin at that time was 3.1.0 released on June, 3rd 2018)
Karl Heinz Marbaise (https://github.com/khmarbaise) fixed it by adding an optional parameter that allows you to call it in the following way:
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
The commit description is available at: (https://github.com/apache/maven-help-plugin/commit/316656983d780c04031bbadd97d4ab245c84d014)
Again, you should always verify the exit code of the command and redirect all stderr to /dev/null on unix.

mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['

This is the cleanest solution there is:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.version -q -DforceStdout
Advantages:
This works fine on all operating systems and all shells.
No need for any external tools!
[important] This works even if project version is inherited from parent pom.xml
Note:
maven-help-plugin version 3.2.0 (and above) has forceStdout option. You may replace 3.2.0 in above command with a newer version from the list of available versions of mvn-help-plugin from artifactory, if available.
Option -q suppresses verbose messages ([INFO], [WARN] etc.)
Alternatively, you can add this entry in your pom.xml, under plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
</plugin>
and then run above command compactly as follows:
mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout
If you want to fetch groupId and artifactId as well, check this answer.

Why not use the right tool for the job? Using xpath syntax is the best approach to retrieving the version number, since it is the intended method of accessing a XML data structure. The expression below is traversing the pom using the "local name" of the elements, in other words ignoring namespace declarations which may or may not be present in the xml.
xmllint --xpath "//*[local-name()='project']/*[local-name()='version']/text()" pom.xml

This will avoid the need for grepping off log entries from the output:
mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q

python -c "import xml.etree.ElementTree as ET; \
print(ET.parse(open('pom.xml')).getroot().find( \
'{http://maven.apache.org/POM/4.0.0}version').text)"
As long as you have python 2.5 or greater, this should work. If you have a lower version than that, install python-lxml and change the import to lxml.etree. This method is quick and doesn't require downloading any extra plugins. It also works on malformed pom.xml files that don't validate with xmllint, like the ones I need to parse. Tested on Mac and Linux.

I kept running into side cases when using some of the other answers here, so here's yet another alternative.
version=$(printf 'VER\t${project.version}' | mvn help:evaluate | grep '^VER' | cut -f2)

There is also one option without need Maven:
grep -oPm1 "(?<=<version>)[^<]+" "pom.xml"

This is by far the easiest bash cut and paste solution:
VERSION=$(mvn exec:exec -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive -q)
echo $VERSION
it echoes
1.4

If you don't mind to write the version into a temporary file, there is another solution (without grep/sed) that works well for me. (EDIT: see rjrjr's answer for a much simpler solution without any temporary file hassle)
I use the Exec Maven Plugin along with the echo binary. In contrast to the Maven Help Plugin, the Exec Plugin allows output redirection into a file, which can be used to bypass grep/sed, and makes it even possible to parse strange things like multiline version strings (with CDATA block in version tag), at least to a certain extent.
#!/usr/bin/env sh
MVN_VERSION=""
VERSION_FILE=$( mktemp mvn_project_version_XXXXX )
trap "rm -f -- \"$VERSION_FILE\"" INT EXIT
mvn -Dexec.executable="echo" \
-Dexec.args='${project.version}' \
-Dexec.outputFile="$VERSION_FILE" \
--non-recursive \
--batch-mode \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec > /dev/null 2>&1 ||
{ echo "Maven invocation failed!" 1>&2; exit 1; }
# if you just care about the first line of the version, which will be
# sufficent for pretty much every use case I can imagine, you can use
# the read builtin
[ -s "$VERSION_FILE" ] && read -r MVN_VERSION < "$VERSION_FILE"
# Otherwise, you could use cat.
# Note that this still has issues when there are leading whitespaces
# in the multiline version string
#MVN_VERSION=$( cat "$VERSION_FILE" )
printf "Maven project version: %s\n" "$MVN_VERSION"

Just for the record, it's possible to configure Maven's Simple SLF4J logging directly in the command line to output only what we need by configuring:
org.slf4j.simpleLogger.defaultLogLevel=WARN and
org.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO
as documented at http://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version
As a result, one can run simply tail -1 and get:
$ MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version | tail -1
1.0.0-SNAPSHOT
Note that this is a one-liner. MAVEN_OPTS are being rewritten only for this particular mvn execution.

I noticed some spurious Downloaded: lines coming in the output that were breaking my original assignment. Here's the filter I've settled on; hope it helps!
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n')
EDIT
Not 100% sure why, but when running this through a post-build script in Jenkins, the output was coming out as [INFO]version, e.g. [INFO]0.3.2.
I dumped the output to a file and ran it through my first filter directly from BASH, it works fine.., so again, unsure what's going on in Jenkins land.
To get it 100% in Jenkins, I've added a follow-up sed filter; here's my latest
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n' | sed -E 's/\[.*\]//g')
EDIT
One last note here.. I found out tr was still resulting in things like /r/n0.3.2 (again only when running via Jenkins). Switched to awk and the problem has gone away! My final working result
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version \
| egrep -v '^\[|Downloading:' | sed 's/[^0-9\.]//g' | awk 1 ORS=''

A simple maven only solution
mvn -q -N org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${project.version}'
And for bonus points parsed part of a version
mvn -q -N org.codehaus.mojo:build-helper-maven-plugin:3.0.0:parse-version \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}'

I've recently developed the Release Candidate Maven plugin that solves this exact problem so that you don't have to resort to any hacky shell scripts and parsing the output of the maven-help-plugin.
For example, to print the version of your Maven project to a terminal, run:
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version
which gives output similar to maven-help-plugin:
[INFO] Detected version: '1.0.0-SNAPSHOT'
1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
However, you can also specify an arbitrary output format (so that the version could be picked up from the log by a CI server such as TeamCity):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="##teamcity[setParameter name='env.PROJECT_VERSION' value='{{ version }}']"
Which results in:
[INFO] Detected version: '1.0.0-SNAPSHOT'
##teamcity[setParameter name='env.PROJECT_VERSION' value='1.0.0-SNAPSHOT']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
To save the output to a file (so that a CI server such as Jenkins could use it):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="PROJECT_VERSION={{ version }}" \
-DoutputUri="file://\${project.basedir}/version.properties"
The resulting version.properties file will look as follows:
PROJECT_VERSION=1.0.0-SNAPSHOT
On top of all the above, Release Candidate also allows you to set the version of your project (which is something you'd probably do on your CI server) based on the API version you've defined in your POM.
If you'd like to see an example of Release Candidate being used as part of the Maven lifecycle, have a look at the pom.xml of my other open-source project - Build Monitor for Jenkins.

The easy to understand all-in-one solution that outputs the maven project version, and suppresses extraneous output from [INFO] and Download messages:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['
Same thing, but split onto two lines:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version | grep -v '\['
Outputs: 4.3-SNAPSHOT
So, using your project.version in a simple bash script:
projectVersion=`mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['`
cd "target/"$projectVersion"-build"
Other solutions on this page didn't seem to combine all the tricks into one.

This worked for me, offline and without depending on mvn:
VERSION=$(grep --max-count=1 '<version>' <your_path>/pom.xml | awk -F '>' '{ print $2 }' | awk -F '<' '{ print $1 }')
echo $VERSION

I found right balance for me. After mvn package maven-archiver plugin creates target/maven-archiver/pom.properties with contents like this
version=0.0.1-SNAPSHOT
groupId=somegroup
artifactId=someArtifact
and I am using bash just to execute it
. ./target/maven-archiver/pom.properties
then
echo $version
0.0.1-SNAPSHOT
Of course this is not safe at all to execute this file, but execution can easily be converted into perl or bash script to read and set environment variable from that file.

Should be easier since this bug is fixed in maven-help-plugin 3.0.0: MPH-99 Evaluate has no output in quiet mode.

Add the following plugin to your pom.xml
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>generate-version-file</id>
<phase>prepare-package</phase>
<goals>
<goal>evaluate</goal>
</goals>
<configuration>
<expression>project.version</expression>
<output>${project.build.directory}/version.txt</output>
</configuration>
</execution>
</executions>
</plugin>
...
This will generate a target/version.txt file as a normal part of your build.
All you then need to do to get this to the shell is the following:
#!/bin/sh
value=`cat target/version.txt`
echo "$value"
#!/bin/bash
value=$(<target/version.txt)
echo "$value"

Exec plugin works without any output parsing because output can be redirected into file and injected back into the job environment via EnvInject plugin:

Either you have mvn give you the answer (as most answers suggest), or you extract the answer from the pom.xml. The only drawback of the second approach is that you can very easily extract the value of the <version/> tag, but it will be meaningful only if it's literal, that is, not a Maven property. I chose this approach anyway because:
mvn is way to verbose and I simply don't like filtering its output.
Starting mvn is very slow compared to reading the pom.xml.
I always use literal values in <version/>.
mvn-version is a zsh shell script that uses xmlstarlet to read the pom.xml and print the version of the project (if it exists) or the version of the parent project (if it exists):
$ mvn-version .
1.0.0-SNAPSHOT
The advantage is that it's way quicker than running mvn:
$ time mvn-version .
1.1.0-SNAPSHOT
mvn-version . 0.01s user 0.01s system 75% cpu 0.019 total
$ time mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
> -Dexpression=project.version
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate 4.17s user 0.21s system 240% cpu 1.823 total
The difference on my machine is greater than two orders of magnitude.

Base on the question, I use this script below to automatic increase my version number in all maven parent/submodules:
#!/usr/bin/env bash
# Advances the last number of the given version string by one.
function advance\_version () {
local v=$1
\# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=\`echo $v | sed \-e 's/\[^0-9\]\[^0-9\]\*$//'\`
local last\_num=\`echo $cleaned | sed \-e 's/\[0-9\]\*\\.//g'\`
local next\_num=$(($last\_num+1))
\# Finally replace the last number in version string with the new one.
echo $v | sed \-e "s/\[0-9\]\[0-9\]\*\\(\[^0-9\]\*\\)$/$next\_num/"
}
version=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)
new\_version=$(advance\_version $version)
mvn versions:set -DnewVersion=${new\_version} -DprocessAllModules -DgenerateBackupPoms=false

Quickest way that gets you just the text without all the trimmings
mvn help:evaluate -q -DforceStdout -D"expression=project.version"

this is an edit from above
cat pom.xml | grep "" | head -n 1 | sed -e "s/version//g" |
sed -e "s/\s*[<>/]*//g"
I tested it out on on the cmdline works well
grep "" pom.xml | head -n 1 | sed -e "s/version//g" | sed -e "s/\s*[<>/]*//g"
is another version of the same. I have a need to get the version number in Jenkins CI in k8s without mvn installed so this is most helpful
thanks all.

I need exactly this requirement during my Travis job but with multiple values.
I start with this solution but when calling multiple time this is very slow (I need 5 expresions).
I wrote a simple maven plugin to extract pom.xml's values into .sh file.
https://github.com/famaridon/ci-tools-maven-plugin
mvn com.famaridon:ci-tools-maven-plugin:0.0.1-SNAPSHOT:environment -Dexpressions=project.artifactId,project.version,project.groupId,project.build.sourceEncoding
Will produce that:
#!/usr/bin/env bash
CI_TOOLS_PROJECT_ARTIFACTID='ci-tools-maven-plugin';
CI_TOOLS_PROJECT_VERSION='0.0.1-SNAPSHOT';
CI_TOOLS_PROJECT_GROUPID='com.famaridon';
CI_TOOLS_PROJECT_BUILD_SOURCEENCODING='UTF-8';
now you can simply source the file
source .target/ci-tools-env.sh
Have fun.

One alternative would be to parse with yq (https://github.com/kislyuk/yq) like so:
cat pom.xml | xq -r '.project.version'
Notice the executable is xq not yq
To get xq, install yq like so pip install yq

In docker containers with only busybox available I use awk.
version=$(
awk '
/<dependenc/{exit}
/<parent>/{parent++};
/<version>/{
if (parent == 1) {
sub(/.*<version>/, "");
sub(/<.*/, "");
parent_version = $0;
} else {
sub(/.*<version>/, "");
sub(/<.*/, "");
version = $0;
exit
}
}
/<\/parent>/{parent--};
END {
print (version == "") ? parent_version : version
}' pom.xml
)
Notes:
If no artifact version is given parent version is printed instead.
Dependencies are required to come after artifact and parent version. (This could be overcome quite easily but I don't need it.)

mvn help:evaluate -Dexpression=project.version | sed -e 1h -e '2,3{H;g}' -e '/\[INFO\] BUILD SUCCESS/ q' -e '1,2d' -e '{N;D}' | sed -e '1q'
I'm just adding small sed filter improvement I have recently implemented to extract project.version from maven output.

Related

get mvn dependency version with cli

I'm trying to get the Version of one Artifact via cli as described here:
http://maven.apache.org/plugins/maven-help-plugin/evaluate-mojo.html
RESULT+=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -Dartifact=$GROUP_ID:$ARTIFACT_ID -q -DforceStdout)
echo "$RESULT"
The Problem is:
"Note: Should respect the Maven format, i.e. groupId:artifactId[:version]. The latest version of the artifact will be used when no version is specified."
So I always get the last possible Version as an answer.
But I need to know, which Version is used and not what could be used.
Found a way via dependency:list Plugin and grep
ARTIFACT_ID = artefactId
RESULT += $(mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:list -DincludeArtifactIds=$ARTIFACT_ID -DforceStdout -DoutputScope=false | grep $ARTIFACT_ID | sed 's/.*jar:\(.*\):.*/\1/')
echo $RESULT

How to chain multiple properties in an expression using maven help:evaluate? [duplicate]

I would like to retrieve from the command line the groupId, the artifactId & the version of a Maven project.
The proposed solution in this topic "How to get Maven project version to the bash command line" is to use the following plugin:
mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.artifactId
It works well but I can't figure out how to set, at the same time, the project.groupId, project.artifactId & project.version to the -Dexpression argument.
I would avoid launching 3 times the Maven command with a different -Dexpression argument each time...
Thks
For the moment, I retrieve data by doing the following:
local pom_groupid=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.groupId |grep -Ev '(^\[|Download\w+:)'`
local pom_artifactid=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.artifactId |grep -Ev '(^\[|Download\w+:)'`
local pom_version=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.version |grep -Ev '(^\[|Download\w+:)'`
Here's another approach that doesn't require creating a Maven plugin even though Olivier has shown that it is pretty easy to make one.
mvn -q -Dexec.executable=echo -Dexec.args='${project.groupId} ${project.artifactId} ${project.version}' --non-recursive exec:exec 2>/dev/null
Note that this is tailored to the linux environment. On windows you could probably create a batch file that prints its input or something.
One drawback of this approach is that you may have to add | grep -v "something" to the very end of the command above (after the 2>/dev/null) to filter out some text that maven prints to stdout. In my case I only had one line of text to filter that'll only appear at my company.
Credit where it is due: I adapted this info from this other StackOverflow thread.
This is the cleanest solution available:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.groupId -q -DforceStdout
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.artifactId -q -DforceStdout
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.version -q -DforceStdout
Advantages:
This works fine on all operating systems (OS X, Ubuntu, Windows etc.) and on all shells (bash, zsh etc.)
[very important] This works fine even if groupId or version is inherited from parent pom.xml.
Note that xmllint-based solutions fail when POM properties are inherited!
Zero dependency on external tools! (notice that I'm not using any echo or grep)
Alternatively, you can add this entry in your pom.xml, under plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
</plugin>
and then run commands compactly as follows:
mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout
mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
Please note:
maven-help-plugin version 3.2.0 (and above) has forceStdout option. You may replace 3.2.0 in above command with a newer version from the list of available versions of mvn-help-plugin from artifactory, if available.
Option -q suppresses verbose messages.
In bash, consider the following lines I use to get them.
It uses xmllint and some string manipulation.
GROUP_ID=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:groupId/text()' | xmllint --shell pom.xml | grep -v /`
ARTIFACT_ID=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:artifactId/text()' | xmllint --shell pom.xml | grep -v /`
VERSION=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:version/text()' | xmllint --shell pom.xml | grep -v /`
I hope this helps.
You can specify multiple expressions for the maven-help-plugin (so you only have to run it once) and then extract them from the captured output by grep'ing for the 'key' you specified:
output=$(printf \
'LOCAL_REPOSITORY=${settings.localRepository}\n'\
'GROUP_ID=${project.groupId}\n'
'ARTIFACT_ID=${project.artifactId}\n'\
'POM_VERSION=${project.version}\n0\n' \
| mvn help:evaluate --non-recursive )
localRepository=$(echo "$output" | grep '^LOCAL_REPOSITORY' | cut -d = -f 2)
groupId=$(echo "$output" | grep '^GROUP_ID' | cut -d = -f 2)
artifactId=$(echo "$output" | grep '^ARTIFACT_ID' | cut -d = -f 2)
pomVersion=$(echo "$output" | grep '^POM_VERSION' | cut -d = -f 2)
Other solutions that parse the pom.xml work for simple use cases, however they fall short if you need to access something that is either not defined in the pom.xml (settings.localRepository) or a potentially derived value (project.version).
A simpler command, derived from #Patrick's answer to get the "GAV" format:
echo '${project.groupId}:${project.artifactId}:${project.version}' | mvn -N -q -DforceStdout help:evaluate
In case of an external *.pom file to evaluate, this command may be useful:
echo '${project.groupId}:${project.artifactId}:${project.version}' | mvn -N -q -DforceStdout help:evaluate -f <path-to-pom-file>
Sometimes, we forget how easy it is to tailor Maven to our need : here is a very simple custom plugin that do one thing, concatenate groupId,artifactId and version and send it to out.
Check it out, run mvn clean install (local) or mvn clean deploy(repository) to make it available in your environment.
Then run mvn my.helper.maven.plugin:helper-maven-plugin:me or mvn helper:me (after adding <pluginGroup>my.helper.maven.plugin</pluginGroup> to your <pluginGroups> in your Maven settings.xml) to have the following line displayed on console :
my.help.me={project.groupId}:{project.artifactId}:{project.version}
To filter out everything but this line, all you have to do is running :
mvn helper:me| grep ^my.help.me=
or even simpler :
mvn -q helper.me
I prefer avoiding new dependencies where I can solve the solution easily. Using powershell:
[xml]$pomXml = Get-Content .\pom.xml
# version
Write-Host $pomXml.project.version
# groupId
Write-Host $pomXml.project.groupId
# artifactId
Write-Host $pomXml.project.artifactId
I had an issue with echo and interactiveMode false + a custom profile.. turns out you can specify all 3 (or 4 if you need the packaging) in the expression by omitting the first ${ and last } ex:
mvn -N -q -DforceStdout help:evaluate -Dexpression='project.groupId}:${project.artifactId}:${project.packaging}:${project.version' -f ./xpp3-1.1.3.4.O.pom
Or more elegantly (this will include packaging) with project.id:
-Dexpression=project.id
This is because the source code wraps the expression:
handleResponse( "${" + expression + "}", output );
Source / Credits:
https://github.com/paul-hammant/maven-plugins/blob/master/maven-help-plugin/src/main/java/org/apache/maven/plugins/help/EvaluateMojo.java
The error I got when using interactiveMode false and a profile with -P:
[ERROR] Maven is configured to NOT interact with the user for input. This Mojo requires that 'interactiveMode' in your settings file is flag to 'true'.

GitLab-CI get pom version in pipeline

I'd like to build docker image via gitlab CI with project's version as a tag:
docker build -t dockerimage:VERSION-IN-POM .
In jenkins' pipeline i'm getting the version like that:
${pom.version}
Is it possible to read the version in a similar, convenient way from gitlab CI? Or do I have to write scripts for that?
Assuming you have maven in build environment, you could use maven help plugin and grep to extract version.
VERSION=$(mvn --non-recursive help:evaluate -Dexpression=project.version | grep -v '\[.*')
echo $VERSION
This work for my variable: gitlab-ci.yml
mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q
Gitlab-CI doesn't offer such comforts, instead it offers you to do whatever you want with the shell script. It's not very hard to do it in command script. You can install xmllint (apt install libxml2-utils on Ubuntu) and then you can get it by a simple query:
xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml
So it can all be solved by these two lines:
- apt install libxml2-utils
- docker build -t dockerimage:$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml) .
Another maven command line alternative to get directly get the version information
mvn --non-recursive help:evaluate -Dexpression=project.version -q -DforceStdout
You can use sed or grep.
It's faster than using mvn --non-recursive help:evaluate ...
Get the artifactID
grep -m1 '<artifactId>' pom.xml | grep -oP '(?<=>).*(?=<)'
Get the version
grep -m1 '<version>' pom.xml | grep -oP '(?<=>).*(?=<)'
If you are using docker, some images don't have newest version of grep, so you need to use come creative solution with cut, example:
grep -m1 '<artifactId>' pom.xml |cut -d '<' -f2 |cut -d '>' -f2
You can use the below command in your .gitlab-ci.yml file :
VERSION=$(mvn --non-recursive help:evaluate -Dexpression=project.version -q -DforceStdout)
echo $VERSION
Furthermore you can get groupId and artifactId by changing Dexpression=project.version to Dexpression=project.artifactId and Dexpression=project.groupId
For more information see the maven documentation for help:evaluate.
As indicated by Ivan in his post, this worked in my script:
-RELEASE_VERSION=xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml
-echo $RELEASE_VERSION
if you know the project name, here is another approach using shell; is to cut the version from the target .jar file created under ./target directory.
Note: This will work only after successful build commands:
cd target
version=`ls <PROJECT_NAME>*.jar`
version=${version#<PROJECT_NAME>}
version=${version%.jar}
cd ..
echo $version
<PROJECT_NAME> is the name of the project (use without <> marks)
Here is a solution with the Maven help:evaluate but with a regex (see the "-E" in command) :
export VERSION=$(mvn --non-recursive help:evaluate -Dexpression=project.version | grep -E '^[0-9]+.[0-9]+.[0-9]+(-[A-Z]+)?$')
echo $VERSION
It will be able to find for example 5.0.1-SNAPHOT or only 5.0.1 or again 5.0.1-GA in the output of the Maven command.
Tested on this kind of realistic Maven output :
Downloaded from fodfin: http://your.server/artifactory/com/thoughtworks/xstream/xstream/1.4.11.1/xstream-1.4.11.1.jar (621 kB at 369 kB/s)
[INFO] No artifact parameter specified, using 'be.test.super.package:the-application:pom:5.0.1-SNAPSHOT' as project.
[INFO]
5.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15.127 s
[INFO] Finished at: 2022-10-06T14:40:29+02:00
[INFO] ------------------------------------------------------------------------
I ended up using
vars:
stage: prepare
script:
- echo "POM_VERSION=$(mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q)" > vars.env
- echo "POM_NAME=$(mvn -Dexec.executable='echo' -Dexec.args='${project.name}' --non-recursive exec:exec -q)" >> vars.env
- echo "POM_GROUP_ID=$(mvn -Dexec.executable='echo' -Dexec.args='${project.groupId}' --non-recursive exec:exec -q)" >> vars.env
- echo "POM_ARTIFACT_ID=$(mvn -Dexec.executable='echo' -Dexec.args='${project.artifactId}' --non-recursive exec:exec -q)" >> vars.env
artifacts:
reports:
dotenv: vars.env
jobname:
stage: stage
before_script:
- export "MAVEN_ID=$(mvn help:evaluate -Dexpression=project.id -q -DforceStdout)"
- >
IFS=: read -r MAVEN_GROUPID MAVEN_ARTIFACTID MAVEN_PACKAGING MAVEN_VERSION <<< ${MAVEN_ID}
script:
- >
echo -e "groupId: ${MAVEN_GROUPID}\nartifactId: ${MAVEN_ARTIFACTID}\nversion: ${MAVEN_VERSION}\npackaging: ${MAVEN_PACKAGING}"
mvn help:evaluate -Dexpression=project.id -q -DforceStdout prints artifact identification information in the following format: com.group.id:artifactid:packaging:version
MAVEN_ID variable is parsed using IFS based on the colon (:) as a separator to get common maven variables like artifactId, groupId, version and packaging (explanation)
later these variables can be used in the code, for example for echoing values
this way maven is executed only 1 time to get the information, which can speed up pipeline
IFS is a bash feature, thus corresponding GitLab runner should have bash installed

Is there any plugin available for displaying the version of a Maven project? [duplicate]

Previous I issued a question on how to change Maven project vesion from command line which lead me to a new issue.
Previously I was able to get the version number since the version was stored as a property that was easy to grep and parse from the command line (bash). Now that the pom.xml <version> element is used for this, it no longer is unique since all the dependencies and maybe some others too use this. I think there is no way to get the current version number with a bash script without external tools for parsing XML or some very context-aware sed command.
The most clean solution in my opinion would be for Maven to hand out this version information. I was thinking of writing a custom maven plugin for retrieving different properties but I thought I'd ask here first.
So, is there any easy way to get the value of ${project.version} to the command line?
Solution
I had to cd to the directory manually but that can be done easily. In my bash script I have:
version=`cd $project_loc && mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | sed -n -e '/^\[.*\]/ !{ /^[0-9]/ { p; q } }'`
Which gives me the current version that I can then advance. Grepping might be simpler but I thought I'd like as robust as possible, so I'm satisfied with the first line that starts with a number and try to handle this as a version number.
# Advances the last number of the given version string by one.
function advance_version () {
local v=$1
# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=`echo $v | sed -e 's/[^0-9][^0-9]*$//'`
local last_num=`echo $cleaned | sed -e 's/[0-9]*\.//g'`
local next_num=$(($last_num+1))
# Finally replace the last number in version string with the new one.
echo $v | sed -e "s/[0-9][0-9]*\([^0-9]*\)$/$next_num/"
}
And I use this by simply calling:
new_version=$(advance_version $version)
The Maven Help Plugin is somehow already proposing something for this:
help:evaluate evaluates Maven expressions given by the user in an interactive mode.
Here is how you would invoke it on the command line to get the ${project.version}:
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version
As noted in the comments by Seb T, to only print the version without the maven INFO logs, additionally use -q -DforceStdout:
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
Tom's solution with the Exec Maven Plugin is much better, but still more complicated than it needs to be. For me it's as simple as:
MVN_VERSION=$(mvn -q \
-Dexec.executable=echo \
-Dexec.args='${project.version}' \
--non-recursive \
exec:exec)
After doing some research I found the following:
Maven has been blamed because integration with DevOps tools is not easy due to the fact that it does not follow some good practices regarding CLI tools, i.e:
http://www.faqs.org/docs/artu/ch01s06.html (not available anymore)
"The Unix Way"
(ii) Expect the output of every program to become the input of another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.
What does it actually mean?
Your output should be:
"grepable": (One "record" per line)
"cutable": (Delimited "fields")
exit codes: 0 for success, nonzero for failure.
messaging (stderr) vs. output (stdout)
(ref: Make awesome command line apps with ruby by Dave Copeland Jan 18, 2012 https://youtu.be/1ILEw6Qca3U?t=372)
Honesty I think Dave Copeland was right when he said that maven does't play fairly with others. So I decided to give a look to maven's source code as well as to maven-help-plugin's source code as well. It seems that they have fixed a little bit the maven's -q switch (I was using version 3.5.3 at that time), so now if you pass it, you won't get all the annoying non-sense logging stuff that prevents maven from being used within automated scripts. So you should be able to use something like this:
mvn help:evaluate -Dexpression=project.version -q
The problem is that this command prints nothing because by default the help plugin outputs through the logger which has been silenced by the -q switch. (latest available version of the plugin at that time was 3.1.0 released on June, 3rd 2018)
Karl Heinz Marbaise (https://github.com/khmarbaise) fixed it by adding an optional parameter that allows you to call it in the following way:
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
The commit description is available at: (https://github.com/apache/maven-help-plugin/commit/316656983d780c04031bbadd97d4ab245c84d014)
Again, you should always verify the exit code of the command and redirect all stderr to /dev/null on unix.
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['
This is the cleanest solution there is:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.version -q -DforceStdout
Advantages:
This works fine on all operating systems and all shells.
No need for any external tools!
[important] This works even if project version is inherited from parent pom.xml
Note:
maven-help-plugin version 3.2.0 (and above) has forceStdout option. You may replace 3.2.0 in above command with a newer version from the list of available versions of mvn-help-plugin from artifactory, if available.
Option -q suppresses verbose messages ([INFO], [WARN] etc.)
Alternatively, you can add this entry in your pom.xml, under plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
</plugin>
and then run above command compactly as follows:
mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout
If you want to fetch groupId and artifactId as well, check this answer.
Why not use the right tool for the job? Using xpath syntax is the best approach to retrieving the version number, since it is the intended method of accessing a XML data structure. The expression below is traversing the pom using the "local name" of the elements, in other words ignoring namespace declarations which may or may not be present in the xml.
xmllint --xpath "//*[local-name()='project']/*[local-name()='version']/text()" pom.xml
This will avoid the need for grepping off log entries from the output:
mvn -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive exec:exec -q
python -c "import xml.etree.ElementTree as ET; \
print(ET.parse(open('pom.xml')).getroot().find( \
'{http://maven.apache.org/POM/4.0.0}version').text)"
As long as you have python 2.5 or greater, this should work. If you have a lower version than that, install python-lxml and change the import to lxml.etree. This method is quick and doesn't require downloading any extra plugins. It also works on malformed pom.xml files that don't validate with xmllint, like the ones I need to parse. Tested on Mac and Linux.
I kept running into side cases when using some of the other answers here, so here's yet another alternative.
version=$(printf 'VER\t${project.version}' | mvn help:evaluate | grep '^VER' | cut -f2)
There is also one option without need Maven:
grep -oPm1 "(?<=<version>)[^<]+" "pom.xml"
This is by far the easiest bash cut and paste solution:
VERSION=$(mvn exec:exec -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive -q)
echo $VERSION
it echoes
1.4
If you don't mind to write the version into a temporary file, there is another solution (without grep/sed) that works well for me. (EDIT: see rjrjr's answer for a much simpler solution without any temporary file hassle)
I use the Exec Maven Plugin along with the echo binary. In contrast to the Maven Help Plugin, the Exec Plugin allows output redirection into a file, which can be used to bypass grep/sed, and makes it even possible to parse strange things like multiline version strings (with CDATA block in version tag), at least to a certain extent.
#!/usr/bin/env sh
MVN_VERSION=""
VERSION_FILE=$( mktemp mvn_project_version_XXXXX )
trap "rm -f -- \"$VERSION_FILE\"" INT EXIT
mvn -Dexec.executable="echo" \
-Dexec.args='${project.version}' \
-Dexec.outputFile="$VERSION_FILE" \
--non-recursive \
--batch-mode \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec > /dev/null 2>&1 ||
{ echo "Maven invocation failed!" 1>&2; exit 1; }
# if you just care about the first line of the version, which will be
# sufficent for pretty much every use case I can imagine, you can use
# the read builtin
[ -s "$VERSION_FILE" ] && read -r MVN_VERSION < "$VERSION_FILE"
# Otherwise, you could use cat.
# Note that this still has issues when there are leading whitespaces
# in the multiline version string
#MVN_VERSION=$( cat "$VERSION_FILE" )
printf "Maven project version: %s\n" "$MVN_VERSION"
Just for the record, it's possible to configure Maven's Simple SLF4J logging directly in the command line to output only what we need by configuring:
org.slf4j.simpleLogger.defaultLogLevel=WARN and
org.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO
as documented at http://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version
As a result, one can run simply tail -1 and get:
$ MAVEN_OPTS="\
-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.plugins.help=INFO" \
mvn help:evaluate -o -Dexpression=project.version | tail -1
1.0.0-SNAPSHOT
Note that this is a one-liner. MAVEN_OPTS are being rewritten only for this particular mvn execution.
I noticed some spurious Downloaded: lines coming in the output that were breaking my original assignment. Here's the filter I've settled on; hope it helps!
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n')
EDIT
Not 100% sure why, but when running this through a post-build script in Jenkins, the output was coming out as [INFO]version, e.g. [INFO]0.3.2.
I dumped the output to a file and ran it through my first filter directly from BASH, it works fine.., so again, unsure what's going on in Jenkins land.
To get it 100% in Jenkins, I've added a follow-up sed filter; here's my latest
version=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v '^\[|Downloading:' | tr -d ' \n' | sed -E 's/\[.*\]//g')
EDIT
One last note here.. I found out tr was still resulting in things like /r/n0.3.2 (again only when running via Jenkins). Switched to awk and the problem has gone away! My final working result
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version \
| egrep -v '^\[|Downloading:' | sed 's/[^0-9\.]//g' | awk 1 ORS=''
A simple maven only solution
mvn -q -N org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${project.version}'
And for bonus points parsed part of a version
mvn -q -N org.codehaus.mojo:build-helper-maven-plugin:3.0.0:parse-version \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-Dexec.executable='echo' \
-Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}'
I've recently developed the Release Candidate Maven plugin that solves this exact problem so that you don't have to resort to any hacky shell scripts and parsing the output of the maven-help-plugin.
For example, to print the version of your Maven project to a terminal, run:
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version
which gives output similar to maven-help-plugin:
[INFO] Detected version: '1.0.0-SNAPSHOT'
1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
However, you can also specify an arbitrary output format (so that the version could be picked up from the log by a CI server such as TeamCity):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="##teamcity[setParameter name='env.PROJECT_VERSION' value='{{ version }}']"
Which results in:
[INFO] Detected version: '1.0.0-SNAPSHOT'
##teamcity[setParameter name='env.PROJECT_VERSION' value='1.0.0-SNAPSHOT']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
To save the output to a file (so that a CI server such as Jenkins could use it):
mvn com.smartcodeltd:release-candidate-maven-plugin:LATEST:version \
-DoutputTemplate="PROJECT_VERSION={{ version }}" \
-DoutputUri="file://\${project.basedir}/version.properties"
The resulting version.properties file will look as follows:
PROJECT_VERSION=1.0.0-SNAPSHOT
On top of all the above, Release Candidate also allows you to set the version of your project (which is something you'd probably do on your CI server) based on the API version you've defined in your POM.
If you'd like to see an example of Release Candidate being used as part of the Maven lifecycle, have a look at the pom.xml of my other open-source project - Build Monitor for Jenkins.
The easy to understand all-in-one solution that outputs the maven project version, and suppresses extraneous output from [INFO] and Download messages:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['
Same thing, but split onto two lines:
mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version | grep -v '\['
Outputs: 4.3-SNAPSHOT
So, using your project.version in a simple bash script:
projectVersion=`mvn -o org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\['`
cd "target/"$projectVersion"-build"
Other solutions on this page didn't seem to combine all the tricks into one.
This worked for me, offline and without depending on mvn:
VERSION=$(grep --max-count=1 '<version>' <your_path>/pom.xml | awk -F '>' '{ print $2 }' | awk -F '<' '{ print $1 }')
echo $VERSION
I found right balance for me. After mvn package maven-archiver plugin creates target/maven-archiver/pom.properties with contents like this
version=0.0.1-SNAPSHOT
groupId=somegroup
artifactId=someArtifact
and I am using bash just to execute it
. ./target/maven-archiver/pom.properties
then
echo $version
0.0.1-SNAPSHOT
Of course this is not safe at all to execute this file, but execution can easily be converted into perl or bash script to read and set environment variable from that file.
Should be easier since this bug is fixed in maven-help-plugin 3.0.0: MPH-99 Evaluate has no output in quiet mode.
Add the following plugin to your pom.xml
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>generate-version-file</id>
<phase>prepare-package</phase>
<goals>
<goal>evaluate</goal>
</goals>
<configuration>
<expression>project.version</expression>
<output>${project.build.directory}/version.txt</output>
</configuration>
</execution>
</executions>
</plugin>
...
This will generate a target/version.txt file as a normal part of your build.
All you then need to do to get this to the shell is the following:
#!/bin/sh
value=`cat target/version.txt`
echo "$value"
#!/bin/bash
value=$(<target/version.txt)
echo "$value"
Exec plugin works without any output parsing because output can be redirected into file and injected back into the job environment via EnvInject plugin:
Either you have mvn give you the answer (as most answers suggest), or you extract the answer from the pom.xml. The only drawback of the second approach is that you can very easily extract the value of the <version/> tag, but it will be meaningful only if it's literal, that is, not a Maven property. I chose this approach anyway because:
mvn is way to verbose and I simply don't like filtering its output.
Starting mvn is very slow compared to reading the pom.xml.
I always use literal values in <version/>.
mvn-version is a zsh shell script that uses xmlstarlet to read the pom.xml and print the version of the project (if it exists) or the version of the parent project (if it exists):
$ mvn-version .
1.0.0-SNAPSHOT
The advantage is that it's way quicker than running mvn:
$ time mvn-version .
1.1.0-SNAPSHOT
mvn-version . 0.01s user 0.01s system 75% cpu 0.019 total
$ time mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
> -Dexpression=project.version
mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate 4.17s user 0.21s system 240% cpu 1.823 total
The difference on my machine is greater than two orders of magnitude.
Base on the question, I use this script below to automatic increase my version number in all maven parent/submodules:
#!/usr/bin/env bash
# Advances the last number of the given version string by one.
function advance\_version () {
local v=$1
\# Get the last number. First remove any suffixes (such as '-SNAPSHOT').
local cleaned=\`echo $v | sed \-e 's/\[^0-9\]\[^0-9\]\*$//'\`
local last\_num=\`echo $cleaned | sed \-e 's/\[0-9\]\*\\.//g'\`
local next\_num=$(($last\_num+1))
\# Finally replace the last number in version string with the new one.
echo $v | sed \-e "s/\[0-9\]\[0-9\]\*\\(\[^0-9\]\*\\)$/$next\_num/"
}
version=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)
new\_version=$(advance\_version $version)
mvn versions:set -DnewVersion=${new\_version} -DprocessAllModules -DgenerateBackupPoms=false
Quickest way that gets you just the text without all the trimmings
mvn help:evaluate -q -DforceStdout -D"expression=project.version"
this is an edit from above
cat pom.xml | grep "" | head -n 1 | sed -e "s/version//g" |
sed -e "s/\s*[<>/]*//g"
I tested it out on on the cmdline works well
grep "" pom.xml | head -n 1 | sed -e "s/version//g" | sed -e "s/\s*[<>/]*//g"
is another version of the same. I have a need to get the version number in Jenkins CI in k8s without mvn installed so this is most helpful
thanks all.
I need exactly this requirement during my Travis job but with multiple values.
I start with this solution but when calling multiple time this is very slow (I need 5 expresions).
I wrote a simple maven plugin to extract pom.xml's values into .sh file.
https://github.com/famaridon/ci-tools-maven-plugin
mvn com.famaridon:ci-tools-maven-plugin:0.0.1-SNAPSHOT:environment -Dexpressions=project.artifactId,project.version,project.groupId,project.build.sourceEncoding
Will produce that:
#!/usr/bin/env bash
CI_TOOLS_PROJECT_ARTIFACTID='ci-tools-maven-plugin';
CI_TOOLS_PROJECT_VERSION='0.0.1-SNAPSHOT';
CI_TOOLS_PROJECT_GROUPID='com.famaridon';
CI_TOOLS_PROJECT_BUILD_SOURCEENCODING='UTF-8';
now you can simply source the file
source .target/ci-tools-env.sh
Have fun.
One alternative would be to parse with yq (https://github.com/kislyuk/yq) like so:
cat pom.xml | xq -r '.project.version'
Notice the executable is xq not yq
To get xq, install yq like so pip install yq
In docker containers with only busybox available I use awk.
version=$(
awk '
/<dependenc/{exit}
/<parent>/{parent++};
/<version>/{
if (parent == 1) {
sub(/.*<version>/, "");
sub(/<.*/, "");
parent_version = $0;
} else {
sub(/.*<version>/, "");
sub(/<.*/, "");
version = $0;
exit
}
}
/<\/parent>/{parent--};
END {
print (version == "") ? parent_version : version
}' pom.xml
)
Notes:
If no artifact version is given parent version is printed instead.
Dependencies are required to come after artifact and parent version. (This could be overcome quite easily but I don't need it.)
mvn help:evaluate -Dexpression=project.version | sed -e 1h -e '2,3{H;g}' -e '/\[INFO\] BUILD SUCCESS/ q' -e '1,2d' -e '{N;D}' | sed -e '1q'
I'm just adding small sed filter improvement I have recently implemented to extract project.version from maven output.

How to get Maven groupId, artifactId & project version to the command line

I would like to retrieve from the command line the groupId, the artifactId & the version of a Maven project.
The proposed solution in this topic "How to get Maven project version to the bash command line" is to use the following plugin:
mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.artifactId
It works well but I can't figure out how to set, at the same time, the project.groupId, project.artifactId & project.version to the -Dexpression argument.
I would avoid launching 3 times the Maven command with a different -Dexpression argument each time...
Thks
For the moment, I retrieve data by doing the following:
local pom_groupid=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.groupId |grep -Ev '(^\[|Download\w+:)'`
local pom_artifactid=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.artifactId |grep -Ev '(^\[|Download\w+:)'`
local pom_version=`mvn org.apache.maven.plugins:maven-help-plugin:2.2:evaluate -Dexpression=project.version |grep -Ev '(^\[|Download\w+:)'`
Here's another approach that doesn't require creating a Maven plugin even though Olivier has shown that it is pretty easy to make one.
mvn -q -Dexec.executable=echo -Dexec.args='${project.groupId} ${project.artifactId} ${project.version}' --non-recursive exec:exec 2>/dev/null
Note that this is tailored to the linux environment. On windows you could probably create a batch file that prints its input or something.
One drawback of this approach is that you may have to add | grep -v "something" to the very end of the command above (after the 2>/dev/null) to filter out some text that maven prints to stdout. In my case I only had one line of text to filter that'll only appear at my company.
Credit where it is due: I adapted this info from this other StackOverflow thread.
This is the cleanest solution available:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.groupId -q -DforceStdout
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.artifactId -q -DforceStdout
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \
-Dexpression=project.version -q -DforceStdout
Advantages:
This works fine on all operating systems (OS X, Ubuntu, Windows etc.) and on all shells (bash, zsh etc.)
[very important] This works fine even if groupId or version is inherited from parent pom.xml.
Note that xmllint-based solutions fail when POM properties are inherited!
Zero dependency on external tools! (notice that I'm not using any echo or grep)
Alternatively, you can add this entry in your pom.xml, under plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
</plugin>
and then run commands compactly as follows:
mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout
mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout
mvn help:evaluate -Dexpression=project.version -q -DforceStdout
Please note:
maven-help-plugin version 3.2.0 (and above) has forceStdout option. You may replace 3.2.0 in above command with a newer version from the list of available versions of mvn-help-plugin from artifactory, if available.
Option -q suppresses verbose messages.
A simpler command, derived from #Patrick's answer to get the "GAV" format:
echo '${project.groupId}:${project.artifactId}:${project.version}' | mvn -N -q -DforceStdout help:evaluate
In case of an external *.pom file to evaluate, this command may be useful:
echo '${project.groupId}:${project.artifactId}:${project.version}' | mvn -N -q -DforceStdout help:evaluate -f <path-to-pom-file>
In bash, consider the following lines I use to get them.
It uses xmllint and some string manipulation.
GROUP_ID=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:groupId/text()' | xmllint --shell pom.xml | grep -v /`
ARTIFACT_ID=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:artifactId/text()' | xmllint --shell pom.xml | grep -v /`
VERSION=`echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:version/text()' | xmllint --shell pom.xml | grep -v /`
I hope this helps.
You can specify multiple expressions for the maven-help-plugin (so you only have to run it once) and then extract them from the captured output by grep'ing for the 'key' you specified:
output=$(printf \
'LOCAL_REPOSITORY=${settings.localRepository}\n'\
'GROUP_ID=${project.groupId}\n'
'ARTIFACT_ID=${project.artifactId}\n'\
'POM_VERSION=${project.version}\n0\n' \
| mvn help:evaluate --non-recursive )
localRepository=$(echo "$output" | grep '^LOCAL_REPOSITORY' | cut -d = -f 2)
groupId=$(echo "$output" | grep '^GROUP_ID' | cut -d = -f 2)
artifactId=$(echo "$output" | grep '^ARTIFACT_ID' | cut -d = -f 2)
pomVersion=$(echo "$output" | grep '^POM_VERSION' | cut -d = -f 2)
Other solutions that parse the pom.xml work for simple use cases, however they fall short if you need to access something that is either not defined in the pom.xml (settings.localRepository) or a potentially derived value (project.version).
Sometimes, we forget how easy it is to tailor Maven to our need : here is a very simple custom plugin that do one thing, concatenate groupId,artifactId and version and send it to out.
Check it out, run mvn clean install (local) or mvn clean deploy(repository) to make it available in your environment.
Then run mvn my.helper.maven.plugin:helper-maven-plugin:me or mvn helper:me (after adding <pluginGroup>my.helper.maven.plugin</pluginGroup> to your <pluginGroups> in your Maven settings.xml) to have the following line displayed on console :
my.help.me={project.groupId}:{project.artifactId}:{project.version}
To filter out everything but this line, all you have to do is running :
mvn helper:me| grep ^my.help.me=
or even simpler :
mvn -q helper.me
I prefer avoiding new dependencies where I can solve the solution easily. Using powershell:
[xml]$pomXml = Get-Content .\pom.xml
# version
Write-Host $pomXml.project.version
# groupId
Write-Host $pomXml.project.groupId
# artifactId
Write-Host $pomXml.project.artifactId
I had an issue with echo and interactiveMode false + a custom profile.. turns out you can specify all 3 (or 4 if you need the packaging) in the expression by omitting the first ${ and last } ex:
mvn -N -q -DforceStdout help:evaluate -Dexpression='project.groupId}:${project.artifactId}:${project.packaging}:${project.version' -f ./xpp3-1.1.3.4.O.pom
Or more elegantly (this will include packaging) with project.id:
-Dexpression=project.id
This is because the source code wraps the expression:
handleResponse( "${" + expression + "}", output );
Source / Credits:
https://github.com/paul-hammant/maven-plugins/blob/master/maven-help-plugin/src/main/java/org/apache/maven/plugins/help/EvaluateMojo.java
The error I got when using interactiveMode false and a profile with -P:
[ERROR] Maven is configured to NOT interact with the user for input. This Mojo requires that 'interactiveMode' in your settings file is flag to 'true'.

Resources