问题
I have a small example of a Jenkins declarative pipeline that should run on both 'Windows' and 'Linux' agents in parallel. The goal is to dynamically build a configuration matrix (e.g. Release / Debug configurations; different CMake parameters; etc.) and let all combinations run in parallel. However, I'm stuck in building a pipeline that executes the parallel steps from a prepared variable.
This is a version of the script where the parallel stages are specified explicitly within the parallel{}
block:
pipeline {
agent any
stages {
stage ("Parallel Build") {
parallel {
stage ("Windows") {
steps {
echo "TEST Windows"
}
}
stage ("Linux") {
steps {
echo "TEST Linux"
}
}
}
}
}
}
My plan is to create the stages in the parallel{}
block dynamically (depending on the required configurations), but I'm not sure about the syntax or if this is possible at all.
Something like this:
def stage_list = {
stage ("Windows") { <=== How to correctly create the stage_list?
steps {
echo "TEST Windows"
}
}
stage ("Linux") {
steps {
echo "TEST Linux"
}
}
}
pipeline {
agent any
stages {
stage ("Parallel Build") {
parallel stage_list <== How to replace a block with variable?
}
}
}
The above will return an error in Jenkins:
WorkflowScript: 17: Expected a block for parallel @ line 17, column 9.
stage ("Parallel Build") {
^
WorkflowScript: 17: Expected one of "steps", "stages", or "parallel" for stage "Parallel Build" @ line 17, column 9.
stage ("Parallel Build") {
^
Does anyone have an idea how this could be done?
Edit: After the first two answers I would like to update my question a bit.
I tested the suggested way of creating the stage_list
variable. However, if I put this call of parallel stage_list
into my original structure I get the same error as before. It runs well when using with script
like this
pipeline {
agent any
stages {
stage ("Parallel Build") {
steps {
script {
parallel stepsForParallel
}
}
}
}
}
Can somebody explain the difference to me? Why does does it work with steps
and script
but not without them?
Edit 2: For documentation reasons I wanted to finish my question with what I did to solve the problem:
SmartToms answer and Jenkins' official documentation on Pipeline Syntax with Docker made clear that declarative pipeline and scripted pipeline are two separate approaches that need to be handled differently (pay attention to the "Toggle Scripted Pipeline" link below each example).
One way to solve my question is to use scripted pipeline - if anyone is interested in an example for this, here is a link to a gist with the pipeline script that shows the principle.
回答1:
From this documentation, this could be done like that :
// Creation of the stage_list
def stage_list = ["Windows", "Linux"]
// Creation of a map of stages
def stepsForParallel = stage_list.collectEntries {
["echoing ${it}" : transformIntoStage(it)]
}
// Run the stages in parallel
parallel stepsForParallel
// Creation of the stage
def transformIntoStage(inputString) {
return {
stage (inputString) {
steps {
echo "TEST "+inputString
}
}
}
}
You can find more information about parallel Jenkins declarative pipeline here.
Edit:
Why does does it work with
steps
andscript
but not without them?
According to this documentation, I think that using parallel
with a list is the old method (prior Declarative Pipeline 1.2), which required to use Scripted Pipeline within a Declarative Pipeline.
It seems that the new method parallel
(from Declarative Pipeline 1.2) can not be used with a list. So, to do it you have to use the old Scripted Pipeline method, therefore you need to encapsulate your command pipeline stage_list
with script
which needs to be itself encapsulated with steps
.
You can find more information about Scripted Pipeline and Declarative Pipeline here.
回答2:
Based on SmartTom's example, but this one you can copy/paste and it works:
// Creation of the stage_list
def node_list = ["win7", "linux"]
// Creation of a map of stages
def stepsForParallel = node_list.collectEntries {
["echoing ${it}" : transformIntoStage(it)]
}
// Run the stages in parallel
parallel stepsForParallel
// Creation of the stage
def transformIntoStage(inputString) {
return {
node (inputString) {
echo "TEST "+inputString
}
}
}
I would recommend you use scripted pipeline syntax, that is much more powerful and flexible
来源:https://stackoverflow.com/questions/54926419/jenkins-parallel-build-on-different-agents