在Jenkins管道中使用Groovy迭代地图是不可能的

时间:2016-10-20 15:59:45

标签: dictionary jenkins groovy 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。 (这可能与提出“真实”异常时发生的异常有关,阻止我们知道发生了什么)。

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

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

2 个答案:

答案 0 :(得分:19)

自从我玩这个游戏以来已经过了一段时间,但迭代地图(和其他容器)的最好方法是使用“经典”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函数放在工作流库中来解决这个问题。

答案 1 :(得分:0)

或更简单

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