How to set project version in maven at build time?

12,985

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.

Share:
12,985

Related videos on Youtube

xbmono
Author by

xbmono

Updated on June 04, 2022

Comments

  • xbmono
    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
      vatbub about 6 years
      Did 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
      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
      vatbub about 6 years
      As 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
      vatbub about 6 years
      But you probably won't get around calling maven twice
    • xbmono
      xbmono almost 6 years
      I 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
      Franklin Yu about 5 years
      Not something OP wants, but this is possible with Gradle.
  • xbmono
    xbmono about 6 years
    Thanks. 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
    StefanHeimberg about 6 years
    vote 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
    Emdadul Sawon over 2 years
    It works fine if current parent do not have any other parent.
  • Max Cascone
    Max Cascone about 2 years
    The versions:set works like a charm! Just what i needed! Thank you!