小编典典

无法在Jenkins Pipeline中使用Groovy在地图上进行迭代

jenkins

我们正在尝试迭代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。(这可能与在引发“真实”异常时发生的异常有关,使我们无法知道发生了什么)。

我们正在使用最新稳定的jenkins(2.19.1),并将所有插件更新为今天(2016/10/20)。

是否有解决方案来迭代MapJenkins管道Groovy脚本中的元素?


阅读 366

收藏
2020-07-25

共1个答案

小编典典

自从我玩这个游戏已经有一段时间了,但是迭代地图(和其他容器)的最佳方法是使用“经典” for循环或“ for
in”。请参见错误:二进制方法接受闭包的错误处理

对于您的特定问题,大多数(全部?)管道DSL命令将添加一个序列点,这意味着它可以保存管道的状态并在以后恢复它。例如,考虑等待用户输入,您甚至希望通过重新启动来保持此状态。结果是每个活动实例都必须序列化-
但是不幸的是,标准Map迭代器无法序列化。原始线程

我能想到的最好的解决方案是定义一个将Map转换为可序列化MapEntries列表的Function。该函数不使用任何流水线步骤,因此其中的任何内容都无需序列化。

@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函数放置在工作流库中来解决该问题。

2020-07-25