web-dev-qa-db-de.com

Jenkins-Pipeline - Durchlaufen einer Liste

Ich muss Werte aus einer Datei in meiner Pipeline lesen. Ich benutze split () was sie in ein Array setzt. Ich muss sie in eine Arraylist einfügen, also benutze ich Arrays.asList () . Das Problem, das ich habe, ist, dass ich die size () oder length () - Methoden nicht verwenden kann, sodass ich keine for-Schleife machen kann

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

oder

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

weil ich die Fehlermeldung bekomme: nicht klassifiziertes Feld Java.util.Arrays $ ArrayList length

Also habe ich versucht, für jede Schleife eine zu verwenden, aber wenn ich eine Aktion (wie zum Beispiel den Befehl ls) in meinem finally-Block durchführe, iteriert es nur 1 Mal. Wenn ich jedoch einfach den Befehl 'Echo' ausführen, werden die Elemente wie gewünscht iteriert. Gibt es Ratschläge, wie ich meinen Code so ändern kann, dass er jedes Element in der Liste durchläuft, wenn ein Befehl verwendet wird?

Funktioniert einwandfrei ....

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
        }
    }
}

OUTPUT (iteriert für jedes Element):

[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

Aber wenn ich etwas unternehme, wie zum Beispiel 'ls -l' , so iteriert es nur 1 Mal

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'
        }
    }
}

AUSGABE (nur 1 mal durchlaufen):

[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
6
mdo123

ArrayList (und generell Lists) haben kein Längen- oder Größenfeld, sondern eine size()-Methode. Verwenden Sie das also für:

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

Laut diesem Tutorial: https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#serializing-local-variables

... eine mit der Annotation @NonCPS... markierte Methode wird von der Pipeline-Engine als "native" behandelt, und ihre lokalen Variablen werden nicht gespeichert. Es kann jedoch not keine Aufrufe von Pipeline-Schritten durchführen

In Ihrem Fall ist der Aufruf sh eine Pipeline-Schrittoperation, die Sie scheinbar nicht innerhalb einer mit @NonCPS annotierten Methode ausführen können.

Wenn Sie ein Array in eine List umwandeln, können Sie, da wir uns in Groovy Land befinden, einfach die .toList()-Methode für das Array verwenden.

3
Olaf

Ich kann Ihnen nicht genau sagen, warum, denn ich habe nicht herausgefunden, wie ich nützliche Informationen über Jenkins finden kann, ohne stundenlang zu googeln, aber ich kann Ihnen folgendes sagen:

Für einen Moment dachte ich, du kannst es gut laufen lassen, indem du 'Echo Line' NACH der sh 'Echo $ Line' hinzufügst, aber das hat sich herausgestellt, weil Jenkins eine PREVIOUS Version des Skripts ausgeführt hat ...

Ich habe alles Mögliche ausprobiert und keines davon hat funktioniert, dann habe ich Folgendes gefunden:

Warum jede Schleife in einer Jenkinsfile beim ersten Durchlauf stoppt

Es ist ein bekannter Fehler in der Jenkins-Pipeline!

(Der bekannte Fehler ist JENKINS-26481 , der besagt, dass "zumindest einige Closures nur einmal in Groovy CPS-DSL-Scripts ausgeführt werden, die vom Workflow-Plugin verwaltet werden.")

1
RustyCar

Ich bevorzuge diese Lösung :

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}"
    }
}

Wenn Sie eine deklarative Pipeline verwenden, müssen Sie den Aufruf in eine Skriptanweisung einschließen:

stage('master') {
    steps {
        script {
            echo_all(abcs);
        }
    }
0
Matthias M