L'intégration continue avec CruiseControl.NET

Cet article a pour objet de présenter puis de mettre en place pas à pas un système d'intégration continue d'une application grâce à la plateforme CruiseControl.NET. Et après l'article : détente avec du sudoku.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

La complexité croissante des projets applicatifs actuels implique la mise en place d'usines de développement. Ces « usines » permettent de limiter les tâches répétitives pour les développeurs en leur fournissant un système complet d'intégration automatique des différents éléments d'un projet.

Plus concrètement, certains projets possèdent des dizaines de développeurs et la taille de l'application implique parfois des heures de compilation. De plus, si des tests unitaires sont couplés à ce processus, la mise en place d'un serveur d'intégration continue s'avère essentielle pour la qualité d'exécution d'un tel projet.

Voici un exemple de principe d'intégration continue qui reprend certains aspects énoncés par les méthodes dites « agiles » :

  1. L'équipe de développement programme la journée sur un projet en utilisant un outil de contrôle de version (CVS, Subversion, VSS, ClearCase, …).
  2. Un développement est terminé pendant la journée, le développeur concerné le met à jour dans le contrôle de version (checkin).
  3. Le système d'intégration continue détecte la mise à jour des sources et lance une compilation incrémentale (qui n'implique que le bloc de code mis à jour).
  4. La journée se termine.
  5. La nuit, à heure fixe, une compilation complète du code est démarrée grâce au système d'intégration continue. On appelle aussi ce processus le nightlybuild.
  6. La compilation se termine, une série de tests unitaires sont lancés pour valider la nouvelle version compilée.
  7. Le matin, le chef de projet et les développeurs ont accès à un reporting convivial sur les résultats du nightlybuild.

Cet article a pour objet de réaliser la mise en place pas à pas d'un système d'intégration continue grâce à l'outil CruiseControl.NET qui se base sur le framework .NET.

II. Exemple simple de processus d'intégration continue

Le processus décrit dans l'introduction est un peu trop complexe à mettre en place dans le cadre de cet article, nous allons donc le réduire à effectuer des compilations complètes de l'application dès qu'une modification est détectée. La faible taille de l'application d'exemple le permet. Cette application s'appellera EasyCalc.

Image non disponible

  1. Le développeur enregistre une modification sur le serveur principal (on suppose que le développement se fait avant sur son poste).
  2. Vérification, à intervalle régulier par le serveur CruiseControl.NET, d'une modification des sources en utilisant les données du système de fichier (pas de contrôle de version).
  3. Une modification est détectée (sinon, rien ne se passe ensuite) alors le script NAnt est lancé (étape 4).
  4. Compilation de toutes les sources du projet si une modification est détectée suivit de tests unitaires du nouveau binaire avec Nunit.
  5. Génération d'un reporting de résultats.
  6. Consultation des résultats et suivi de l'évolution du build par l'équipe de projet.

Dans le chapitre suivant, nous allons créer les sources de notre application EasyCalc ainsi que les tests unitaires associés. Ensuite, nous écrirons le script NAnt qui sera lancé à chaque modification détectée. Et nous terminerons par l'installation de CruiseControl.NET pour l'orchestration générale.

L'ensemble des outils utilisés seront opensource. Ce choix ne provient pas d'une raison de coût ou de conviction mais uniquement parce les frameworks utilisés sont leader dans leur domaine (NAnt et NUnit).
De plus, ces outils venant du monde Java, les explications techniques fournies s'adapteraient très bien à un projet fait avec le langage de Sun.

III. Création des sources de notre application

Pour mettre en place notre système d'intégration continue, nous avons besoin d'une application à compiler et à tester.

Nous allons créer le projet EasyCalc qui sera volontairement simpliste. En dehors de ce contexte d'apprentissage, il n'aurait que peu d'intérêt à être intégré dans une usine de build (compilation).

Nous pourrions utiliser Visual Studio pour le développement mais nous allons nous contenter de créer les fichiers sources. La compilation sera ensuite faite avec un script Nant.

Les sources sont en C# mais comme le code n'est pas essentiel dans cet article, si vous développez en VB.NET, les principes sont les mêmes.

EasyCalc se découpe en trois projets principaux :

  • la librairie EasyCalcLib.dll qui constitue le cœur de l'application ;
  • une application console (Easycalc.exe) qui se charge uniquement d'interfacer EasyCalcLib.dll avec l'utilisateur.
  • une librairie de tests unitaires, TestCalc.dll qui utilise Nunit.

L'application effectuera au choix une des quatre opérations élémentaires sur deux nombres passés en paramètres. Voici un exemple :

« EasyCalc.exe 2 3 + »

Affichera :

« Le résultat de l'opération est 5 »

Pour commencer, créez un répertoire qui contiendra les sources, par exemple : C:\ArticleCC\Sources

III-A. EasyCalcLib

Créez un sous-répertoire nommé C:\ArticleCC\Sources\EasyCalcLib

Placez dans ce répertoire, un fichier Calc.cs qui contient le code suivant :

 
Sélectionnez
using System;

namespace EasyCalcLib
{
        public class Calc
        {
                string[] args;

                public Calc(string[] args)
                {
                         this.args = args;
                }

                public double Calculer()
                {
                        if(args == null || args.Length != 3)
                                throw new Exception("Le nombre d'arguments est invalide");

                        try
                        {
                                double resultat;
                                switch(args[2])
                                {
                                        case "+":
                                                resultat = addition(Int32.Parse(args[0]),Int32.Parse(args[1]));
                                                break;
                                        case "-":
                                                resultat = soustraction(Int32.Parse(args[0]),Int32.Parse(args[1]));
                                                break;
                                        case "*":
                                                resultat = multiplication(Int32.Parse(args[0]),Int32.Parse(args[1]));
                                                break;
                                        case "/":
                                                resultat = division(Int32.Parse(args[0]),Int32.Parse(args[1]));
                                                break;
                                        default:
                                                throw new Exception("Opérateur inconnu");
                                }
                                return resultat;
                        }
                        catch(Exception ex)
                        {
                                throw new Exception("Erreur pendant le calcul : " + ex.Message);
                        }
                }

                private int addition(int nb1,int nb2)
                {
                        return nb1 + nb2;
                }

                private int soustraction(int nb1,int nb2)
                {
                        return nb1 - nb2;
                }

                private int multiplication(int nb1,int nb2)
                {
                        return nb1 * nb2;
                }

                private double division(int nb1,int nb2)
                {
                        return Math.Round((double)nb1 / nb2,2); // arrondis à 2 décimales
                }
        }
}

III-B. EasyCalc

Créez un sous-répertoire nommé C:\ArticleCC\Sources\EasyCalc

Placez dans ce répertoire, un fichier MainClass.cs qui contient le code suivant :

 
Sélectionnez
using System;
using EasyCalcLib;

namespace EasyCalc
{
        class MainClass
        {
                [STAThread]
                static void Main(string[] args)
                {
                        Calc calc = new Calc(args);
                        Console.WriteLine(
                                String.Format("Le résultat de l'opération est : {0}",
                                calc.Calculer())
                        );

                        Console.ReadLine();
                }
        }
}

III-C. TestCalc

Il s'agit de la librairie de tests unitaires. Elle utilise les classes du framework NUnit qui est inclus dans l'installation de NAnt. Il est donc inutile de l'installer sauf si vous désirez profiter des différents outils fournis avec l'installateur de Nunit.

Pour en savoir plus sur NUnit, vous pouvez consulter l'article suivant :

Les tests unitaires avec NUnit : http://jab.developpez.com/tutoriels/dotnet/nunit/

Les tests unitaires font partie intégrante des systèmes d'intégration continue, car ils permettent de valider la bonne qualité d'une application, si vous ne connaissez pas ces principes, mieux vaut consulter l'article cité avant de continuer.

Créez un sous-répertoire nommé C:\ArticleCC\Sources\TestCalc

Placez dans ce répertoire, un fichier TestClass.cs qui contient le code suivant :

 
Sélectionnez
using System;
using NUnit.Framework;
using EasyCalcLib;

namespace TestCalc
{
        [TestFixture]
        public class TestClass
        {
                [Test]
                public void Addition()
                {
                        Calc calc = new Calc(new string[] {"3","5","+"});
                        Assert.AreEqual(8,calc.Calculer());
                }

                [Test]
                public void Soustraction()
                {
                        Calc calc = new Calc(new string[] {"4","1","-"});
                        Assert.AreEqual(3,calc.Calculer());
                }

                [Test]
                public void Multiplication()
                {
                        Calc calc = new Calc(new string[] {"3","3","*"});
                        Assert.AreEqual(9,calc.Calculer());
                }

                [Test]
                public void DivisionEntiere()
                {
                        Calc calc = new Calc(new string[] {"12","3","/"});
                        Assert.AreEqual(4,calc.Calculer());
                }

                [Test]
                public void Division2Decimales()
                {
                        Calc calc = new Calc(new string[] {"9","8","/"});
                        Assert.AreEqual(1.12,calc.Calculer());
                }

                [Test]
                public void DivisionParZero()
                {
                        Calc calc = new Calc(new string[] {"4","0","/"});
                        Assert.AreEqual(Double.PositiveInfinity,calc.Calculer());
                }
        }
}

Les tests définis ici passent tous avec succès si les sources données précédemment sont respectées. Nous le vérifierons dans la suite de l'article.

IV. Écriture du script NAnt

NAnt est un outil de permettant de définir au format xml une série de tâches successives. Au départ utilisé pour la compilation indépendamment de l'environnement de développement, ses tâches ont été étendues à de nombreux autres usages.

Si vous ne connaissez pas NAnt, il est préférable, avant de continuer, de consulter l'article suivant (en ignorant la partie Visual Studio .NET si besoin) :

Débuter avec NAnt sous Visual Studio.NET :  http://defaut.developpez.com/tutoriel/dotnet/nant/

L'application EasyCalc est développée dans la technologie .NET, mais ce n'est pas d'une obligation. Vous pouvez, en effet, utiliser NAnt avec d'autres compilateurs.

  1. Rendez-vous sur http://nant.sourceforge.net/ et téléchargez la dernière version de Nant (0.85 RC3 au moment d'écrire cet article).
  2. Décompressez l'archive récupérée dans le répertoire de votre choix. Nous supposerons que le répertoire de NAnt choisi est C:\Program Files\nant\
  3. Créez le fichier EasyCalc.build dans le répertoire C:\ArticleCC\Sources et placez-y le script suivant :
 
Sélectionnez
<?xml version="1.0"?>
<project name="EasyCalc" default="test" basedir="." xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
    <description>Compilation et tests de EasyCalc.</description>
    <property name="workingDir" value="C:\ArticleCC"/>
    <property name="sourcesDir" value="${workingDir}\Sources"/>
    <tstamp property="builddate" pattern="yyyyMMdd_HHmm" />
    <property name="outputDir" value="${workingDir}\Binaries\EasyCalc-${builddate}"/>
    <property name="testsResultDir" value="${workingDir}\Binaries"/>
    
    <target name="build" description="Compilation des sources de EasyCalc">
                <mkdir dir="${outputDir}" failonerror="false" />
                <csc target="library" output="${outputDir}\EasyCalcLib.dll" debug="false">
            <sources>
                <include name="${sourcesDir}\EasyCalcLib\*.cs" />
            </sources>
        </csc>
        <csc target="exe" output="${outputDir}\EasyCalc.exe" debug="false">
            <sources>
                <include name="${sourcesDir}\EasyCalc\*.cs" />
            </sources>
            <references >
                                <include name="${outputDir}\EasyCalcLib.dll" />
                         </references>
        </csc>
        <csc target="library" output="${outputDir}\TestCalc.dll" debug="false">
            <sources>
                <include name="${sourcesDir}\TestCalc\*.cs" />
            </sources>
            <references >
                                <include name="${outputDir}\EasyCalcLib.dll" />
                                <include name="C:\Program Files\nant\bin\lib\net\1.1\nunit.framework.dll" />
                         </references>
        </csc>
    </target>
    
    <target name="test" description="Test de EasyCalc" depends="build">
                <nunit2>
                        <formatter type="Xml" usefile="true" extension=".xml" outputdir="${testsResultDir}"/>
                        <test assemblyname="${outputDir}\TestCalc.dll" />
                </nunit2>
    </target>
</project>

Le script se découpe en trois parties :

IV-A. La définition des propriétés

  • workingDir : le répertoire principal contenant tous les fichiers de notre projet.
  • sourcesDir : le répertoire contenant les sources de EasyCalc.
  • outputDir : le répertoire qui contiendra les nouveaux fichiers binaires (il sera unique pour chaque compilation et permettra d'historiser les données).
  • testsResultDir : le répertoire qui recevra le log Nunit.

La compilation (« build »)

Trois compilations pour trois projets sont effectuées :

  • EasyCalcLib dont dépend les deux autres projets ;
  • EasyCalc, l'application console ;
  • La dll de tests, TestCalc.dll qui dépend du framework NUnit. Ici la référence est faite vers le NUnit inclus dans Nant.

Les tests unitaires (« tests »)

La tâche <nunit2> est appelée en spécifiant d'écrire un fichier de log des tests au format xml. Ainsi CruiseControl pourra le récupérer et afficher les informations. On veille aussi bien à spécifier la dll contenant la série de tests.

Cette task est dépendante de « build » et ne se fera pas si cette dernière échoue.

V. Installation et configuration de CruiseControl.NET

V-A. Installation

CruiseControl.NET contient trois éléments principaux :

  • le serveur qui est le centre du système et qui se charge de gérer l'ensemble du processus d'intégration continue ;
  • le webdashboard, une interface web permettant de consulter les différents projets répartis sur un ou plusieurs serveurs. Dans notre cas, nous aurons un projet branché sur un serveur ;
  • le cctray, un outil de monitoring symbolisé par un petit icône dans la traybar indiquant le statut du ou des projets en cours (rouge, jaune ou vert pour signifier : échec, compilation en cours ou succès).

Téléchargez l'installateur principal sur le site du projet (version 1.0 RC2 au moment d'écrire cet article) : http://ccnet.thoughtworks.com/.

Vérifiez que IIS est installé sur votre machine avec le support d'ASP.NET.

Installez CruiseControl.NET en décochant la possibilité de lancer le serveur en tant que service (ce n'est pas utile dans le cadre de cet article). Le répertoire d'installation devrait être C:\Program Files\CruiseControl.NET

Vérifiez que vous avez accès au DashBoard en tapant dans votre navigateur : http://127.0.0.1/ccnet

Si tout va bien, vous devriez voir apparaître cette interface :

Image non disponible

Le message d'erreur est normal puisque nous n'avons pas encore démarré le serveur.

Téléchargez le projet CCTray qui est indépendant du projet principal et installez-le.

V-B. Configuration

Ouvrez le fichier C:\Program Files\CruiseControl.NET\server\ccnet.config

Ce fichier contient la définition des projets CruiseControl et la quasi-totalité de la configuration du serveur. Le site de l'éditeur détaille sa structure et ses possibilités, n'hésitez pas à le consulter.

Nous allons créer un nœud <project/> pour y définir notre projet EasyCalc.

Copiez dans ccnet.config, le xml suivant :

 
Sélectionnez
<cruisecontrol>
  <project>
   <name>EasyCalc</name> 
    <webURL>http://localhost/ccnet-dashboard/ ?_action_ViewProjectReport=true&amp;server=local&amp;project=EasyCalc</webURL> 
    <triggers>
        <intervalTrigger seconds="60"/>
    </triggers>
    <workingDirectory>.</workingDirectory>
    <modificationDelaySeconds>2</modificationDelaySeconds>
    <sourcecontrol type="filesystem">
      <repositoryRoot>C:\ArticleCC\Sources</repositoryRoot>
    </sourcecontrol>
    <tasks>
        <nant>
                        <executable>C:\Program Files\nant\bin\nant.exe</executable>
                        <buildFile>C:\ArticleCC\Sources\EasyCalc.build</buildFile>
                        <targetList>
                                <target>test</target>
                        </targetList>
                </nant>
    </tasks>
    <publishers>
        <merge>
                <files>
                        <file>C:\ArticleCC\Binaries\*-results.xml</file>
                </files>
        </merge>
        <xmllogger />
    </publishers>
  </project>
</cruisecontrol>

Les actions effectuées sont les suivantes :

  • <triggers/> permet ici de définir un intervalle entre chaque vérification des sources, 60 secondes dans notre cas ;
  • <sourcecontrol/> permet de choisir le système de contrôle des modifications (souvent CVS, VSS, ClearCase, …). Ici nous nous baserons uniquement sur une lecture du système de fichier grâce aux dates des fichiers. Le répertoire à monitorer est défini dans <repositoryRoot/> ;
  • <tasks> décrit les tâches à effectuer quand une modification est détectée. Il s'agit, dans notre exemple, de lancer la tâche « test » du script NAnt qui se chargera ensuite de lancer la compilation et les tests.
  • <publishers/> permet de récupérer les logs générés (seul NUnit ici) et ensuite d'appeler le qui créera le log CruiseControl de l'intégration courante.

Ce log sera placé ensuite dans ce répertoire : C:\Program Files\CruiseControl.NET\server\EasyCalc\Artifacts\buildlogs.

Ce répertoire n'existe pas jusqu'à la première intégration effectuée. L'ensemble de ces fichiers de logs sera parsé et mis en page grâce à des feuilles xsl se trouvant dans C:\Program Files\CruiseControl.NET\webdashboard\xsl

V-C. Premier démarrage et cctray

Démarrez-le CCTray précédemment installé, il apparaît gris dans la barre des tâches. En effet, aucun serveur n'y est configuré.

Faites un clic-droit dessus puis « Settings ».

Dans la partie « BuildServer », cliquez sur « Add » et ajoutez le serveur « 127.0.0.1 » et son projet « EasyCalc ».

Exécutez C:\Program Files\CruiseControl.NET\server\ccnet.exe

Si tout se passe bien, 4 nouveaux fichiers devraient être détectés et une intégration démarrée.

Image non disponible

Cette information permet de comprendre que toute la compilation et les tests se sont bien passés.

Si au moins un test échoue, le cctray apparaît en rouge (pour l'éviter, il faudrait modifier le script NAnt avec un failonerror à false pour les tests nunit, nous le testerons pas ici).

Pour essayer cela, provoquons un échec du test unitaire « Division2Decimal » :

Dans le fichier C:\ArticleCC\Sources\EasyCalcLib\Calc.cs, modifiez la ligne :

 
Sélectionnez
return Math.Round((double)nb1 / nb2,2); // arrondis à 2 décimales

Par :

 
Sélectionnez
return Math.Round((double)nb1 / nb2,3); // arrondis à 3 décimales

Enregistrez le fichier. Au bout de quelque temps (60 secondes maximum), le serveur CruiseControl va détecter la modification et lancer l'intégration. À la fin, l'intégration apparaîtra en échec.

Image non disponible

Rappelons qu'à chaque compilation un nouveau répertoire est crée par notre script NAnt. L'ensemble des binaires se trouvent dans C:\ArticleCC\Binaries.

Image non disponible

V-D. Le dashboard

Pour analyser, la raison de l'échec précédent, ouvrons-le Dashboard : http://127.0.0.1/ccnet.

Cliquez sur EasyCalc puis sur le dernier résultat en échec dans le menu de gauche. Un écran ressemblant à ceci devrait apparaître :

Image non disponible

À gauche, apparaît la liste des derniers builds effectués ainsi qu'un menu permettant d'atteindre les différents sous-rapports.

Au centre, nous trouvons des informations concernant l'intégration. On trouve le nom des fichiers modifiés ainsi que la raison de l'échec : « Tests failed » suivis du détail du test échoué (le test Division2Decimales).

Pour plus d'informations concernant les tests et le log du script NAnt, vous pouvez consultez les parties concernant NAnt et NUnit sur le menu de gauche.

Sachez que le dashboard est paramétrable. Vous pouvez éditer le fichier C:\Program Files\CruiseControl.NET\webdashboard\dashboard.config pour y relier d'autres serveurs CruiseControl.NET mais aussi pour configurer les différents éléments de l'interface.
Consultez le site de l'éditeur pour plus de précisions :  http://ccnet.thoughtworks.com.

VI. Conclusion

Le principe d'intégration continue est intéressant pour de nombreux projets naissant ou existant depuis longtemps. Il permet, en plus d'automatiser, de valider la qualité d'une application et d'informer, non seulement les développeurs, mais aussi le client ou la maîtrise d'ouvrage du projet. La convivialité et les capacités de personnalisation de l'interface web fournie avec CruiseControl.NET permettent effectivement d'obtenir un rendu accessible à tous les maillons d'un projet.

De plus, CruiseControl.NET a la capacité de s'interfacer avec la plupart des outils du marché. Nous avons utilisé ici NAnt et NUnit mais MSBuild, FXCop, MBUnit, NCover et autres outils de compilation, de tests ou d'audit de code sont intégrables facilement.

L'arrivée de TeamSystem de Microsoft risque de changer les choses mais CruiseControl.NET a une bonne carte à jouer pour se faire une place dans le monde de l'intégration continue. La raison ? Il est solide et OpenSource.

Téléchargez la version PDF de cet article.

VII. Remerciements

Merci à Isabelle et Jean-Jacques pour m'avoir fait découvrir les principes et les outils liés aux usines de build et de tests.

Merci à Pedro204 pour la relecture.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 minosis. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.