Конвейер Дженкинса — как перебирать список

Мне нужно прочитать значения из файла в моем конвейере. Я использую split(), который помещает их в массив. Мне нужно поместить их в Arraylist, поэтому я использую Arrays.asList(). Проблема, с которой я столкнулся, заключается в том, что я не могу использовать методы size() или length(), поэтому я не могу создать цикл for, например

for (ii = 0; ii < var.length; ii++)

or

for (ii = 0; ii < var.size; ii++)

потому что я получаю сообщение об ошибке: длина неклассифицированного поля java.util.Arrays$ArrayList

Поэтому я попытался использовать цикл for для каждого, но когда я выполняю какое-либо действие (например, команду ls) в моем блоке finally, он повторяется только 1 раз. Но если я просто запускаю команду «эхо», она повторяется для каждого элемента, как и предполагалось. Любые советы о том, как изменить мой код, чтобы он повторялся для каждого элемента в списке при использовании любой команды?

Работает корректно....

node{
    wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [[fileId: 'dest_hosts.txt', targetLocation: '', variable: 'DEST_HOST']]]) {
        HOST = Arrays.asList(readFile(env.DEST_HOST).split("\\r?\\n"))
        deploy(HOST)
    }
}

@NonCPS
def deploy(host){
    for (String target : host){
        try {
            echo target
        }
        finally {
           echo target
        }
    }
}

ВЫВОД (повторяется для каждого элемента):

[Pipeline] node
Running on <obfuscated>
[Pipeline] {
[Pipeline] wrap
provisoning config files...
copy managed file [<obfuscated>] to file:/var/lib/jenkins/<obfuscated>
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
www.testhost.com
[Pipeline] echo
www.testhost.com
[Pipeline] echo
www.testhost2.com
[Pipeline] echo
www.testhost2.com
[Pipeline] }
Deleting 1 temporary files
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Но если я предприму какое-либо действие, такое как 'ls -l', оно повторится только 1 раз

node{
    wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [[fileId: 'dest_hosts.txt', targetLocation: '', variable: 'DEST_HOST']]]) {
        HOST = Arrays.asList(readFile(env.DEST_HOST).split("\\r?\\n"))
        deploy(HOST)
    }
}

@NonCPS
def deploy(host){
    for (String target : host){
        try {
            echo target
        }
        finally {
           sh 'ls -l'
        }
    }
}

ВЫВОД (повторяется только 1 раз):

[Pipeline] node
Running on <obfuscated>
[Pipeline] {
[Pipeline] wrap
provisoning config files...
copy managed file [<obfuscated>] to file:/var/lib/jenkins/<obfuscated>
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
www.testhost.com
[Pipeline] sh
[sandbox%2Fpipeline-test-new1] Running shell script
+ ls -l
total 8
-rw-r--r-- 1 jenkins jenkins 10 Jun 17 16:07 someFile
[Pipeline] }
Deleting 1 temporary files
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

person mdo123    schedule 07.07.2016    source источник


Ответы (4)


ArrayList (и вообще Lists) не имеют поля длины или размера, у них есть метод size(). Так что используйте это в for:

for (ii = 0; ii < var.size(); ii++)
person Krzysztof Krasoń    schedule 08.07.2016
comment
Спасибо, это работает. Хотя мне все еще любопытно, почему второй цикл for выше повторяется только один раз, есть идеи? - person mdo123; 09.07.2016
comment
Я сейчас испытываю нечто подобное. Насколько я могу судить, это связано с вызовом sh. Вы что-то выяснили по этому поводу? - person pmmaga; 22.12.2016
comment
@pmmaga нет, извини, я не подумал об этом. Я только что использовал ответ @ krzyk, но я не принял ответ @ krzyk, потому что я думаю, что часть ответа должна включать объяснение поведения, которое я описал выше. В частности, почему цикл for each работает с эхом в блоке finally, но повторяется только один раз при выполнении команды sh. Я подумал, что, возможно, sh cmd возвращает ненулевой статус выхода, но цикл for each должен продолжаться для каждого элемента, поэтому я не уверен. - person mdo123; 02.01.2017
comment
@krzyk, не могли бы вы обновить свой ответ, включив в него объяснение, почему цикл for each работает для команды echo, но не для команды sh? - person mdo123; 02.01.2017

Согласно этому руководству: https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#serializing-local-variables

... метод, помеченный аннотацией @NonCPS..., будет рассматриваться движком Pipeline как «родной», а его локальные переменные никогда не сохраняются. Однако он может не выполнять какие-либо вызовы шагов конвейера.

В вашем случае вызов sh представляет собой пошаговую операцию конвейера, которую вы, по-видимому, не можете выполнить из аннотированного метода @NonCPS.

Что касается превращения массива в List, то, поскольку мы находимся в стране Groovy, вы можете просто использовать метод .toList() для массива.

person Olaf    schedule 25.08.2017

Я предпочитаю это решение:

node('master') {
    stage('Test 1: loop of echo statements') {
        echo_all(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}"
    }
}

Если вы используете декларативный конвейер, вы должны обернуть вызов оператором скрипта:

stage('master') {
    steps {
        script {
            echo_all(abcs);
        }
    }
person Matthias M    schedule 31.01.2019
comment
выглядит вполне законно. Было бы полезно отметить, почему вы предпочитаете это в качестве своего решения, и, возможно, дать ссылку на то, что такое декларативный конвейер, источник ~ jenkins.io/doc/book/pipeline/syntax/#declarative-pipeline - person mdo123; 31.01.2019

Я не могу ТОЧНО сказать почему, так как я не понял, как найти полезную информацию о Дженкинсе, не тратя часы на гугление, но я могу сказать вам следующее:

На мгновение я подумал, что вы можете заставить его работать нормально, добавив «echo line» ПОСЛЕ sh «echo $line», но это оказалось вызвано тем, что Дженкинс запускал ПРЕДЫДУЩУЮ версию скрипта...

Я пробовал все виды вещей, и ни один из них не работал, затем я нашел это:

Почему каждый цикл в файле Jenkins сначала останавливается итерация

Это известная ошибка в конвейере Дженкинса!

(известная ошибка - JENKINS-26481, в которой говорится: "По крайней мере, некоторые замыкания выполняются только один раз внутри сценариев Groovy CPS DSL, управляемых подключаемым модулем рабочего процесса")

person RustyCar    schedule 17.07.2017