Services collaboratifs
- PARTAGE
- Evento
- Guide utilisateur
- Notes de version
- Filesender
- RENAvisio
- Rendez-vous
- Sourcesup
- Universalistes
Cette partie du TP va montrer la gestion d'un projet avec le gestionnaire de sources Git, tout en intégrant au fur et à mesure les développements avec Jenkins. Jenkins fonctionnera en se servant de Maven pour “builder” le projet et lancer les tests unitaires, puis analysera la qualité du code, et pour finir déploiera sur un serveur Nexus le binaire produit.
Quelques mots sur Git avant de commencer. Git est un gestionnaire de sources décentralisé, il ne nécessite pas un serveur centrale pour que les développeurs puissent partager leur travail. Chaque développeur possède en local l'intégralité du dépôt (les fichiers sources, leurs différentes versions, les branches, les tags). Il est toutefois pratique d'avoir un serveur central comme point d'entrée, à jour avec tous les développements, permettant à d'autres développeurs ou utilisateurs de venir récupérer les sources.
La documentation officielle est disponible en français ici.
Lors de ce TP nous nous appuierons sur un dépôt Git hébergé sur la plateforme SourceSup. Ce dépôt sera lié à un projet SourceSup afin de gérer les droits d'accès.
Chaque stagiaire se crée un projet sur la forge afin de pouvoir effectuer certaines commandes du TP :
Nom complet du projet : form-git-XXX Etablissement : GIP RENATER Description publique du projet : projet support du TP de la formation Git Nom Unix du projet : form-git-XXX Code source : choisir git
La plateforme SourceSup permet d'interagir avec les dépôts qu'elle héberge seulement via le protocole SSH pour gérer l'identification des développeurs. Les stagiaires vont donc devoir se créer une clé SSH sur les machines locale, puis l'uploader sur la forge.
# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: b8:2f:11:e5:66:6f:7e:a8:30:22:ad:9b:2c:b0:89:8c The key's randomart image is: +--[ RSA 2048]----+ | | | . | | o | | ..+ | | .+S. | |. . .. o | |=o. o +. o . | |Eo + ..+ o . | | .=. .o. . | +-----------------+
Le but est d'être capable d'utiliser le client “ligne de commande” Git et d'interagir sur les sources du projet, comprendre le fonctionnement des branches, de leur fusion, ainsi que la gestion des conflits. Nous verrons aussi comment créer des jobs, les lancer, faire des tests unitaires avec JUnit.
Sur CentOS, un paquet Git existe permettant d'installer un client afin d'utiliser Git en lignes de commandes.
# yum install git wget
Maintenant que Git est installé sur votre poste, vous pouvez personnalisé son environnement. Pour cela, il existe des fichiers regroupant la configuration nécessaire à l'utilisation du client Git. Ces fichiers sont situés :
Il est important de configurer le pseudo ainsi que le mail de l'utilisateur car ces informations seront utilisées par Git. Remplacer USERNAME ET USERMAIL par vos valeurs dans les commandes ci dessous.
# git config --global user.name USERNAME # git config --global user.email USERMAIL
# more ~/.gitconfig
D'autres configuration peuvent être ajoutées, comme des alias de commande Git, pour cela éditer le fichier de configuration :
# emacs ~/.gitconfig
[alias] ci = commit co = checkout st = status br = branch
# git config --list user.name=USERNAME user.email=USERMAIL alias.ci=commit alias.co=checkout alias.st=status alias.br=branch core.repositoryformatversion=0 core.filemode=true core.bare=false core.logallrefupdates=true remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* remote.origin.url=git+ssh://git@git.renater.fr:2222/form-git-XXX.git branch.master.remote=origin branch.master.merge=refs/heads/master
Jenkins est un serveur d'intégration continue et de déploiement continu. Ce serveur est open-source et multi-plateforme. Jenkins va permettre de “builder” des projets, effectuer des tests sur le code, et de déployer les sources sur un serveur.
L'intégration continue est un processus dans lequel les développements sont intégrés les uns aux autres le plus tôt possible, ainsi que de générer des artéfacts et tester les sources du projet.
Pour que le processus d'intégration continue soit efficace, certains pré-requis doivent être mis en place :
Les bénéfices qu'une équipe peut retirer de la mise en place d'un processus d'intégration continue :
Jenkins est un serveur applicatif, qui possède sa propre gestion de comptes utilisateurs pour gérer l'authentification ainsi que les permissions sur les jobs. Sa gestion a été simplifiée afin que l'utilisateur de la forge n'ait pas besoin de créer de compte :
Le principe est le même pour les serveurs Sonar et Nexus, les utilisateurs de la forge n'ont pas besoin de créer/gérer de compte utilisateur sur ces plateformes.
Pour créer un job sur la forge, un administrateur d'un projet doit se rendre sur l'interface de son projet sur SourceSup, puis :
Cette page vous présente les différents menus qu'un job offre.
En utilisant le plugin de SourceSup, votre job a été créé avec quelques paramètres pré-configurés, notamment :
Les sources du dépôt du projet seront téléchargées par Jenkins afin que celui-ci puisse exécuter les différentes actions qui peuvent être ajoutées dans la configuration du job, comme packager ses sources, générer des artéfacts, etc. Jenkins réserve un espace de travail pour chaque job, dans lequel il stockera les sources et effectuera les traitements. Suite à la création du job, l'espace de travail est pour l'instant vide.
Maven est un gestionnaire de build très répandu, permettant de gérer les dépendances de son projet, de packager les sources, de lancer les tests unitaires, etc.
Jenkins fonctionne très bien avec cet outil de build. Il est possible de rajouter des actions pré-build afin de demander à Maven de lancer des actions, comme de packager vos sources.
Nous allons l'utiliser pour notre TP. Ajoutons à notre job une action pre-build, nommée “invoquer des cibles maven de haut niveau”
Cette action requiert quelques paramètres, notamment les cibles Maven à invoquer. Indiquer dans le champ “cibles” :
clean package
L'action “clean” va nettoyer l'espace de travail du job, afin de pouvoir re-packager notre code, avec l'action “package”.
Cette action lancera la commande “mvn clean package” sur l'espace de travail du job.
Il existe deux méthodes pour faire appel à une analyse SonarQube depuis un job Jenkins :
Dans ce TP, nous utiliserons le Sonar Runner pour lancer notre analyse Sonar
sonar.projectKey=form:git:XXX sonar.projectName=Projet Form-git-XXX sonar.projectVersion=1.0 sonar.sources=src sonar.language=java sonar.java.binaries=target/
Jenkins lancera les outils dont il connait l'existence, et transmettra les résultats, des fichiers xml, au serveur SonarQube. Celui-ci en fera une synthèse et stockera les données, afin de présenter les différents problèmes relevés à l'utilisateur.
SonarQube est un serveur applicatif fournissant une analyse complète de la qualité du code d'un projet, en se basant sur des outils existant (PMD, Checkstyle, Findbugs, etc.). SonarQube permet de visualiser les différents problèmes soulevés comme :
SonarQube regroupe toutes ses informations et en présente une vue d'ensemble, à un instant donné ou bien sur la durée grâce à l'historique des analyses précédentes. Cela permet d'avoir une idée de l'évolution de la qualité du projet, une chute brusque de la qualité du projet pourrait par exemple être due à l'arrivée d'une nouvelle personne sur le projet.
Maintenant que notre projet pourra être analyse au fur et à mesure des développements, revenons à notre dépôt Git, nous allons le cloner en local pour récupérer ses sources.
Le clonage d'un dépôt Git existant consiste à le recopier entièrement en local. Contrairement à SVN où l'utilisateur ne récupère qu'une version spécifique du code source en effectuant un “checkout”, avec Git, le développeur reçois tout le contenu du dépôt. Tous les fichiers sources, leur historique, les branches et tags. Tout cela sera stocké dans le dossier “.git” situé à la racine de la copie de travail créée lors du clonage.
# cd /opt
# git clone git+ssh://git@git.renater.fr:2222/form-git-XXX.git
# cd form-git-XXX # ll .git drwxr-xr-x 2 root root 4096 Mar 4 14:40 branches -rw-r--r-- 1 root root 271 Mar 4 14:40 config -rw-r--r-- 1 root root 73 Mar 4 14:40 description -rw-r--r-- 1 root root 23 Mar 4 14:40 HEAD drwxr-xr-x 2 root root 4096 Mar 4 14:40 hooks drwxr-xr-x 2 root root 4096 Mar 4 14:40 info drwxr-xr-x 4 root root 4096 Mar 4 14:40 objects drwxr-xr-x 4 root root 4096 Mar 4 14:40 refs
Notre copie de travail est fonctionnelle, nous allons pouvoir développer dessus.
# cd /opt/form-git-XXX/ # wget https://services.renater.fr/_media/sourcesup/formation/demo.tar.gz # tar -xvzf demo.tar.gz # cd demo # mv src pom.xml .settings .project .. # cd .. # rm -rf demo
<artifactId>jtetris-XXX</artifactId>
Notre démo est présente dans notre copie de travail git. Nous allons pouvoir l'utiliser pour travailler dessus. Toutefois la seule présence des fichiers sur notre copie de travail n'est pas suffisant pour que git les prennes en compte.
Ces dossiers et fichiers font partie de notre copie de travail, il faut indiquer au client Git qu'il devra les ajouter au dépôt Git local lors du prochain commit. Pour cela nous allons utiliser la commande “git add”.
Sur une copie de travail, chaque fichier peut avoir deux états :
La commande “git add” est multi-usage, elle permet en effet :
Cette commande ajoute les fichiers et dossiers en argument à la zone d'index du dépôt local. Tous les fichiers présents dans cette zone seront ensuite ajoutés dans le prochain instantané :
# git add src pom.xml
Si on ajoute un répertoire à la zone d'index, par défaut tous les fichiers situés dedans sont ajouté automatiquement également. Dans notre cas, tous les fichiers contenus dans le dossier 'src' ont été ajoutés à la zone d'index.
# git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: pom.xml new file: src/main/java/fr/cd/jtetris/Constantes.java new file: src/main/java/fr/cd/jtetris/bean/Bloc.java new file: src/main/java/fr/cd/jtetris/bean/Grille.java new file: src/main/java/fr/cd/jtetris/bean/GrilleListener.java ..... Untracked files: (use "git add <file>..." to include in what will be committed) .project .settings/
# git status -s A pom.xml A src/main/java/fr/cd/jtetris/Constantes.java A src/main/java/fr/cd/jtetris/bean/Bloc.java A src/main/java/fr/cd/jtetris/bean/Grille.java ..... ?? .project ?? .settings/
'' = unmodified ? = untracked M = modified A = added D = deleted R = renamed C = copied U = updated but unmerged
Si vous décidez qu'un fichier ne doit finalement pas faire partie du prochain instantané, il faut le faire sortir de la zone d'index. La commande git rm va répondre à notre besoin, en lui passant l'argument –cached.
Testons sur un fichier que nous venons d'ajouter :
# git rm --cached src/main/java/fr/cd/jtetris/Constantes.java rm src/main/java/fr/cd/jtetris/Constantes.java
Le status du fichier a changé, il n'est plus marqué comme “ajouté à la zone d'index”. Vérifions avec la commande “git status” :
# git status A pom.xml A src/main/java/fr/cd/jtetris/bean/Bloc.java A src/main/java/fr/cd/jtetris/bean/Grille.java .......... ?? .project ?? .settings/ ?? src/main/java/fr/cd/jtetris/Constantes.java
# git add src/main/java/fr/cd/jtetris/Constantes.java
Notre zone d'index contenant les nouveaux répertoires créés, nous allons les valider afin de les inclure dans le dépôt Git.
# git commit -m "ajout de l'arborescence du projet" [master (root-commit) 438e882] ajout de l'arborescence du projet 24 files changed, 1421 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/fr/cd/jtetris/bean/Bloc.java create mode 100644 src/main/java/fr/cd/jtetris/bean/Grille.java create mode 100644 src/main/java/fr/cd/jtetris/bean/GrilleListener.java create mode 100644 src/main/java/fr/cd/jtetris/factory/BlocFactory.java .....
Un instantané a été créé, la zone d'index a été vidée, une nouvelle révision a été construite avec ce qu'elle contenait.
# git commit -a -m "instantané direct"
Il est possible que certains types de fichiers ne doivent pas être ajoutés dans le dépôt Git, comme par exemple des fichiers de configuration d'un IDE. Plutôt que de risquer d'ajouter ces fichiers à la zone d'index et ensuite au dépôt, il est possible d'indiquer dans un fichier tous les patrons de noms des fichiers à ignorer. Ce fichier se nomme .gitignore :
# touch .gitignore # emacs .gitignore
.settings .project
# git status -s
?? .gitignore
Afin de visualiser les modifications effectuées sur votre copie de travail, vous pouvez utiliser la commande “git diff”. Celle-ci a un fonctionnement un peu particulier. En effet, utiliser sans argument, elle va renvoyée les modifications qui n'ont pas encore été indexées et laisser de côté les autres.
# emacs src/main/java/fr/cd/jtetris/util/BlocUtil.java
package fr.cd.jtetris.util; /** * Utilitaire de gestion des blocs * * @author CD * @version 1.0.0 * @since 1.0.0 */ public final class BlocUtil { /** * Constructeur privé pour classe utilitaire * @since 1.0.0 */ private BlocUtil() { } /** * Renvoie la colonne * * ex : * Pour le bloc * part1 = 0 0 1 0 * part2 = 0 0 1 0 * part3 = 0 1 1 0 * part4 = 0 0 0 0 * * La colonne 2 a pour valeur binaire : 1 1 1 0 * La colonne 3 a pour valeur binaire : 0 0 1 0 * * @param parts Un bloc * @param index Index de la colonne recherch<C3><A9>e * @return Valeur de la colonne * @since 1.0.0 */ public static int getColonne(int[] parts, int index, int largeur) { final int hauteur = parts.length; int val = 0; for (int i=0; i<hauteur; i++) { int part = parts[i]; val += (part & 1 << (largeur - index - 1)) == 0 ? 0 : 1 << (hauteur - 1 - i); } return val; } public static String mafonction() { return "Hello"; } }
# git diff diff --git a/src/main/java/fr/cd/jtetris/util/BlocUtil.java b/src/main/java/fr/cd/jtetris/util/BlocUtil.java index fa340bc..3b829ce 100644 --- a/src/main/java/fr/cd/jtetris/util/BlocUtil.java +++ b/src/main/java/fr/cd/jtetris/util/BlocUtil.java @@ -47,4 +47,8 @@ public final class BlocUtil { return val; } + public static String mafonction() {^M + return "Hello";^M + }^M +^M }
Pour voir le différentiel entre le dernier instantané et les modifications qui font parties de la zone d'index, il faut utiliser la commande “git diff” avec l'argument “–staged”.
# touch src/main/java/fr/cd/jtetris/util/AutreUtil.java # emacs src/main/java/fr/cd/jtetris/util/AutreUtil.java
package fr.cd.jtetris.util; /** * Utilitaire de gestion des blocs * * @author CD * @version 1.0.0 * @since 1.0.0 */ public final class AutreUtil { /** * Constructeur privé pour classe utilitaire */ private AutreUtil() { } /** * Renvoie la colonne * * * @param parts Un bloc * @param index Index de la colonne recherchée * @return Valeur de la colonne * @since 1.0.0 */ public static int getAutreColonne(int[] parts, int index, int largeur) { final int hauteur = parts.length; int val = 0; for (int i=0; i<hauteur; i++) { int part = parts[i]; val += (part & 1 << (largeur - index - 1)) == 0 ? 0 : 1 << (hauteur - 1 - i); } return val; } }
# git add src/main/java/fr/cd/jtetris/util/AutreUtil.java # git diff --staged
Après avoir créé un commit, si vous vous rendez compte qu'un fichier n'a pas été ajouté à la zone de suivi de version, il est possible de corriger cet oublie. Plutôt que de créer un nouveau commit, dont la seule raison d'existence serait de corriger/compléter le commit précédent, il est préférable de modifier le dernier commit afin de garder des commits cohérent.
Nous avons auparavant créer un commit, et depuis nous avons créer un fichier, qui a été ajouté à la zone d'index comme nous l'indique “git status -s”
# git status -s A src/main/java/fr/cd/jtetris/util/AutreUtil.java M src/main/java/fr/cd/jtetris/util/BlocUtil.java
Corriger le commit précédent :
git commit --amend
Il est possible de préciser l'option '-m' à la commande afin de modifier le commentaire précédemment enregistré.
git commit --amend -m "commentaire"
Pour supprimer un fichier qui est en suivi de version, il faut utiliser la commande “git rm”. Celle-ci va supprimer le fichier de la copie locale, et ajouter à la zone d'index la suppression du fichier dans le dépôt.
# git rm src/main/java/fr/cd/jtetris/util/AutreUtil.java rm 'src/main/java/fr/cd/jtetris/util/AutreUtil.java'
La commande “git st” nous montre que cette suppression sera présente dans le prochain commit :
# git st -s D src/main/java/fr/cd/jtetris/util/AutreUtil.java M src/main/java/fr/cd/jtetris/util/BlocUtil.java
Un autre besoin pourrait être de supprimé un fichier du suivi de version, mais de le garder dans la copie locale. L'option '–cached' est utilisée dans ce cas avec la commande 'git rm' :
Nous pouvons maintenant pousser nos commits effectués sur le dépôt distant hébergé sur la forge. En effet jusqu'ici, toutes les modifications que nous avons fait sont restées en local. La commande push va nous permettre de les transférer au dépôt
git push origin master git push X11 forwarding request failed on channel 0 Counting objects: 46, done. Delta compression using up to 4 threads. Compressing objects: 100% (37/37), done. Writing objects: 100% (46/46), 20.13 KiB | 0 bytes/s, done. Total 46 (delta 7), reused 0 (delta 0) To git+ssh://git@git.renater.fr:2222/form-git-XXX/form-git-XXX-2.git * [new branch] master -> master
Le dépôt git sur le serveur Git a été mis à jour avec les dernières modifications, les autres utilisateurs du projet pourront récupérer ces changements.
Maintenant que nous avons pousser du code sur le dépôt distant, nous pouvons lancer l'exécution de notre Job. Rendez vous sur l'interface de Jenkins, cliquer sur le nom de votre job et lancer son exécution.
Durant l'exécution, un build du projet puis une analyse du code sont réalisés. Une fois le job fini, vous pouvez vous rendre sur l'interface Sonar depuis l'interface de SourceSup, ou en cliquant ici
Nous n'avons maintenant plus de travail en cour, nous allons pouvoir créer notre branche, et ensuite switcher sur cette nouvelle branche.
Toutefois, notre copie de travail comporte encore des modifications dans la zone d'index que nous n'avons pas commiter. Partons du principe que ces modifications ne doivent pas être commitées tout de suite, mais nous ne souhaitons pas les perdre.
Git possède une fonctionnalité répondant à ce besoin, la notion de remisage. Git va mettre de côté les modifications inclues dans la zone d'index, et vous pourrez les récupérer plus tard.
git st -s D src/main/java/fr/cd/jtetris/util/AutreUtil.java M src/main/java/fr/cd/jtetris/util/BlocUtil.java
# git stash Saved working directory and index state WIP on master: 0b98764 ajout de l'arborescence du projet HEAD is now at 0b98764 ajout de l'arborescence du projet
git st -s
Nous n'avons maintenant plus de travail en cour, nous allons pouvoir créer notre branche, et ensuite switcher sur cette nouvelle branche.
# git branch testunit # git co testunit Switched to branch 'testunit'
La création d'une branche ne fait que créer un nouveau pointeur dans le dépôt git, pour changer la copie de travail avec le code de la branche, il faut récupérer la version désigner par ce pointeur.
En Java, mais aussi dans d'autres langages comme C, PHP, etc., il existe des framework permettant d'écrire facilement des tests unitaires puis de les exécuter. Dans notre exemple, nous utiliserons la bibliothèque JUnit pour développer nos tests unitaires.
Pour cela nous aurons besoin d'ajouter la dépendance JUnit à notre fichier pom.xml afin d'indiquer à Maven qu'il devra télécharger cette archive.
... <name>JTetris</name> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> ...
# cd /opt/form-git-XXX/ # mkdir src/test
package fr.cd.jtetris.bean; import static org.junit.Assert.*; import org.junit.Assert; import org.junit.Test; public class BlocTest { @Test public void testRotationDirecte() { boolean v = true; Assert.assertEquals(true, v); } } /code> * src/test/java/fr/cd/jtetris/util/LigneUtilTest.java <code LigneUtilTest.java> package fr.cd.jtetris.util; import static org.junit.Assert.*; import org.junit.Test; public class LigneUtilTest { /** * ligne compl<C3><A8>te : 1 1 1 1 1 1 1 1 1 1 1 1 1 --> 8191 */ @Test public void testIsComplete() { int ligne = 0; boolean complete = LigneUtil.isComplete(ligne); assertEquals(false, complete); ligne = 8191; complete = LigneUtil.isComplete(ligne); assertEquals(true, complete); } } /code> * src/test/java/fr/cd/jtetris/util/BlocUtilTest.java <code BlocUtilTest.java> package fr.cd.jtetris.util; import static org.junit.Assert.*; import org.junit.Test; public class BlocUtilTest { /** * Pour le bloc * * X . * X . * X X * * La colonne 1 a pour valeur binaire : 1 1 1 * La colonne 0 a pour valeur binaire : 0 0 1 */ @Test public void testGetColonne() { int[] parts = {1,1,3}; int result = BlocUtil.getColonne(parts, 1, 2); assertEquals(7, result); result = BlocUtil.getColonne(parts, 0, 2); assertEquals(1, result); } } /code> incluons le à notre branche <code> # git add src/test # git commit -m "ajout des test"
# git co master # git branch --no-merged
package fr.cd.jtetris.util; import fr.cd.jtetris.Constantes; /** * Utilitaire de traitement des lignes * @author CD * @version 1.0.0 * @since 1.0.0 */ public final class LigneUtil { /** * Constructeur privé pour classe utilitaire */ private LigneUtil() { } /** * Indique si une ligne est complète * @param ligne La ligne à tester * @return true si la ligne est complète, false sinon */ public static boolean isComplete(int ligne) { return ligne == ((1 << Constantes.NB_COLONNES) - 1); } public static boolean isAutreFonction() { return true;; } }
# git add src/main/java/fr/cd/jtetris/util/LigneUtil.java # git commit -m "ajout fonction"
# git merge gui -m "fusion de branche"
# git stash apply Removing src/main/java/fr/cd/jtetris/util/AutreUtil.java On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: src/main/java/fr/cd/jtetris/util/AutreUtil.java modified: src/main/java/fr/cd/jtetris/util/BlocUtil.java
Le tableau de bord de l'analyse vous fournit plusieurs informations sur la qualité du code source, notamment les problèmes relevés
Des problèmes existent donc sur notre projet. Cliquer sur le lien des problèmes Majeur, vous pourrez voir la liste des défaillances relevées par l'analyse, avec une explication du problème, une suggestion pour la résoudre, et dans quel fichier elles ont été relevées.
Plusieurs anomalie facile à corriger se trouve dans le fichier : “src/main/java/fr/cd/jtetris/bean/Grille.java”, il s'agit d'accolades qui n'ont pas été écrites. Ce qui n'est pas faux en Java mais pas forcément recommandé par les outils d'analyses de code.
Vous pouvez afficher le fichier entier sur Sonar, afin de voir précisément sur quelles lignes les problèmes apparaissent. Nous allons corriger quelques anomalies.
Sur votre copie de travail git, éditer maintenant le fichier pom.xml
# emacs pom.xml
<distributionManagement> <repository> <id>sourcesup</id> <url>http://sourcesup.renater.fr/nexus/content/repositories/form-git-XXX-releases</url> </repository> <snapshotRepository> <id>sourcesup</id> <url>http://sourcesup.renater.fr/nexus/content/repositories/form-git-XXX-snapshots</url> </snapshotRepository> </distributionManagement>
Cette configuration indique à Maven l'URL des dépôts Nexus sur lesquels déployer les artefacts générés par un build du projet.
# git add pom.xml # git commit -m "ajout déploiement sur nexus"
# git push origin master
Nuxéo est un serveur de gestion électronique de document.