web-dev-qa-db-fra.com

Charger la bibliothèque partagée Jenkins Pipeline à partir du même référentiel

TL; DR Existe-t-il un moyen d'importer du code dans le Jenkinsfile à partir du référentiel local (autre que le load étape)?

Pourquoi?

J'ai expérimenté que pour les builds complexes, le Jenkinsfile devient assez volumineux et peu maintenable.
Maintenant que le travail de construction est du code, ce serait merveilleux d'avoir les mêmes moyens que pour les autres codes. C'est-à-dire que je voudrais le diviser en unités plus petites (plus faciles à maintenir) et tester les unités .

Ce que j'ai essayé

  • bibliothèques partagées : permet de diviser notre logique Jenkins Pipeline en fichiers plus petits dans un module séparé et même de le tester à l'unité.
    Cependant, ils doivent être dans un référentiel différent et (sinon sur GitHub) doivent être configurés dans Jenkins.
  • load Step : permet de charger des scripts groovy à partir du référentiel.
    Cependant, les fichiers doivent être des scripts et non des classes groovy "complètes", ce qui rend difficile d'avoir plusieurs fichiers ou classes qui dépendent les uns des autres. Par exemple, l'héritage est impossible.
    De plus, ces fichiers ne sont pas affichés lorsque vous effectuez un replay sur un travail Jenkins, ce qui les rend difficiles à développer et à déboguer.

Mes questions

  • Existe-t-il un moyen (ou une solution) de créer une bibliothèque partagée dans le même référentiel que le Jenkinsfile et d'importer cette bibliothèque dans le Jenkinsfile?
  • Ou y a-t-il encore une autre façon que je n'ai pas encore essayée?

Exemple de structure de répertoire

Similaire à la structure de répertoires décrite pour bibliothèques partagées J'aimerais avoir les éléments suivants dans un seul référentiel .

(root)
+- someModule
|   +- ...
+- jenkins           # Classes/Scripts used by Jenkins in a separate module
|   +- src                       # Groovy source files
|      +- org
|          +- foo
|              +- Bar.groovy     # for org.foo.Bar class
|   +- test                      # Groovy test files
|      +- org
|          +- foo
|              +- BarTest.groovy # Test for org.foo.Bar class
|   +- pom.xml or build.groovy   # Build for local library
+- Jenkinsfile     # Build "someModule", uses classes from "jenkins" module
21
schnatterer

Solution de contournement:

library identifier: 'shared-library@version', retriever: legacySCM(scm)

L'approche actuellement adoptée dans PR 37 ne fonctionnera pas correctement avec les agents de build et ne fonctionnera de toute façon que pour les scripts utilisant l'étape library, pas la @Library annotation.

Au fait, les fichiers chargés à partir de l'étape load do apparaissent dans Replay . Mais il est vrai que votre script ne peut pas faire référence statiquement à des types définis dans de tels fichiers. En d'autres termes, vous pouvez simuler la bibliothèque vars/*.groovy mais non src/**/*.groovy— la même limitation que le PR 37 actuel.

6
Jesse Glick

Je suppose que la bonne façon de le faire est d'implémenter un SCMRetriever personnalisé.

Cependant, vous pouvez utiliser le hack suivant:

En supposant jenkins/vars/log.groovy dans votre référentiel local contient:

def info(message) {
    echo "INFO: ${message}"
}

Votre Jenkinsfile peut charger cette bibliothèque partagée à partir du jenkins/ répertoire utilisant library étape:

node('node1') { // load library
    checkout scm
    // create new git repo inside jenkins subdirectory
    sh('cd jenkins && git init && git add --all . && git commit -m init &> /dev/null') 
    def repoPath = sh(returnStdout: true, script: 'pwd').trim() + "/jenkins"
    library identifier: 'local-lib@master', retriever: modernSCM([$class: 'GitSCMSource', remote: repoPath])
}

node('node2') {
    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}
4
Pawel Wiejacha

Vous pouvez jeter un oeil au plugin que j'ai écrit, qui permet d'utiliser des sous-répertoires de dépôt où votre pipeline est en tant que bibliothèques partagées: https://github.com/karolgil/SharedLibrary

Après l'avoir construit et installé, vous pouvez simplement mettre ce qui suit dans votre pipeline:

@SharedLibrary('dir/in/repo') _

Pour commencer à utiliser dir/in/repo comme bibliothèque partagée pour vos pipelines.

3
Karol Gil

Je voulais faire la même chose et j'ai fini par créer ceci:

https://github.com/jenkinsci/workflow-cps-global-lib-plugin/pull/37

et voici comment je l'utilise:

https://github.com/syndesisio/syndesis-pipeline-library/blob/master/Jenkinsfile#L

Dans mon cas, je voulais créer un fichier Jenkins qui en fait tests la bibliothèque de pipelines que contient le référentiel.

Faites-moi savoir ce que vous pensez et n'hésitez pas à ajouter vos commentaires sur le RP.

2
iocanel

J'ai trouvé que la version de Pawel avait des problèmes si vous extrayez le pipeline de SCM (non intégré dans la configuration de l'interface utilisateur du travail Jenkins). Ceci est ma version pour ces cas:

node {
    def jenkinsDir = sh(returnStdout: true, script: 'pwd').trim().replaceAll('(.*)(@[0-9]*$)', '$1') + "@script/jenkins"
    ssh("cd ${jenkinsDir} && ls -l vars/ && if [ -d .git ]; then rm -rf .git; fi; git init && git add --all . && git commit -m init &> /dev/null")
    library identifier: 'local-lib@master', retriever: modernSCM([$class: 'GitSCMSource', remote: jenkinsDir])

    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}

Dans ces cas, le pipeline lui-même est extrait dans un autre espace de travail (même nom de répertoire mais avec @script dans le nom) que l'endroit où le pipeline lui-même sera exécuté (et où votre code sera également extrait).

Le répertoire "jenkins" est uniquement disponible (au moins avec la dernière version avec le dossier "vars") dans l'espace de travail où le pipeline est extrait, car l'autre n'est pas encore extrait et à jour (peut-être même dans un branche différente).

0
lqbweb