27

I tried to get the git commit message in jenkinsfile and prevent the build based on commit message.

env.GIT_COMMIT doesn't return the commit details in jenkinsfile.

How to get the git latest commit message and prevent the jenkins build if the commit message contains [ci skip] in it?

Yahwe Raj
  • 1,947
  • 5
  • 25
  • 37
  • 3
    try sh "git log -1" and grep the relevant text. – Amityo Dec 14 '16 at 10:30
  • @Amityo: Thanks it really helpful. I need one more query... how to prevent jenkins build in jenkinsfile, if the message contains [ci skip] content? – Yahwe Raj Dec 15 '16 at 05:21
  • issue has been created to provide GIT_COMMIT_MESSAGE you can vote to get it soon https://issues.jenkins-ci.org/browse/JENKINS-52490 – ImranRazaKhan Jul 12 '18 at 14:35

5 Answers5

23

I had the same issue. I'm using pipelines. I solved this issue by implementing a shared library.

The code of the library is this:

// vars/ciSkip.groovy

def call(Map args) {
    if (args.action == 'check') {
        return check()
    }
    if (args.action == 'postProcess') {
        return postProcess()
    }
    error 'ciSkip has been called without valid arguments'
}

def check() {
    env.CI_SKIP = "false"
    result = sh (script: "git log -1 | grep '.*\\[ci skip\\].*'", returnStatus: true)
    if (result == 0) {
        env.CI_SKIP = "true"
        error "'[ci skip]' found in git commit message. Aborting."
    }
}

def postProcess() {
    if (env.CI_SKIP == "true") {
        currentBuild.result = 'NOT_BUILT'
    }
}

Then, in my Jenkinsfile:

pipeline {
  stages {
    stage('prepare') { steps { ciSkip action: 'check' } }
    // other stages here ...
  }
  post { always { ciSkip action: 'postProcess' } }
}

As you can see, the build is marked as NOT_BUILT. You can change it to ABORTED if you prefer, but it cannot be set to SUCCESS because a build result can only get worse

csalazar
  • 748
  • 1
  • 7
  • 13
19

The build will pass when [ci skip] is provided in the last git log, but will not run the actual build code (the replacement to the first echo statement)

node {
  checkout scm
  result = sh (script: "git log -1 | grep '\\[ci skip\\]'", returnStatus: true) 
  if (result != 0) {
    echo "performing build..."
  } else {
    echo "not running..."
  }
}
Amityo
  • 5,635
  • 4
  • 22
  • 29
12

As for declarative pipeline one can use 'changelog' in 'when' directive to skip a stage:

when {
    not {
    changelog '.*^\\[ci skip\\] .+$'
    }
}

See: https://jenkins.io/doc/book/pipeline/syntax/#when

third_man
  • 121
  • 1
  • 3
  • 1
    '^.*\\[ci skip\\].*$' or '.*\\[ci skip\\].*' may make more sense – bias Nov 21 '19 at 22:41
  • This won't work for 1st build as it would not have any changelog – Shrinivas Shukla Nov 26 '19 at 19:37
  • 2
    Is there some way to limit this to the most recent commit message? Having tested this if the most recent commit message does not match, but the previous commit does this still skips. – Vala Sep 30 '20 at 14:49
  • @Thor84no I have verified what you've reported as well. Unfortunately the `changelog` inside `when` does match more than just the latest commit message :-( – BigGillyStyle Jul 13 '21 at 14:04
  • 1
    I just tried this with Jenkins 2.303.3, and it works just fine. It did not look at previous commits. – Mani Jan 07 '22 at 11:06
  • FWIW, this feature was created by this PR: https://github.com/jenkinsci/pipeline-model-definition-plugin/pull/178 – Mani Jan 07 '22 at 11:14
8

I think you could easily do that in multi branch pipeline job configuration Branch Sources > Additional Behaviours > Polling ignores commits with certain messages multi branch pipeline job configuration

hakamairi
  • 4,464
  • 4
  • 30
  • 53
  • When using this approach, $CHANGE_ID is not available in the Jenkinsfile. – Idan Adar Mar 25 '17 at 08:40
  • 2
    @hakamairi is this option available for multibranch as i am unable to find it? – ImranRazaKhan Jul 23 '18 at 17:16
  • Do you have an updated version of this? It seems the "Advanced Behaviors" is no longer avaiable in the branch sources section in 2021. You can add behaviors, but none of the options seem to be related to commit messages. Any ideas? – Seth Lutske Jul 14 '21 at 21:11
6

As of today, it's quite easy to achieve. The interesting line is the extension named MessageExclusion where excludedMessage accepts a regular expression.

checkout([ $class: 'GitSCM', 
  branches: [[name: '*/master']], 
  doGenerateSubmoduleConfigurations: false, 
  extensions: [[
    $class: 'MessageExclusion', excludedMessage: '.*skip-?ci.*'
  ]], 
  submoduleCfg: [], 
  userRemoteConfigs: [[
    credentialsId: 'xxx', url: 'git@github.com:$ORG/$REPO.git'
  ]]
])
mana
  • 6,347
  • 6
  • 50
  • 70
  • 2
    Are those built-in classes? – ntwrkguru Jun 29 '18 at 16:37
  • Interesting situation that I observe when using this; I'm unable to use git from within my Docker build. Not sure what one has to do with the other yet, but if I use the plain old 'checkout scm', it works. If I use this method, it doesn't. – ntwrkguru Jun 29 '18 at 17:20