Comment réaliser correctement une action parallèle dynamique avec un pipeline déclaratif?

21

Actuellement, je vais avoir besoin d'une implémentation qui doit trouver tous les fichiers dans un répertoire et démarrer une tâche parallèle pour chaque fichier trouvé.

Est-il possible d'y parvenir en utilisant des pipelines déclaratifs?

pipeline {
    agent any
    stages {
        stage("test") {
            steps {
                dir ("file_path") {
                    // find all files with complete path
                    parallel (
                        // execute parallel tasks for each file found.
                        // this must be dynamic
                        }
                    }
                }
            }
        }
    }
}
thclpr
la source
Comment puis-je faire si je veux exécuter plusieurs étapes séquentiellement et non en parallèle?
Frank Escobar
Bien sûr, mais de cette façon, vous ne pouvez pas générer dynamiquement les tâches parallèles, par exemple, en fonction de certains fichiers du référentiel.
Raúl Salinas-Monteagudo Il y a

Réponses:

22

Géré pour le résoudre avec le code suivant:

pipeline {
    agent { label "master"}
    stages {
        stage('1') {
            steps {
                script {
                    def tests = [:]
                    for (f in findFiles(glob: '**/html/*.html')) {
                        tests["${f}"] = {
                            node {
                                stage("${f}") {
                                    echo '${f}'
                                }
                            }
                        }
                    }
                    parallel tests
                }
            }
        }       
    }
}
thclpr
la source
Veuillez également consulter les exemples officiels de Pipeline - jenkins.io/doc/pipeline/examples/#parallel-multiple-nodes
phedoreanu
@phedoreanu j'utilise un pipeline déclaratif ...
thclpr
@phedoreanu J'ai rejeté votre modification, la modification du code devrait avoir de bonnes raisons, votre commentaire ne me suffit pas pour permettre une modification de ce type sur une réponse qui était une solution autonome. Je pense que vous auriez dû commenter le sujet avec l'auteur de la réponse avant de procéder à cette modification.
Tensibai
@phedoreanu Je pense que vous avez un meilleur travail dérivé, alors veuillez écrire votre propre réponse et expliquer pourquoi elle est meilleure (dans la gestion des erreurs, les modèles, etc.) à la place.
Tensibai
Salut, j'ai compris la même chose après quelques tentatives infructueuses. Mon seul problème en ce moment est que si je mets deux sections {..} d'étapes à l'intérieur d'un nœud pour certaines raisons, le graphique des étapes du flux de travail et Blu Ocean se confondent. Par exemple, dans le graphique des étapes du flux de travail, j'obtiens NaNy NaNd et dans Blue Ocean, j'obtiens uniquement la première étape.
Giuseppe
6

Cela fonctionne également si vous souhaitez rester dans l' Declarative Pipelineespace

// declare our vars outside the pipeline
def tests = [:]
def files

pipeline {
    agent any
    stages {
        stage('1') {
            steps {
                script {
                    // we've declared the variable, now we give it the values
                    files = findFiles(glob: '**/html/*.html')
                    // Loop through them
                    files.each { f ->
                        // add each object from the 'files' loop to the 'tests' array
                        tests[f] = {
                            // we're already in the script{} block, so do our advanced stuff here
                            echo f.toString()
                        }
                    }
                    // Still within the 'Script' block, run the parallel array object
                    parallel tests
                }
            }
        }       
    }
}
primetheus
la source
Si vous souhaitez allouer chaque tâche parallèle à différents nœuds Jenkins, enveloppez simplement les actions dans un node {}bloc, comme ceci: tests[f] = { node { echo f.toString() } }
primetheus
1

Il est beaucoup plus facile d'utiliser des pipelines scriptés pour cela, car vous pouvez utiliser Groovy arbitraire, mais vous devriez toujours pouvoir le faire avec des pipelines déclaratifs à l'aide de l' findFilesétape.

jayhendren
la source
1

Sachez que les étapes de génération dynamique peuvent entraîner des problèmes dans certaines étapes de génération, par exemple lorsque vous appelez un autre travail:

pipeline {
    stages {
        stage('Test') {
            steps {
                script {
                    def tests = [:]
                    for (f in findFiles(glob: '**/html/*.html')) {
                        // Create temp variable, otherwise the name will be the last value of the for loop
                        def name = f
                        tests["${name}"] = {
                            build job: "${name}"
                        }
                    }
                    parallel tests
                }
            }
        }       
    }
}
Christian Gripp
la source