我可以使用闭包在 Jenkins 声明式管道中定义一个阶段吗?

Wil*_*ode 9 groovy closures jenkins jenkins-pipeline

我正在尝试做这样的事情:

def makeStage = {
  stage('a') {
    steps {
      echo 'Hello World'
    }
  }
} 
pipeline {
  agent none
  stages {
    makeStage()
  }
}
Run Code Online (Sandbox Code Playgroud)

但它给了我这个例外:

WorkflowScript: 11: Expected a stage @ line 11, column 5.
   makeStage()
   ^
Run Code Online (Sandbox Code Playgroud)

是否可以将阶段定义为外部闭包,如果可以 - 如何定义?

Joh*_*ynh 11

太晚了,但如果有人遇到这个问题,一个可能的解决方案是将生成的阶段包装在一个脚本声明中并.call在生成的阶段上调用。

所以对你来说:

def makeStage = {
  return {
    stage('a') {
      echo 'Hello World'
    }
  }
}

pipeline {
  agent none
  stages {
    stage ('hello world') {
      steps {
        script {
          makeStage().call()
        }      
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

哎呀。编辑后,我在 makeStage 声明中的舞台('a')上有“步骤”。“steps”是一个声明性管道指令,因此它在脚本块内抛出错误。

  • 请注意,以这种方式添加阶段是将声明性阶段(管道模型定义)与脚本化阶段混合在一起。这两件事并不相等,尽管它们可能看起来相同。您甚至可以将多个阶段注入到单个声明性阶段,但这是滥用或反模式。检查 Blue Ocean UI 并发现以这种方式注入的阶段不提供与常规声明性阶段相同的功能。例如,您不能从该阶段重新启动管道,或设置阶段选项,仅举这两件事。我不建议混合这两种不同的东西。 (2认同)

Szy*_*iak 5

您不能在声明性管道之外定义阶段。声明式管道的主要目的是提供简化和自以为是的语法,以便您可以专注于应该做什么(通过使用一些可用的步骤)而不是如何去做。

如果您对更灵活的管道实现方式感兴趣,您可以选择脚本化管道方法,它在语法上并不那么严格 - 它仅受 Groovy 和 CPS 执行模块的限制。

您示例中的工作(脚本化)管道如下所示:

#!groovy

def makeStage = {
  stage('a') {
    echo 'Hello World'
  }
} 

node {
    makeStage()
}
Run Code Online (Sandbox Code Playgroud)

注意:脚本管道中没有steps内部方法stage。如果你把它留在那里,你会得到

java.lang.NoSuchMethodError: No such DSL method 'steps' found among 
    steps [archive, bat, build, catchError, checkout, deleteDir, dir, 
    dockerFingerprintFrom, ...
Run Code Online (Sandbox Code Playgroud)

声明性管道中的脚本

声明式管道定义了一个script步骤,允许您放置一个脚本管道块。但是,它仍然不允许您动态定义阶段或/和将阶段定义提取到函数或闭包中。scriptstep 在舞台内执行,因此您无法在此块内控制舞台是否执行。但是,在某些情况下,如果您想做一些比仅调用声明性管道的预定义步骤更复杂的事情,则此步骤可能非常有用。

  • @star,请记住,以这种方式添加的阶段不是声明性的管道阶段。在这种情况下,您将来自管道模型定义插件的声明性阶段与脚本化阶段混合在一起。这两件事并不相等。检查 Blue Ocean UI 并看看是否可以重新启动这样的阶段。你不能。所以如果你想在管道块之外定义一个声明性管道阶段,这是不可能的。添加等效的脚本化阶段是可能的(您甚至可以将多个阶段注入到单个声明性阶段),但这实际上是一种反模式。无需投反对票。 (4认同)