Thématiques principales

dimanche 10 décembre 2017

Maven : Introduction

Qu'est ce que Maven ? Je vais vous en faire un résumé rapide mais pour ceux qui veulent une bible et de details, consulter ce livre.

Généralités

Maven est un gestionnaire de build ou constructeur de projet. Il est open source et soutenu par la fondation Apache. Maven a pour but de simplifier, rationaliser et automatiser la construction d'un projet sur l’ensemble de ses phases et activités de façon a garantir la qualité de no build.

Initialement orienté pour les projet Java, Maven est maintenant capable de construire des projets de tout type de nature, c++, Python, etc....

Ainsi, et c'est sa fonction première, Maven va permettre de compiler le code de notre application, ceci en fournissant des moyens de gestion simple pour les dépendances du projet. Cependant, s’arrêter a cela, serait hyper réducteur car Maven a plus la vocation de couvrir tout le périmètre de build.

En fait avec Maven, il est possible de:
  • préparer la compilation (en générant du code par exemple) 
  • effectuer la compilation
  • exécuter des tests unitaire, 
  • faire de l'analyse de code,
  • faire du packaging (construction de jar, war, tar.gz ou même des deb) 
  • exécuter des procédures d'installation sur des plateformes spécifiques de tests, exécuter des tests fonctionnels (avec roboframework par exemple)
  • préparer un livrable
  • générer differentes doc (technique ou utilisateur)
  • etc... car il est possible d'adjoindre des plugins supplémentaires pour compléter son fonctionnement.
Tout ceci concerne les activités directement lié au build de notre projet mais avec maven, il sera aussi possible d'aller plus loin en permettant la constitution de processus plus générique autour de la gestion du projet comme :
  • la construction automatique de template de projet
  • la gestion de multi-projet, de leurs dépendances et de leur orchestration dans un même process
  • la gestion d'un cache local de vos dépendances
  • la gestion des builds passés sous la forme de SNAPSHOT et de RELEASE
  • du deployement de documentation web en ligne

Configuration

Maven s'articule autour d'un runner que l'on telecharge ici. Je ne vais pas rentrer dans le details de l'installation de Mave, mais celle-ci se résume globalement a spécifier convenablement JAVA_HOME qui exécutera Maven. (Attention, ce dernier n'est pas forcement celui employé pour la compilation). On pourra specifier ce JAVA_HOME directement lors de l'appele de Maven en faisant un alias par exemple sous unix/cygwin.

Il est ensuite nécessaire de configurer ce que l'on appelle les Settings. Ce setting est constitué de deux fichiers, le fichier système présent dans le répertoire conf de Maven et un fichier utilisateur présent dans le répertoire .m2 de l'utilisateur courant.

Comme on peut se le douter, le setting système permet de configurer Maven pour toutes ses utilisations alors que celui de l'utilisateur sera spécifique au compte utilisateur lançant le processus Maven. (la commande mvn, que nous verrons plus loin)

L'ordre de chargement de ces settings se réalisera toujours dans le sens Systeme puis Utilisateur, le dernier chargé faisant fois de sa configuration en cas de conflits. A noter qu'il est possible de spécifier un setting lors du build afin de personnaliser celui-ci avec l'option -s

Le settings est le fichier de configuration dans lequel seront définis les variables d’environnement locales (comme les differentes versions Java installées sur la machine),  les repositories de dépendances (artifactory ou nexus, SNAPSHOT ou RELEASE), les serveur web, des serveurs de base de données, des server de vérification de code (Sonar par exemple) , des secrets éventuels pour s'y connecter, etc.... en fait toute configuration et ressource spécifique a l'environnement de build, utilisable non directement par les projets.

Par convention (unix) on build dans un compte spécifique (maven par exemple) et on initialise ces données dans le settings utilisateur, le settings système étant réservé aux configurations partagées.

Par exemple un settings spécifiant les variables pour la compilation en java 6, 7 ou 8, les variables pourront alors être utiliser dans les pom.xml des projets (nous verrons par la suite ce que sont les pom):


<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository>/home/m2Repo</localRepository>
  <profiles>
    <profile>
      <id>compiler</id>
        <properties>
          <JAVA_1_6_HOME>jdk1.6.0_33_win_x64</JAVA_1_6_HOME>
          <JAVA_1_7_HOME>jdk1.7.0_80_win_x64</JAVA_1_7_HOME>
          <JAVA_1_8_HOME>jdk1.8.0_66_win_x64</JAVA_1_8_HOME>
        </properties>
    </profile>
  </profiles>  
  <activeProfiles>
    <activeProfile>compiler</activeProfile>
  </activeProfiles>
</settings>


Ici nous avons spécifique un répertoire différents du répertoire par défaut du repository maven locale qui permet a Maven de stoker toutes les dépendances dont il aura besoin lors des builds (nous verrons également ce point par la suite)

Dans ce cas ci, nous n'utilisons pas de repository distant permettant a Maven de resoudre les dépendances manquantes de son repository locale. Nous sommes donc dans une configuration hors-ligne. Donc si lors du build Maven, il manque une dépendance dans le repository locale, Maven finira en echec.

Pour permettre a Maven de résoudre des dépendances manquantes et de les mettre dans son repository locale, on ajoutera le serveur central Maven :


<profile>
  <id>securecentral</id>
  <!--Override the repository (and pluginRepository) "central" from the
     Maven Super POM -->
  <repositories>
    <repository>
      <id>central</id>
      <url>https://repo1.maven.org/maven2</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <url>https://repo1.maven.org/maven2</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </pluginRepository>
  </pluginRepositories>
</profile>


Processus Maven

Maintenant que Maven est configuré (sommairement) intéressons nous aux processus de build en lui-même.

Nous l'avons vu précédemment, Maven répond a un grand nombre de besoin, son processus va s'appuyer sur de nombreux plugin décrits sur cette page qui vont interagir afin de procéder a l’exécution de tout ou partie du cycle de vie.

Le cycle de vie Maven est ce que l'on pourra appelé complet. Il se compose d'un cycle par défaut contenant les processus de compilation, test, packaging et déploiement précédé optionnellement d'un cycle de nettoyage des projets et suivi optionnellement d'un cycle de génération de site documentant les projets.




Ainsi via l'appel de la commande mvn (répertoire bin de Maven) et en se plaçant dans notre projet, il sera alors possible de faire appel a un processus déroulant les phases décrites par le schéma ci dessus. A noter que les deux cycles de vie optionnels clean et site ne seront déroulés que si appeler explicitement via la commande Maven alors que le cycle de vie Default sera de toutes façon exécuter jusqu’à l’étape (ou phase dans le jargon Maven) explicitement appelée

Ainsi, la commande


$ mvn compile 


exécute les phases validate a compile du cycle default, tandis que


$ mvn clean test


exécute toutes les phases du cycle clean et les phases validate a test du cycle default.

Ainsi, la commande


$ mvn clean deploy site-deploy


exécute toutes les phases, mais ce ne sera pas forcement une bonne idée....

Mais on a parler de plugins ? qu'est ce que c'est?

Et bien tout le processus présenté ci dessus est la modélisation des activités classiques auxquelles les builds vont répondre. Cependant, on peut facilement imaginer que d'un projet a l'autre les builds ne vont pas s'appuyer sur les même concepts selon les phases. Ainsi tout bêtement la compilation d'un projet Java ne sera pas la même chose qu'une compilation d'un projet C++. De même, certains projets vont s'appuyer sur des configurations differentes de packaging, de compilations, de test. Et même sur des projets relativement semblables, des choix technologiques peuvent amener des outils différents.

Face a cette richesse de besoin et de possibilité, Maven a adopté le principe du : voici un plugin implémentant le comportement par défaut pour le cas le plus général et si le plugin ne correspond pas, est bien il existe des moyens de créer les siens (nous reviendrons sur ce point dans un autre article).

Ainsi pour que pour chaque phase soit proposée  les outils et les moyens de configuration adaptés, Maven va s'appuyer sur ces fameux plugins pour donner une implémentation et une opérationnabilité liés aux spécificités de chaque projet. Le plugin selon le cas sera configuré difficilement ou simplement substitué par un autre, voir même parfois ajouter et exécuté parallèlement.

Pour une liste exhaustive de l'ensemble des plugins "standard" utilisable je vous invite a consulté cette page. Cela donnera une idée des possibilités par défaut, et les plugins utilisables selon les phases des cycles de vie Maven.

Il manque maintenant un dernier élément a tout cela. Comment donner a Maven la carte des plugins a utiliser pour son cycle de vie et leur configuration? Le POM!

Project Object Model

Le POM ou fichier pom.xml est ce qui permet à Maven de connaitre le comment builder le projet courant.

Il va en exister de différents types, si l'on veut suivre de bonnes pratiques Maven, on va s'appuyer sur le pattern parent/module/projet (décrit aussi dans cet article):

  • Des pom projet supportant la production d'un composant logiciel spécifique de type jar, deb, ear, etc... Il s'agit de ce que l'on peut considérer comme étant la composante Maven qui nous vient en premier a l'esprit. Ce pom va donc définir les variables locales au projet, les processus spécifiques nécessaire à la compilation du composant, les dépendances et ou encore de quel pom parent le projet va hériter.
  • Des pom parent qui ont pour but de factoriser des comportements standard de build dont vont heriter des pom projets . Dans ces pom on trouvera alors l'ensemble des spécificités propre à des familles de projets partageant des processus ou des propriétés de compilation commune.
  • Des pom module permettant d'orchestrer la construction d'un ensemble de projets techniquement interdépendant en les agrégeant.

Attention un POM se définit en XML, de ce fait, ce dernier est conforme a ce que l'on appelle un schéma (XSD) pour en structurer les informations a la manière d'une grammaire. Ainsi, tous les types de pom se base sur le même XSD amenant souvent a des utilisations fusionnées des précédents concepts présentés. Alors bien sur, Maven aurait pu simplement définir des XSD différent pour répondre aux différents types. Le choix a été fait de ne pas brider leur utilisation et de permettre malgré tout quelques digressions. Quelques digressions ne signifie pas que cela doit être une généralité car suivre le pattern parent/module/projet permet largement de couvrir 90% des cas d'utilisation. Et comme dans tous les cas d'utilisation des patterns, si vous faites autrement, c'est que vous avez une vraie bonne raison technique (et pas une raison du type : on livre demain...)

Pour avoir une illustration plus précise de cette décomposition, je vous invite a consulter cette question sur stackoverflow. Elle traite bien de la question et nous ramène comme souvent au problème de la division des préoccupations et des besoins comme en POO et ce selon la complexité du problème. En effet, dans un cas simple, on préférera avoir un POM projet classique.... ensuite lorsque les projets commenceront a se multiplier un peu on décidera de construire un POM parent pour factoriser les propriétés et donc on y déposera également une définition des modules à construire (la liste des POM projets). Finalement, lorsque l'on aura des projets dont les POM parent n'auront plus de points communs et qu'il faudra les diviser, alors on placera des POM modules afin d'orchestrer le ou les builds possibles pour les lots de projets a gérer...

Ainsi rien que par cet exemple, certes, on se rend compte que progressivement on en arrivera de toute façon a tendre vers l'application du pattern parent/module/projet... cependant, afin d’éviter des modifications douloureuses dans les dépendances des builds, il est vraiment préférable de définir de suite un structure de POM parent, factorisant des processus standard de build, et des modules définissant séparément les lots de builds.

Je ne vous ferais pas l'affront de vous donner un exemple, avec les differentes références que je vous ai donné ci dessus, vous avez largement les moyens de soit débuter, soit enrichir l'architecture des builds de vos projets.

Voila, un grand tour d'horizon de Maven, ce que l'on en fait et ce qui est important de faire des le départ au niveau structure des projets. Ceci n’était cependant qu'une introduction donc dans les prochains articles sur Maven sous essayeront de voir les points suivant:

  • un POM et une architecture parent/module/projet en vrai
  • comment faire son propre plugin
  • c'est quoi les archétypes

Aucun commentaire:

Enregistrer un commentaire