为常规执行调整groovy CPS闭包

时间:2017-01-19 14:31:34

标签: jenkins parallel-processing closures jenkins-pipeline currying

我们在一些工作中动态创建并行步骤。感谢this thread我找到了如何动态创建带有参数的地图,以便在并行步骤中使用。

但是现在我想重用部分用于创建这些并行步骤的代码。为此,我觉得我需要为闭包做好准备。

然而,currying似乎无法正常工作。在闭包内引用循环变量(valueCopy)会做正确的事情(as mentioned here),但是currying不能达到我的预期。

我做错了什么,这是不是(还)支持,是否有任何解决方法?这可能是Jenkins管道中的一个错误吗?

希望任何人都知道为什么这不起作用和/或如何使其正常工作。

Jenkins:LTS(2.32.1)&最新的插件更新截至2017/01/19。

解决方案:

升级到Pipeline后:Groovy插件版本2.40 eveything正在按预期工作。

执行管道脚本:

def echoSome(val) {
    echo val
}

def buildClosures() {
    def someList = ["1", "2", "3"]
    def closures = [:]
    for (value in someList) {
        final valueCopy = value

        closures[value] = {val ->
                echo valueCopy.toString()
                echo val.toString()
            }.curry(value)
    }
    closures
}

parallel buildClosures()

输出:

[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 3
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 3
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS

预期产出:

[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS

3 个答案:

答案 0 :(得分:4)

我不确定它是currying还是for循环,但是这个函数需要标记为NonCPS,如下所述:https://github.com/jenkinsci/pipeline-examples/blob/master/docs/BEST_PRACTICES.md#groovy-gotchas

基本上,这样做:

@NonCPS
def buildClosures() {
    def someList = ["1", "2", "3"]
    def closures = [:]
    for (value in someList) {
        final valueCopy = value

        closures[value] = {val ->
                echo valueCopy.toString()
                echo val.toString()
            }.curry(value)
    }
    closures
}

我认为这是你的for循环,但无论如何,只要你不使用经典的“C Style”循环,你就需要将你的功能标记为NonCPS。

答案 1 :(得分:0)

这似乎是对Groovy语言或Jenkins groovy运行时的限制,我不确定是哪一个,但值得注意的是他们的示例完全按照您的方式执行,为循环的每次迭代声明一个新变量

他们评论了他们的例子

  每次迭代

//新变量;我会被改变

我不认为使用C风格的循环会消除这种限制并且currying(这个用例需要)也不能解决问题。笨拙,但很容易解决。

https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#creating-multiple-threads

答案 2 :(得分:0)

发现最新的Pipeline: Groovy插件(2.40)与至少Jenkins版本2.60.3相结合(尽管插件主页表明你至少需要Jenkins 2.73.3)但一切都按预期工作。