5

I've been reaching to a point that I really want to use iteration to save redundant code on stage level when building multi-platforms. Below is showcasing what I'm trying to do:

def map = [ Bob : 42, Alice: 54, Max : 33 ] pipeline { agent none stages { map.each { entry -> stage ($entry.key) { steps{ timestamps{ echo "$entry.value" } } } } } } 

I think the concept here is pretty straight forward, but the builds are failing by telling me:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: WorkflowScript: 13: Expected a stage @ line 13, column 9. map.each { entry -> ^ WorkflowScript: 12: No stages specified @ line 12, column 5. stages { ^ 2 errors 

Does this mean jenkins have not yet support user to iterate on stages? If there's anything wrong with what I did, please let me know. Thanks!

-----EDIT------

BTW, @NonCPS is also tried, I don't think this is a each problem in pipeline script...

def map = [ Bob : 42, Alice: 54, Max : 33 ] pipeline { agent none stages { iter_stages map } } @NonCPS def iter_stages(dd) { dd.each { entry -> stage ($entry.key) { steps{ timestamps{ echo "$entry.value" } } } } } 

2 Answers 2

19

OP was in the right direction, but there are a few issues with the code:

  • The code to create dynamic stages needs to be in a script block.
  • You need at least one stage with steps so that you can put the above logic
  • You don't need steps inside a dynamic stage (probably because it is in script block, which means it is no longer declarative).
  • The value passed to stage name has a syntax error, it is probably a typo

Here is the code that works the way the OP wants:

def map = [ Bob : 42, Alice: 54, Max : 33 ] pipeline { agent any stages { stage('Initialize') { steps { script { map.each { entry -> stage (entry.key) { timestamps{ echo "$entry.value" } } } } } } } } 

Here is how the pipeline will look like:

Pipeline view

Since this is so dynamic anyway, it should probably use the scripted pipeline syntax instead of the above (which is declarative pipeline), which also makes it possible to avoid the Initialize stage.

def map = [ Bob : 42, Alice: 54, Max : 33 ] node { map.each { entry -> stage (entry.key) { timestamps{ echo "$entry.value" } } } } 
Sign up to request clarification or add additional context in comments.

2 Comments

If the stage is repeated as shown below Then the script leads to stackoverflow(:)) error\n stages { stage('Stage1') { ... map.each { entry -> stage (entry.key) { . } ... } } stage('Stage2') { ... map.each { entry -> stage (entry.key) { . } ... } } }
@vikaspachisia Try wrapping the inner stage blocks in a script block.
1

I think this can help you. I don't really know why you want to iterate on stages and not just iterate your function inside a step of a stage:

def map = [ Bob : 42, Alice: 54, Max : 33 ] pipeline { agent any stages { stage('loop') { steps { loopNames(map) } } } } def loopNames(map){ map.each { key, value -> println "Age of " + key + " is " + value + "."; } } 

Call a groovy function in your pipeline and pass map as parameter. Below the pipeline I define the content of the function.

Output of this run: [Pipeline] { [Pipeline] stage [Pipeline] { (loop) [Pipeline] echo Age of Bob is 42. [Pipeline] echo Age of Alice is 54. [Pipeline] echo Age of Max is 33. [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS 

3 Comments

Thanks for answering, the reason I want to do it on stage level is because the keys are stage names. Say I have multiple platforms as keys, and the values are different configurations for different platforms. I want each stage to represent one platform build.
Why not using parameters for the names and use when to check if the parameter value is what you expect. If not the stage is skipped
Ah, I think there’s some misunderstanding. I need to have those stages tuning in parallel when I get a iteration solution from this. If I’m using “when” conditions, that makes no difference, right? Please correct me if I’m not reading your idea right.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.