Search code examples
jenkinsjenkins-pipelinejenkins-blueocean

Get step id in Jenkins Pipeline for linking to BlueOcean or Pipeline Steps view (flowGraphTable)


Given a Jenkins pipeline that runs a series of steps, some within parallel blocks, is there any way to obtain within the pipeline the Flow id of a given step or the most recent step?

What's a Flow ID? If you look at a Run of your Pipeline job you can see a "Pipeline Steps" link that points to flowGraphTable/. There you have links to specific job steps like execution/node/113/. These seem to represent a FlowNode.

Is there any way to get these IDs from within the pipeline, for generating links etc?

In particular I want to get a link to the sub-Flow for my parallel branches so I can link to the BlueOcean views of them. (The builtin Jenkins view is useless because it doesn't show a subtree).

I can see that the BlueOcean links correspond to the /execution/ links, they have the same id value. If my pipeline branch is myjob/9/execution/node/78/ then on blueocean it'll be jobname/9/pipeline/78.

But how do I get that ID if I want to use the build summary plugin or similar to generate the links and add them to the build results page?


Solution

  • In particular I want to get a link to the sub-Flow for my parallel branches so I can link to the BlueOcean views of them.

    You can get the head flow node (most recent step) of the current thread (aka branch) using CpsThread.current().head.get(). Then you can use FlowNode.iterateEnclosingBlocks() to find the parent branch by checking whether a block start node contains an instance of ThreadNameAction.

    Complete pipeline example:

    import org.jenkinsci.plugins.workflow.cps.CpsThread
    import org.jenkinsci.plugins.workflow.graph.FlowNode
    import org.jenkinsci.plugins.workflow.actions.LabelAction
    import org.jenkinsci.plugins.workflow.actions.ThreadNameAction
    
    pipeline {
        agent any
        
        stages {
            stage("parallel start"){
                parallel {
                    stage("A"){
                        steps{
                            showCurrentBranchUrls()
                            echo "Another step"
                        }
                    }
                    stage("B"){
                        steps{
                            echo "Some stuff"
                            showCurrentBranchUrls()
                            echo "More stuff"
                        }
                    }
                }
            }
        }
    }
    
    void showCurrentBranchUrls() {
        // Get the most recent FlowNode of current branch
        FlowNode headNode = CpsThread.current().head.get()
        
        // Find the nearest parent branch
        FlowNode branchNode = getFlowNodeOfParentBranch( headNode )
        if( branchNode ) {
            // Print some useful URLs based on branchNode
            echo "Blue Ocean branch view: ${JENKINS_URL}blue/organizations/jenkins/${JOB_NAME}/detail/${JOB_BASE_NAME}/${BUILD_ID}/pipeline/${branchNode.id}"
            echo "Blue Ocean branch log: ${JENKINS_URL}blue/rest/organizations/jenkins/pipelines/${JOB_NAME}/runs/${BUILD_ID}/nodes/${branchNode.id}/log"
            echo "Pipeline steps: ${JENKINS_URL}${branchNode.url}"
        }
    }
    
    // Get FlowNode of parent branch
    @NonCPS
    FlowNode getFlowNodeOfParentBranch( FlowNode node ) {
        node.iterateEnclosingBlocks().find{ enclosing ->
            enclosing != null && 
            enclosing.getAction( LabelAction.class ) != null && 
            enclosing.getAction( ThreadNameAction.class ) != null
        }
    }
    

    In a sandboxed pipeline script the code may trigger some security errors, so I recommend to put it into a shared library which doesn't have such restrictions.


    In case you want to find the node ID of another branch instead of the current branch, the class PipelineNodeGraphVisitor comes in handy. There are already many examples on SO, e. g. this one of mine.


    For further reading, here is a good overview about working with the Jenkins Flow Graph.