Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkinsfile - Conditional stage execution in the Script Pipeline syntax

We are using the Script Pipeline syntax for our Jenkinsfile which has a lot of stage defined to build and deploy our code. We have a use case where I want to run all my stages if I am doing a Full Build but only run one specific stage if I need to perform some AWS routing. I know I can use the if(<expression>) to skip a stage or run a stage. Problem is I don't want to apply that if condition to every stage in my Jenkinsfile.

In the new Declarative Pipeline syntax this is easily possible using the stage..when option. We have a lot of custom Groovy helper function used in our infrastructure so it is not possible at this point for me to switch from the Script Pipeline syntax to the new Declarative Pipeline syntax. What I ended up doing on my existing Jenkinsfile is something like this..

Original Jenkinsfile

  stage('Checkout Code') {}
  stage('Build') {}
  parallel(
    stage('Sonar Analysis') {}
    stage('CLM Analysis') {}
    stage('Security Analysis') {}
  )
  stage('Build Docker Image') {}
  ...
  ...
  stage('QA Deploy') {}
  stage('QA Routing') {}
  ...
  ...
  stage('Prod Deploy') {}
  stage('Prod Routing') {}

Changed to

  if (fullDeploy){
    stage('Full Build') {
        stage('Checkout Code') {}
        stage('Build') {}
        parallel(
          stage('Sonar Analysis') {}
          stage('CLM Analysis') {}
          stage('Security Analysis') {}
        )
        stage('Build Docker Image') {}
        ...
        ...
        stage('QA Deploy') {}
        stage('QA Routing') {}
        ...
        ...
        stage('Prod Deploy') {}
        stage('Prod Routing') {}          
    }
  }

  if (routeOnly){
    stage('Prod Routing') {}    
  } 

This feels a little hacky to me and I couldn't find any things on the Jenkins docs that provides a good way to do this.

Has anyone got a better way in which I can incorporate this?

like image 540
Ali Bhagat Avatar asked Aug 19 '17 23:08

Ali Bhagat


People also ask

How do you condition in Jenkins pipeline?

Jenkins “when” Directive: Execution of the pipeline stages can be controlled with conditions. These conditions must be defined in the when block within each stage. Jenkins supports a set of significant conditions that can be defined to limit stage execution. Each when block must contain at least one condition.

What syntax does the scripted pipeline in Jenkins follows?

Creating Your Jenkins Pipeline Script. Pipelines have specific sentences or elements to define script sections, which follow the Groovy syntax.

How do you call a stage in another stage in Jenkins pipeline?

In the pipeline job 'Test A' - Stage 'Checkout_A' it calls other pipeline job 'Test B' - Stage 'Checkout_B' , after that stage in Test B is completed the controller should retun back to pipeline job 'Test A' and execute Stage ('Build_A') which again calls pipeline job 'Test B' - Stage ('Build_B') then controller should ...


2 Answers

I also disliked the idea of having a redundant if{} block inside my stage{}. I solved this by overwriting the stage as follows

def stage(name, execute, block) {
    return stage(name, execute ? block : {echo "skipped stage $name"})
}

now you can disable a stage as follows

stage('Full Build', false) { 
    ...
}

Update You could also mark stage skipped using below def

import org.jenkinsci.plugins.pipeline.modeldefinition.Utils

def stage(name, execute, block) {
    return stage(name, execute ? block : {
        echo "skipped stage $name"
        Utils.markStageSkippedForConditional(STAGE_NAME)
    })
}
like image 124
culmat Avatar answered Sep 23 '22 17:09

culmat


(Built on top of culmat's answer https://stackoverflow.com/a/46784839/9993205)

Below provides 2 choices:

  1. mark stage as skipped, but still show in UI,
  2. or completely skip stage - hide in UI

vars/stageConditional.groovy:

import org.jenkinsci.plugins.pipeline.modeldefinition.Utils

def skipped(name, execute, block){
    log.HEADER "STAGE: $name"
    return stage(name, execute ? block : {
        echo "Skipped (shown in UI) stage $name"
        Utils.markStageSkippedForConditional(STAGE_NAME)
    })
}
def hidden(name, execute, block) {
    log.HEADER "STAGE: $name"
    if (execute){
        return stage(name, block)
    } else {
        echo "Hidden (not shown in UI) stage $name"
    }
}

Usage: it is a drop-in replacements for a stage, with condition added.

Example: unless dockerize is true, both stages are hidden (note: stage is inside stage). Otherwise build, but publish conditionally (e.g. not in bugfix/feature branch), marking stage as skipped.

        stageConditional.hidden('Java: build Docker image', plan.docker.dockerize) {
          gradlew('buildImage')

          stageConditional.skipped('Java: push Docker image', plan.publish.publish) {
            gradlew('pushImage')
          }
        }
like image 35
Aleksejs Spiridonovs Avatar answered Sep 20 '22 17:09

Aleksejs Spiridonovs