web-dev-qa-db-ja.com

Jenkins Pipeline内でGroovyを使用してマップを反復することは不可能

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の要素を反復処理するソリューションはありますか?

17
Ad N

私がこれを試してからしばらく経ちましたが、マップ(およびその他のコンテナー)を反復処理する最良の方法は、「クラシック」forループまたは「for in」を使用することでした。参照 バグ:クロージャを受け入れるバイナリメソッドの誤処理

特定の問題に対して、ほとんどの(すべて?)パイプラインDSLコマンドはシーケンスポイントを追加します。つまり、パイプラインの状態を保存し、後で再開することが可能です。たとえば、ユーザー入力を待つことを考えてください。再起動してもこの状態を維持したいとします。その結果、すべてのライブインスタンスをシリアル化する必要がありますが、標準の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関数を配置することで回避できる可能性があります。

23
Norbert Lange

またははるかに簡単

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