Jenkins管道 - 在阶段层面上进行迭代

5

我已经到了一个想要使用迭代来节省在构建多平台时舞台级别上冗余代码的地步。

以下是展示我正在尝试做的事情:

def map = [
        Bob  : 42,
        Alice: 54,
        Max  : 33
]

pipeline {
    agent none
    stages {
        map.each { entry ->
            stage ($entry.key) {
                steps{
                    timestamps{
                        echo "$entry.value"
                    }
                }
            }
        }
    }
}

我认为这里的概念非常简单,但构建失败并告诉我:

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

这是否意味着Jenkins尚未支持用户在阶段上进行迭代?如果我所做的有任何问题,请告诉我。谢谢!
-----编辑------
顺便说一下,@NonCPS也尝试了,我不认为这是管道脚本中的each问题...
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个回答

18

OP方向正确,但代码存在一些问题:

  • 创建动态阶段的代码需要在script块中。
  • 您需要至少一个带有步骤的阶段,以便可以放置上述逻辑。
  • 在动态阶段内不需要steps(可能是因为它在script块中,这意味着它不再是声明性的)。
  • 传递给阶段名称的值存在语法错误,可能是拼写错误。

以下是符合OP要求的代码:

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"
                            }
                        }
                    }
                }
            }
        }
    }
}

管道的外观如下:

Pipeline view

由于此过程非常动态,因此应该使用脚本化管道语法而不是以上的声明性管道,这也使得可以避免Initialize阶段。

def map = [
        Bob  : 42,
        Alice: 54,
        Max  : 33
]

node {
    map.each { entry ->
        stage (entry.key) {
            timestamps{
                echo "$entry.value"
            }
        }
    }
}

如果如下所示重复了阶段 那么脚本会导致stackoverflow(:))错误\n 阶段 { 阶段('阶段1') { ... map.each { entry -> stage (entry.key) { . } ... } } 阶段('阶段2') { ... map.each { entry -> stage (entry.key) { . } ... } } } - vikas pachisia
@vikaspachisia 请尝试将内部的 stage 块包装在一个 script 块中。 - haridsv

1
我认为这可以帮助你。我不太清楚你为什么想要在阶段上进行迭代,而不是在阶段的步骤中迭代你的函数:
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 + ".";
    }
}

在您的管道中调用一个Groovy函数并将map作为参数传递。 在管道下面,我定义了函数的内容。
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

1
感谢您的回答,我想在舞台级别上执行它的原因是因为键是舞台名称。假设我有多个平台作为键,而值是不同平台的不同配置。我希望每个舞台代表一个平台构建。 - ZDunker
为什么不使用参数来命名,并使用 when 来检查参数值是否符合预期。如果不符合,则跳过该阶段。 - lvthillo
啊,我觉得有些误解。当我从中获取迭代解决方案时,我需要将这些阶段并行调整。如果我使用“when”条件,那没什么区别,对吧?请纠正我,如果我没有正确理解你的想法。 - ZDunker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接