Thursday, March 28, 2019

Jenkinsfile - Skip Release

If you trigger your Jenkins builds after every commit in git, then after a release, which does a git commit with the new version number, Jenkins will pickup the commit and release the project again, which of course leads to another Jenkins build/release cycle ... infinity. To work around this you have to have a 'when' expression to your Jenkins file to verify that the last commit was not due to a release and also that it contains files from your directory so it doesn't perform a release again (see the stage('Release') below). Initially, I thought this was an issue with the release plugin so I raised an issue on github. Here's how I worked it out Here's what the git log looks like immediately after a release:
$ git log --oneline -n 2
e45e8db (HEAD -> dragon, origin/dragon, origin/HEAD) [Gradle Release Plugin] - new version commit:  'utils-0.0.15.APTNG-SNAPSHOT'.
a3d19fc (tag: utils-0.0.14.APTNG) [Gradle Release Plugin] - pre tag commit:  'utils-0.0.14.APTNG'.
This is the Jenkinsfile I used to reason if a release is required.
#!/usr/bin/env groovy

def dir='services/common/utils'
def version
// Only update the description with the release version number if it performs a release
def isRelease = false

pipeline {
    agent {
        label 'build_slave_lable'
    }
    stages {
        stage('Compile') {
            steps {
                script {
                    // Added this to update the build description with the version number from the gradle.properties
                    version = sh(
                            script: "cd $dir && grep version gradle.properties | sed 's/version=//g'",
                            returnStdout: true
                    ).trim()
                    currentBuild.description = "$version"
                }
                sh "cd $dir && ./gradlew assemble
            }
        }
        stage('Unit Test') {
            steps {
                sh "cd $dir && ./gradlew test
            }
        }
        stage('Release') {
            when {
                expression {
                    def branchName = sh(script: 'git rev-parse --abbrev-ref HEAD', returnStdout: true).trim()
                    // # GIT log command will only print out the file paths from the last commit
                    // # See https://stackoverflow.com/a/17583922/529256
                    // # Example:
                    // $ git log -n 1 --name-only --pretty=format:
                    // services/common/utils/gradle.properties
                    def lastCommitFiles = sh(script: 'git log -n 1 --name-only --pretty=format:',
                                             returnStdout: true).trim()
                    def hasFiles = lastCommitFiles.contains(dir)
                    // Verify that the last commit was not a release of this module
                    def lastCommitMessage = sh(script: 'git log -n 1 --oneline', returnStdout: true).trim()
                    def wasNotRelease = !lastCommitMessage.contains("[Gradle Release Plugin]")
                    // Release only if:
                    // - This is the 'release' branch
                    // - AND last commit has files from this directory
                    // - AND last commit was a not a release of this module
                    return branchName == 'dragon' && hasFiles && wasNotRelease
                }
            }
            steps {
                sh "cd services/common/utils && ./gradlew release -Prelease.useAutomaticVersion=true"
                script {
                    isRelease = true
                }
            }
        }
    }
    post {
        success {
            script {
                if (isRelease) {
                    // Update the build description to the release version number if the release was performed
                    def description = "$version".replaceAll("-SNAPSHOT", "")
                    currentBuild.description = description
                }
            }
        }
    }
}

No comments:

Post a Comment