111

I have a job that will create files, unless one of the values being fed to it matches an older value. What's the cleanest way in Jenkins to abort or exit the job, without it being FAILED? It exiting is the correct behavior so I want the build marked SUCCESS.

It'll end up in an if statement like so;

stage ('Check value') {

     if( $VALUE1 == $VALUE2 ) {
       //if they do match exit as a success, else continue with the rest of the job 
    }

}

I don't want to throw an error code unless that can somehow translate into it being marked a successful build.

Alex
  • 4,612
  • 6
  • 29
  • 49

7 Answers7

98

Please note: The following works for scripted pipelines only. For a solution for declarative pipelines see @kgriffs' answer.

---

Figured it out. Outside of any stages (otherwise this will just end the particular stage as a success) do the following;

if( $VALUE1 == $VALUE2 ) {
   currentBuild.result = 'SUCCESS'
   return
}

return will stop the stage or node you're running on which is why running it outside of a stage is important, while setting the currentBuild.result prevents it from failing.

Gerold Broser
  • 171
  • 1
  • 10
Alex
  • 4,612
  • 6
  • 29
  • 49
26

The Executor.interrupt(Result) method is the cleanest, most direct way I could find to stop a build prematurely and mark it as a success.

script {
    currentBuild.getRawBuild().getExecutor().interrupt(Result.SUCCESS)
    sleep(1)   // Interrupt is not blocking and does not take effect immediately.
}

Pros:

  • Works in a declarative pipeline just as well as a scripted one.
  • No try/catch or exceptions to handle.
  • Marks the calling stage and any successive stages as green/passing in the UI.

Cons:

  • Requires a number of in-process script approvals, including one that is considered insecure. Approve and use with caution.
Ben Amos
  • 381
  • 3
  • 6
23

You can also use error to exit the current stage, then you don't have to consider the current stage hierarchy and similar stuff:

def autoCancelled = false

try {
  stage('checkout') {
    ...
    if (your condition) {
      autoCancelled = true
      error('Aborting the build.')
    }
  }
} catch (e) {
  if (autoCancelled) {
    currentBuild.result = 'SUCCESS'
    // return here instead of throwing error to keep the build "green"
    return
  }
  // normal error handling
  throw e
}

But this would lead to a red stage, if the error occurs within a stage.

enter image description here

It depends on your requirements, which way you want to use.

CSchulz
  • 331
  • 2
  • 3
15

If it is acceptable to set the build status to ABORTED instead of SUCCESS, the following snippet may be used within a pipeline stage to short-circuit the build:

steps {
    script {
        currentBuild.result = 'ABORTED'
        error("Aborting the build.")
    }
}

I tested setting the result to SUCCESS, but doing so resulted in a failed build (using Jenkins 2.235.5). It seems that ABORTED is respected by the error step, while SUCCESS is overridden.

Gerold Broser
  • 171
  • 1
  • 10
kgriffs
  • 251
  • 2
  • 4
4

I was almost able to accomplish this with declarative pipeline. This allows you to exit the before the pipeline starts based on the outcome of a shell script. I was not able to get this working within the pipeline itself (either within or between stages).

node('master'){
    env.status_code = sh(script: 'exit 0 # or 200 or other', returnStatus:true)
}
println 'status_code: ' + env.status_code
if(env.status_code == '200'){
    println 'Now is not the time to run the pipeline.'
    println 'Exiting without running subsequent stages.'
    currentBuild.result = 'SUCCESS'
    return
} else if(env.status_code == '0'){
    println 'Time to run. Let\'s go!'
} else {
    error 'Unable to check if it\'s time to run.'
}

pipeline {
  agent any
  stages {
      stage('Run only if exit status for was 0'){
          steps{
             sh 'echo hi'
          }
      }
  }
}

when directive may help if you only want to skip certain stages, not exit entirely.

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

1

Honestly you shouldn't need to use the exit command specifically, but there is a Conditional BuildStep Plugin which may achieve the same end result (code that doesn't run).

I haven't come up against this yet, so haven't used the plugin.

There is also conditionals as found in this prior Stack Overflow post on Jenkins: Jenkins Pipeline Conditional Step/Stage

MrMesees
  • 111
  • 5
0

Go to "Manage Jenkins" -> "In-process Script Approval" and write below line in 'Signatures already approved:' box

new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException hudson.model.Result jenkins.model.CauseOfInterruption[]

enter image description here

Now in your pipeline, add below lines,

currentBuild.result = "SUCCESS"
throw new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException(hudson.model.Result.SUCCESS)

This worked for me.

Example Jenkinsfile,

pipeline {
    agent any
    environment {
        ENVIRONMENT = "skip"
    }
stages {
    stage('Check Conditions') {
        steps {
            script {
                if (env.ENVIRONMENT == 'skip') {
                    echo "Skipping pipeline for this environment..."

                    currentBuild.result = "SUCCESS"
                    throw new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException(hudson.model.Result.SUCCESS)

                }

            }
        }
    }

    stage('Next Stage') {
        steps {

            echo "This won't run if ENVIRONMENT was 'skip'"

        }
    }

}

}

To make the state as 'Aborted' instead of Success, one can use below lines,

currentBuild.result = "ABORTED"
throw new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException(hudson.model.Result.ABORTED)

References:

Anon
  • 103
  • 2