Dynamic Parallel stages in Jenkins Pipeline outside 'script' block











up vote
1
down vote

favorite












I am trying to construct parallel stages dynamically, as demonstrated here and here. Specifically, I am trying to do this in a function defined outside the scope of the pipeline, e.g.:



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
}


The problem is, it seems this only works when the dynamic parallel generation code is inside a script{} block within the steps{} block of the pipeline (as seen in the first source).



When running something similar to the code snippet above, I see this error in 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


Is there any way to have it defined as a function in the way I showed in the initial code snippet, or am I stuck with having a ton of script{} blocks in my pipeline definition?










share|improve this question
























  • What is in line 1383 of your script? The error seems to be caused there according to the error message
    – Joerg S
    Nov 11 at 7:22















up vote
1
down vote

favorite












I am trying to construct parallel stages dynamically, as demonstrated here and here. Specifically, I am trying to do this in a function defined outside the scope of the pipeline, e.g.:



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
}


The problem is, it seems this only works when the dynamic parallel generation code is inside a script{} block within the steps{} block of the pipeline (as seen in the first source).



When running something similar to the code snippet above, I see this error in 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


Is there any way to have it defined as a function in the way I showed in the initial code snippet, or am I stuck with having a ton of script{} blocks in my pipeline definition?










share|improve this question
























  • What is in line 1383 of your script? The error seems to be caused there according to the error message
    – Joerg S
    Nov 11 at 7:22













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I am trying to construct parallel stages dynamically, as demonstrated here and here. Specifically, I am trying to do this in a function defined outside the scope of the pipeline, e.g.:



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
}


The problem is, it seems this only works when the dynamic parallel generation code is inside a script{} block within the steps{} block of the pipeline (as seen in the first source).



When running something similar to the code snippet above, I see this error in 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


Is there any way to have it defined as a function in the way I showed in the initial code snippet, or am I stuck with having a ton of script{} blocks in my pipeline definition?










share|improve this question















I am trying to construct parallel stages dynamically, as demonstrated here and here. Specifically, I am trying to do this in a function defined outside the scope of the pipeline, e.g.:



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
}


The problem is, it seems this only works when the dynamic parallel generation code is inside a script{} block within the steps{} block of the pipeline (as seen in the first source).



When running something similar to the code snippet above, I see this error in 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


Is there any way to have it defined as a function in the way I showed in the initial code snippet, or am I stuck with having a ton of script{} blocks in my pipeline definition?







jenkins groovy jenkins-pipeline






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 10 at 8:46









Szymon Stepniak

16.1k83061




16.1k83061










asked Nov 9 at 23:21









Clayton Keleher

214




214












  • What is in line 1383 of your script? The error seems to be caused there according to the error message
    – Joerg S
    Nov 11 at 7:22


















  • What is in line 1383 of your script? The error seems to be caused there according to the error message
    – Joerg S
    Nov 11 at 7:22
















What is in line 1383 of your script? The error seems to be caused there according to the error message
– Joerg S
Nov 11 at 7:22




What is in line 1383 of your script? The error seems to be caused there according to the error message
– Joerg S
Nov 11 at 7:22












1 Answer
1






active

oldest

votes

















up vote
1
down vote













The declarative pipeline does not allow you to put Groovy code inside steps {} block - it expects a valid Jenkins pipeline step in this place. This is why script {} block got introduced that can be put inside the steps {} block to execute some Groovy code.



If you need flexibility and non-opinionated syntax then you might use scripted pipeline instead. Here you can mix Groovy code with existing pipeline steps with almost no limitations.



Jenkins documentation explains shortly the difference between both approaches and why they exist:




When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipeline found Groovy to be a solid foundation upon which to build what is now referred to as the "Scripted Pipeline" DSL. [2].



As it is a fully featured programming environment, Scripted Pipeline offers a tremendous amount of flexibility and extensibility to Jenkins users. The Groovy learning-curve isn’t typically desirable for all members of a given team, so Declarative Pipeline was created to offer a simpler and more opinionated syntax for authoring Jenkins Pipeline.



Both are fundamentally the same Pipeline sub-system underneath. They are both durable implementations of "Pipeline as code." They are both able to use steps built into Pipeline or provided by plugins. Both are able to utilize Shared Libraries




Your example in scripted pipeline may look like this:



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

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


And declarative pipeline with script {} block in steps would look like this:



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
}





share|improve this answer





















  • For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
    – Clayton Keleher
    Nov 12 at 23:28










  • So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
    – Clayton Keleher
    Nov 13 at 1:22













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53234490%2fdynamic-parallel-stages-in-jenkins-pipeline-outside-script-block%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote













The declarative pipeline does not allow you to put Groovy code inside steps {} block - it expects a valid Jenkins pipeline step in this place. This is why script {} block got introduced that can be put inside the steps {} block to execute some Groovy code.



If you need flexibility and non-opinionated syntax then you might use scripted pipeline instead. Here you can mix Groovy code with existing pipeline steps with almost no limitations.



Jenkins documentation explains shortly the difference between both approaches and why they exist:




When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipeline found Groovy to be a solid foundation upon which to build what is now referred to as the "Scripted Pipeline" DSL. [2].



As it is a fully featured programming environment, Scripted Pipeline offers a tremendous amount of flexibility and extensibility to Jenkins users. The Groovy learning-curve isn’t typically desirable for all members of a given team, so Declarative Pipeline was created to offer a simpler and more opinionated syntax for authoring Jenkins Pipeline.



Both are fundamentally the same Pipeline sub-system underneath. They are both durable implementations of "Pipeline as code." They are both able to use steps built into Pipeline or provided by plugins. Both are able to utilize Shared Libraries




Your example in scripted pipeline may look like this:



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

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


And declarative pipeline with script {} block in steps would look like this:



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
}





share|improve this answer





















  • For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
    – Clayton Keleher
    Nov 12 at 23:28










  • So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
    – Clayton Keleher
    Nov 13 at 1:22

















up vote
1
down vote













The declarative pipeline does not allow you to put Groovy code inside steps {} block - it expects a valid Jenkins pipeline step in this place. This is why script {} block got introduced that can be put inside the steps {} block to execute some Groovy code.



If you need flexibility and non-opinionated syntax then you might use scripted pipeline instead. Here you can mix Groovy code with existing pipeline steps with almost no limitations.



Jenkins documentation explains shortly the difference between both approaches and why they exist:




When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipeline found Groovy to be a solid foundation upon which to build what is now referred to as the "Scripted Pipeline" DSL. [2].



As it is a fully featured programming environment, Scripted Pipeline offers a tremendous amount of flexibility and extensibility to Jenkins users. The Groovy learning-curve isn’t typically desirable for all members of a given team, so Declarative Pipeline was created to offer a simpler and more opinionated syntax for authoring Jenkins Pipeline.



Both are fundamentally the same Pipeline sub-system underneath. They are both durable implementations of "Pipeline as code." They are both able to use steps built into Pipeline or provided by plugins. Both are able to utilize Shared Libraries




Your example in scripted pipeline may look like this:



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

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


And declarative pipeline with script {} block in steps would look like this:



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
}





share|improve this answer





















  • For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
    – Clayton Keleher
    Nov 12 at 23:28










  • So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
    – Clayton Keleher
    Nov 13 at 1:22















up vote
1
down vote










up vote
1
down vote









The declarative pipeline does not allow you to put Groovy code inside steps {} block - it expects a valid Jenkins pipeline step in this place. This is why script {} block got introduced that can be put inside the steps {} block to execute some Groovy code.



If you need flexibility and non-opinionated syntax then you might use scripted pipeline instead. Here you can mix Groovy code with existing pipeline steps with almost no limitations.



Jenkins documentation explains shortly the difference between both approaches and why they exist:




When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipeline found Groovy to be a solid foundation upon which to build what is now referred to as the "Scripted Pipeline" DSL. [2].



As it is a fully featured programming environment, Scripted Pipeline offers a tremendous amount of flexibility and extensibility to Jenkins users. The Groovy learning-curve isn’t typically desirable for all members of a given team, so Declarative Pipeline was created to offer a simpler and more opinionated syntax for authoring Jenkins Pipeline.



Both are fundamentally the same Pipeline sub-system underneath. They are both durable implementations of "Pipeline as code." They are both able to use steps built into Pipeline or provided by plugins. Both are able to utilize Shared Libraries




Your example in scripted pipeline may look like this:



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

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


And declarative pipeline with script {} block in steps would look like this:



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
}





share|improve this answer












The declarative pipeline does not allow you to put Groovy code inside steps {} block - it expects a valid Jenkins pipeline step in this place. This is why script {} block got introduced that can be put inside the steps {} block to execute some Groovy code.



If you need flexibility and non-opinionated syntax then you might use scripted pipeline instead. Here you can mix Groovy code with existing pipeline steps with almost no limitations.



Jenkins documentation explains shortly the difference between both approaches and why they exist:




When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipeline found Groovy to be a solid foundation upon which to build what is now referred to as the "Scripted Pipeline" DSL. [2].



As it is a fully featured programming environment, Scripted Pipeline offers a tremendous amount of flexibility and extensibility to Jenkins users. The Groovy learning-curve isn’t typically desirable for all members of a given team, so Declarative Pipeline was created to offer a simpler and more opinionated syntax for authoring Jenkins Pipeline.



Both are fundamentally the same Pipeline sub-system underneath. They are both durable implementations of "Pipeline as code." They are both able to use steps built into Pipeline or provided by plugins. Both are able to utilize Shared Libraries




Your example in scripted pipeline may look like this:



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

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


And declarative pipeline with script {} block in steps would look like this:



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
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 10 at 8:45









Szymon Stepniak

16.1k83061




16.1k83061












  • For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
    – Clayton Keleher
    Nov 12 at 23:28










  • So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
    – Clayton Keleher
    Nov 13 at 1:22




















  • For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
    – Clayton Keleher
    Nov 12 at 23:28










  • So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
    – Clayton Keleher
    Nov 13 at 1:22


















For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
– Clayton Keleher
Nov 12 at 23:28




For some reason this doesn't work for me. I've copied an even simpler version of that block into my pipeline file, and it still does not work and throws the same error as above when it gets to the point of executing the parallel tests line. For some reason the line it's pointing to in the stacktrace is actually the stage declaration in the dynamic parallel steps function. The strangest part is that I created a separate sample pipeline in the same jenkins instance, and THAT worked. So I guess it's something to do with my specific pipeline file, but I have no idea how to even begin debugging.
– Clayton Keleher
Nov 12 at 23:28












So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
– Clayton Keleher
Nov 13 at 1:22






So, a coworker of mine figured out the error, and it's really dumb... One of the arguments of the original function definition (not the same as the code snippet) was called "stage", and it was of type String. This was there so I could pass in context of what stage in the pipeline was calling the function. The problem was, this "stage" variable was overwriting the the stage() declaration in the node{ stage("..."){ ... } } block. This is also why we saw the error in the stack trace, with jenkins complaining that String has no method call(). Quite the humbling experience.
– Clayton Keleher
Nov 13 at 1:22




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53234490%2fdynamic-parallel-stages-in-jenkins-pipeline-outside-script-block%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Schultheiß

Verwaltungsgliederung Dänemarks

Liste der Kulturdenkmale in Wilsdruff