Maven Release Plugin use in Jenkins Pipeline

29,122

Solution 1

Thanks to @Daniel Omoto comment, I found out that Jenkins provides option for GIT polling. One is exactly what I needed (and the provided example is for maven-release-plugin!):

GIT poll screenshot

Solution 2

IMHO with the advent of git and pull requests, I don't think using maven-release-plugin or maven-version-plugin with a Jenkins pipeline is a good idea.

Using Multibranch Pipeline with the versioning technique mentioned here is more in line with continuous delivery: https://axelfontaine.com/blog/dead-burried.html

Using the versioning technique above, the pom.xml now looks like this:

<project>
    ...
    <version>${revision}</version>

    <properties>
        <!-- Sane default when no revision property is passed in from the commandline -->
        <revision>0-SNAPSHOT</revision>
    </properties>

    <scm>
        <connection>scm:git:your-git-repo-url</connection>
    </scm>

    <distributionManagement>
        <repository>
            <id>artifact-repository</id>
            <url>your-artifact-repo-url</url>
        </repository>
    </distributionManagement>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-scm-plugin</artifactId>
                <version>1.9.5</version>
                <configuration>
                   <tag>${project.artifactId}-${project.version}</tag>
                </configuration>
            </plugin>
        </plugins>
    </build>
    ...
</project>

You can now produce releases on your Jenkins server very easily by configuring a Multibranch Pipeline with a Jenkinsfile to build on all branches and deploy only from master branch:

pipeline {
  agent any
  environment {
    REVISION = "0.0.${env.BUILD_ID}"
  }
  triggers {
    pollSCM('')
  }
  options {
    disableConcurrentBuilds()
    buildDiscarder(logRotator(numToKeepStr: '30'))
  }
  tools {
    maven '3.5.2'
    jdk 'jdk8'
  }
  stages {
    stage ('Initialize') {
      steps {
        sh '''
          echo "PATH = ${PATH}"
          echo "M2_HOME = ${M2_HOME}"
        '''
      }
    }
    stage ('Build') {
      steps {
        sh 'mvn clean package'
      }
    }
    stage ('Deploy') {
      when {
        branch 'master'
      }
      steps {
        script {
          currentBuild.displayName = "${REVISION}"
        }
        sh 'mvn deploy scm:tag -Drevision=${REVISION}'
      }
    }
  }
} 

See https://jenkins.io/blog/2017/02/07/declarative-maven-project/#set-up on how to configure a Multibranch Pipeline.

With this technique you develop only on non-master branches. Then create a pull request to merge your changes back to master branch. This should then deploy your artifact automatically to your artifact repository.


Addendum

When publishing to a Maven repository using the above method, the pom.xml will not have the proper version. To get Maven to publish the proper version, use the flatten-maven-plugin: http://www.mojohaus.org/flatten-maven-plugin/usage.html.

Also, check out: https://maven.apache.org/maven-ci-friendly.html

Solution 3

In case somebody has the same problem with the loop or that subsequent builds get triggered BUT has a Trigger who starts the jenkins pipeline on every push to the repository (Instead of polling).

Here is who I did it: I checked if the last commit contains "[maven-release-plugin]" in the comment.

Code in jenkinsfile:

def lastCommit = sh returnStdout: true, script: 'git log -1 --pretty=%B'

if (lastCommit.contains("[maven-release-plugin]")){
            sh "echo  Maven release detected"  //dont trigger build

        } else {
            sh "echo Last commit is not from maven release plugin" //do build steps 
            <..build Job...>
        }

Solution 4

This is is what we put as a first stage in our pipeline:

stage('Check commit message') {
     when { changelog '.*\\[maven-release-plugin\\].*' }
     steps {
       script {
          pom = readMavenPom file: 'pom.xml'
          currentBuild.displayName = pom.version
          currentBuild.result = 'NOT_BUILT'
       }
       error('Skipping release build')
     }
}

You will need to install https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/ plugin to read maven pom, or just put a fixed description for the skipped build. The build following the release will have grey colour.

Share:
29,122

Related videos on Youtube

frinux
Author by

frinux

Updated on January 17, 2020

Comments

  • frinux
    frinux over 4 years

    I'm using Jenkins Pipeline to automatically build and deploy my Java apps. I also use maven-release-plugin to perform Maven deploy to Artifactory.

    The problem is my Jenkinsfile (or Jenkins Pipeline Configuration) :

    1. We commit a version 0.1.00-SNAPSHOT on release branch
    2. Jenkins Pipeline get the code, and perform maven release
    3. Maven Release changes the version to 0.1.00
    4. Maven Release tags GIT branch, commit and deploy the artifact
    5. Maven Release changes the version to 0.2.00-SNAPSHOT and commit
    6. Jenkins Pipeline detect a change in GIT, so triggers a new build

    You understood that the last step creates an infinite loop, even if there is no useful commit.

    Here is the interesting part of my Jenkinsfile :

    sshagent([git_credential]) {
        sh "${maven_bin} --settings ${maven_settings} -DreleaseVersion=${release_version} -DdevelopmentVersion=${development_version} release:prepare release:perform -B"
    }
    

    How can I break the loop (avoid Jenkins to trigger new build when Maven commits on GIT)?

    Thanks

    • ivoruJavaBoy
      ivoruJavaBoy over 7 years
      Sorry i'm not getting it, you want to perform a build every changes, and this is common, but why every commit you perform a release too? I think the problem is that the build triggered by the commit should not do also a release.. In my opinion, the job triggered should be the build one, the release job should not be triggered automatically.. the first kind of job wont have any loop because a simple maven build does not commit anything, the release one should not be triggered by a commit, as itself make a last commit to update the dev version...creating a loop
    • frinux
      frinux over 7 years
      The aim is to automatically perform a maven release, when something is pushed on the "release" branch. I'm already triggering build on each "master" branch to perform unit test. It could be called continuous deployment if you wish.
    • ivoruJavaBoy
      ivoruJavaBoy over 7 years
      My fault, i missed when you was referring to the release branches..let me think about it, sounds intersting :)
    • ivoruJavaBoy
      ivoruJavaBoy over 7 years
      I've some ideas: can you avoid the pom from the change to trigger the release? it should fix the problem as for my assumptions the only commit makes the plugin on the branches is the updated DEV version, also you can create a file with the pipeline, taking note of the revision commited by maven and check for it before every maven release, if the revision is the same one, you want trigger again the release, if not you would trigger.. how does it sound?
    • frinux
      frinux over 7 years
      Interesting, for now I found another dirty hack: the developmentVersion for maven release plugin is suffixed by a string "REMOVE_ME_TO_ENABLE_RELEASE", which is removed by the developer when he is ready to release the version (I know that's dirty...)
    • ivoruJavaBoy
      ivoruJavaBoy over 7 years
      Yeah, even if dirty, it's a trick that makes it work as expected.. so good enough XD
    • frinux
      frinux over 7 years
      Maybe that the central problem is the way Jenkins triggers on GIT repos (poll scm option). It would be nice to add some conditions to this option, to trigger on conditions (for instance "when the commit comment does not contains xxx")
    • Daniel Omoto
      Daniel Omoto over 7 years
      Just out of curiosity, would ignoring commits by certain users/paths under "Additional Behaviors" in the SCM git step be a possibility? I'm assuming Jenkins is running as a system user, so you could ignore all commits from that user from triggering a new build.. Or you could ignore that file from triggering a new build?
  • u123
    u123 over 6 years
    So what happens the day you need to build a bugfix from the tag (branch of the tag)? As I understand using the above process its only the artifacts that gets deployed that gets strict versions. The versions on the tag in source still contain -SNAPSHOT so there is no guarantee that you get same result when building at a later time.
  • Dennis Hoer
    Dennis Hoer over 6 years
    That is a good question. If you create a branch from a tag, you could update the Jenkinsfile e.g., branch 1.0.5 tag and update revision to REVISION = "1.0.5.${env.BUILD_ID}"
  • Adriaan Koster
    Adriaan Koster over 5 years
    Maven complains about <version>${revision}</version> in a root pom, and doesn't run when this is in a module pom. So this approach does not work for multi-module projects IMO
  • learner
    learner over 3 years
    How can i get the version from a freestyle project?
  • Mikhail Skotnikov
    Mikhail Skotnikov over 3 years
    @AdriaanKoster maybe use you use Maven version which does not support this feature. According to maven.apache.org/maven-ci-friendly.html you need Maven 3.5.0-beta-1 or higher and multimodule projects are supported
  • Adriaan Koster
    Adriaan Koster over 3 years
    @MikhailSkotnikov My comment is from 2018 so I guess it didn't work at the time. Thanks for the update.