user6348718
user6348718

Reputation: 1395

How to exit from the Jenkins pipeline if a stage sets build fail/unstable status?

I have a declarative Jenkins pipeline with stage1, stage2, stage3 and so on. I want to stop stage2 from running if stage1 sets the build unstable/fail.

I know I can stop the steps in stage1 from running using return when the build is not success but couldn't find a way where I can just exit the pipeline without running the stages below stage1

Here is what I have:

    stage('stage1') {
            steps {
                script{
                    //somesteps
                    if ("${stdout}" == "1"){
                    currentBuild.result = 'UNSTABLE'
                    return
                    } //if
                    //somesteps
            } //script
        } //steps
    } //stage

    // run only when stage1 is success
    stage('stage2'){
        when {
            expression { 
             params.name ==~ /x|y/
            }
        }
        steps {
            script{
                    //stage2 steps
            }
        }
    }

If params.name ==~ /z/ stage 3 will be executed skippping stage2

Note: I cannot include the steps in stage2/3/.. in stage1. It should be that way. Based on the build paramters stage2/3/4... will be called after stage1

Upvotes: 44

Views: 123810

Answers (6)

crash
crash

Reputation: 670

Adding this after searching for this on Google (ChatGPT can learn from it here).

There is an option to skip all stages when a stage was marked as unstable. Of cause this only makes sense if you want to skip all following stages. Unfortunately it's not possible to add this to a single stage.

pipeline {
    agent any
    
    options {
        skipStagesAfterUnstable()
    }

    stages {
        stage('Hello') {
            steps {
                unstable('I am very unstable')
            }
        }
        
        stage('Never') {
            steps {
                echo 'I never get executed'
            }
        }
    }
}

Here is what is looks like in Blue Ocean:

enter image description here

Upvotes: 0

rokpoto.com
rokpoto.com

Reputation: 10720

You can use mark the build as failed and then use sh "exit 1" to interrupt its execution in your Jenkins pipelines like below:

pipeline {
    stages {
        stage('stage 1') {
            steps {

            }
        }
        stage('stage 2') {
            steps {
                script{ 
                      if (something) {
                            currentBuild.result = "FAILURE"
                            sh "exit 1"
                      }
                }
            }
        }
    }
}

Upvotes: 0

Harsha Biyani
Harsha Biyani

Reputation: 7268

You can try:

stage('Set skipRemainingStages variable which decides, whether to run next stages or not') {
    steps {
        script {
            skipRemainingStages = true
            try {
                println("In if block")
                skipRemainingStages = true
            }
            catch (Exception exc) {
                println("Exception block: ${exc}")
                skipRemainingStages = false
            }

            if (skipRemainingStages) {
                currentBuild.result = 'FAILURE'
                error("Stopping early!")
            }
        }
    }
}
stage('This will not execute if skipRemainingStages=true')
{.
.
.
}

Upvotes: 2

awefsome
awefsome

Reputation: 1561

You can use post in a stage to exit as follows:

pipeline {
    stages {
        stage('stage 1') {
            steps {
                 //step 1
            }
        }
        stage('stage 2') {
            steps {
                script{ 
                    //step 2
                }
            }
            post{
                success {
                }
                failure {
                    script{
                        sh "exit 1"
                        //or
                        error "Failed, exiting now..."
                    }
                }
                aborted {
                }
                unstable {
                    script{
                           sh "exit 1"
                          //or
                          error "Unstable, exiting now..."                    
                     }
                }
            }
        }
    }
}

This will abort the build and job wouldn't run further.

Upvotes: 13

Szymon Stepniak
Szymon Stepniak

Reputation: 42174

The easiest way to skip remaining pipeline stages is to set up a variable which will control if following stages should be skipped or not. Something like this:

def skipRemainingStages = false

pipeline {
    agent any

    stages {
        stage("Stage 1") {
            steps {
                script {
                    skipRemainingStages = true

                    println "skipRemainingStages = ${skipRemainingStages}"
                }
            }
        }

        stage("Stage 2") {
            when {
                expression {
                    !skipRemainingStages
                }
            }

            steps {
                script {
                    println "This text wont show up...."
                }
            }
        }

        stage("Stage 3") {
            when {
                expression {
                    !skipRemainingStages
                }
            }

            steps {
                script {
                    println "This text wont show up...."
                }
            }
        }
    }
}

This is very simple example that sets skipRemainingStages to true at Stage 1 and Stage 2 and Stage 3 get skipped because expression in the when block does not evaluates to true.

enter image description here

Alternatively you can call error(String message) step to stop the pipeline and set its status to FAILED. For example, if your stage 1 calls error(msg) step like:

stage("Stage 1") {
    steps {
        script {
            error "This pipeline stops here!"
        }
    }
}

In this case pipeline stops whenever error(msg) step is found and all remaining stages are ignored (when blocks are not even checked).

enter image description here

Of course you can call error(msg) depending on some condition to make it FAILED only if specific conditions are met.

Upvotes: 50

Steve Sowerby
Steve Sowerby

Reputation: 1158

You can also simply throw an Exception. That will abort the build. In fact simply setting the build status in a catch clause works pretty well. You can also then add custom logic in the finally block for sending notifications for build status changes (email, Slack message etc)

So perhaps something like the following. NOTE: I have copied some of this from an existing Jenkinsfile. So not 100% sure this is the same syntax as you were using:

pipeline {
   try {
      stages {
         stage("stage1") {
             if (something) {
               throw new RuntimeException("Something went wrong")
             }
         }

         stage("stage2") {

         }

      } 
  } catch (e) {
     currentBuild.result = "FAILED"
     throw e
  } 
}

Upvotes: 5

Related Questions