Groovy собирает возвращаемый GString в сценарии Jenkins Workflow

Кажется, что в следующем фрагменте кода:

def formattedPaths = affectedFiles.collect {
    "${it.editType.name} ${it.path}"
}

по крайней мере, иногда formattedPaths оценивается как GString вместо списка. Этот фрагмент кода является фрагментом более крупного сценария Jenkins Workflow, например:

node {
     currentBuild.rawBuild.changeSets[0].collect { 
         """<b>${it.user}</b> @ rev. ${it.revision}: ${it.msg}
         ${affectedFilesLog(it.affectedFiles)}"""
     }
}

def affectedFilesLog(affectedFiles) {
    println "Affected files [${affectedFiles.class}]: $affectedFiles"
    def formattedPaths = affectedFiles.collect {
        "${it.editType.name} ${it.path}"
    }

    println "formattedPaths [${formattedPaths.class}]: $formattedPaths"
    formatItemList(formattedPaths)
}

def formatItemList(list) {
    if (list) {
        return list.join('\n')
    }

    return  '(none)'
}

Запуск этого скрипта в Jenkins приводит к выводу:

Running: Print Message
Affected files [class java.util.ArrayList]: [hudson.scm.SubversionChangeLogSet$Path@5030a7d8]
Running: Print Message
formattedPaths [class org.codehaus.groovy.runtime.GStringImpl]: edit my/path/flow.groovy
(...)
groovy.lang.MissingMethodException: No signature of method: java.lang.String.join() is applicable for argument types: (java.lang.String) values: [
]

И это заставляет меня поверить, что в коде:

println "Affected files [${affectedFiles.class}]: $affectedFiles"
def formattedPaths = affectedFiles.collect {
    "${it.editType.name} ${it.path}"
}

println "formattedPaths [${formattedPaths.class}]: $formattedPaths"

affectedFiles равно ArrayList (скрипт выводит Affected files [class java.util.ArrayList]: [hudson.scm.SubversionChangeLogSet$Path@5030a7d8] в выводе)

но результатом выполнения метода сбора на нем - присвоенного formattedPaths - является GString (выход: formattedPaths [class org.codehaus.groovy.runtime.GStringImpl]: edit my/path/flow.groovy)

Разве метод сбора не должен всегда возвращать список?


person Kamil Roman    schedule 03.11.2015    source источник
comment
Да, он всегда должен создавать список. Я подозреваю, что здесь может происходить что-то еще... Почему Running: Print Message повторяется дважды? Это работает с несколькими потоками? Я подозреваю, что второй поток может дать сбой, но вы смотрите на распечатку первого потока...   -  person tim_yates    schedule 03.11.2015
comment
Я предполагаю, что первое сообщение предназначено для затронутых файлов println [${affectedFiles.class}]: $affectedFiles, а второе — для println formattedPaths [${formattedPaths.class}]: $formattedPaths   -  person Kamil Roman    schedule 03.11.2015


Ответы (3)


После обсуждения в комментариях, указывающего на то, что это могут быть некоторые побочные эффекты, создаваемые плагином Jenkins Workflow, я решил использовать простой цикл for-each:

def affectedFilesLog(affectedFiles) {
    println "Affected files [${affectedFiles.class}]: $affectedFiles"

    def ret = ""
    for (Object affectedFile : affectedFiles) {
        ret += affectedFile.path + '\n'
    }

    println("affectedFilesLog ret [${ret.class}]: $ret")
    if (!ret) {
        return '(brak)'
    }

    return ret;
}

РЕДАКТИРОВАТЬ 19/11/2015: плагин рабочего процесса Jenkins неправильно обрабатывает функции, использующие замыкания, см. https://issues.jenkins-ci.org/browse/JENKINS-26481 и его копии. Так что лучшим решением было переписать код на обычный цикл for-each на языке Java.

person Kamil Roman    schedule 05.11.2015
comment
Работал и для меня. Отход от метода сбора и закрытия цикла с индексацией for решил проблему для меня. - person lilkunien; 12.03.2021

В настоящее время вы не можете использовать метод collect. JENKINS-26481

person Jesse Glick    schedule 04.11.2015

Я предполагаю, что ваш код не является потокобезопасным. Если вы передаете некоторые объекты в качестве параметров другим функциям, не изменяйте это. Всегда создавайте и возвращайте новый измененный объект. Не изменяйте исходные данные. Вы должны проверить, где живут ваши объекты. Это только внутри функции или в глобальной области видимости?

person CyberAleks    schedule 03.11.2015
comment
Будут ли форматированные пути использоваться где-то еще? Ваш код кажется правильным. Он должен работать. Может быть, есть какие-то побочные эффекты? - person CyberAleks; 04.11.2015
comment
Да, они используются в теле уведомления по электронной почте. Хорошо, спасибо, я, вероятно, буду повторять цикл for each вместо использования метода collect. - person Kamil Roman; 04.11.2015
comment
Я думаю, что метод collect не является проблемой. Он всегда возвращает ArrayList. Вы можете попробовать это здесь groovyconsole.appspot.com с другим объектом. Я предполагаю, что formattedPaths может быть перезаписан некоторыми побочными эффектами после того, как вы сделаете сбор, но до того, как он будет напечатан. - person CyberAleks; 04.11.2015
comment
Вы можете попробовать использовать явный тип List formattedPaths = ... Так что его нельзя перезаписать с помощью GString, вы получите ошибку, и вы увидите, какая функция пытается это сделать в трассировке стека. - person CyberAleks; 04.11.2015
comment
возможно, есть некоторые побочные эффекты, создаваемые плагином рабочего процесса jenkins, который выполняет скрипт. Я изменил код, чтобы использовать простой код для каждого цикла, и он работает. Спасибо - person Kamil Roman; 05.11.2015