Невозможность итерации по карте с использованием 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).

Есть ли решение для итерации по элементам в Map в конвейере Дженкинса Groovy script?

Ответ 1

Прошло некоторое время с тех пор, как я играл с этим, но лучший способ перебирать карты (и другие контейнеры) был с "классическим" для циклов или "для". См. Ошибка: неправильное использование двоичных методов, принимающих закрытие

К вашей конкретной проблеме большинство (все?) конвейерных DSL-команд добавят точку последовательности, и я имею в виду ее возможность сохранить состояние конвейера и возобновить его позднее. Например, подумайте о ожидании ввода пользователя, вы хотите сохранить это состояние даже через перезапуск. В результате каждый живой экземпляр должен быть сериализован, но стандартный итератор карты, к сожалению, не сериализуем. Оригинальная тема

Лучшее решение, которое я могу придумать, - это определение функции для преобразования Карты в список сериализуемых 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 в библиотеку рабочих процессов.

Ответ 2

Или намного проще

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