无法在 Jenkins Pipeline 中使用 Groovy 遍历 Map

Impossibility to iterate over a Map using Groovy within Jenkins Pipeline

我们正在尝试迭代 Map,但没有成功。我们将我们的问题简化为这个最小的例子:

def map = [
           'monday': 'mon',
           'tuesday': 'tue',
           ]

如果我们尝试迭代:

map.each{ k, v -> println "${k}:${v}" }

只输出第一个条目:monday:mon


我们知道的备选方案甚至无法进入循环:

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。 (这可能与引发 'real' 异常时发生的异常有关,使我们无法知道发生了什么)。

我们使用最新的稳定版 jenkins (2.19.1),所有插件截至今天 (2016/10/20) 都是最新的。

是否有在 Jenkins 管道 Groovy 脚本中迭代 Map 中的元素的解决方案?

我已经有一段时间没玩这个了,但是迭代地图(和其他容器)的最好方法是使用 "classical" for 循环,或者 "for in"。参见 Bug: Mishandling of binary methods accepting Closure

对于您的具体问题,大多数(所有?)管道 DSL 命令都会添加一个序列点,我的意思是可以保存管道的状态并在以后恢复它。例如,考虑等待用户输入,即使重启也希望保持此状态。 结果是每个活动实例都必须序列化——但不幸的是,标准 Map 迭代器不可序列化。 Original Thread

我能想到的最佳解决方案是定义一个函数,将 Map 转换为可序列化的 MapEntries 列表。该函数未使用任何管道步骤,因此无需在其中序列化任何内容。

@NonCPS
def mapToList(depmap) {
    def dlist = []
    for (def entry2 in depmap) {
        dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
    }
    dlist
}

这显然必须为每个要迭代的地图调用,但好处是,循环体保持不变。

for (def e in mapToList(map))
{
    println "key = ${e.key}, value = ${e.value}"
}

您必须第一次批准 SimpleImmutableEntry 构造函数,或者您很可能可以通过将 mapToList 函数放在工作流库中来解决这个问题。

或者更简单

for (def key in map.keySet()) {
  println "key = ${key}, value = ${map[key]}"
}