我有以下代码,我想要在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
这是为什么?
答案 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() }
}