How to set project version in maven at build time?
Solution 1
With Maven you can set the version at build time with
mvn versions:set -DnewVersion=${bamboo.inject.version}
as @vatbub already commented in your question.
In addition to this i wrote a Shell script that can be used in build pipeline to generate the version according to the maven project version and add the build number from the build server.
https://gist.github.com/StefanHeimberg/c19d7665e8df087845c036fe8b88c4f2
The Script reads the maven project version, add a the build number and writes a text file with all the new numbers that can be used.
The next step is to inject this text file in the Build Pipeline and call the versions plugin as stated above
pom.xml:
something like
<project>
<groupId>ch.stefanheimberg.example</groupId>
<artifactId>your-awesome-app</artifactId>
<version>5.1.2-SNAPSHOT</version>
</project>
or
<project>
<groupId>ch.stefanheimberg.example</groupId>
<artifactId>your-awesome-app</artifactId>
<version>5.1-SNAPSHOT</version>
</project>
Step 1:
./generate_version_txt.sh ${bamboo.buildNumber}
Step 2:
Inject generated version.txt in the build system that all the properties can be used in all tasks / plugins, etc...
In my case Bamboo CI ready the version.txt file and declares the content of the file as environment variables under the bamboo.inject.
prefix.
For example ${bamboo.inject.long_version}
Step 3:
Update Maven Project version
mvn versions:set -DnewVersion=${bamboo.inject.version}
Step 4:
Run Maven Build
mvn clean verify
Step 5:
Run Docker build
for example use it also as docker tag version. etc...
docker build --build-arg version=${bamboo.inject.version} --tag your-awesome-app:${bamboo.inject.version} .
Example Dockerfile:
FROM jboss/wildlfy
ARG version
ADD target/your-awesome-app-${version}.war /opt/jboss/wildfly/standalone/deployments/
I know that can be a problem / not possible in your case with the groovy script. but perhaps it is an other view at your problem. and possibly also another solution for it.
(sorry for my english. but i hope it is understandable what i mean)
Solution 2
I ran into a similar problem and ended up using the maven flatten plugin to ensure that all variables are removed from the POMs before being deployed. This remove all references to the string ${revision} and replace by the actual value at build time, without interfering with the original POMs.
Related videos on Youtube
xbmono
Updated on June 04, 2022Comments
-
xbmono almost 2 years
I am trying to implement semantic versioning in our project. I tested maven semver plugin but that didn't help me so please don't ask me why. I finally ended up using maven groovy. It works like a charm, however, when I install or deploy the maven project the version in repository is the variable name.
This is despite the fact that all the artefacts and jar files are packaged with correct version.
So please look at my pom.xml
<?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> <groupId>com.mytest.test</groupId> <artifactId>test-tag</artifactId> <version>${revision}</version> <description>Test</description> <properties> <ChangeType>TO_BE_SET</ChangeType> </properties> <build> <plugins> <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>gmaven-plugin</artifactId> <version>1.5</version> <executions> <execution> <phase>validate</phase> <goals> <goal>execute</goal> </goals> <configuration> <providerSelection>2.0</providerSelection> <properties> <script>git describe --abbrev=0 --tags</script> </properties> <source> def tagIt = 'git tag -a vXXXX -m "Auto tagged"' def changeType = project.properties.ChangeType def command = project.properties.script def process = command.execute() process.waitFor() def describe = process.in.text.trim() println "Setting revision to: " + describe if(!describe.startsWith("v")) { describe = "1.0.1" } else { describe = describe.substring(1) } project.properties.setProperty('revision', describe) </source> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <id>default-compile</id> <phase>none</phase> </execution> <execution> <id>default-testCompile</id> <phase>none</phase> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>default-testResources</id> <phase>none</phase> </execution> </executions> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>default-jar</id> <phase>package</phase> </execution> </executions> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <executions> <execution> <id>default-test</id> <phase>none</phase> </execution> </executions> </plugin> </plugins> </build> </project>
the version is ${revision} a variable name that is being set in groovy script. What groovy code does is getting the last tag from GIT and and then set it to the property 'revision'.
The final jar file has the correct version extracted but when installed into repository, the folder name and jar name are like:
m2\repository\com\mytest\test\test-tag\${revision}\test-tag-${revision}.jar
I tried to default 'revision' to a value using:
<properties> <revision>1.0.1</revision> </properties>
but then groovy code setting the value has no effect.
I also tried different phase for the maven groovy plugin, no luck. Have I missed anything? Can anyone please help me on this?
I'd like to mention that as vatbub and StefanHeimberg mentioned I can use versions:set to set the version but this requires me to do an extra commit to GIT which I am trying to avoid, wondering if I can achieve this by writing a maven plugin instead?
-
vatbub about 6 yearsDid you try the versions maven plugin? It has a
set
goal which can modify the project version. (more info) However, afaik, maven parses the pom and changes which are made to the pom during the build are only taken into account in subsequent builds. In that case, you would need to invoke versions:set and then call maven a 2nd time to perform the actual build. -
xbmono about 6 years@vatbub thanks for prompt reply. The groovy code determines the version so I need to execute the groovy-maven-plugin and then get the output and then run versions:set and then later mvn install. Not sure how I can do this!
-
vatbub about 6 yearsAs I said, Maven is terribly bad at handling changes to the pom that occur during the build. I guess the best solution is to create a lightweight command line tool that just outputs the desired version to the console and pipe that output to
versions:set
-
vatbub about 6 yearsBut you probably won't get around calling maven twice
-
xbmono almost 6 yearsI ended up using versions:set as you said. Actually I created a new plugin off versions:set and customised it in order to get latest tags and other information and then set version automatically
-
Franklin Yu about 5 yearsNot something OP wants, but this is possible with Gradle.
-
-
xbmono about 6 yearsThanks. The thing is I can do the same thing with groovy. I can write the version into a file and use it in versions:set. But the problem with this, you will have an extra commit in GIT repository for changing the Pom file and I am trying to avoid that, otherwise this is the same thing that maven release plugin does. By the way, it wasn’t me who voted down, someone else did. I’ll wait for more answers to see if anyone has come up with a better solution
-
StefanHeimberg about 6 yearsvote down ist not a problem... thats how the community works. but i would be happy to know WHY someone voted down. Some constructive Feedback would be appriciated. I know my answer was not THE answer to the Problem but possibly another way to solve this
-
Emdadul Sawon over 2 yearsIt works fine if current parent do not have any other parent.
-
Max Cascone about 2 yearsThe
versions:set
works like a charm! Just what i needed! Thank you!