为什么Jenkinsfile中的每个循环在第一次迭代时停止

时间:2016-06-02 14:24:41

标签: jenkins groovy jenkins-pipeline

以下是我Jenkinsfile的内容:

node {
    // prints only the first element 'a'
    [ 'a', 'b', 'c' ].each {
        echo it
    }
}

在Jenkins中执行作业时(使用Pipeline plugin),只打印列表中的第一项。

有人能解释我这种奇怪的行为吗?这是一个错误吗?或者只是我不理解Groovy语法?

修改for (i in items)按预期工作:

node {
    // prints 'a', 'b' and 'c'
    for (i in [ 'a', 'b', 'c' ]) {
        echo i
    }
}

4 个答案:

答案 0 :(得分:17)

这里接受的答案表明这是一个已知的错误,并使用了对我不起作用的解决方法,因此我将提供最近我发现的更新。

尽管解决了JENKINS-26481(最近,截至撰写本文时),很多人可能会遇到Jenkins的旧版本,但修复程序不可用。文字列表上的for循环迭代有时可能有效,但JENKINS-46749JENKINS-46747等相关问题似乎仍然困扰着许多用户。此外,根据Jenkinsfile中的确切上下文,可能echo将起作用,而sh失败,并且事情可能会无声地失败,或者它们可能会因序列化失败而导致构建崩溃。

如果你不喜欢惊喜(跳过循环和无声失败),如果你希望你的Jenkinsfiles在Jenkins的多个版本中最便携,那么主要的想法似乎是你应该总是在你的for中使用经典的计数器-loops并忽略其他常规功能。

This gist是我见过的最佳参考,并列出了许多你认为应该相同但行为却出奇的不同的案例。无论您正在查看何种迭代,无论您是否尝试使用@NonCPS,都可以在{{1}内直接进行迭代,这是建立健全性检查和调试设置的良好起点。 },或调用一个单独的函数。

同样,我不赞成这项工作本身,但我将下面的迭代测试用例的要点嵌入后代:

node{}

答案 1 :(得分:5)

感谢@batmat #jenkins IRC channel回答此问题!

这实际上是一个已知错误:JENKINS-26481

答案 2 :(得分:2)

此问题的解决方法是将所有命令扩展为平面文本文件,作为groovy脚本。然后使用加载步骤加载文件并执行。

例如:

@NonCPS
def createScript(){
    def cmd=""
    for (i in [ 'a', 'b', 'c' ]) {
        cmd = cmd+ "echo $i"
    }
    writeFile file: 'steps.groovy', text: cmd
}

然后调用函数

createScript()
load 'steps.groovy'

答案 3 :(得分:0)

这里是curl不带NonCPS的循环示例:

#!/usr/bin/env groovy

node('master') {
    stagesWithTry([
        'https://google.com/',
        'https://github.com',
        'https://releases.hashicorp.com/',
        'https://kubernetes-charts.storage.googleapis.com',
        'https://gcsweb.istio.io/gcs/istio-release/releases'
    ])
    stage ('ALlinOneStage'){
        stepsWithTry([
            'https://google.com/',
            'https://github.com',
            'https://releases.hashicorp.com/',
            'https://kubernetes-charts.storage.googleapis.com',
            'https://gcsweb.istio.io/gcs/istio-release/releases'
        ])
    }
}
//loop in one stage
def stepsWithTry(list){
    for (int i = 0; i < list.size(); i++) {
        try {
        sh "curl --connect-timeout 15 -v -L ${list[i]}"
        } catch (Exception e) {
            echo "Stage failed, but we continue"
        }
    }
}
//loop in multiple stage
def stagesWithTry(list){
    for (int i = 0; i < list.size(); i++) {
        try {
            stage(list[i]){
          sh "curl --connect-timeout 15 -v -L ${list[i]}"
            }
        } catch (Exception e) {
            echo "Stage failed, but we continue"
        }
    }
}