确定Jenkins声明性管道中的失败阶段

Pet*_*ahn 10 jenkins jenkins-pipeline

如何报告声明性管道失败的阶段?在失败块中,我想获取failedStage.name并报告它(最终松弛).

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?'
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

zet*_*t42 9

概述

这通常可以使用 Blue Ocean 插件 API 来实现。类PipelineNodeGraphVisitor可用于迭代所有管道节点(例如阶段、并行分支和步骤)。我们只需要检查equals的type属性。FlowNodeWrapperFlowNodeWrapper.NodeType.STAGE

此外,我们可以从ErrorAction存储在节点中的s 中获取失败原因。

代码

您通常会将以下代码放入共享库中,因为如果直接插入到管道代码中,它会阻止管道在沙箱环境中运行。

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' }
}
Run Code Online (Sandbox Code Playgroud)

演示管道

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:\n" + failedStages.join('\n')

                // To get a list of just the stage names:
                //echo "Failed stage names: " + failedStages.displayName
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

蓝色海景

蓝海截图

笔记

如果您想获得具有其他结果的阶段,请FAILURE查看我的函数getFailedStages()。您可以简单地更改条件,例如:

  • it.result in ['FAILURE','UNSTABLE']
    • 也得到不稳定的阶段
  • it.result != 'SUCCESS'
    • 获取所有不成功的阶段,其中还包括跳过的阶段

可能的替代实现:

严格来说,Blue Ocean API 不是必需的。它只是简化了很多代码。你可以只使用基本的 Jenkins 管道 API 来做同样的事情。作为起点,寻找FlowGraphWalker迭代管道节点。查看 Blue Ocean 的代码,PipelineNodeGraphVisitor了解他们如何确定“舞台”节点类型。

  • @max-cascone 是的。我们为分布在 7 或 8 个发行版中的 1500 多个内核构建 Linux 内核模块。我们的内核检测系统通常会找到 1-5 个新的,然后构建它们,但是当我们更改源代码时,我们必须全部重建它们。这就是linux内核驱动的乐趣 (2认同)

hay*_*lem 5

您可以在每个阶段使用post指令,通过特定操作和通知来应对失败。

这并不完全理想,因为如果您希望在所有阶段都必须重复它,而且我不认为您可以动态访问您的阶段名称,所以它确实是冗长和硬编码的。不过,您可能可以重构它以使用库。

pipeline {
    agent { label 'master'}
    stages {
        stage('Ok') {
            steps {
                echo 'do thing'
            }
            post {
                failure {
                    echo 'FAILED (in stage OK - should not happen :))'
                }
            }
        }
        stage('NotOK') {
            steps {
                sh 'make fail'
            }
            post {
                failure {
                    echo 'FAILED (in stage NotOK)'
                }
            }
        }
    }
    post {
        always {
            echo 'COMPLETED (global)'
        }
        failure {
            echo 'FAILED (global)'
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 根据 Jenkins 版本,您可能可以访问 `env.STAGE_NAME` 来获取当前阶段名称,并访问 `currentBuild.currentResult` 来获取当前阶段结果 (3认同)

Pet*_*ahn 2

PipelineVisitor 是一个很好的方法。但是,如果您只想查看错误,那么可以利用FlowGraphTable可能会更好。

下面提供了每个失败步骤的映射列表,并遍历下游作业。我发现它非常有用。

您需要使用共享库来避免安全沙箱警告/批准

List<Map> getStepResults() {
    def result = []
    WorkflowRun build = currentBuild()
    FlowGraphTable t = new FlowGraphTable(build.execution)
    t.build()
    for (def row in t.rows) {
        if (row.node.error) {
            def nodeInfo = [
                    'name': "${row.node.displayName}",
                    'url': "${env.JENKINS_URL}${row.node.url}",
                    'error': "${row.node.error.error}",
                    'downstream': [:]

            ]
            if (row.node.getAction(LogStorageAction)) {
                nodeInfo.url += 'log/'
            }

            for (def entry in getDownStreamJobAndBuildNumber(row.node)) {
                nodeInfo.downstream["${entry.key}-${entry.value}"] = getStepResults(entry.key, entry.value)
            }
            result << nodeInfo
        }
    }
    log(result)
    return result
}

Map getDownStreamJobAndBuildNumber(def node) {
    Map downStreamJobsAndBuilds = [:]
    for (def action in node.getActions(NodeDownstreamBuildAction)) {
        def result = (action.link =~ /.*\/(?!\/)(.*)\/runs\/(.*)\//).findAll()
        if (result) {
            downStreamJobsAndBuilds[result[0][1]] = result[0][2]
        }
    }
    return downStreamJobsAndBuilds
}
Run Code Online (Sandbox Code Playgroud)