Jenkins Pipeline Groovy compareTo运算符不起作用

时间:2018-08-16 01:59:35

标签: jenkins groovy jenkins-pipeline

我有以下代码,我想要在json对象列表中获取具有最旧CreateDate的对象:

import groovy.json.JsonSlurperClassic

def result = """{
    "Metadata": [
        {
            "Status": "Active", 
            "CreateDate": "2018-08-14T18:59:52Z", 
        }, 
        {
            "Status": "Active", 
            "CreateDate": "2018-05-18T16:11:45Z", 
        }
    ]
}"""

def all = new JsonSlurperClassic().parseText(result)

def oldest = all.Metadata.min { a, b -> 
        Date.parse("yyyy-M-d'T'H:m:s'Z'", a.CreateDate).getTime() <=> 
        Date.parse("yyyy-M-d'T'H:m:s'Z'", b.CreateDate).getTime() }
print "oldest=" + oldest

在Jenkins脚本控制台中可以正常工作。即:它将打印输出

oldest=[Status:Active, CreateDate:2018-05-18T16:11:45Z]

但是当在Pipeline下运行相同的代码时,它会打印

oldest=1

这是为什么?

1 个答案:

答案 0 :(得分:2)

这是Groovy CPS变压器错误。脚本控制台和Jenkins管道之间的区别在于,脚本控制台在香草Groovy环境中执行脚本,而Jenkins管道使用groovy-cps执行。这意味着Jenkins管道Groovy脚本在使用CPS转换的Groovy shell中执行-修改代码,使其支持这种连续传递样式。

根据CpsDefaultGroovyMethodsTest,groovy-cps支持collection.min {}操作,但仅在使用带有单个参数的闭包时才支持。我为带有两个参数的闭包创建了一个测试用例,例如:

[3,2,5,4,5].min { int a, int b -> a <=> b }

而不是2,我得到-1-似乎正在返回compareTo()方法的值,而不是给定集合的实际最小值。

解决方案

绕过此问题的最简单方法是提取

def oldest = all.Metadata.min { a, b -> 
    Date.parse("yyyy-M-d'T'H:m:s'Z'", a.CreateDate).getTime() <=> 
    Date.parse("yyyy-M-d'T'H:m:s'Z'", b.CreateDate).getTime() }

使用@NonCPS注释的方法-该注释指示groovy-cps解释器跳过CPS转换,并按原样运行此方法。您可以在下面找到工作示例:

import groovy.json.JsonSlurper

node {
    stage("Test") {
        def result = """{
            "Metadata": [
                {
                    "Status": "Active", 
                    "CreateDate": "2018-08-14T18:59:52Z", 
                }, 
                {
                    "Status": "Active", 
                    "CreateDate": "2018-05-18T16:11:45Z", 
                }
            ]
        }"""

        def all = new JsonSlurper().parseText(result)

        def oldest = getOldest(all)

        println "oldest = ${oldest}"
    }
}

@NonCPS
def getOldest(all) {
    return all.Metadata.min { a, b -> 
                Date.parse("yyyy-M-d'T'H:m:s'Z'", a.CreateDate).getTime() <=> 
                Date.parse("yyyy-M-d'T'H:m:s'Z'", b.CreateDate).getTime() }
}