Stages 阶段(if)

一般来说,当我们使用脚本步骤时,可以用声明式的语法来使用Groovy的条件式。例如,如果我们只想在某个布尔参数RELEASE被设置时发生释放,我们可以这样编码

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

但在这种情况下,我们最终会得到一个看起来成功执行的阶段,但事实上,它没有做任何事情。

声明式的表达方式是when指令,它将根据条件跳过或执行整个阶段。
然后在stage阶段的when指令中评估其值

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

这段代码甚至更短,缩进更少。Jenkins将在构建概述中显示要跳过或执行的阶段,因此我们可以找到执行发布的最后一个构建,而无需检查日志。

Either A or B (if/else)

有时我们希望发生一件或另一件事。例如,我们有一个机制来构建pre-release版本,另一个机制用来构建最终release本。

下面是使用if和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"
                    }
                }
            }
        }
    }
}

这很短,而且还可以阅读。然而,对Jenkins来说,这只是一个步骤,要在事后找出发生了什么并不容易,因为我们需要检查执行的日志。

我们可以使用两个连续的阶段与when来获得更多的声明性,其中第一个when只有在第二个是假的情况下才能为真,反之亦然。

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

这段代码稍微多了一点,但读起来还是不错的,通过查看图表,我们可以更好地理解它。
但毕竟,这两个阶段都在做相同的事情(发布),最好是按名称以外的内容对它们进行分组。

为此,我们可以把这两个阶段包在一个平行的部分中

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

现在,当我们看pipeline图时,我们会得到一个很好的概述,即构建的方式。

One of Many (switch)

在某些情况下,我们不仅要在两个选项中选择一个,还要在许多选项中选择一个。例如,我们想增加一个部署阶段,但想通过参数选择目标阶段。

同样,我们可以退回到脚本,并使用开关来处理这个问题

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

同样,这在Jenkinsfile中是很短的,可读性很强,但在pipeline图中,很难看到部署到哪里去了。
但我们可以采用与之前相同的技巧,只是现在我们使用一个选择参数

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

与上面简单的脚本解决方案相比,这要多出很多代码,但pipeline图变得更有表现力。

参考:https://www.zippyops.com/condition-in-pipeline