jenkins - list stages for each parallel branch

1k views Asked by At

I got code that list all branches and stages for my pipeline

def List getBranchResults() {
    def visitor = new PipelineNodeGraphVisitor(currentBuild.rawBuild)
    echo "${visitor}"
    def branches = visitor.pipelineNodes.findAll{
        it.type == FlowNodeWrapper.NodeType.PARALLEL 
    }
    def stages = visitor.pipelineNodes.findAll{
        it.type == FlowNodeWrapper.NodeType.STAGE
    }
    echo "${stages}"
    def results = branches.collect{
        branch -> [ 
        id: branch.id, 
        displayName: branch.displayName, 
        result: "${branch.status.result}",]
    }
    echo "Branch results:\n" + results.join('\n')
}
def build_jobs = [:]
def build_results
build_jobs['1'] = {
    node('builder'){
        stage('A'){
            sh 'echo 1'
        }
        stage('B'){
           "error"
        }
    }
}
build_jobs['2'] = {
    node('builder'){
        sh 'echo 2'
    }
}
build_jobs['3'] = {
    node('builder'){
        stage('A'){
            sh 'echo 3'
        }
        stage('B'){
            
        }
    }
}
parallel build_jobs
getBranchResults( )

How I can connect between those two ? I want to print for each branch it stages. Also I want to print the failed stage (if it exists) for each branch

For example:

Branch results:
[id:15, displayName:1, result:SUCCESS]
Stage results for 1:
[id=55,displayName=A,type=STAGE]
[id=25,displayName=B,type=STAGE] - FAILURE
1

There are 1 answers

0
zett42 On BEST ANSWER

We can associate branches and child stages by querying FlowNode.allEnclosingIds for each node. If this list contains branch ID, we have a child stage.

I have implemented this in function getStageResultsForBranch() below. It appears to work with the sample code. If stages have nested sub stages, it will return these too, which may not be what you want.

Sample code:

import io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeGraphVisitor
import io.jenkins.blueocean.rest.impl.pipeline.FlowNodeWrapper

@NonCPS
def List getBranchResults() {

    def visitor = new PipelineNodeGraphVisitor(currentBuild.rawBuild)

    def branches = visitor.pipelineNodes.findAll{
        it.type == FlowNodeWrapper.NodeType.PARALLEL 
    }

    def results = branches.collect{ branch -> [ 
        id: branch.id, 
        displayName: branch.displayName, 
        result: "${branch.status.result}",
    ]}
    
    return results
}

@NonCPS
def List getStageResultsForBranch( String branchId ) {

    def visitor = new PipelineNodeGraphVisitor(currentBuild.rawBuild)

    def childStages = visitor.pipelineNodes.findAll{ stage ->
        stage.type == FlowNodeWrapper.NodeType.STAGE &&
        stage.node.allEnclosingIds.contains( branchId )
    }
    
    def results = childStages.collect{ stage -> [ 
        id: stage.id, 
        displayName: stage.displayName, 
        result: "${stage.status.result}",
    ]}
    
    return results
}

node {
    def build_jobs = [:]
    def build_results
    
    build_jobs['1'] = {
        stage('1.A'){
            sh 'echo 1'
        }
        stage('1.B'){
           error 'an error'
        }
    }
    build_jobs['2'] = {
        sh 'echo 2'
    }
    build_jobs['3'] = {
        stage('3.A'){
            sh 'echo 3'
        }
        stage('3.B'){
                        
        }
    }
    
    try {
        parallel build_jobs
    }
    finally {
        stage('Final') {
            for( branchRes in getBranchResults() ) {
                def stageResults = getStageResultsForBranch( branchRes.id )

                echo "BRANCH RESULT: $branchRes\n" +
                     "  STAGE RESULTS:\n  ${stageResults.join('\n  ')}"
            }
        }
    }
}

(I have removed the build job nodes for testing)

Output:

BRANCH RESULT: [id:8, displayName:1, result:FAILURE]
  STAGE RESULTS:
  [id:12, displayName:1.A, result:SUCCESS]
  [id:29, displayName:1.B, result:FAILURE]

BRANCH RESULT: [id:9, displayName:2, result:SUCCESS]
  STAGE RESULTS:

BRANCH RESULT: [id:10, displayName:3, result:SUCCESS]
  STAGE RESULTS:
  [id:15, displayName:3.A, result:SUCCESS]
  [id:21, displayName:3.B, result:NOT_BUILT]