TAGL/TP: Difference between revisions

From air
Jump to navigation Jump to search
 
(64 intermediate revisions by 4 users not shown)
Line 1: Line 1:
Travaux pratiques de l'UE [[TAGL]].
Travaux pratiques de l'UE [[TAGL]].


Version courante : 2016
==Séance 1==

===Git===
Anciennes versions : [[TAGL/TP 2014]] [[TAGL/TP 2015]]

=Séance 1 : Gestion de versions=
==Git==


Création d'un dépôt Git local
Création d'un dépôt Git local


====Méthode simple: init first====
===Méthode simple: init first===


Via cette méthode, on crée un dépôt local, avec un répertoire de travail, puis on pousse ses modifications vers un dépôt "bare".
Via cette méthode, on crée un dépôt local, avec un répertoire de travail, puis on pousse ses modifications vers un dépôt "bare".
Line 53: Line 57:
Lors des prochaines commandes ''git push'', grâce à cette liaison, tous les commits sur la branche locale //master// seront poussées sur le serveur distant.
Lors des prochaines commandes ''git push'', grâce à cette liaison, tous les commits sur la branche locale //master// seront poussées sur le serveur distant.


====Méthode moins simple: bare first====
===Méthode moins simple: bare first===


Si on commence dans par le serveur "vide", il faudra le cloner au lieu de le définir comme un dépôt distant.
Si on commence dans par le serveur "vide", il faudra le cloner au lieu de le définir comme un dépôt distant.
Line 103: Line 107:
Un plug-in existe pour éditer des fichier reStructuredText dans Eclipse: ReST Editor, disponible sur le [https://marketplace.eclipse.org/content/rest-editor Marketplace Eclipse]
Un plug-in existe pour éditer des fichier reStructuredText dans Eclipse: ReST Editor, disponible sur le [https://marketplace.eclipse.org/content/rest-editor Marketplace Eclipse]


=Séance 2a: Intégration en continue=
===GitHub & Travis-CI===

===GitHub & [[Travis-CI]]===


Travis-CI est un service permettant d'exécuter un script dans une machine virtuelle Ubuntu dès que vous effectuez un push sur un de vos dépôts GitHub.
Travis-CI est un service permettant d'exécuter un script dans une machine virtuelle Ubuntu dès que vous effectuez un push sur un de vos dépôts GitHub.
L'intérêt est de savoir si la version d'un projet que vous avez rendu publique peut être compilée et si ses tests passent.
L'intérêt est de savoir si la version d'un projet que vous avez rendu publique peut être compilée et si ses tests passent.


La machine virtuelle "offerte" par Travis est préconfigurée pour le language indiqué dans son fichier de configuration ('''.travis.yml'''), mais il est possible d'utiliser la commande '''sudo apt-get install ...''' pour ajouter vos dépendances.
Pour utiliser Travis:



Pour utiliser [[Travis-CI]]:

# Créez compte individuel sur GitHub https://github.com
# ''Fork''ez le dépôt https://github.com/heroku/node-js-getting-started
# Ajoutez un collaborateur (i.e. votre binôme) au projet ''forké'', via les paramètres (''settings'') de ce projet
# Pour l'exemple, activez le service (ou hook) ''Email'' depuis les paramètres du dépôt: à chaque fois que vous ou un de vos collaborateurs ferra un '''git push''', vous recevrez une notification par mail.
# Activez le service Travis-CI: identifiez-vous (''sign in'') sur https://travis-ci.org/ avec votre compte GitHub
# Activez le service pour les projets sur lesquels vous souhaitez appliquer les principes d'intégration continue


[[Travis-CI]] utilise un fichier nommé '''.travis.yml''' (attention: fichier caché sous Unix) pour se configurer et choisir les opérations à effectuer.
#. Créez compte individuel sur GitHub https://github.com
Ce fichier doit se trouver à la racine de votre dépôt Git.
#. ''Fork''ez le projet TAGL '''cron4j''' depuis https://github.com/donsez/tagl
#. Ajoutez un collaborateur (i.e. votre binôme) au projet ''forké'', via les paramètres (//settings//) de ce projet
#. Pour l'exemple, activez le service (ou hook) //Email// depuis les paramètres du dépôt: à chaque fois que vous ou un de vos collaborateurs ferra un ''git push'', vous recevrez une notification par mail.
#. Activez le service Travis-CI: identifiez-vous (//sign in//) sur https://travis-ci.org/ avec votre compte GitHub


''Commit/Push'' '''.travis.yml''' pour Ant:
Faites un '''Commit''' puis un '''Push''' du fichier '''.travis.yml''' ci-dessous.


<pre>
<pre>
language: java
language: node_js
node_js:
- "0.11"
- "0.10"
- "0.8"
- "0.6"
- iojs
- iojs-v1.0.2


</pre>
jdk:
- oraclejdk7
- openjdk6
- openjdk7



script:
Ce fichier '''.travis.yml''' indique à [[Travis-CI]] que les scripts de ce projet dans ce dépôt seront exécutés avec plusieurs versions de [[Node.js]].
- pushd cron4j-original && ant rel && popd

Ajoutez dans le fichier '''package.json''' la section suivante:
<pre>
"devDependencies": {
"jshint": "^2.6.0"
},
"scripts": {
"test": "./node_modules/jshint/bin/jshint index.js"
}
</pre>
</pre>
et incrémentez le numéro de version.


Faites un '''Commit''' puis un '''Push''' des fichiers touchés.
===Maven===
[http://maven.apache.org/download.cgi Changer et installer Maven 3].



'''Remarque:'''
'''jshint''' peut être lancé localement avec les commandes suivantes:
<pre>
<pre>
sudo npm install jshint
mvn -version
jshint index.js
</pre>
</pre>


A lire
Créer '''cron4j-mvn''' (layout + pom.xml) en réorganisant les sources de cron4j-original. Pour cela, vous utiliserez préalablement un [https://maven.apache.org/guides/introduction/introduction-to-archetypes.html archetype Maven] ''simple'' ou ''quickstart''. (la version de cron4j est la 2.5.5).
* http://docs.travis-ci.com/user/languages/javascript-with-nodejs/
* https://github.com/docdis/learn-travis/blob/master/README.md


=Séance 2b: Livraison en continue=
Modifier .travis.yml pour ''mvn -DskipTests=true clean install'' (Commit/Push)


==[[Heroku]]==
[https://www.heroku.com/ Heroku] est une plateforme cloud de type PaaS permettant l'exécution d'applications et de services en ligne écrits dans les langages et plateformes suivantes : Ruby, [[Node.js]], [[Python]], Java, et PHP.


# Créez un compte gratuit sur [https://signup.heroku.com Heroku]
===Tests Unitaires avec JUnit 4===
# Forkez le dépôt https://github.com/heroku/node-js-getting-started
Survoller le tutoriel [http://www.vogella.com/tutorials/JUnit/article.html Unit Testing with JUnit]
# Dans Heroku, créez une nouvelle app Node.js, et liez-la au repository Github créé à l'étape précédente
# Choisissez l'option "Déploiement automatique" depuis la branche **master**
# Modifiez le fichier index.js pour afficher la version de service dans la page HTML
<pre>
var fs = require('fs');
var package = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
var version=package.version;
...
response.send('Hello World! (current version: '+version+')');
...
</pre>


Incrémentez le numéro de version dans le fichier ''package.json''
Ajouter le test unitaire suivant au layout du projet

Faites un '''Commit''' puis un '''Push''' des fichiers touchés.

Naviguez l'application sur Heroku

# Modifiez le fichier index.js pour franciser le message dans la page HTML
<pre>
...
response.send('Bonjour Tout Le Monde! (version courante: '+version+')');
...
</pre>

Incrémentez le numéro de version dans le fichier '''package.json''

Faites un '''Commit''' puis un '''Push''' des fichiers touchés.

Naviguez l'application sur Heroku

=Séance 3: Builders=
Les builders permettent d'automatiser l'exécution en chaine des outils pour la production et la livraison en production des produits logiciels.

==[[Make]]==

==[[Ant]]==

Faire les exercices 0, 1, 3 de ./tpant.htm dans http://lig-membres.imag.fr/donsez/cours/tpant.zip

==[[Maven]]==

[http://maven.apache.org/download.cgi Charger et installer Maven 3].

Debian/Ubuntu & friends:
<pre>
sudo apt-get update && sudo apt-get install maven
</pre>

<pre>
mvn -version
</pre>

Faites une copie du projet, basée sur Maven:

# Dans votre dépôt Git, créez un dossier '''cron4j-mvn''': il contiendra le projet Cron4J avec la structure Maven
# Dans ce dossier, utilisez l'[https://maven.apache.org/guides/introduction/introduction-to-archetypes.html archetype] Maven [http://maven.apache.org/archetype/maven-archetype-bundles/maven-archetype-quickstart/ maven-archetype-quickstart] (la version des sources de cron4j utilisés est la 2.5.5) (groupId: it.sauronsoftware.cron4j, artifactId: cron4j):
#:<pre>mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart</pre>
# Cette commande crée un projet avec un fichier ''pom.xml'', et une classe et un test modèles: supprimez ces modèles
# Copiez les sources de Cron4J depuis le dossier '''cron4j-original''' ([https://github.com/donsez/tagl https://github.com/donsez/tagl]) dans le dossier '''src/main/java''' de votre projet Maven
# Faites un essai de compilation:
#:<pre>mvn clean verify</pre>
# Lancez un des exemples avec mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"] ... ([http://mojo.codehaus.org/exec-maven-plugin/usage.html doc. exec plugin], [http://mojo.codehaus.org/exec-maven-plugin/java-mojo.html doc. Exec:java goal])
# Enfin modifiez le fichier '''.travis.yml''' à la racine de votre dépôt Git afin que Travis exécute la commande '''mvn clean verify''' à chaque mise à jour du dépôt GitHub.

==Tests Unitaires avec JUnit 4==
Survoller le tutoriel [http://www.vogella.com/tutorials/JUnit/article.html Unit Testing with JUnit]


# Veillez à bien utiliser la dépendance JUnit 4.8.2 dans pom.xml
# Ajouter le test unitaire suivant au projet, dans le fichier '''src/test/it/sauronsoftware/SchedulingPatternTest.java
<pre>
<pre>
package it.sauronsoftware;
package it.sauronsoftware;
Line 187: Line 289:
</pre>
</pre>


# Committez et Pushez ce nouveau fichier, pour que Travis lance les tests dès que possible
# Lancez les tests unitaires avec <pre>mvn test</pre> Ce test va '''échouer''': corrigez le.
# Committez et Pushez la version corrigée des tests: Travis enverra un mail pour indiquer si les tests échouent ou non
#: '''Attention:''' Travis va exécuter les tests ''dès que possible''. Il est possible de recevoir un mail indiquant que les tests du premier ''push'' échouent alors que l'on a déjà ''pushé'' la correction.
# Naviguez sur http://travis-ci.org pour vérifier les builds effectués.
# Créez des tests unitaires supplémentaire du i.s.c.CronParser


===[[Maven]] avec [[Travis-CI]]===
Rechercher la dépendance JUnit 4 dans [http://search.maven.org/#search|ga|1|JUnit Maven Central]


===Git (suite)===
Ajouter la dépendance JUnit 4 au pom.xml


# Forkez le projet '''tagl''' d'un autre binome (i.e. autre que ''donsez/tagl'')
#: '''Attention:''' donnez lui un nom différent (e.g. ''tagl-licensing'')
# Clonez ce nouveau dépôt
# Lancez une compilation pour valider l'état du projet (bonne pratique)
#:<pre>mvn clean verify</pre>
# Situez vous dans une nouvelle branch git:
#:<pre>git checkout -b add-license</pre>
# Ajoutez une bannière de licence dans le fichier '''cron4j-mvn/pom.xml'''
# Lancez une nouvelle compilation pour valider vos modifications
# Commitez et pushez (vers votre fork de ce dépôt, i.e. ''tagl-licensing'') (pour pusher une branche nouvellement créée: git push origin add-license)
# Via le site de GitHub, proposez un "Pull Request" au projet initial


Vous pouvez ensuite supprimer le clone de ce fork.

Lorsque le ''pull request'' aura été accepté, vous pourrez supprimer votre fork (''tagl-licensing'') de votre compte GitHub.
Lancer le build mvn test

Modifier '''.travis.yml''' pour ''mvn clean test'' (Commit/Push)

Regarder votre mail box.

Naviguer sur http://travis-ci.org pour vérifier les builds effectués.

Créer des tests unitaires du i.s.c.CronParser

===Git (suite)===
# Forker le projet '''cron4j-mvn''' d'un autre binome (ie l'origine)
# Ajouter une bannière de licence dans le pom.xml
# Lancer mvn clean install (bonne pratique)
# Commiter
# Faire un Push request vers l'origine


===Contrôle Continu===
===Contrôle Continu===
Ajoutez au pom.xml le plugin Covertura pour la couverture de code.


Dans votre dépôt ''tagl''.
Répondez aux questions : ''Mais qu'est ce que la couverture de code ? En quoi c'est utile ?''


# Ajoutez le plugin [http://mojo.codehaus.org/cobertura-maven-plugin/usage.html Cobertura] à votre projet Maven.
Ajoutez au pom.xml les plugins pour la gestion du site et des rapports (Javadoc, tests unitaires, tags list (FIXME, TODO, ...), ...): http://maven.apache.org/plugins/maven-site-plugin/ et d'autres.
## Configurez le plugin pour [http://mojo.codehaus.org/cobertura-maven-plugin/examples/report-formats.html générer un rapport] HTML. Le résultat se trouvera dans ''target/site/cobertura''

## Le plugin ne s'exécute automatiquement pas durant la compilation, il faut utiliser la commande : <pre>mvn cobertura:cobertura</pre>
Pour la prochaine séance, regardez les exemples d'utilisation de cron4j dans cron4j-original/examples
## '''Bonus:''' Modifiez le fichier ''pom.xml'' pour que le ''goal'' '''cobertura''' soit exécuté pendant la ''phase'' '''package'''.
# Répondez aux questions : ''Mais qu'est ce que la couverture de code ? En quoi c'est utile ?''
# Ajoutez au projet Maven les plugins pour la génération d'un site et de rapports (Javadoc, tests unitaires, tags list (FIXME, TODO, ...), ...): voir http://maven.apache.org/plugins/maven-site-plugin/ et d'autres.
# Regardez les exemples d'utilisation de cron4j dans cron4j-original/examples
# À rendre : pom.xml


===Bonus Track===
===Bonus Track===
Line 308: Line 416:
L'activation se fait via ''Settings > Webhooks & Services > Configure services''.
L'activation se fait via ''Settings > Webhooks & Services > Configure services''.


==Séance 2==
=Séance 4 : Gestion d'un dépôt d'artefacts=
'''(introduite en 2015-2016)'''
AOP & AspectJ


Le dépôt https://www.npmjs.com/ est le dépôt principal des artefacts pour Javascript et [[Node.js]]. [https://docs.npmjs.com/getting-started/what-is-npm Pour en savoir plus ...]
Ajouter le [http://mojo.codehaus.org/aspectj-maven-plugin/ plugin Maven pour AspectJ] au pom.xml


Côté client, il s'utilise avec les commandes npm, [https://www.npmjs.com/package/bower bower], ...
Ajouter un aspect de trace à l'invocation des méthodes run() de l'interface java.lang.Runnable (uniquement pour les objets ''schedulé''s).


Ce TP a pour objectif de faire évoluer l'artefact suivant XXXX et l'ajouter au dépôt npmjs (manuellement et via Travis-CI).
===Contrôle continu===
Compléter l'aspect de trace avec le positionnement du [http://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html java.lang.ThreadLocal] pour passer 1) l'identifiant du job et 2) le compteur des appels de la méthode de l'objet.


Il vous faut pour cela comprendre le format du manifeste [https://docs.npmjs.com/files/package.json package.json]
==Séance 3==
@WIP


=Séance 5: Pelix & iPOPO=
Injection de dépendances avec [[Guice]]


Pelix est une plate-forme d'application à services (SOA).
iPOPO est un modèle de composants orientés services (SOCM).


La documentation de Pelix et iPOPO est disponible sur https://ipopo.coderxpress.net/
==Séance 4==
[[Tutorial OSGi avec Apache Felix]]


===Installation de iPOPO===


* Pour installer iPOPO, lancer la commande :


pip install --user iPOPO
==Séance 5==

* ou par les sources:
** Cloner le dépôt Git depuis https://github.com/tcalmant/ipopo
** Se placer dans la branche ''dev''
** Lancer la commande:

sudo python setup.py install

===Shell Pelix===

Pour lancer un shell Pelix, utilisez la commande:

python -m pelix.shell.console

Les commandes disponibles sont décrites ici: [https://ipopo.coderxpress.net/wiki/doku.php?id=ipopo:refcards:shell Shell Commands]

===Rappels de Python===

* Pas de déclaration du type d'une variable
* Les méthodes d'une classe ont toute comme premier paramètre ''self'', équivalent du ''this'' en Java.
* Blocs définis par indentation (4 espaces ou 1 tab)
* Une ligne finissant par ':' démarre toujours un bloc

<syntaxhighlight lang="python">
#!/usr/bin/python
# -- Content-Encoding: UTF-8 --
# Import d'un module
import pelix

# Définition d'une classe
class MaClasse:
# Constructeur
def __init__(self):
self.default = "stanger"
print("Classe construite")

# Méthode, avec un argument
def sayHello(self, name):
if not name:
# Nom vide ou nul
return "Hello, " + str(self.default)
else:
# Nom valide
return "Hello, " + str(name)

objet = MaClasse()
print(objet.sayHello(""))
print(objet.sayHello("World"))
</syntaxhighlight>

===Service Ping-Pong===

1. Écrire un fichier ''pong.py'', définissant une classe ''Pong'' ayant une méthode ''pong'' prenant en paramètre un message et retournant le message préfixé par "PONG:".

Exemple:
pong = Pong()
pong.pong("Hello") # <-- Retourne "PONG:Hello"

2. Écrire un fichier ''ping.py'', définissant une classe ''Ping'' ayant une méthode ''ping'' prenant en paramètre un message, créant un objet Pong et retournant le résultat de Pong.pong(message) préfixé par "PING:"

Exemple:

ping = Ping()
ping.ping("Hello") # <-- Retourne "PING:PONG:Hello"

3. Transformer le fichier ''pong.py'' pour qu'il devienne un bundle Pelix enregistrant un objet Pong comme étant un service ayant pour spécification "tagl.pong"
* Définir une classe ''Activator'', décorée avec ''@BundleActivator''
* Enregistrer le service dans la méthode ''Activator.start'' et le désenregistrer dans ''Activator.stop''
* S'inspirer du fichier "ipopo/samples/remote/provider.py"

Dans un shell Pelix, installer et démarrer le bundle 'pong' et vérifier que le service est bien inscrit avec la commande ''sl''

4.Transformer la classe ''Ping'' dans ''ping.py'' en un composant iPOPO
* L'objet Pong utilisé dans ''ping()'' doit être un service injecté par iPOPO (''@Requires'')
* Appeler la méthode ''ping()'' dès que le service Pong est injecté (''@BindField'') ou disparait (''@UnbindField'')
* S'inspirer du fichier "ipopo/samples/remote/consumer.py"

Dans un shell Pelix, installer et démarrer le bundle 'ping' et vérifier son comportement si le bundle ''pong'' ou le bundle ''ping'' est arrêté et redémarré.

5. Mettre à jour le bundle ''pong''
* Remplacer le préfixe "PONG" par "NI"
* Dans le shell Pelix, mettre à jour le bundle ''pong'' sans redémarrer la plate-forme (commande ''udpate'').
* Vérifier les traces dans le shell pour valider la mise à jour du service.

===Remote Services===

* Ajouter les propriétés permettant l'export du service Pong dans ''pong.py'' (s'inspirer de ''provider.py'')

* Lancer deux shells iPOPO (dans deux terminaux)
* Dans chaque shell iPOPO, installer les bundles:
** ''pelix.remote.dispatcher'': Exportateur de services
** ''pelix.remote.registry''; Importateur de services
** ''pelix.remote.discovery.multicast'': Découverte de services via Multicast
** ''pelix.remote.xml_rpc'': Transport XML-RPC
** ''pelix.http.basic'': Serveur HTTP

Attention: il peut être nécessaire de désactiver votre pare-feu pour que les Remote Services fonctionnent

* Instancier les composants depuis le shell iPOPO, dans chaque framework:
** Serveur HTTP sur le port 8080: ''instantiate pelix.http.service.basic.factory http-server pelix.http.port=8080'' (penser à changer de port dans chaque framework)
** Multicast Discovery: ''instantiate pelix-remote-discovery-multicast-factory multicast-discovery''
** XML-RPC Exporter: ''instantiate pelix-xmlrpc-exporter-factory xml-rpc-exporter''
** XML-RPC Importer: ''instantiate pelix-xmlrpc-exporter-factory xml-rpc-importer''

* Installer le bundle ''ping'' dans un des frameworks et le bundle ''pong'' dans l'autre.
* Le composant ping peut appeler le service pong, qui est dans l'autre framework.


* Voir le code de ''run_remote.py'' pour voir comment démarrer un framework Pelix et installer des bundles depuis Python.
* Jouer un peu avec ''run_remote.py'' (voir ''run_remote.py --help'')

=Séance 6=
[[Tutorial OSGi avec Apache Felix]]

=Séance 7=
Faire un projet PDE pour un bundle cron4j.gogo (indépendant de cron4j.bundle)
Faire un projet PDE pour un bundle cron4j.gogo (indépendant de cron4j.bundle)


Utilisation de https://eclipse.org/tycho/
Utilisation de https://eclipse.org/tycho/

=Séance 8 : [[MicroService]]s - Application avec [[Docker]] & [[Puppet]]=
Si vous avez le temps, déployez les 2 [[MicroService]]s Node.js suivants au moyen de [[Docker]].
* mqtt2ws sur les ports 1884 et 4004
* mqtt2ws sur les ports 1885 et 4005

Testez au moyen de mqttpub.js et de votre navigateur Web sur les URL http://localhost:4004 et http://localhost:4005

Si vous avez le temps, déployez les 2 [[MicroService]]s Node.js suivants au moyen de [[Rkt]].

=Séance 9 : Monitoring en continue=


=Séance 10 : Performance Debugging=
Voir '''Brendan Gregg, Systems Performance: Enterprise and the Cloud''', ISBN-13: 978-0133390094 , 2013, http://www.brendangregg.com/sysperfbook.html [https://www.youtube.com/watch?v=abLan0aXJkw video @ USENIX 2012]

Latest revision as of 09:39, 1 September 2015

Travaux pratiques de l'UE TAGL.

Version courante : 2016

Anciennes versions : TAGL/TP 2014 TAGL/TP 2015

Séance 1 : Gestion de versions

Git

Création d'un dépôt Git local

Méthode simple: init first

Via cette méthode, on crée un dépôt local, avec un répertoire de travail, puis on pousse ses modifications vers un dépôt "bare". Cette méthode est la plus simple, car on dispose immédiatement d'un répertoire de travail.

# Création d'un dépôt Git dans le dossier simple-repo
git init simple-repo

# Création d'un README
cd simple-repo
echo "Hello, World" > README

# Ajout du versionnement du fichier README
git add README

# Commit
git commit

À ce niveau, on a un dépôt Git complètement fonctionnel. Cependant, il est intéressant de pousser ses modifications vers un autre dépôt, sur une autre machine. On va donc créer un dépôt bare sur une autre machine (ou autre dossier pour l'exemple)

git init --bare server-repo

On considère que l'URL pour accéder à ce dépôt est URL_REPO. On va d'abord ajouter ce dépôt serveur à la liste des dépôts connu-repos de votre dépôt local. Étant donné qu'il s'agit du dépôt "principal" à utiliser, on l'appellera //origin//, par convention.

git remote add origin URL_REPO
# Récupération de ses informations
git fetch origin

Ce serveur distant est "vide": il n'a aucune branche. On va donc enregistrer notre branche sur le serveur

git push origin master

À partir de cette commande, la branche locale //master// sera liée à la branche distante //origin/master//. Lors des prochaines commandes git push, grâce à cette liaison, tous les commits sur la branche locale //master// seront poussées sur le serveur distant.

Méthode moins simple: bare first

Si on commence dans par le serveur "vide", il faudra le cloner au lieu de le définir comme un dépôt distant.

# Création du dépôt vide
git init --bare server-repo

On considère que ce dépôt est accessible à l'URL URL_REPO

# Clonage du dépôt
git clone URL_REPO clone-repo

Un avertissement indique que l'on clone un dépôt vide: le dépôt local à donc une branche master, mais elle n'est pas liée au dépôt distant, car celui-ci n'a aucune branche. Le dépôt distant est automatiquement appelé //origin//.

# Commit dans le dépôt local
cd clone-repo
echo hello > readme.rst
git add readme.rst
git commit et ses dépendances

Comme dans la méthode simple, il faut pousser la branche master vers le dépôt distant:

git push origin master

De l'importance des README

Il est très important d'avoir au moins 2 fichiers dans votre dépôt Git:

  • LICENSE: contenant le texte **complet** de la licence de votre projet
  • README: décrivant votre projet et comment l'utiliser. Ce fichier doit rappeler le nom de la licence de votre projet

Il est aussi recommandé d'avoir les fichiers suivants:

  • AUTHORS: contenant la liste des noms/pseudos et e-mails des auteurs de commits ou de code inclus dans ce projet
  • INSTALL: contenant la liste des dépendances de ce projet et des commandes à utiliser pour le compiler et l'installer

Les fichiers LICENSE sont des fichiers textes bruts. Les autres fichiers sont généralement dans un format offrant un peu plus de lisibilté, par exemple dans les formats Markdown (.md) ou reStructuredText (.rst)

Un plug-in existe pour éditer des fichier reStructuredText dans Eclipse: ReST Editor, disponible sur le Marketplace Eclipse

Séance 2a: Intégration en continue

GitHub & Travis-CI

Travis-CI est un service permettant d'exécuter un script dans une machine virtuelle Ubuntu dès que vous effectuez un push sur un de vos dépôts GitHub. L'intérêt est de savoir si la version d'un projet que vous avez rendu publique peut être compilée et si ses tests passent.

La machine virtuelle "offerte" par Travis est préconfigurée pour le language indiqué dans son fichier de configuration (.travis.yml), mais il est possible d'utiliser la commande sudo apt-get install ... pour ajouter vos dépendances.


Pour utiliser Travis-CI:

  1. Créez compte individuel sur GitHub https://github.com
  2. Forkez le dépôt https://github.com/heroku/node-js-getting-started
  3. Ajoutez un collaborateur (i.e. votre binôme) au projet forké, via les paramètres (settings) de ce projet
  4. Pour l'exemple, activez le service (ou hook) Email depuis les paramètres du dépôt: à chaque fois que vous ou un de vos collaborateurs ferra un git push, vous recevrez une notification par mail.
  5. Activez le service Travis-CI: identifiez-vous (sign in) sur https://travis-ci.org/ avec votre compte GitHub
  6. Activez le service pour les projets sur lesquels vous souhaitez appliquer les principes d'intégration continue

Travis-CI utilise un fichier nommé .travis.yml (attention: fichier caché sous Unix) pour se configurer et choisir les opérations à effectuer. Ce fichier doit se trouver à la racine de votre dépôt Git.

Faites un Commit puis un Push du fichier .travis.yml ci-dessous.

language: node_js
node_js:
  - "0.11"
  - "0.10"
  - "0.8"
  - "0.6"
  - iojs
  - iojs-v1.0.2


Ce fichier .travis.yml indique à Travis-CI que les scripts de ce projet dans ce dépôt seront exécutés avec plusieurs versions de Node.js.

Ajoutez dans le fichier package.json la section suivante:

  "devDependencies": {
    "jshint": "^2.6.0"
  },
  "scripts": {
    "test": "./node_modules/jshint/bin/jshint index.js"
  }

et incrémentez le numéro de version.

Faites un Commit puis un Push des fichiers touchés.


Remarque: jshint peut être lancé localement avec les commandes suivantes:

sudo npm install jshint
jshint index.js

A lire

Séance 2b: Livraison en continue

Heroku

Heroku est une plateforme cloud de type PaaS permettant l'exécution d'applications et de services en ligne écrits dans les langages et plateformes suivantes : Ruby, Node.js, Python, Java, et PHP.

  1. Créez un compte gratuit sur Heroku
  2. Forkez le dépôt https://github.com/heroku/node-js-getting-started
  3. Dans Heroku, créez une nouvelle app Node.js, et liez-la au repository Github créé à l'étape précédente
  4. Choisissez l'option "Déploiement automatique" depuis la branche **master**
  5. Modifiez le fichier index.js pour afficher la version de service dans la page HTML
 var fs = require('fs');
 var package = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
 var version=package.version;
...
 response.send('Hello World! (current version: '+version+')');
...

Incrémentez le numéro de version dans le fichier package.json

Faites un Commit puis un Push des fichiers touchés.

Naviguez l'application sur Heroku

  1. Modifiez le fichier index.js pour franciser le message dans la page HTML
...
 response.send('Bonjour Tout Le Monde! (version courante: '+version+')');
...

Incrémentez le numéro de version dans le fichier 'package.json

Faites un Commit puis un Push des fichiers touchés.

Naviguez l'application sur Heroku

Séance 3: Builders

Les builders permettent d'automatiser l'exécution en chaine des outils pour la production et la livraison en production des produits logiciels.

Make

Ant

Faire les exercices 0, 1, 3 de ./tpant.htm dans http://lig-membres.imag.fr/donsez/cours/tpant.zip

Maven

Charger et installer Maven 3.

Debian/Ubuntu & friends:

sudo apt-get update && sudo apt-get install maven
mvn -version

Faites une copie du projet, basée sur Maven:

  1. Dans votre dépôt Git, créez un dossier cron4j-mvn: il contiendra le projet Cron4J avec la structure Maven
  2. Dans ce dossier, utilisez l'archetype Maven maven-archetype-quickstart (la version des sources de cron4j utilisés est la 2.5.5) (groupId: it.sauronsoftware.cron4j, artifactId: cron4j):
    mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart
  3. Cette commande crée un projet avec un fichier pom.xml, et une classe et un test modèles: supprimez ces modèles
  4. Copiez les sources de Cron4J depuis le dossier cron4j-original (https://github.com/donsez/tagl) dans le dossier src/main/java de votre projet Maven
  5. Faites un essai de compilation:
    mvn clean verify
  6. Lancez un des exemples avec mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"] ... (doc. exec plugin, doc. Exec:java goal)
  7. Enfin modifiez le fichier .travis.yml à la racine de votre dépôt Git afin que Travis exécute la commande mvn clean verify à chaque mise à jour du dépôt GitHub.

Tests Unitaires avec JUnit 4

Survoller le tutoriel Unit Testing with JUnit

  1. Veillez à bien utiliser la dépendance JUnit 4.8.2 dans pom.xml
  2. Ajouter le test unitaire suivant au projet, dans le fichier src/test/it/sauronsoftware/SchedulingPatternTest.java
package it.sauronsoftware;

import it.sauronsoftware.cron4j.SchedulingPattern;
import it.sauronsoftware.cron4j.InvalidPatternException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class SchedulingPatternTest {

  @BeforeClass
  public static void testSetup() {
  }

  @AfterClass
  public static void testCleanup() {
    // Teardown for data used by the unit tests
  }

  @Test(expected = InvalidPatternException.class)
  public void testExceptionIsThrown() {
    SchedulingPattern sp = new SchedulingPattern("0 5 * *");
  }

  @Test
  public void testPattern() {
    String pattern;
    pattern="0 5 * * *|8 10 * * *|22 17 * * *";
    assertTrue(pattern + "is correct", SchedulingPattern.validate(pattern));
    pattern="0 5 * *";
    assertTrue(pattern + "is correct", SchedulingPattern.validate(pattern));
  }
}
  1. Committez et Pushez ce nouveau fichier, pour que Travis lance les tests dès que possible
  2. Lancez les tests unitaires avec
    mvn test
    Ce test va échouer: corrigez le.
  3. Committez et Pushez la version corrigée des tests: Travis enverra un mail pour indiquer si les tests échouent ou non
    Attention: Travis va exécuter les tests dès que possible. Il est possible de recevoir un mail indiquant que les tests du premier push échouent alors que l'on a déjà pushé la correction.
  4. Naviguez sur http://travis-ci.org pour vérifier les builds effectués.
  5. Créez des tests unitaires supplémentaire du i.s.c.CronParser

Maven avec Travis-CI

Git (suite)

  1. Forkez le projet tagl d'un autre binome (i.e. autre que donsez/tagl)
    Attention: donnez lui un nom différent (e.g. tagl-licensing)
  2. Clonez ce nouveau dépôt
  3. Lancez une compilation pour valider l'état du projet (bonne pratique)
    mvn clean verify
  4. Situez vous dans une nouvelle branch git:
    git checkout -b add-license
  5. Ajoutez une bannière de licence dans le fichier cron4j-mvn/pom.xml
  6. Lancez une nouvelle compilation pour valider vos modifications
  7. Commitez et pushez (vers votre fork de ce dépôt, i.e. tagl-licensing) (pour pusher une branche nouvellement créée: git push origin add-license)
  8. Via le site de GitHub, proposez un "Pull Request" au projet initial

Vous pouvez ensuite supprimer le clone de ce fork. Lorsque le pull request aura été accepté, vous pourrez supprimer votre fork (tagl-licensing) de votre compte GitHub.

Contrôle Continu

Dans votre dépôt tagl.

  1. Ajoutez le plugin Cobertura à votre projet Maven.
    1. Configurez le plugin pour générer un rapport HTML. Le résultat se trouvera dans target/site/cobertura
    2. Le plugin ne s'exécute automatiquement pas durant la compilation, il faut utiliser la commande :
      mvn cobertura:cobertura
    3. Bonus: Modifiez le fichier pom.xml pour que le goal cobertura soit exécuté pendant la phase package.
  2. Répondez aux questions : Mais qu'est ce que la couverture de code ? En quoi c'est utile ?
  3. Ajoutez au projet Maven les plugins pour la génération d'un site et de rapports (Javadoc, tests unitaires, tags list (FIXME, TODO, ...), ...): voir http://maven.apache.org/plugins/maven-site-plugin/ et d'autres.
  4. Regardez les exemples d'utilisation de cron4j dans cron4j-original/examples
  5. À rendre : pom.xml

Bonus Track

Clone SVN -> Git

Source: http://www.yterium.net/Migrer-un-projet-SVN-vers-GIT

# Cloner le dépôt SVN en dépôt Git (conservation historique)
$ git svn clone  svn://svn.code.sf.net/p/cron4j/code/trunk cron4j-original
$ cd cron4j-original
# Test compilation
$ ant jar
$ cd ..

Préparation TAGL

# Clone du dépôt TAGL
$ git clone git@github.com:donsez/tagl.git
$ cd tagl
# "Fetch" du dépôt local cloné précédemment
$ git fetch file://$(pwd)/../cron4j-original
# Fusion de ce qui vient d'être fetché
$ git merge FETCH_HEAD
# Envoi sur le serveur
$ git push


Cherry-picking: reprise des modifications d'un collègue

On considère que:

  • votre dépôt Git distant est à l'adresse URL_DEPOT
  • votre collègue a un dépôt Git à l'adresse URL_COLLEGUE


# Dossier temporaire
cd /tmp

# Clone de votre dépôt
git clone URL_DEPOT mon_depot

# Déplacement dans votre dépôt
cd mon_depot

# Définition du dépôt distant
git remote add collegue URL_COLLEGUE

# Récupération des infos du dépôt du collègue
git fetch collegue

# Maintenant, on peut voir les branches du collègue
git branch -a

# On peut fusionner avec une branche
git merge collegue/master

# Si vous avez des conflits, éditez les fichiers concernés,
# et committez avec git commit

# Push vers votre dépôt distant
git push origin

# Optionnel: supprimez la référence vers le dépôt du collègue
git remote rm collegue


Archetype webapp

L'archetype webapp (http://maven.apache.org/archetype/maven-archetype-bundles/maven-archetype-webapp/) permet de créer le squelette d'une webapp. Créez un simple webapp monsite en version 0.1.0. (add/commit/push). Vous pourrez tester cette webapp en ajoutant au pom.xml le plugin maven Jetty.

mvn -Djetty.port=9999 jetty:run

Naviguez sur http://localhost:9999/monsite

Scrum tools

Ces 3 services peuvent être couplé à votre dépôt GitHub pour votre gestion de projet agile avec Scrum :

L'activation se fait via Settings > Webhooks & Services > Configure services.

Séance 4 : Gestion d'un dépôt d'artefacts

(introduite en 2015-2016)

Le dépôt https://www.npmjs.com/ est le dépôt principal des artefacts pour Javascript et Node.js. Pour en savoir plus ...

Côté client, il s'utilise avec les commandes npm, bower, ...

Ce TP a pour objectif de faire évoluer l'artefact suivant XXXX et l'ajouter au dépôt npmjs (manuellement et via Travis-CI).

Il vous faut pour cela comprendre le format du manifeste package.json

Séance 5: Pelix & iPOPO

Pelix est une plate-forme d'application à services (SOA). iPOPO est un modèle de composants orientés services (SOCM).

La documentation de Pelix et iPOPO est disponible sur https://ipopo.coderxpress.net/

Installation de iPOPO

  • Pour installer iPOPO, lancer la commande :
  pip install --user iPOPO
  sudo python setup.py install

Shell Pelix

Pour lancer un shell Pelix, utilisez la commande:

  python -m pelix.shell.console

Les commandes disponibles sont décrites ici: Shell Commands

Rappels de Python

  • Pas de déclaration du type d'une variable
  • Les méthodes d'une classe ont toute comme premier paramètre self, équivalent du this en Java.
  • Blocs définis par indentation (4 espaces ou 1 tab)
  • Une ligne finissant par ':' démarre toujours un bloc
#!/usr/bin/python
# -- Content-Encoding: UTF-8 --
# Import d'un module
import pelix

# Définition d'une classe
class MaClasse:
   # Constructeur
   def __init__(self):
       self.default = "stanger"
       print("Classe construite")

   # Méthode, avec un argument
   def sayHello(self, name):
       if not name:
           # Nom vide ou nul
           return "Hello, " + str(self.default)
       else:
           # Nom valide
           return "Hello, " + str(name)

objet = MaClasse()
print(objet.sayHello(""))
print(objet.sayHello("World"))

Service Ping-Pong

1. Écrire un fichier pong.py, définissant une classe Pong ayant une méthode pong prenant en paramètre un message et retournant le message préfixé par "PONG:".

Exemple:

     pong = Pong()
     pong.pong("Hello") # <-- Retourne "PONG:Hello"

2. Écrire un fichier ping.py, définissant une classe Ping ayant une méthode ping prenant en paramètre un message, créant un objet Pong et retournant le résultat de Pong.pong(message) préfixé par "PING:"

Exemple:

     ping = Ping()
     ping.ping("Hello") # <-- Retourne "PING:PONG:Hello"

3. Transformer le fichier pong.py pour qu'il devienne un bundle Pelix enregistrant un objet Pong comme étant un service ayant pour spécification "tagl.pong"

  • Définir une classe Activator, décorée avec @BundleActivator
  • Enregistrer le service dans la méthode Activator.start et le désenregistrer dans Activator.stop
  • S'inspirer du fichier "ipopo/samples/remote/provider.py"

Dans un shell Pelix, installer et démarrer le bundle 'pong' et vérifier que le service est bien inscrit avec la commande sl

4.Transformer la classe Ping dans ping.py en un composant iPOPO

  • L'objet Pong utilisé dans ping() doit être un service injecté par iPOPO (@Requires)
  • Appeler la méthode ping() dès que le service Pong est injecté (@BindField) ou disparait (@UnbindField)
  • S'inspirer du fichier "ipopo/samples/remote/consumer.py"

Dans un shell Pelix, installer et démarrer le bundle 'ping' et vérifier son comportement si le bundle pong ou le bundle ping est arrêté et redémarré.

5. Mettre à jour le bundle pong

  • Remplacer le préfixe "PONG" par "NI"
  • Dans le shell Pelix, mettre à jour le bundle pong sans redémarrer la plate-forme (commande udpate).
  • Vérifier les traces dans le shell pour valider la mise à jour du service.

Remote Services

  • Ajouter les propriétés permettant l'export du service Pong dans pong.py (s'inspirer de provider.py)
  • Lancer deux shells iPOPO (dans deux terminaux)
  • Dans chaque shell iPOPO, installer les bundles:
    • pelix.remote.dispatcher: Exportateur de services
    • pelix.remote.registry; Importateur de services
    • pelix.remote.discovery.multicast: Découverte de services via Multicast
    • pelix.remote.xml_rpc: Transport XML-RPC
    • pelix.http.basic: Serveur HTTP

Attention: il peut être nécessaire de désactiver votre pare-feu pour que les Remote Services fonctionnent

  • Instancier les composants depuis le shell iPOPO, dans chaque framework:
    • Serveur HTTP sur le port 8080: instantiate pelix.http.service.basic.factory http-server pelix.http.port=8080 (penser à changer de port dans chaque framework)
    • Multicast Discovery: instantiate pelix-remote-discovery-multicast-factory multicast-discovery
    • XML-RPC Exporter: instantiate pelix-xmlrpc-exporter-factory xml-rpc-exporter
    • XML-RPC Importer: instantiate pelix-xmlrpc-exporter-factory xml-rpc-importer
  • Installer le bundle ping dans un des frameworks et le bundle pong dans l'autre.
  • Le composant ping peut appeler le service pong, qui est dans l'autre framework.


  • Voir le code de run_remote.py pour voir comment démarrer un framework Pelix et installer des bundles depuis Python.
  • Jouer un peu avec run_remote.py (voir run_remote.py --help)

Séance 6

Tutorial OSGi avec Apache Felix

Séance 7

Faire un projet PDE pour un bundle cron4j.gogo (indépendant de cron4j.bundle)

Utilisation de https://eclipse.org/tycho/

Séance 8 : MicroServices - Application avec Docker & Puppet

Si vous avez le temps, déployez les 2 MicroServices Node.js suivants au moyen de Docker.

  • mqtt2ws sur les ports 1884 et 4004
  • mqtt2ws sur les ports 1885 et 4005

Testez au moyen de mqttpub.js et de votre navigateur Web sur les URL http://localhost:4004 et http://localhost:4005

Si vous avez le temps, déployez les 2 MicroServices Node.js suivants au moyen de Rkt.

Séance 9 : Monitoring en continue

Séance 10 : Performance Debugging

Voir Brendan Gregg, Systems Performance: Enterprise and the Cloud, ISBN-13: 978-0133390094 , 2013, http://www.brendangregg.com/sysperfbook.html video @ USENIX 2012