无法在Jenkins Pipeline中使用Groovy在地图上进行迭代 [英] Impossibility to iterate over a Map using Groovy within Jenkins Pipeline
问题描述
我们正在尝试遍历Map
,但没有成功.我们将问题简化为以下最小示例:
We are trying to iterate over a Map
, but without any success. We reduced our issue to this minimal example:
def map = [
'monday': 'mon',
'tuesday': 'tue',
]
如果我们尝试迭代:
map.each{ k, v -> println "${k}:${v}" }
仅输出第一项:monday:mon
我们所知道的替代方法甚至无法进入循环:
The alternatives we know of are not even able to enter the loop:
for (e in map)
{
println "key = ${e.key}, value = ${e.value}"
}
或
for (Map.Entry<String, String> e: map.entrySet())
{
println "key = ${e.key}, value = ${e.value}"
}
都失败了,都只显示异常java.io.NotSerializableException: java.util.LinkedHashMap$Entry
. (这可能与在引发真实"异常时发生的异常有关,使我们无法知道发生了什么).
Are failing, both only showing the exception java.io.NotSerializableException: java.util.LinkedHashMap$Entry
. (which could be related to an exception occurring while raising the 'real' exception, preventing us from knowing what happened).
我们正在使用最新的稳定的詹金斯(2.19.1),并将所有插件更新为今天(2016/10/20).
We are using latest stable jenkins (2.19.1) with all plugins up-to-date as of today (2016/10/20).
是否有解决方案来迭代Jenkins管道Groovy脚本中Map
中的元素?
Is there a solution to iterate over elements in a Map
within a Jenkins pipeline Groovy script ?
推荐答案
自从我玩这个游戏已经有一段时间了,但是迭代地图(和其他容器)的最佳方法是使用经典" for循环,或者为".请参阅错误:二进制方法接受闭包的错误处理
Its been some time since I played with this, but the best way to iterate through maps (and other containers) was with "classical" for loops, or the "for in". See Bug: Mishandling of binary methods accepting Closure
对于您的特定问题,大多数(全部?)管道DSL命令将添加一个序列点,这意味着可以保存管道的状态并在以后恢复它.例如,考虑等待用户输入,您甚至希望通过重新启动来保持此状态. 结果是每个活动实例都必须序列化-但是不幸的是,标准Map迭代器无法序列化. 原始主题
To your specific problem, most (all?) pipeline DSL commands will add a sequence point, with that I mean its possible to save the state of the pipeline and resume it at a later time. Think of waiting for user input for example, you want to keep this state even through a restart. The result is that every live instance has to be serialized - but the standard Map iterator is unfortunately not serializable. Original Thread
我能想到的最好的解决方案是定义一个将Map转换为可序列化MapEntries列表的Function.该函数不使用任何流水线步骤,因此其中的任何内容都无需序列化.
The best solution I can come up with is defining a Function to convert a Map into a list of serializable MapEntries. The function is not using any pipeline steps, so nothing has to be serializable within it.
@NonCPS
def mapToList(depmap) {
def dlist = []
for (def entry2 in depmap) {
dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
}
dlist
}
显然,要迭代的每个映射都必须调用此函数,但是从另一方面来说,循环的主体保持不变.
This has to be obviously called for each map you want to iterate, but the upside it, that the body of the loop stays the same.
for (def e in mapToList(map))
{
println "key = ${e.key}, value = ${e.value}"
}
您将不得不第一次批准SimpleImmutableEntry
构造函数,或者很可能可以通过将mapToList函数放置在工作流库中来解决该问题.
You will have to approve the SimpleImmutableEntry
constructor the first time, or quite possibly you could work around that by placing the mapToList function in the workflow library.
这篇关于无法在Jenkins Pipeline中使用Groovy在地图上进行迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!