web-dev-qa-db-fra.com

Comment choisir dynamiquement une branche git à utiliser dans la construction de Jenkins

J'essaie de créer une nouvelle configuration de projet pour le serveur de génération Jenkins. Pour simplifier ce que j'essaie de faire, je n'utiliserai que deux composants pour décrire le problème.

ComposantA

  • La modification de ce composant déclenche la construction de ce projet sur le serveur CI.
  • Le serveur CI a une branche configurée de manière statique pour surveiller les modifications et créer. Par exemple. maîtriser ou développer une branche.
  • Ce composant contient un fichier de configuration avec la version requise de ComponentB dont il dépend.

Composant b

  • Les modifications apportées à ce composant ne déclenchent pas la génération de ce projet sur le serveur CI (un autre projet couvrira le développement de ComponentB).
  • Les versions individuelles du composant sont marquées
  • ComponentA a requis la version de ComponentB dans son fichier de configuration
  • Le serveur CI ne sait pas quelle branche (balise) à extraire jusqu'à ce que le fichier de configuration de ComponentA soit en quelque sorte analysé.

Quelle est la bonne façon de réaliser cela sur Jenkins? J'essayais de savoir comment ajouter ce comportement dynamique d'analyse du fichier de configuration et de faire en sorte que Git Plugin vérifie la branche en fonction de la version attendue de ComponentB, mais je n'en ai aucune idée.

Dans la prochaine étape, je souhaiterai peut-être même avoir des caractères génériques (tels que 5.3. *) Dans le fichier de configuration. Je devrai donc rechercher la balise la plus récente de ComponentB correspondant au caractère générique.

EDIT

Maintenant, je vois que j'ai trop simplifié mon problème et, en raison de la simplification, la principale limitation n’est plus présente.

La principale limitation est que les composants A et B doivent être construits ensemble. Il n'est pas possible de les construire séparément car ils forment un seul exécutable/bibliothèque et le script de construction nécessite des fichiers source des deux composants.

Si vous demandez pourquoi une configuration aussi étrange, donnons une description aux composants A et B:

  • ComponentA: code spécifique à la plate-forme native
  • ComponentB: code indépendant de la plateforme native

Il peut y avoir plusieurs composants en tant que composant - un pour chaque plate-forme, mais un seul composant B. La fusion de A à B génère un code source complet pour une plate-forme unique, mais chaque plate-forme ne peut pas être mise à jour vers la dernière version de B, il est donc nécessaire de contrôler quelle version de B doit être utilisé pour construit.

22
Ladislav Mrnka

Une option pour réaliser ce que vous voulez consiste à utiliser la configuration suivante:

Créez deux emplois Jenkins:

  • "Composant A" (déclenché automatiquement lors des modifications du SCM)
  • "Composant B" (déclenché "manuellement")

Étape 1

Définissez le branchparamètre de construction pour "Composant B":

enter image description here

Utilisez ce paramètre comme spécificateur de branche "Git Plugin":

enter image description here

Vous devriez maintenant pouvoir déclencher manuellement la construction de "Composant B" en spécifiant un paramètre de branche (balise) approprié, par ex. tags/5.3.0.

Étape 2

Ajoutez une nouvelle étape de génération "Execute Shell" à votre construction "Composant A", qui extraira la version "Composant B" du fichier de configuration dans l'espace de travail et préparera b.properties fichier avec les paramètres de construction "Composant B".

enter image description here

Installez un déclencheur paramétré plug-in Jenkins et ajoutez une nouvelle étape de génération "Déclencheurs/appels sur d'autres projets" au travail "Composant A":

enter image description here

En utilisant votre b.properties fichier en tant que source des paramètres de construction.

Maintenant, chaque fois que "Composant A" est reconstruit, un nouveau "Composant B" sera déclenché, avec la branche/balise cible en tant que paramètre de construction.

Ajout du support de joker

Si vous voulez supporter les versions génériques, vous pouvez utiliser git ls-remote commande pour trouver la dernière balise, comme celle-ci:

#B=$(obtain B version from the config file in a usual way)   

LATEST=$(\
    git ls-remote --tags YOUR_REPOSITORY_URL "$B"\
    |cut -d / -f3|sort -r --version-sort|head -1\
)

cat <<EOF > b.properties
    branch=tags/$LATEST
EOF

Ceci listera toutes les balises, correspondant au modèle de version "B", dans le référentiel distant "Composant B", et sauvegardera le dernier numéro de version dans la variable LATEST.

Ajoutez ceci à votre étape "Exécuter Shell" du travail "Composant A" et il devrait être capable de gérer des modèles de numéros de version tels que: 5.3.*

Le problème est que le script Shell s'exécutera en tant qu'utilisateur du démon Jenkins. Il doit donc disposer des informations d'identification appropriées pour accéder au référentiel Git distant (par exemple, via la clé de publication ssh).

Sinon, vous voudrez peut-être consulter = Credential Binding Plugin , pour réutiliser les informations d'identification Git stockées dans Jenkins même.

Utilisation du pipeline de style Jenkins 2.0

Vous pouvez également résoudre le problème en utilisant un Jenkins 2.0-style Pipeline , qui vous permettra d'extraire le code des composants A et B dans un seul espace de travail, puis d'appliquer une étape de construction commune. pour eux.

Votre pipeline pourrait ressembler à ceci:

node {

   //Settings
   def credentialsId = '8fd28e34-b04e-4bc5-874a-87f4c0e05a03'    
   def repositoryA = 'ssh://[email protected]/projects/a.git'
   def repositoryB = 'ssh://[email protected]/projects/b.git'

   stage('Checkout component A') {
      git credentialsId: credentialsId , 
      url: repositoryA , branch : "master"
   }

   stage("Resolve and checkout component B") {
      def deps = readProperties file: 'meta.properties'
      echo "Resolved B version = ${deps['b']}"

      dir("module/b") {
           //Clone/Fetch Component B 
           checkout scm:[
                $class: 'GitSCM', 
                userRemoteConfigs: [[url: repositoryB, credentialsId: credentialsId]], 
                branches: [[name: 'refs/tags/*']]
           ], 
           changelog: false, poll: false

           //Checkout the tag, matching deps['b'] pattern     
           sshagent([credentialsId]) {
                sh "git checkout \$(git tag -l \"${deps['b']}\" |sort -r --version-sort|head -1)"
           }
      }
   }

   stage("Build A+B") {
        //Apply a common build step
   }

}

Nous utilisons ici la commande "readProperties", qui fait partie du plug-in Pipeline Utility Steps , pour extraire le modèle de version "Composant B" de meta.properties. Des commandes readYaml, readJSON sont également disponibles.

Ensuite nous récupérons/clonons le "Composant B", avec le changelog: false, poll: false _ drapeaux, pour l’empêcher d’être enregistrés pour l’enquête SCM, dans le dossier "module/b" de l’espace de travail actuel.

Ensuite, appelez une commande Shell pour sélectionner la balise, basée sur le modèle de version que nous avons obtenu ci-dessus, et extrayez-la (les caractères génériques de style 5.3. * Devraient également fonctionner).

L'invocation sh est encapsulée dans sshagent , afin de lui permettre de réutiliser les informations d'identification appropriées à partir du magasin d'informations d'identification Jenkins.

18
zeppelin

Utiliser le Credential Binding Plugin a très bien fonctionné pour moi (également mentionné par @zeppelin)

Pas:

Dans la section Informations d'identification globales :

  1. Add Credentials De type: "Nom d'utilisateur avec mot de passe". Il doit s'agir du nom d'utilisateur et du mot de passe du serveur git du référentiel du composant B utilisant le protocole [~ # ~] https [~ # ~] (l'option SSH n'est pas bon pour cela)

enter image description here

Dans votre configuration de travail Jenkins:

  1. Placez le composant A dans la gestion normale du code source sous la section Git de tous les champs obligatoires ( Référentiels , Branches, etc.).
    • Il sera plus simple et plus propre de placer le référentiel dans un sous-répertoire: sous Comportements supplémentaires , choisissez Check out to a sub-directory Et écrivez: component_a
  2. Assurez-vous également d’enregistrer les déclencheurs de construction le Build when a change is pushed to GitHub
  3. Dans la section Environnement de construction, cochez la case Use secret text(s) or file(s)

    • mettre dans Variable un nom: MY_CRED
    • dans Credentials choisissez les informations d'identification spécifiques que vous avez créées à l'étape 1.

    enter image description here

  4. Maintenant, en utilisant le MY_CRED Dans le code Execute Shell , vous aurez accès au référentiel du composant B:

    DIR="component_b"
    if [ "$(ls -A $DIR/.git)" ]; then
        cd $DIR
        git fetch
    else
        git clone https://[email protected]/proj/component_b.git $DIR 
        cd $DIR
    fi
    git show
    

    enter image description here

    • Remarque : vous ne verrez PAS l'utilisateur et le mot de passe dans les journaux, il devrait donc être sûr. vous verriez: git clone 'https://****@github.com/proj/component_b.git' component_b
  5. Effectuez toutes vos analyses de la configuration du composant A pour obtenir la balise souhaitée: TAG=$(cat ./component_a/config.cfg | grep ... | sed ...)

  6. Commander le tag souhaité: cd component_b; git checkout -f $TAG
    • Remarque: la balise force -f.
  7. Maintenant, lancez le code et testez-le comme vous le souhaitez ...
2
Chananel P

1 - l’ajout du projet B en tant que sous-dépôt du projet A serait-il une solution possible?

2- (si l’inclusion du code source complet pour B devrait vraiment être évitée): pousserait les constructions de B vers un repo B_builds, Et ajouterait ce repo en tant que sous-repo de A être un solution possible ?


Justification: une façon de rendre plus explicite la dépendance entre A et B consiste à la représenter dans les dépendances du référentiel.

Cela nécessiterait d'ajouter une étape supplémentaire lors de la gestion du projet A:

update `B` sub repo in `A` project, and Push this to `A`

chaque fois que vous produisez une nouvelle version pour B.

Cependant, vous auriez une vue claire, à partir de A, sur le moment où les versions de B ont été intégrées (par exemple: "nous n’utilisions que B 2.0.1 À partir de A 4.3.2 ] "), et pousser à A déclenchera votre flux habituel de Jenkins.

1
LeGEC