Show a Jenkins pipeline stage as failed without failing the whole job

前端 未结 7 1043
被撕碎了的回忆
被撕碎了的回忆 2020-12-01 02:26

Here\'s the code I\'m playing with

node {
    stage \'build\'
    echo \'build\'

    stage \'tests\'
    echo \'tests\'

    stage \'end-to-end-tests\'
             


        
相关标签:
7条回答
  • 2020-12-01 03:04

    This is now possible, even with declarative pipelines:

    pipeline {
        agent any
        stages {
            stage('1') {
                steps {
                    sh 'exit 0'
                }
            }
            stage('2') {
                steps {
                    catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                        sh "exit 1"
                    }
                }
            }
            stage('3') {
                steps {
                    sh 'exit 0'
                }
            }
        }
    }
    

    In the example above, all stages will execute, the pipeline will be successful, but stage 2 will show as failed:

    As you might have guessed, you can freely choose the buildResult and stageResult, in case you want it to be unstable or anything else. You can even fail the build and continue the execution of the pipeline.

    Just make sure your Jenkins is up to date, since this is a fairly new feature.

    0 讨论(0)
  • 2020-12-01 03:08

    I recently tried to use vaza's answer Show a Jenkins pipeline stage as failed without failing the whole job as template for writing a function that excutes a job in an own stage named like the job name. Surprisingly it worked, but maybe some groovy experts have a look at it :)

    Here is how it looks like if one of the jobs is aborted:

    def BuildJob(projectName) {
        try {
           stage(projectName) {
             node {      
               def e2e = build job:projectName, propagate: false
               result = e2e.result
               if (result.equals("SUCCESS")) {
               } else {
                  error 'FAIL' //sh "exit 1" // this fails the stage
               }
             }
           }
        } catch (e) {
            currentBuild.result = 'UNSTABLE'
            result = "FAIL" // make sure other exceptions are recorded as failure too
        }
    }
    
    node {
        BuildJob('job1')
        BuildJob('job2')
    }
    
    0 讨论(0)
  • 2020-12-01 03:12

    Solution steps

    • You must emit an error in a stage to mark it as an error
    • Outside the scope of the stage, handle the exception and choose the build status
    • This makes the effect desired by a couple of users here, including myself, @user3768904, @Sviatlana

    Success with failed Step Example

    node("node-name") {
      try {
        stage("Process") {
          error("This will fail")
        }
      } catch(Exception error) {
        currentBuild.result = 'SUCCESS'
        return
      }
      stage("Skipped") {
         // This stage will never run
      }
    }
    

    Aborted with failure Step Example

    node("node-name") {
      try {
        stage("Process") {
          error("This will fail")
        }
      } catch(Exception error) {
        currentBuild.result = 'ABORTED'
        return
      }
      stage("Skipped") {
         // This stage will never run
      }
    }
    

    0 讨论(0)
  • 2020-12-01 03:13

    In order to show a successful build with a failed stage when a downstream job fails AND support a user being able to cancel a build (including all subsequent stages), I had to use a combination of various solutions, specifically when, try/catch, throw and catchError().

    env.GLOBAL_BUILD_ABORTED = false        // Set if the user aborts the build
    
    pipeline {
        agent any
    
        stages {
            stage('First Stage') {
                when { expression { env.GLOBAL_BUILD_ABORTED.toBoolean() == false } }
    
                steps {
                    catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                        myLocalBuildMethod('Stage #1, build #1')
                        myLocalBuildMethod('Stage #1, build #2')
                    }
                }
            }
    
            stage('Second Stage') {
                when { expression { env.GLOBAL_BUILD_ABORTED.toBoolean() == false } }
    
                steps {
                    catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                        myLocalBuildMethod('Stage #2, build #1')
                        myLocalBuildMethod('Stage #2, build #2')
                        myLocalBuildMethod('Stage #2, build #3')
                    }
                }
            }
        }
    }
    
    def myLocalBuildMethod(myString) {
        /* Dummy method to show User Aborts vs Build Failures */
    
        echo "My Local Build Method: " + myString
    
        try {
            build (
                job: "Dummy_Downstream_Job"
            )
    
        } catch (e) {
            /* Build Aborted by user - Stop All Test Executions */
            if (e.getMessage().contains("was cancelled") || e.getMessage().contains("ABORTED")) {
    
                env.GLOBAL_BUILD_ABORTED = true
            }
            /* Throw the execiption to be caught by catchError() to mark the stage failed. */
            throw (e)
        }
    
        // Do other stuff...
    }
    
    0 讨论(0)
  • 2020-12-01 03:18

    Stage takes a block now, so wrap the stage in try-catch. Try-catch inside the stage makes it succeed.

    The new feature mentioned earlier will be more powerful. In the meantime:

    try {
       stage('end-to-end-tests') {
         node {      
           def e2e = build job:'end-to-end-tests', propagate: false
           result = e2e.result
           if (result.equals("SUCCESS")) {
           } else {
              sh "exit 1" // this fails the stage
           }
         }
       }
    } catch (e) {
       result = "FAIL" // make sure other exceptions are recorded as failure too
    }
    
    stage('deploy') {
       if (result.equals("SUCCESS")) {
          build 'deploy'
       } else {
          echo "Cannot deploy without successful build" // it is important to have a deploy stage even here for the current visualization
       }
    }
    
    0 讨论(0)
  • 2020-12-01 03:18

    You could add a explicit fail task, such as 'sh "not exist command"' in the stage.

    if (result.equals("SUCCESS")) {
       stage 'deploy'
       build 'deploy'
    } else {
       try {
           sh "not exist command"
       }catch(e) {
       }
    }
    
    0 讨论(0)
提交回复
热议问题