是否可以创建具有可选输入阶段的Jenkins管道?
以下代码段未实现此目标。
该阶段(以及输入提示)仅应针对特定分支运行。
此阶段适用于所有分支。使用输入步骤时,将忽略when过滤器。
stage('Approve') { when { expression { BRANCH_NAME ==~ /^qa[\w-_]*$/ } } input { message "Approve release?" ok "y" submitter "admin" parameters { string(name: 'IS_APPROVED', defaultValue: 'y', description: 'Deploy to master?') } } steps { script { if (IS_APPROVED != 'y') { currentBuild.result = "ABORTED" error "User cancelled" } } } }
过滤器不会被忽略,它只是在输入步骤之后进行评估。在您的示例中,将始终询问您是否进行部署,并且如果您不在QA分支上,则什么也不会发生。
现在您可以问为什么詹金斯不首先评估“何时”指令。在这种情况下,您将无法在when条件中使用输入参数。
并且具有多个when指令就像在声明性管道中编写脚本。
但是,有一个表达式可以让您控制何时评估“何时”指令。这是beforeAgent。它使您可以在分配代理之前评估when语句。与此类似,您将需要诸如beforeInput之类的东西。您可以为此创建功能请求。
我不再使用input指令,而是现在在脚本块中使用input,因为它提供了更大的灵活性,例如,当有人必须批准某些内容时,我将发送Slack通知,这对于声明式方法是不可能的。您将需要一个notify指令。如果有一个,是否要在输入步骤之前或之后进行评估?
您会发现,进行声明式的操作并不总是最好的方法。因此,我推荐的方法如下(免责声明:未经测试!):
pipeline { // We want to use agents per stage to avoid blocking our build agents // while we are waiting for user input. agent none ... // The question mark naming convention is helpful to show you which // approval stage belongs to which work stage. stage('Release?') { // Don't allocate an agent because we don't want to block our // slaves while waiting for user input. agent none when { // You forgot the 'env.' in your example above ;) expression { env.BRANCH_NAME ==~ /^qa[\w-_]*$/ } } options { // Optionally, let's add a timeout that we don't allow ancient // builds to be released. timeout time: 14, unit: 'DAYS' } steps { // Optionally, send some notifications to the approver before // asking for input. You can't do that with the input directive // without using an extra stage. slackSend ... // The input statement has to go to a script block because we // want to assign the result to an environment variable. As we // want to stay as declarative as possible, we put noting but // this into the script block. script { // Assign the 'DO_RELEASE' environment variable that is going // to be used in the next stage. env.DO_RELEASE = input ... } // In case you approved multiple pipeline runs in parallel, this // milestone would kill the older runs and prevent deploying // older releases over newer ones. milestone 1 } } stage('Release') { // We need a real agent, because we want to do some real work. agent any when { // Evaluate the 'when' directive before allocating the agent. beforeAgent true // Only execute the step when the release has been approved. environment name: 'DO_RELEASE', value: 'yes' } steps { // Make sure that only one release can happen at a time. lock('release') { // As using the first milestone only would introduce a race // condition (assume that the older build would enter the // milestone first, but the lock second) and Jenkins does // not support inter-stage locks yet, we need a second // milestone to make sure that older builds don't overwrite // newer ones. milestone 2 // Now do the actual work here. ... } } }