web-dev-qa-db-fra.com

Jenkins pipeline - Comment parcourir une liste

Je suis obligé de lire les valeurs d'un fichier de mon pipeline. J'utilise split () qui les met dans un Array. Je dois les mettre dans un Arraylist, donc j'utilise Arrays.asList () . Le problème que je rencontre est que je ne peux pas utiliser les méthodes size () ou length () afin que je ne puisse pas créer de boucle for telle que

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

ou

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

parce que j'ai l'erreur: champ non classifié Java.util.Arrays $ longueur ArrayList

J'ai donc essayé d'utiliser une boucle pour chaque boucle, mais lorsque je fais une action (comme la commande ls par exemple) dans mon bloc finale, il ne fait qu'une itération. Mais si je lance simplement la commande 'echo', elle itère pour chaque élément comme il est supposé le faire. Un conseil sur la façon de modifier mon code pour le faire itérer pour chaque élément de la liste lorsque vous utilisez une commande?

Fonctionne correctement ....

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 (itère pour chaque élément):

[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

Mais si je prends des mesures telles que 'ls -l' cela ne fait qu'itérer 1 fois

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

OUTPUT (seulement itère 1 fois):

[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 (et généralement Lists) n'ont pas de champ de longueur ou de taille, mais une méthode size() Alors utilisez cela dans le pour:

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

Selon ce tutoriel: https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#serializing-local-variables

... une méthode marquée avec l'annotation @NonCPS... sera traitée comme "native" par le moteur Pipeline et ses variables locales ne seront jamais enregistrées. Cependant, il ne peut pas faire appel à des étapes Pipeline

Dans votre cas, l'appel sh est une opération d'étape de pipeline que vous ne pouvez apparemment pas exécuter à partir d'une méthode annotée @NonCPS.

En ce qui concerne la transformation d'un tableau en List, vous pouvez simplement utiliser la méthode .toList(), car nous sommes en Groovy Land.

3
Olaf

Je ne peux pas vous dire PRÉCISEMMENT pourquoi, car je n'ai pas trouvé comment trouver des informations utiles sur Jenkins sans passer des heures à googler, mais je peux vous dire ceci:

Pendant un moment, j'ai pensé que vous pouviez le faire fonctionner correctement en ajoutant 'echo line' APRÈS le sh 'echo $ line', mais cela s'est avéré dû à l'exécution par Jenkins d'une version PREVIOUS du script ...

J'ai essayé toutes sortes de choses et aucune d'entre elles n'a fonctionné, puis j'ai trouvé ceci:

Pourquoi chaque boucle d'un fichier Jenkins est interrompue à la première itération

C'est un bug connu dans le pipeline Jenkins!

(Le bogue connu est JENKINS-26481 , qui indique "Au moins certaines fermetures ne sont exécutées qu'une fois dans les scripts Groovy CPS DSL gérés par le plug-in de flux de travaux")

1
RustyCar

Je préfère cette solution :

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

Si vous utilisez un pipeline déclaratif, vous devez envelopper l'appel dans une instruction de script:

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