10.5. Générer vos tâches de build Maven automatiquement

Rédigé par Evgeny Goldin

Comme mentionné dans la section précédente, le nombre de tâches de build que votre serveur Jenkins héberge peut varier. Lorsque ce nombre grossira, il deviendra plus difficile non seulement de les voir dans le tableau de bord Jenkins, mais aussi de les configurer. Imaginez ce que nécessiterait la configuration de 20 à 50 tâches une par une ! De plus, plusieurs de ces tâches pourraient avoir en commun des éléments de configuration, comme des goals Maven ou des paramètres de configuration mémoire, ce qui résulte en une configuration dupliquée et un surplus de maintenance.

Par exemple, si vous décidez d'exécuter mvn clean install au lieu de mvn clean deploy pour vos tâches de release et de passer à des méthodes de déploiement alternatives, comme celles fournies par le pluginArtifactory , vous n'aurez plus d'autre choix que d'ouvrir toutes les tâches concernées et de les mettre à jour manuellement.

Sinon, vous pourriez tirer parti du fait que Jenkins est un outil simple et direct qui garde trace de toutes ses définitions sur le disque dans des fichiers bruts. En effet, vous pouvez mettre à jour les fichiers config.xml de vos tâches directement dans le répertoire .jenkins/jobs où ils sont conservés. Bien que cette approche fonctionnerait, elle est loin d'être idéale parce qu'elle implique un nombre assez important de sélections manuelles et de remplacements délicats dans des fichiers XML Jenkins.

Il y a une troisième façon d'atteindre le nirvana des mises à jour massives de tâches : générer vos fichiers de configuration automatiquement en utilisant une sorte de fichier de définition. Le Maven Jenkins Plugin fait exactement cela : générer les fichiers config.xml pour toutes les tâches en utilisant des définitions standards conservées dans un unique fichier pom.xml.

10.5.1. Configurer une tâche

Quand vous configurez une tâche avec le Maven Jenkins Plugin, vous pouvez définir tous les éléments habituels de configuration, comme les goals Maven, l'emplacement du POM, les URL de dépôts, les adresses e-mail, le nombre de jours pendant lesquels conserver les logs, et ainsi de suite. Le plugin essaie de vous rapprocher au plus près de la configuration classique d'une tâche dans Jenkins.

Jetons un oeil à la tâche de build de Google Guice :

<job>
    <id>google-guice-trunk</id>
    <description>Building Google Guice trunk.</description>
    <descriptionTable>
        <row>
            <key>Project Page</key>
            <value>
                <a href="http://code.google.com/p/google-guice/">
                    <b><code>code.google.com/p/google-guice</code></b>
                </a>
            </value>
            <escapeHTML>false</escapeHTML>
            <bottom>false</bottom>
        </row>
    </descriptionTable>
    <jdkName>jdk1.6.0</jdkName>
    <mavenName>apache-maven-3</mavenName>
    <mavenOpts>-Xmx256m -XX:MaxPermSize=128m</mavenOpts>
    <daysToKeep>5</daysToKeep>
    <useUpdate>false</useUpdate>
    <mavenGoals>-e clean install</mavenGoals>
    <trigger>
        <type>timer</type>
        <expression>0 0 * * *</expression>
    </trigger>
    <repository>
        <remote>http://google-guice.googlecode.com/svn/trunk/</remote>
    </repository>
    <mail>
        <recipients>jenkins@evgeny-goldin.org</recipients>
    </mail>
</job>

Cette tâche utilise un certain nombre de configurations standards comme <jdkName>, <mavenName> et <mavenOpts>. Le code est récupéré à partir d'un dépôt Subversion (défini dans l'élément <repository>), et un <trigger> cron qui exécute la tâche pendant la nuit à 00:00. Les notifications Email sont envoyées aux personnes spécifiées avec l'élément <mail>. Cette configuration ajoute aussi un lien vers la page du projet dans le tableau de description généré automatiquement pour chaque tâche.

Cette tâche générée est affichée dans votre serveur Jenkins comme illustré dans Figure 10.27, “Une tâche générée avec le Maven Jenkins plugin”.

Une tâche générée avec le Maven Jenkins plugin

Figure 10.27. Une tâche générée avec le Maven Jenkins plugin


Voici une autre tâche réalisant la build de la branche master du projet Jenkins hébergé chez GitHub :

<job>
    <id>jenkins-master</id>
    <jdkName>jdk1.6.0</jdkName>
    <numToKeep>5</numToKeep>
    <mavenName>apache-maven-3</mavenName>
    <trigger>
        <type>timer</type>
        <expression>0 1 * * *</expression>
    </trigger>
    <scmType>git</scmType>
    <repository>
        <remote>git://github.com/jenkinsci/jenkins.git</remote>
    </repository>
    <mail>
        <recipients>jenkins@evgeny-goldin.org</recipients>
        <sendForUnstable>false</sendForUnstable>
    </mail>
</job>

Elle génère la tâche montrée dans Figure 10.28, “Tâche générée jenkins-master”.

Tâche générée jenkins-master

Figure 10.28. Tâche générée jenkins-master


La documentation du plugin fournit une référence détaille de tous les paramètres qui peuvent être configurés.

10.5.2. Réutiliser une configuration de tâche par héritage

Être capable de générer des tâches Jenkins jobs en utilisant une configuration centralisée, comme un POM Maven, résout le problème de la création et de la mise à jour de plusieurs tâches à la fois. Tout ce que vous avez à faire est de modifier les définitions de job, relancer le plugin et charger les définitions mises à jour avec Administrer Jenkins“Recharger la configuration à partir du disque”. Cette approche a aussi l'avantage de rendre facile le stockage de vos configurations de tâche dans un système de gestion de versions, ce qui rend par la même plus facile le suivi des changements faits aux configurations de build.

Cela ne résout toutefois pas le problème consistant à maintenir des tâches qui partagent un certain nombre de propriétés identiques, comme les goals Maven, les destinataires email ou l'URL du dépôt de code. Pour cela, le Maven Jenkins Plugin fournit de l'héritage de tâches, démontré dans l'exemple suivant:

<jobs>
    <job>
        <id>google-guice-inheritance-base</id>
        <abstract>true</abstract>
        <jdkName>jdk1.6.0</jdkName>
        <mavenName>apache-maven-3</mavenName>
        <daysToKeep>5</daysToKeep>
        <useUpdate>true</useUpdate>
        <mavenGoals>-B -e -U clean install</mavenGoals>
        <mail><recipients>jenkins@evgeny-goldin.org</recipients></mail>
    </job>
 
    <job>
        <id>google-guice-inheritance-trunk</id>
        <parent>google-guice-inheritance-base</parent>
        <repository>
            <remote>http://google-guice.googlecode.com/svn/trunk/</remote>
        </repository>
    </job>
 
    <job>
        <id>google-guice-inheritance-3.0-rc3</id>
        <parent>google-guice-inheritance-base</parent>
        <repository>
            <remote>http://google-guice.googlecode.com/svn/tags/3.0-rc3/</remote>
        </repository>
    </job>
 
    <job>
        <id>google-guice-inheritance-2.0-maven</id>
        <parent>google-guice-inheritance-base</parent>
        <mavenName>apache-maven-2</mavenName>
        <repository>
            <remote>http://google-guice.googlecode.com/svn/branches/2.0-maven/
            </remote>
        </repository>
    </job>
</jobs>

Dans cette configuration, google-guice-inheritance-base est une tâche parent abstraite contenant toutes les propriétés communes : le nom du JDK, le nom de Maven, le nombre de jours de conservation des logs, la politique de mise à jour SVN, les goals Maven et les destinataires email. Les trois tâches suivantes sont très courtes, spécifiant simplement qu'elles étendent une tâche <parent> et ajoutent les configurations manquantes (URLs de dépôt dans ce cas). Une fois générées, elles héritent de toutes les propriétés de la tâche parente automatiquement.

Toute propriété héritée peut être rédéfinie, comme démontré dans la tâche google-guice-inheritance-2.0-maven où Maven 2 est utilisé à la place de Maven 3. Si vous voulez "annuler" une propriété hériétée, vous devrez la redéfinir avec une valeur vide.

L'héritage de tâches est un concept très puissant qui permet aux tâches de former des groupes hiérarchiques de n'importe quel type et dans n'importe quel but. Vous pouvez grouper vos tâches d'IC, noctures ou de release de cette façon, en centralisant les déclencheurs d'exécution partagés, les goals Maven ou les destinataires email dans des tâches parentes. Cette approche emprunté au monde orienté object permet de résoudre le problème de maintenance de tâches partageant un certain nombre de propriétés identiques.

10.5.3. Le support des plugins

En plus de configurer une tâche et de réutiliser ses définitions, vous pouvez bénéficier d'un support spécial pour un certain nombre de plugins Jenkins. À l'heure actuelle, une utilisation simplifiée des plugins Parameterized Trigger et Artifactory est fournie, un support pour d'autres plugins populaires est prévu dans de futures versions.

Ci-dessous se trouve un exemple d'invocation de tâches avec le plugin Parameterized Trigger. Utiliser cette option suppose que vous avez déjà ce plugin installé :

<job>
    <id>google-guice-inheritance-trunk</id>
    ...
    <invoke>
        <jobs>
            google-guice-inheritance-3.0-rc3,
            google-guice-inheritance-2.0-maven
        </jobs>
    </invoke>
</job>
 
<job>
    <id>google-guice-inheritance-3.0-rc3</id>
    ...
</job>
 
<job>
    <id>google-guice-inheritance-2.0-maven</id>
    ...
</job>

L'élément <invoke> vous permet d'invoquer d'autres tâches chaque fois que la tâche courante se termine correctement. Vous pouvez créer un pipeline de tâches de cette façon, vous assurant que chaque tâche du pipeline invoque la suivante. Notez que s'il y a plus d'un exécuteur Jenkins disponible au moment de l'invocation, les tâches spécifiées démarreront en parallèle. Pour une exécution en série, vous devrez connecter chaque tâche amont à une tâche aval avec <invoke>.

Par défaut, l'invocation ne se fait que quand la tâche courante est stable. Ceci peut être modifié, comme montré dans les exemples suivants :

<invoke>
    <jobs>jobA, jobB, jobC</jobs>
    <always>true</always>
</invoke>
 
<invoke>
    <jobs>jobA, jobB, jobC</jobs>
    <unstable>true</unstable>
</invoke>
 
<invoke>
    <jobs>jobA, jobB, jobC</jobs>
    <stable>false</stable>
    <unstable>false</unstable>
    <failed>true</failed>
</invoke>

La première invocation dans l'exemple ci-dessus invoque toujours les tâches avals. Ceci peut être utilisé pour un pipeline de tâches qui devraient toujours être exécutées même si certaines, ou leurs tests, échouent.

La seconde invocation dans l'exemple ci-dessus invoque les tâches avals même si une tâche amont est instable : l'invocation prend place quels que soient les résultats des tests. Cela peut être utilisé pour un pipeline de tâches moins sensibles aux tests et à leurs échecs.

La troisième invocation ci-dessus invoque les tâches avals seulement quand une tâche amont échoue mais pas lorsqu'elle est stable ou instable. Cette configuration peut vous être utile si une tâche en échec doit effectuer des actions additionnelles autres que les notifications email tradtionnelles.

Artifactory est un dépôt de binaires à usage général qui peut être utilisé comme gestionnaire de dépôt Maven. Le plugin Jenkins Artifactory, montré dans Figure 10.29, “Configuration du plugin Jenkins pour Artifactory”, fournit un certain nombre d'avantages pour les tâches de build Jenkins. Nous avons déjà passé en revue quelques-unes d'entre elles dans Section 5.9.4, “Déployer vers un gestionnaire de dépôt d’entreprise”, notamment la capacité à déployer des artefacts à l'achèvement de la tâche ou d'envoyer avec des informations de l'environnement de build avec les artefacts pour une meilleure traçabilité.

Configuration du plugin Jenkins pour Artifactory

Figure 10.29. Configuration du plugin Jenkins pour Artifactory


Vous pouvez aussi utiliser le plugin Jenkins Artifactory conjointement au Maven Jenkins Plugin pour déployer dans Artifactory, comme montré dans l'exemple suivant :

<job>
    ...
    <artifactory>
        <name>http://artifactory-server/</name>
        <deployArtifacts>true</deployArtifacts>
        <includeEnvVars>true</includeEnvVars>
        <evenIfUnstable>true</evenIfUnstable>
    </artifactory>
</job>

Les informations d'identité pour le déploiement sont spécifiées dans la configuration de Jenkins dans l'écran Administrer Jenkins→Configurer le système. Elles peuvent aussi être spécifiées pour chaque tâche Jenkins. Les dépôts Maven par défaut sont libs-releases-local et libs-snapshots-local. Vous trouverez plus de détails dans la documentation du plugin à l'adresse http://wiki.jenkins-ci.org/display/JENKINS/Artifactory+Plugin.

10.5.4. Les tâches Freestyle

En supplément des tâches Maven, le Maven Jenkins Plugin vous permet de configurer des tâches freestyle Jenkins. Un exemple est montré ici :

<job>
    <id>free-style</id>
    <jobType>free</jobType>
    <scmType>git</scmType>
    <repository>
        <remote>git://github.com/evgeny-goldin/maven-plugins-test.git</remote>
    </repository>
    <tasks>
        <maven>
            <mavenName>apache-maven-3</mavenName>
            <jvmOptions>-Xmx128m -XX:MaxPermSize=128m -ea</jvmOptions>
            <properties>plugins-version = 0.2.2</properties>
        </maven>
        <shell><command>pwd; ls -al; du -hs .</command></shell>
    </tasks>
</job>

Les tâches Freestyle vous permettent d'exécuter un shell ou une commande batch, exécuter Maven ou Ant, et invoquer d'autres tâches. Elles fournissent un environnement d'exécution bien pratique pour les scripts systèmes ou tout autre type d'activité qui n'est pas directement implémentée dans Jenkins ou l'un des ses plugins. En utilisant cette approche, vous pouvez générer des fichiers de configuration de tâche de build Freestyle de façon similaire à l'approche que nous avons vue pour les tâches de build Maven, ce qui peut aider à rendre votre environnement de construction plus cohérent et maintenable.