44

Let's say we have the following Jenkinsfile:

stage name: "Cool stage"
    sh 'whoami'
stage name: "Better stage"
    def current_stage = getCurrentStageName()
    echo "CONGRATULATIONS, you are on stage: $current_stage"

The question is how to implement getCurrentStageName(). I know, that I can get an access to build run-time using currentBuild.rawBuild. But how to get stage name from that point?

I need this for some customization in email notifications, so that I can always catch failed stage name and include it into email body.

Jesse Glick
  • 24,539
  • 10
  • 90
  • 112
Aleks
  • 1,301
  • 2
  • 12
  • 9
  • 2
    Did you even find an answer to this? I'm looking for the same thing now – Craigt Oct 05 '16 at 07:57
  • 4
    Not the real answer but workaround. You may create a sort of wrapper, which will accept stage name, write it into global variable and call `stage` – Aleks Oct 06 '16 at 12:08

4 Answers4

45

You can now do this in a built-in manner, since Jenkins 2.3. Like so:

steps {
    updateGitlabCommitStatus name: STAGE_NAME, state: 'running'
    echo '${STAGE_NAME}'
}

For more information see: https://issues.jenkins-ci.org/browse/JENKINS-44456

Jansky
  • 1,455
  • 1
  • 17
  • 33
12

This should work from a pipeline shared library:

#!/usr/bin/env groovy

import hudson.model.Action;

import org.jenkinsci.plugins.workflow.graph.FlowNode
import org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode
import org.jenkinsci.plugins.workflow.actions.LabelAction


def getStage(currentBuild){
    def build = currentBuild.getRawBuild()
    def execution = build.getExecution()
    def executionHeads = execution.getCurrentHeads()
    def stepStartNode = getStepStartNode(executionHeads)

    if(stepStartNode){
        return stepStartNode.getDisplayName()
    }
}

def getStepStartNode(List<FlowNode> flowNodes){
    def currentFlowNode = null
    def labelAction = null

    for (FlowNode flowNode: flowNodes){
        currentFlowNode = flowNode
        labelAction = false

        if (flowNode instanceof StepStartNode){
            labelAction = hasLabelAction(flowNode)
        }

        if (labelAction){
            return flowNode
        }
    }

    if (currentFlowNode == null) {
        return null
    }

    return getStepStartNode(currentFlowNode.getParents())
}

def hasLabelAction(FlowNode flowNode){
    def actions = flowNode.getActions()

    for (Action action: actions){
        if (action instanceof LabelAction) {
            return true
        }
    }

    return false
}

def call() {
    return getStage(currentBuild)
}

Example usage:

node {
    stage('Stage One'){
        echo getCurrentStage()
    }

    stage('Stage Two'){
        echo getCurrentStage()
    }
}
Trevor Howard
  • 121
  • 1
  • 3
  • 1
    I have managed to modify your script to get a hold of the previously executed stages. Do you know of a way to get the build result of those previous stages? – andsens Aug 11 '17 at 14:08
  • Got it! http://javadoc.jenkins.io/plugin/pipeline-rest-api/com/cloudbees/workflow/flownode/FlowNodeUtil.html#getStatus-org.jenkinsci.plugins.workflow.graph.FlowNode- – andsens Aug 14 '17 at 12:24
  • 2
    I made an example to get result of stages: https://gist.github.com/GuillaumeSmaha/fdef2088f7415c60adf95d44073c3c88 – GuillaumeS Oct 18 '17 at 18:19
  • Great stuff, I was able to extract the `parallel()` branches names as well. – Joerg S Aug 27 '18 at 15:01
  • These functions are not whitelisted for use in sandbox. – haridsv Feb 06 '19 at 05:27
5

Aleks' workaround works fine, just thought it's worth sharing the code

node ("docker") {
    def sendOk = {
        String stage -> slackSend color: 'good', message: stage + " completed, project - ${env.JOB_NAME}:1.0.${env.BUILD_NUMBER}"
    }
    def sendProblem = {
        String stage, error -> slackSend color: 'danger', message: stage + " did not succeed, project - ${env.JOB_NAME}:1.0.${env.BUILD_NUMBER}, error: ${error}, Find details here: ${env.BUILD_URL}"
    }
    def exec = {
        work, stageName -> 
            stage (stageName) {
                try {
                    work.call();
                    sendOk(stageName)
                }
                catch(error) {
                    sendProblem(stageName, error)
                    throw error
                }
            }
    }
    exec({
        git credentialsId: 'github-root', url: 'https://github.com/abc'
        dir ('src') {
            git credentialsId: 'github-root', url: 'https://github.com/abc-jenkins'
        }
        sh "chmod +x *.sh"
    }, "pull")
    exec({ sh "./Jenkinsfile-clean.sh \"1.0.${env.BUILD_NUMBER}\"" }, "clean")
    exec({ sh "./Jenkinsfile-unit.sh \"1.0.${env.BUILD_NUMBER}\"" }, "unit")
    exec({ sh "./Jenkinsfile-build.sh \"1.0.${env.BUILD_NUMBER}\"" }, "build")
    exec({ sh "./Jenkinsfile-dockerize.sh \"1.0.${env.BUILD_NUMBER}\"" }, "dockerize")
    exec({ sh "./Jenkinsfile-push.sh \"1.0.${env.BUILD_NUMBER}\"" }, "push")
    exec({ sh "./Jenkinsfile-prod-like.sh \"1.0.${env.BUILD_NUMBER}\"" }, "swarm")
}
0

As a workaround, in the failure email I include a link to the Pipeline Steps page. This page clearly shows green and red balls for each step, making it easy for the email recipient to figure out not just the stage, but the step that failed.

In the following example email body, the FlowGraphTable link links to Pipeline Steps:

def details = """<p>Job '${env.JOB_NAME}', build ${env.BUILD_NUMBER} result was ${buildStatus}.
  Please scrutinize the build and take corrective action.</p>
  <p>Quick links to the details:
  <ul>
    <li><a href="${env.JOB_URL}">${env.JOB_NAME} job main page</a></li>
    <li><a href="${env.BUILD_URL}">Build ${env.BUILD_NUMBER} main page</a></li>
    <ul>
      <li><a href="${env.BUILD_URL}console">Console output</a></li>
      <li><a href="${env.BUILD_URL}changes">Git changes</a></li>
      <li><a href="${env.BUILD_URL}flowGraphTable">Pipeline steps</a>.
          This page will show you which step failed, and give you access
          to the job workspace.</li>
    </ul>
  </ul></p>"""

This is an excerpt from my implementation of notifyBuild() that BitwiseMan of CloudBees presents in his article, Sending Notifications in Pipeline.

Community
  • 1
  • 1
John McGehee
  • 9,117
  • 9
  • 42
  • 50