How to continue past a failing stage in Jenkins declarative pipeline syntax

后端 未结 4 476
深忆病人
深忆病人 2021-02-01 06:14

I want to define multiple stages in Jenkins declarative pipeline syntax which can continue past any one of them failing. I cannot find any existing questions which are true dupl

相关标签:
4条回答
  • 2021-02-01 06:38

    I may be missing something, but the idea of declarative, opinionated pipeline is to provide coverage of most simple use cases. The moment you need something the opinionated hasn't covered, you HAVE to resort to scripted pipeline, this is only referring to the "requirement" of "declarative pipeline": not going to happen now.

    As to your other "requirements", they make very little sense, since the whole idea is to wrap low-level ugliness into shared libraries providing users with constructs like:

        mylib.failable_stages({
          stages {
            stage('stage 1') {
              steps {
                echo "I need to run every time"
              }
            }
            stage('stage 2') {
              steps {
                echo "I need to run every time, even if stage 1 fails"
              }
            }
            stage('stage 3') {
              steps {
                echo "Bonus points if the solution is robust enough to allow me to continue *or* be halted based on previous stage status"
              }
            }
          }
        })
    

    Naturally, you would have to find or implement such mylib class and the failable_stages would get a closure, and wrap it in various plumbing/boilerplate code pieces.

    Hope this is helpful.

    0 讨论(0)
  • 2021-02-01 06:41

    This is now possible:

    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.

    EDIT: This is the question that this answer was originally written for. It is also the correct answer for a few other questions, which is why I posted this answer there as well. This is the right solution for multiple similar problems. I've tailored my other answers to their specific questions to make that clear. I only copied the answer to save myself some time. That doesn't mean it's not a good correct answer.

    0 讨论(0)
  • 2021-02-01 06:57

    I achieved it using post. My requirement was to send out slack notification irrespective of the build status.

    @Library('instanceGroups')
    import x.z.y.jenkins.libraries.SlackNotifier
    
    def slackHelper = new x.z.y.jenkins.libraries.SlackNotifier(env)
    final String projectName = "pomeranian"
    final String featureBranchPattern = "f_"
    
    pipeline {
        agent any
        options { disableConcurrentBuilds() }
    
        stages {
            stage('clean') {
                steps {
                    script {
                        try {
                            echo 'Current Branch...' + env.BRANCH_NAME
                            sh 'rm -rf /var/lib/jenkins/.gradle/caches'
                            sh './gradlew clean'
                        } catch (e) {
                            currentBuild.result = 'FAILURE'
                            slackHelper.buildGenericJobFailureNotificationMessage()
                            throw e
                        }
                    }
                }
            }
    
            stage('compile') {
                steps {
                    script {
                        try {
                            sh "./gradlew compileJava"
                        } catch (e) {
                            currentBuild.result = 'FAILURE'
                            slackHelper.getCompilationFailureSlackNotificationMessage()
                            throw e
                        }
                    }
                }
            }
    
            stage('test') {
                steps {
                    script {
                        try {
                            sh "./gradlew test"
                        } finally {
                            junit 'build/test-results/test/*.xml'
    
                            slackHelper.getTestStatuses(currentBuild)
                            slackHelper.buildUnitTestSlackNotificationMessage()
                        }
                    }
                }
            }
    
            stage('publish 2 nexus') {
                steps {
                    script {
                      // some code
                    }
                }
            }
    
            stage('git tagging') {
                steps {
                    script {
                        // some more code...
                }
            }
        }
    
    
        post {
            always {
                script {
                    slackHelper.finalBuildStatusMessage(currentBuild)
                    slackSend(channel: '#ci-cd', attachments: slackHelper.getFinalSlackMessage())
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-01 07:04

    I think it depends on how dependent the jobs are on each other. Derived from your example I would assume that

    • stage 1 is independent from all other stages, because it is the first
    • stage 2 is independent from all other stages, because stage 1 might fail immediatly and stage 2 would still be required to run
    • stage 3 depends on the result of stage 1 and stage 2

    So the correpsonding pipeline could be

    pipeline {
        stages {
            stage('Independent tasks') {
                parallel {
                    stage('stage 1') {
                        steps {
                            sh 'exit 1' // failure
                        }
                    }
                    stage('stage 2') {
                        steps {
                            echo 'Happens even so stage 1 fails'
                            sh 'exit 0' // success
                        }
                    }
                }
                post {  // 'stage 3'
                    failure {
                        echo "... at least one failed"
                    }
                    success {
                        echo "Success!"
                    }
                }
            }
            stage ('stage 4') {
                steps {
                    echo 'Happens only if all previous succeed'
                }
            }
        }
    }
    

    stage 1 and stage 2 will always run, stage 3 reacts on their combined success/failure.


    Additional thought: This concept only works 'at the end' of your pipeline. In case you need it somewhere in the middle AND the build has to continue, you could move it into an own job and use the build job plugin.

    pipeline {
        stages {
        stage('Start own job for stage 1, 2, 3') {
            steps {
                build job: 'stageOneTwoThree', propagate: false, wait: true
            }
        }
        stage ('stage 4') {
            steps {
                echo 'Happens always, because "propagate: false"'
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题