dimanche 28 décembre 2008

Les moteurs de recherche d'artefacts Maven

Voici un résumé des différents moyens pour rechercher les informations d'un artefact Maven.
Un artefact Maven est caractérisé par le triplet GAV (GroupId – ArtifactId – VersionId). Il faut connaître ces trois informations pour ajouter une dépendance dans votre descripteur Maven (pom.xml).

Par exemple, voici la déclaration d'une dépendance:
<dependency>
 <groupId>V</groupId>
 <artifactId>A</artifactId>
 <<version>V</version>
</dependency>

Le repository central officiel de Maven est situé à l'adresse suivante http://repo1.maven.org/maven2/. De nombreux moteurs de recherche existent sur le marché afin d'obtenir les informations des artefacts dans les repository Maven. Chaque moteur a sa particularité de fonctionnement, et ainsi chacun ne renvoie pas des informations identiques pour une même demande d'artefact.

Un premier moteur de recherche connu est celui à l'adresse suivante : http://www.mvnrepository.com/. Celui-ci est déconseillé car il utilise un mirroir du repository central de Maven (http://mirrors.ibiblio.org/pub/mirrors/maven2/) au lieu d'utiliser directement le repository central. Au delà du délai d'attente de synchronisation, ce moteur a été souvent indisponible dans le passé.

Un autre moteur de recherche est celui l'adresse suivante : http://www.mvnindex.org. Il est très efficace et à jour dans ses méta données; je le recommande. De plus, couplé à son plugin Eclipse, ce moteur de recherche devient très pratique. Le seul reproche est qu'une recherche se limite uniquement au repository central.

Mais depuis peu, Sonatype a mis à disposition une instance du gestionnaire de repository Nexus à l'adresse http://repository.sonatype.org/index.html. Il s'agit d'une très bonne initiative que ne propose pas pour l'instant Archiva, le principal challenger de Nexus. L'avantage de cet instance publique est qu'elle agrège plusieurs repositories publiques dont le repository java.net, très utile pour rechercher les artefacts Hudson. Néanmoins, il existe un certain délai pour obtenir les dernières versions des artefacts. Prenons l'exemple de l'artefact "doxygen" de java.net qu'il ne trouve pas. Il ne trouve pas non plus par exemple, la dernière version du plugin clearcase de Hudson en version "0.8.1".

D'autres moteurs existent sur le marché comme l'ancien site "mavenreposearch" (http://maven.ozacc.com/). Il est également déconseillé à cause des données obsolètes renvoyées. Il existe également le moteur de recherche JavaRepo (http://javarepo.xoocode.org/). Partie d'une très bonne initiative puisqu'il peut servir également comme moteur de recherche pour Ivy, il semble ne plus être maintenu.

Et pour finir un nouveau moteur de recherche "mvnbrowser" à l'adresse http://www.mvnbrowser.com/index.html.
Celui-ci est très bien fait. Le premier avantage est la richesse des repositories agrégés. On peut apprécier également la qualité des informations du résultat de la recherche. A ce jour, je conseillerais d'utiliser ce dernier qui est le seule à renvoyer des informations correctes.

Packager Hudson avec ses plugins en Gradle

Dans un précédent post, je spécifiais comment produire avec Maven, l'archive Web de Hudson incorporant un ensemble de plugins; voici son équivalent avec Gradle:

usePlugin('war')
group='org.jvnet.hudson'
version='1.266'
hudsonunpack= new File('build/hudson-unpack')
hudsonunpack.mkdirs()

boolean isPlugin(File dependency){
 if ((dependency.getName()!=null) && (dependency.getName().endsWith(".hpi"))){
  return true;
 }
 return false
}


List plugins = [
  'org.jvnet.hudson.plugins:doxygen:0.1@hpi',
  'org.jvnet.hudson.plugins:gradle:1.1@hpi',
  'org.jvnet.hudson.plugins:zentimestamp:1.0@hpi',
  'org.jvnet.hudson.plugins:clearcase:0.8.1@hpi'
]

List core = [
  'org.jvnet.hudson.main:hudson-war:'+version+'@war'
]

dependencies{
  addMavenRepo('http://download.java.net/maven/2')
  providedCompile core
  providedRuntime plugins
}

createTask('hudson-unpack'){
 dependencies.resolve("providedCompile").each{ depFile ->
  ant.unzip(src: depFile , dest:hudsonunpack)
 }
}

createTask('copy-plugins'){
 pluginsDir = new File(hudsonunpack,'WEB-INF/plugins')
 pluginsDir.mkdirs()
 dependencies.resolve("providedRuntime").each{ depFile ->
  if (isPlugin(depFile))
   ant.copy(file: depFile, todir: pluginsDir)
 }
}


task('hudson-unpack').execute()
task('copy-plugins').execute()


archive_war{
 baseName='hudson'
 manifest.mainAttributes(
  "Main-Class": "Main",
  "Version": version)
 fileSet(dir: hudsonunpack){
  exclude('**/HUDSON.RSA')
  exclude('**/HUDSON.SF')
 }
}

J'avoue que l’utilisation de Gradle dans cet exemple ne permet pas de montrer sa pleine puissance et ses apports en comparaison de Maven. Néanmoins, la première remarque est l'aisance de la spécification des éléments pour la création de l'archive Web. La deuxième remarque concerne l'utilisation des tâches Ant (ant.copy et ant.unzip) pour réaliser l'équivalent des goals "copy" et "unpack" du plugin maven "maven-dependency-plugin". C'est un peu dommage, et pour l'instant sur ce point, Maven est supérieur. Mais une issue Jira (GRADLE-337) a été soumise sur le projet Gradle. N'hésiter pas à voter pour cette issue.

jeudi 25 décembre 2008

Sortie de Seam 2.1.1.GA

Après les deux releases candidate 2.1.1.CR1 et 2.1.1.CR2, JBoss Seam a sortie pour Noël la release 2.1.1.GA. Cette nouvelle version contient les corrections de nombreuses anomalies qui persistaient.

Pour ceux qui utilisent Seam en version 1.x ou 2.0.x, n'hésiter pas à consulter les guides de migration comme le dernier.

Consulter le lien officiel de la sortie.

mardi 23 décembre 2008

Packager Hudson avec ses plugins

Depuis la version 1.259 de Hudson, il est possible de pré packager les plugins de Hudson dans l'archive Web (hudson.war).
Il suffit d'inclure les plugins (*.hpi) dans le répertoire « WEB-INF/plugins » de l'archive. Au lancement les plugins packagés seront déployés dans l'espace de travail de Hudson $HUDSON_HIOME/plugins.

L'exemple suivant montre la récupération d'une archive Hudson et d'un ensemble de plugins, puis son re-packaging avec Maven

<project xmlns="http://maven.apache.org/POM/4.0.0" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><project xmlns="http://maven.apache.org/POM/4.0.0" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelversion>4.0.0</modelversion>

<groupid>org.jvnet.hudson.plugins</groupid>
<artifactid>hudson-war</artifactid>
<packaging>war</packaging>
<version>1.266</version>
<name>hudson-war</name>

<properties>
  <hudson.version>${project.version}</hudson.version>
  <hudson.unpack>${project.build.directory}/hudson-unpack</hudson.unpack>
</properties>

<build>
 <plugins>
  <plugin>
   <groupid>org.apache.maven.plugins</groupid>
   <artifactid>maven-dependency-plugin</artifactid>
   <executions>
    <execution>
    <id>unpack-origin-archive</id>
    <phase>initialize</phase>
    <goals>
    <goal>unpack</goal>
    </goals>
    <configuration>
    <artifactitems>
    <artifactitem>
    <groupid>org.jvnet.hudson.main</groupid>
    <artifactid>hudson-war</artifactid>
    <version>${hudson.version}</version>
    <type>war</type>
   <overwrite>true</overwrite>
    <outputdirectory>${hudson.unpack}</outputdirectory>
    </artifactitem>
    </artifactitems>
    </configuration>
    </execution>

    <execution>
    <id>copy-plugins</id>
    <phase>initialize</phase>
    <goals>
    <goal>copy</goal>
    </goals>
    <configuration>
    <artifactitems>

    <artifactitem>
    <groupid>org.jvnet.hudson.plugins</groupid>
    <artifactid>clearcase</artifactid>
    <version>0.8.1</version>
    <type>hpi</type>
    <outputdirectory>${hudson.unpack}/WEB-INF/plugins</outputdirectory>
    </artifactitem>

    <artifactitem>
     <groupid>org.jvnet.hudson.plugins</groupid>
     <artifactid>doxygen</artifactid>
     <version>0.1</version>
     <type>hpi</type>
     <outputdirectory>${hudson.unpack}/WEB-INF/plugins</outputdirectory>
     </artifactitem>

    <artifactitem>
     <groupid>org.jvnet.hudson.plugins</groupid>
    <artifactid>zentimestamp</artifactid>
    <version>1.0</version>
    <type>hpi</type>
    <outputdirectory>${hudson.unpack}/WEB-INF/plugins</outputdirectory>
    </artifactitem>

    </artifactitems>
    </configuration>
    </execution>

    </executions>
    </plugin>

   <plugin>
    <groupid>org.apache.maven.plugins</groupid>
    <artifactid>maven-war-plugin</artifactid>
    <version>2.1-alpha-2</version>
    <configuration>
    <classifier>withplugins</classifier>
    <webresources>
    <resource>
    <directory>${hudson.unpack}</directory>
    <excludes>
    <exclude>META-INF/HUDSON.SF</exclude>
    <exclude>META-INF/HUDSON.RSA</exclude>
    </excludes>
    </resource>
    </webresources>
    <archive>
    <manifestfile>${hudson.unpack}/META-INF/MANIFEST.MF</manifestfile>
    </archive>
   </configuration>
   </plugin>

   </plugins>
 </build>
</project>

Il vous suffira ensuite de lancer la commande mvn clean package pour obtenir la nouvelle archive Hudson hudson-war-1.266-withplugins.war avec les plugins inclus.

mercredi 17 décembre 2008

Retour sur le barcamp 2

Voici le retour sur la session concernant l’intégration continue et les outils de build du barcamp deuxième edition organisé par OCTO mardi dernier. Cette session s’est déroulée en présence d’une dizaine de personnes ayant chacune un retour d’expérience a faire partager.

Partie sur les outils de build

Le premier sujet abordé a été « Maven au delà du poste de développement ». Un sujet délicat, qui revient souvent dans les équipes que je rencontre. Selon mon expérience, l'outil Maven doit être limité aux phases de compilation, de tests et de packaging. Il faut laisser le déploiement de ces artifacts aux scripts shell ou ksh souvent existant, et maintenus par une équipe spécifique dans les structures d’entreprises de taille importante. Maven doit donc être utilisé pour réaliser des fonctions de build uniquement. En revanche, il est important d’insister sur le fait que dans le cadre de développement JEE, l’archive Web produite doit être indépendante de l’environnement final. C’est au conteneur Web (ex :Tomcat) de contenir la configuration de l’environnement nécessaire comme par exemple la configuration de l’environnement de dev, de recette, de pre-prod et de prod. Et attention a l’utilisation abusive des profils Maven. Ces profils sont très utiles pour choisir le serveur de déploiement dans le cas d'une gestion de configuration des environnements des tests mais ne doit en aucun cas être utilisés pour réaliser un artifact de developement ou de recette en fonction de l’activation d’un profil de dev ou de recette (ex : -Penv=dev ou –Penv=rec). Utiliser cette technique pour ce cas d'utilisation est un abus de la puissance de Maven. En conclusion, il faut produire des artifacts génériques et classifier vos artifact par nature si besoin (sources, tests, …) et non pas par environnement.

L’autre point abordé a été l’utilisation de Maven dans les IDE. Pour Eclipse, l’utilisation de Maven est facilitée par l’intégration du plugin maven-eclipse-plugin (mvn eclipse:eclipse) ou par les plugins Eclipse Q4E ou m2eclipse. Un retour sur les lenteurs du plugin m2eclipse a été notifié. Cela renforce mon choix d’utiliser maven de manière complètement indépendante de l’utilisation des taches quotidiennes de développement au sein de l’IDE. A noter que rien ne vaut la gestion de Maven dans IDEA IntelliJ, qui depuis la version 7 permet une lecture directe des descripteurs Maven (pom.xml). Il a été également abordé la bonne intégration de Maven dans NetBeans. Mais la question que je me pose après coup : pourquoi utiliser NetBeans aujourd’hui pour les développements non Swing?

Il a été discuté ensuite de l’automatisation des tests d’IHM avec Selenium et de son intégration avec Maven. Selenium est un outil très populaire, qui s’impose aujourd’hui en entreprise. On peut affirmer que le concurrent Watij est en perte de vitesse. A noter que pour ceux qui exposent leur logique métier via REST, il est possible d’utiliser Selenium pour tester les flux http de retour dans le cas de XML. Concernant son intégration avec Maven, j’ai insisté qu’il s’agit de tests d’intégration et que Maven ne supporte pas très bien les tests d’intégration. La technique qu’il faut utiliser est de produire un module dédié aux tests d’intégration sur lequel la phase Maven des tests unitaires est skipée et que l'exécution des tests du projet est lié sur la phase Maven « integration-test ». Ensuite, il suffit simplement d’utiliser le plugin selenium server et le tour est joué.

Au delà de tout cela, j’ai essayé de montrer la lourdeur de Maven lorsqu’on sort des conventions en voulant scripter des produits non JEE comne des plugins RCP. Les conventions de Maven et le total manque de flexibilité me permettent d’affirmer qu’il est nécessaire de ne pas choisir Maven systématiquement comme builder pour vos applications Java. Dans ce cadre, il est plus intéressant de rester sur des scripts ANT ou de passer sur des scripts Gant ou Gradle. Gant est un langage de build au-dessus de Ant avec la syntaxe du langage Groovy. Couplé au gestionnaire de dépendances Ivy, il en fait un choix de premier ordre pour donner de la flexibilité à vos scripts de build. En revanche, si vous travaillez sur des projets plus conventionnés, ne pas hésiter a jeter un coup d’œil à Gradle qui est un outil de build comme Gant pour le langage de script en Groovy, mais avec en plus les conventions de Maven et un cycle de vie. Voici sur ce post, un exemple de gestion multi-projet avec Gradle.

D’autres outils on été cités en fin de session comme Raven, il s’agit d’un maven en Ruby. Le projet est en fin de vie. Desolé pour les fans de Ruby, mais Ruby n’a rien a envier comparé à Groovy ou Python (ou son petit frère pour Java : Jython).

A noter que pour ceux qui construisent des projets C/C++, l’outil très utilisé en entreprise est le builder Scons écrit en Python.

Les outils d’intégration continue

La deuxième partie de cette session a concernée plus spécifiquement les serveurs d’intégration continue. Sujet très ancien, tout le monde connaît le poste de Martin Fowler sur le sujet qui date de 2006, il s’agit néanmoins d’un sujet qui explose chez tous les clients ou j’interviens. En terme de choix d’outil, toutes les personnes dans la salle sont unaniment sur le fait que Hudson est le serveur d’intégration continue incontournable en ce moment. Cette affirmation est confirmée par le sondage fait à Devoxx comme signalé sur le blog du créateur de Hudosn: Kohsuke Kawaguchi.

Nous avons également discuté des livraisons très rapprochées de Hudson. Hudson produit une release très régulièrement de son core.
Comme j’en parle ici, il est important au niveau des ses clients de qualifier une version avant d’updater sa version de Hudson et il est bien sûr impossible d’utiliser systématiquement la dernière release de Hudson en production.

Il a été également abordé la gestion dans Hudson d’un projet multi-branche. L’autre approche des mécanismes multi-branche est l’utilisation d’une seule branche au niveau de son SCM et la pratique des pre-tested commit. Aujourd’hui, il s’agit de la seule fonctionnalité manquante au niveau Hudson, et qui pourrait nous faire basculer vers son principal challenger aujourd’hui TeamCty. Mais que les utilisateurs de Hudson se rassurent, cette fonctionnalité est en cours de développement et sera tout prochainement disponible.

Au-delà de ceci, quelques retours de plugins Hudson comme le CI game hudson plugin qui en conclusion ne sert à rien.

Le format court et la richesse du contenu ne m’a pas permit d’aborder de nombreux points qui me tenaient a cœur comme quelle personne ou équipe doit être en charge de faire évoluer le build continue? Et quelles sont les connaissances requises et nécessaires pour laisser une équipe être autonome avec une intégration continue?
Une prochaine fois sûrement.

En conclusion, une très bonne soirée dans des locaux impeccables, et le tout sur les Champs-Elysées.

lundi 15 décembre 2008

Les composantes d’une intégration continue

J’apprécie l’approche apportée par l’article de Meera Subbarao sur son blog sur les trois composantes de l’intégration continue :

  1. Un gestionnaire de configuration comme Subvervsion ou Clearcase
  2. Un moteur d’intégration continue comme Hudson
  3. Un processus de build automatique s’appuyant par exemple sur Ant, Maven, Gant ou le nouvel outil de build Gradle

dimanche 14 décembre 2008

Gradle en version 0.5

La version 0.5 de Gradle est sortie début décembre.
Parmi les nouveautés, on notera :
- Création de propriétés dynamiques
- Génération de bundle OSGI
- Déploiement dans un repository Maven
- Gestion améliorée de plusieurs niveaux de logging
- Le retour à un script de démarrage Windows (gradle.bat)
Cette dernière fonctionnalité est très importante, elle permet de prendre en compte clairement le code de retour de l'exécution d'un script de build Gradle. Une valeur correcte du code de retour de l'exécution d'un script est indispensable pour une possible intégration au sein d'un serveur d'intégration continue. A noter que l'intégration de Gradle dans Hudson à travers son plugin, prend déjà en compte cette fonctionnalité.