詹金斯管道中“脚本”块之外的动态并行阶段

Cla*_*her 3 groovy jenkins jenkins-pipeline

我正在尝试动态构建并行阶段,如此此处所示。具体来说,我正在尝试在管道范围之外定义的函数中执行此操作,例如:

pipeline{
  stages{
    stage('CI'){
      steps{
        doDynamicParallelSteps()
      }
    }
  }
}

def doDynamicParallelSteps(){
  tests = [:]
  for (f in findFiles(glob: '**/html/*.html')) {
    tests["${f}"] = {
      node {
        stage("${f}") {
          echo '${f}'
        }
      }
    }
  }
  parallel tests
}
Run Code Online (Sandbox Code Playgroud)

问题是,这似乎只有在动态并行生成代码在管道的step {}块内的script {}块内时才起作用(如第一个参考资料所示)。

当运行类似于上面的代码片段的内容时,我在jenkins中看到此错误:

hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.lang.String.call() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [teststage, org.jenkinsci.plugins.workflow.cps.CpsClosure2@2e1b48b4]
Possible solutions: wait(), any(), trim(), size(), next(), size()
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:153)
    at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:155)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
    at WorkflowScript.parallelHandler(WorkflowScript:1383)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
    at sun.reflect.GeneratedMethodAccessor110.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
    at com.cloudbees.groovy.cps.impl.ClosureBlock.eval(ClosureBlock.java:46)
    at com.cloudbees.groovy.cps.Next.step(Next.java:83)
    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
    at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
    at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:182)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE
Run Code Online (Sandbox Code Playgroud)

是否可以按照我在初始代码片段中所示的方式将其定义为函数,还是在管道定义中坚持使用大量的script {}块?

Szy*_*iak 8

声明管道不允许你把Groovy代码里面steps {}块-它预计在这个地方的有效詹金斯管道的一步。这就是为什么script {}可以将steps {}块放入块中以执行一些Groovy代码的原因。

如果您需要灵活性和非操作性语法,则可以改用脚本管道。在这里,您可以毫无限制地将Groovy代码与现有管道步骤混合在一起。

Jenkins文档很快解释了这两种方法之间的区别以及它们存在的原因:

最初创建Jenkins Pipeline时,Groovy被选为基础。Jenkins长期以来一直提供嵌入式Groovy引擎,以为管理员和用户提供高级脚本功能。另外,Jenkins Pipeline的实现者发现Groovy是构建现在称为“脚本管道” DSL的坚实基础。[2]。

由于它是功能齐全的编程环境,因此脚本化管道为Jenkins用户提供了极大的灵活性和可扩展性。Groovy学习曲线通常不是给定团队的所有成员所希望的,因此创建了声明式管道,以为编写Jenkins Pipeline提供更简单,更自以为是的语法。

两者基本上是下面的相同管道子系统。它们都是“管道作为代码”的持久实现。他们都可以使用内置在Pipeline中或由插件提供的步骤。两者都可以利用共享库

您在脚本化管道中的示例可能如下所示:

node {
  stage('CI') {
    doDynamicParallelSteps()
  }
}

def doDynamicParallelSteps(){
  tests = [:]
  for (f in findFiles(glob: '**/html/*.html')) {
    tests["${f}"] = {
      node {
        stage("${f}") {
          echo '${f}'
        }
      }
    }
  }
  parallel tests
}
Run Code Online (Sandbox Code Playgroud)

声明式管道中有script {}块的步骤如下所示:

pipeline{
  agent any
  stages{
    stage('CI'){
      steps{
        script {
            doDynamicParallelSteps()
        }
      }
    }
  }
}

def doDynamicParallelSteps(){
  tests = [:]
  for (f in findFiles(glob: '**/html/*.html')) {
    tests["${f}"] = {
      node {
        stage("${f}") {
          echo '${f}'
        }
      }
    }
  }
  parallel tests
}
Run Code Online (Sandbox Code Playgroud)

  • 就我而言,我还需要在 ```for``` 循环之间添加 ```def var = "${f}"``` 到 ```tests``` 字典并使用 ```var` `` 在舞台内,否则我总是得到所有线程的 ```findFiles``` 中的最后一个元素(在我的例子中我使用了数组列表) (3认同)