Почему каждый цикл в файле Jenkinsfile останавливается на первой итерации
вот содержание моего Jenkinsfile
:
node {
// prints only the first element 'a'
[ 'a', 'b', 'c' ].each {
echo it
}
}
при выполнении задания в Jenkins (с плагин трубопровода), печатается только первый элемент в списке.
может кто-нибудь объяснить мне это странное поведение? Это жук? или это просто я не понимаю синтаксис Groovy?
редактировать: the for (i in items)
работает :
node {
// prints 'a', 'b' and 'c'
for (i in [ 'a', 'b', 'c' ]) {
echo i
}
}
3 ответов
в принятом ответе здесь говорится, что это известная ошибка и использует обходной путь, который не работал для меня, поэтому я предложу обновление с тем, что я нашел в последнее время.
несмотря на постановление Дженкинс-26481 (довольно недавно, на момент написания этой статьи) многие люди могут застрять с более старой версией Дженкинса, где исправление недоступно. Итерация for-loop над литеральным списком может иногда работать, но связанные с этим проблемы, такие как Дженкинс-46749 и Дженкинс-46747 кажется, продолжают терзать многих пользователей. Кроме того, в зависимости от точного контекста в вашем Jenkinsfile, возможно echo
будет работать, тогда как sh
терпит неудачу, и вещи могут потерпеть неудачу молча или они могут привести к сбою сборки с неудачами сериализации.
если вы не любите сюрпризы (пропущенные циклы и тихие сбои), и если вы хотите, чтобы ваши Jenkinsfiles были наиболее переносимыми в нескольких версиях Jenkins, основная идея заключается в том, что вы должны всегда используйте классические счетчики в своих for-loops и игнорируйте другие функции groovy.
в этом суть это лучшая ссылка, которую я видел, и излагает многие случаи, которые, как вы думаете, должны работать одинаково, но иметь удивительно разное поведение. Это хорошее начальное место для проверки здравомыслия и отладки вашей установки, независимо от того, какую итерацию вы смотрите и независимо от того, пытаетесь ли вы использовать @NonCPS
, сделайте свою итерацию непосредственно внутри node{}
, или вызывать отдельную функцию.
опять же, я не беру на себя ответственность за саму работу, но я встраиваю суть итерационных тестов ниже для потомков:
abcs = ['a', 'b', 'c']
node('master') {
stage('Test 1: loop of echo statements') {
echo_all(abcs)
}
stage('Test 2: loop of sh commands') {
loop_of_sh(abcs)
}
stage('Test 3: loop with preceding SH') {
loop_with_preceding_sh(abcs)
}
stage('Test 4: traditional for loop') {
traditional_int_for_loop(abcs)
}
}
@NonCPS // has to be NonCPS or the build breaks on the call to .each
def echo_all(list) {
list.each { item ->
echo "Hello ${item}"
}
}
// outputs all items as expected
@NonCPS
def loop_of_sh(list) {
list.each { item ->
sh "echo Hello ${item}"
}
}
// outputs only the first item
@NonCPS
def loop_with_preceding_sh(list) {
sh "echo Going to echo a list"
list.each { item ->
sh "echo Hello ${item}"
}
}
// outputs only the "Going to echo a list" bit
//No NonCPS required
def traditional_int_for_loop(list) {
sh "echo Going to echo a list"
for (int i = 0; i < list.size(); i++) {
sh "echo Hello ${list[i]}"
}
}
// echoes everything as expected
спасибо @batmat on #Дженкинс IRC-канал для ответа на этот вопрос!
Это на самом деле известная ошибка : Дженкинс-26481.
обходной путь для этой проблемы-развернуть все команды в плоский текстовый файл в виде скрипта groovy. Затем используйте load step для загрузки файла и выполнения.
например:
@NonCPS
def createScript(){
def cmd=""
for (i in [ 'a', 'b', 'c' ]) {
cmd = cmd+ "echo $i"
}
writeFile file: 'steps.groovy', text: cmd
}
затем вызовите функцию like
createScript()
load 'steps.groovy'