Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
826 views
in Technique[技术] by (71.8m points)

Determine Failed Stage in Jenkins Declarative Pipeline

How do I report the stage in which a declarative pipeline failed? In the fail block, I want to get failedStage.name and report it (eventually to slack).

pipeline {
    agent { label 'master'}
    stages {
        stage('Ok') {
            steps {
                echo 'do thing'
            }
        }
        stage('NotOK') {
            steps {
                sh 'make fail'
            }
        }
    }
    post {
        always {
            echo 'ok'
        }
        failure {
            echo 'Failed during Which Stage?'
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Overview

This can be achieved generically using Blue Ocean plugin API. Class PipelineNodeGraphVisitor can be used to iterate over all pipeline nodes (such as stages, parallel branches and steps). We just have to check if the type property of FlowNodeWrapper equals FlowNodeWrapper.NodeType.STAGE.

Additionally we can get the failure cause from the ErrorActions stored in the nodes.

Code

You would typically put the following code into a shared library, because it would prevent the pipeline from running in sandbox environment, if inserted directly into pipeline code.

import io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeGraphVisitor
import io.jenkins.blueocean.rest.impl.pipeline.FlowNodeWrapper
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
import org.jenkinsci.plugins.workflow.actions.ErrorAction

// Get information about all stages, including the failure causes.
//
// Returns a list of maps: [[id, displayName, result, errors]]
// The 'errors' member is a list of unique exceptions.

@NonCPS
List<Map> getStageResults( RunWrapper build ) {

    // Get all pipeline nodes that represent stages
    def visitor = new PipelineNodeGraphVisitor( build.rawBuild )
    def stages = visitor.pipelineNodes.findAll{ it.type == FlowNodeWrapper.NodeType.STAGE }

    return stages.collect{ stage ->

        // Get all the errors from the stage
        def errorActions = stage.getPipelineActions( ErrorAction )
        def errors = errorActions?.collect{ it.error }.unique()

        return [ 
            id: stage.id, 
            displayName: stage.displayName, 
            result: "${stage.status.result}",
            errors: errors
        ]
    }
}

// Get information of all failed stages
@NonCPS
List<Map> getFailedStages( RunWrapper build ) {
    return getStageResults( build ).findAll{ it.result == 'FAILURE' }
}

Demo Pipeline

pipeline{
    agent any

    stages {
        stage('SuccessStage') {
            steps {
                echo 'Success'
            }
        }
        stage('FailedStage') {
            steps {
                readFile 'dfgkjsdffj'
            }
        }
        stage('SkippedStage') {
            steps {
                echo 'Skipped because of error in FailedStage'
            }
        }
    }
    post {
        failure {
            script {              
                // Print information about all failed stages
                def failedStages = getFailedStages( currentBuild )
                echo "Failed stages:
" + failedStages.join('
')

                // To get a list of just the stage names:
                //echo "Failed stage names: " + failedStages.displayName
            }
        }
    }
}

Blue Ocean View

BlueOcean screenshot

Notes

If you want to get stages with other results than FAILURE, have a look at my function getFailedStages(). You can simply change the condition, e. g.:

  • it.result in ['FAILURE','UNSTABLE']
    • get unstable stages aswell
  • it.result != 'SUCCESS'
    • get all unsuccesfull stages, which also includes skipped stages

Possible alternative implementation:

Strictly spoken, Blue Ocean API is not necessary. It just simplifies the code alot. You can do the same using only basic Jenkins pipeline API. As a starting point, look for FlowGraphWalker for iterating over the pipeline nodes. Have a look at the code of Blue Ocean's PipelineNodeGraphVisitor to find out how they determine the "Stage" node type.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...