Aleks
Aleks

Reputation: 1349

Access Stage name during the build in Jenkins pipeline

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.

Upvotes: 47

Views: 52921

Answers (4)

Jansky
Jansky

Reputation: 1587

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

Upvotes: 48

Trevor Howard
Trevor Howard

Reputation: 131

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()
    }
}

Upvotes: 12

Kirill Chilingarashvili
Kirill Chilingarashvili

Reputation: 1089

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")
}

Upvotes: 5

John McGehee
John McGehee

Reputation: 10299

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.

Upvotes: 0

Related Questions