Condition in pipeline

Optional Stages (if)
Generally, it is possible to use Groovy’s conditionals in a declarative syntax, when we use a script step. So for example, if we only want a release to happen, if a certain boolean parameter RELEASE is set, we code it like this
pipeline { 
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
    }
    stages {

        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            steps {
                script {
                    if (params.RELEASE) {
                        sh "./gradlew release"
                    }
                }
            }
        }
    }
}

But in that case, we end up with a stage that looks like it was successfully executed, but in fact, it didn’t do anything.

The declarative way of expressing this is the when directive, which will skip or execute a whole stage according to a condition.
And then evaluate its value in a when directive on the release stage
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
    }
    stages {

        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            when { expression { params.RELEASE } }
            steps {
                sh "./gradlew release"
            }
        }
    }
}

This code is even shorter and less indented. Jenkins will display the stage to be skipped or executed in the build overview, so we can find the last build that performed a release without having to check the logs.

Either A or B (if/else)
Sometimes we want either one or another thing to happen. For example, we have a mechanism to build a pre-release and another to build a final release.

So, here’s the version using a script with if and else
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
    }
    stages {
        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            steps {
                script {
                    if (params.RELEASE) {
                        sh "./gradlew release"
                    } else {
                        sh "./gradlew preRelease"
                    }
                }
            }
        }
    }
}

This is short and still readable. However, to Jenkins, this is one step and to find out what happened in hindsight is not easy as we’d need to check the logs on the executions.

We can get more declarative using two successive stages with when, where the first when can only be true if the second is false and vice versa.
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
    }
    stages {
        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish Pre-Release") {
            when { expression { !params.RELEASE } }
            steps {
               sh "./gradlew preRelease"
            }
        }
        stage("Publish Release") {
            when { expression { params.RELEASE } }
            steps {
               sh "./gradlew release"
            }
        }
    }
}

This is a bit more code, but still reads alright and we get a much better understanding by looking at the graph.
But after all, both stages are doing the same thing (publishing) and it would be nicer to have them grouped by something more than just by name.

For this, we can wrap both stages in a parallel section
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
    }
    stages {
        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            parallel {
                stage("Release") {
                    when { expression { params.RELEASE } }
                    steps {
                        sh "./gradlew release"
                    }
                }
                stage('Pre-Release') {
                    when { expression { !params.RELEASE } }
                    steps {
                        sh "./gradlew preRelease"
                    }
                }
            }
        }
    }
}
Now, when we look at the pipeline graph, we get a nice overview, which way the build took.
One of Many (switch)
In some cases, we not only want to choose one out of two but out of many alternatives. E.g. we’d like to add a deploy stage but want to choose the target stage via parameter.

Again, we can fallback to script and use switch for this
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
        choice(name: "DEPLOY_TO", choices: ["", "INT", "PRE", "PROD"])
    }
    stages {
        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            parallel {
                stage('Pre-Release') {
                    when { expression { !params.RELEASE } }
                    steps {
                        sh "./gradlew preRelease"
                    }
                }
                stage("Release") {
                    when { expression { params.RELEASE } }
                    steps {
                        sh "./gradlew release"
                    }
                }
            }
        }
        stage("Deploy") {
            steps {
                script {
                    switch(params.DEPLOY_TO) {
                        case "INT": echo "./deploy.sh int"; break
                        case "PRE": echo "./deploy.sh pre"; break
                        case "PROD": echo "./deploy.sh prod"; break
                    }
                }
            }
        }
    }
}

Again, this is quite short and well readable in the Jenkinsfile, but in the pipeline graph, it is hard to see, where the deployment went to.
But we can apply the same trick as before, only now we use a choice parameter
pipeline {
    agent any
    parameters {
        booleanParam(name: "RELEASE", defaultValue: false)
        choice(name: "DEPLOY_TO", choices: ["", "INT", "PRE", "PROD"])
    }
    stages {
        stage("Build") {
            steps {
                sh "./gradlew build"
            }
        }
        stage("Publish") {
            parallel {
                stage('Pre-Release') {
                    when { expression { !params.RELEASE } }
                    steps {
                        sh "./gradlew preRelease"
                    }
                }
                stage("Release") {
                    when { expression { params.RELEASE } }
                    steps {
                        sh "./gradlew release"
                    }
                }
            }
        }

        stage("Deploy") {
            parallel {
                stage("INT") {
                    when { expression { params.DEPLOY_TO == "INT" } }
                    steps {
                        sh "./deploy int"
                    }
                }
                stage("PRE") {
                    when { expression { params.DEPLOY_TO == "PRE" } }
                    steps {
                        sh "./deploy.sh pre"
                    }
                }
                stage("PROD") {
                    when { expression { params.DEPLOY_TO == "PROD" } }
                    steps {
                        sh "./deploy.sh prod"
                    }
                }
            }
        }
    }
}
This is a lot more code, compared to the simple script solution above, but the pipeline graph gets a lot more expressive.




Recent Comments

No comments

Leave a Comment