Affichage des articles dont le libellé est jenkins. Afficher tous les articles
Affichage des articles dont le libellé est jenkins. Afficher tous les articles

samedi 4 octobre 2014

Jenkins et Scritpler : comprendre l'execution en mode distribué

Pour la mise en place de jobs de construction un peu tordu, la définition dans Jenkins est vite compliquée à gérer.
Il est plus judicieux de créer de scripter son job dans ce cas. Groovy est un intéressant, notamment pour les développeurs issus du monde Java.

Scriptler permet d’exécuter des scripts Grrovy sur Jenkins. Il est intéressant sur plusieurs points :

  • Permet de centraliser les scripts à un même endroit. Facilite la maintenance et la réutilisabilité
  • Les scripts sont paramétrables.
  • les scripts sont commités sur un repo Git local accessible via http://MON_SERVER_JENKINS/scritpler.git à chaque modification. C’est idéal pour pouvoir par la suite pusher vers d’autres repos et assurer ainsi leur sauvegarde. Dommage pour ce point il n’est pas possible de créer de hooks pour pusher automatiquement vers un repository remote, car JGit (le moteur Git de Jenkins) ne prends pas en compte les hooks. Il faudra donc trouver une autre solution pour pusher les commits vers un repo remote (via un Job Jenkins par exemple)
  • offre la possibilité de gérer l’exécution sur le master ou le slave. C’est sur ce point qu’il est utile de connaitre quelques subtilités.
  • Le job Jenkins execute les scripts Groovy de scripter en les référencant dans un build Step.

Scriptler possède deux systèmes d’exécution de scripts, pas ou peu documenté, voici les subtilités à connaitre lors d’un exécution en mode distribué :

Execution sur Master

Appelé “Restriction - Script is always executed on Master“. Dans ce mode, le script s’exécute sur le master dans la même VM que l’exécution du Job :

  • On dispose de l’API de Jenkins pour interagir avec les informations de build (par exemple, renommer un build).
  • On dispose des logs de construction.
  • On dispose des variables d’environnements du build dispo via http://MON_SERVEUR_JENKINS/env-vars.html/?.
    Attention : certaines variables sont relatives à l’exécuteur. Par exemple, $WORKSPACE indique le chemin du workspace sur l’exécuteur et donc, en mode distribué, sur le slave d’exécution.
  • Si l’exécuteur est un slave, le workspace - et donc les sources - ne sont pas accessibles.

Execution sur Slave

Type de script par défaut. Dans ce mode, le script s’exécute sur la même machine que l’exécuteur Jenkins (donc le slave) dans une VM différente. Il s’agit à un mode equivalent à l’execution de script via une commande groovy externe, hors Jenkins.

  • On ne dispose pas de l’API Jenkins.
  • On ne dispose des variables d’environnements du build. Il faudra passer en paramètres du scripts les variables dont on a besoin.
  • On dispose du workspace et donc, de toutes les ressources checkoutées, construites, etc.
  • On n’as pas accès aux logs construction.

En mode distribué, on se rend compte donc de certaines limitations.
un exemple concret :
Lire une information d’un fichier du workspace pour alimenter une description de build n’est pas faisable en mode distribué. Les sources du workspace sont sur le slave, et l’API de modification de description de build n’y est pas disponible (elle est disponible seulement sur le master). Mon billet sur “Afficher la révision comme numéro de build” n’est donc pas fonctionnel en mode distribué… :-(

A suivre…

jeudi 26 septembre 2013

Suivre le développement des règles métier avec Dolphin et Jenkins

Update : une démo de la page statique est disponible à cette adresse : http://dolphindemo.flo.cloudbees.net/

Dolphin est un plugin Maven d'analyse d'annotations de suivi des exigences métier dans le code Java. Il permet d'assurer la traçabilité de règles métier depus les spécifications détaillées et le code. Il permet de connaitre quelle méthode implémente une règle métier particulière et le niveau d'avancement de celle-ci.

C'est un outil que j'ai développé afin d'assurer la traçabilité et avoir une idée de l'avancement de l'implémentation des règles métier au sein des projets.

Nous allons voir comment le mettre en place sur un projet, puis comment tirer parti de son usine logicielle et de Jenkins pour récupérer les indicateurs de manière automatisée en "quasi" temps réel.
Les sources de Dolphin sont récupérable à cette adresse : https://github.com/florentdupont/dolphin.

Enrichir le code avec l'API

 l'API comporte deux annotations :
  • @BusinessRule, pour la traçabilité des règles métier
  • @DevelopmentStatus, pour le suivi d'avancement.
L'annotation @BusinessRule indique les règles métiers implémentées sur une méthode. Cette annotation porte 2 attributs : 
  • id représente l'identifiant de la règle 
  • version représente la version de la règle. 
Par exemple :
  @BusinessRule(id="RG_0009", version="0.1")
  public void myMethod() {
      // blabla
  }

Si plusieurs règles sont appliquées sur une méthode, alors on peut indiquer les différents identifiants en spécifiant les valeurs multiples entre accolades {} : Dans l'exemple ci dessous, myMethod() implémente la règle RG_0009 en version 0.1 et la règle RG_0010 en version 0.2.
  @BusinessRule(id={"RG_0009", "RG_0010"}, version={"0.1", "0.2"})
  public void myMethod() {
    // ...
  }
L'annotation @DevelopmentStatus permet d'indiquer l'avancement d'un développement. L'annotation porte sur une méthode. Par exemple, une méthode en cours de développement :
  @DevelopmentStatus(StatusType.ONGOING)
  public void myMethod() {
    //...    
  }
Il existe 5 types de statut :

  •  TODO : méthode à implémenter 
  • ONGOING : méthode en cours de développement 
  • DONE : méthode implémentée, mais pas encore testée 
  • TESTED : méthode testée unitairement. Passe les tests unitaires 
  • INTEGRATED : méthode testée en intégration. Passe les tests d'intégration. 
Bien que les deux annotations pourraient être utilisées indépendamment, l'intérêt est évidemment de les utiliser conjointement afin de pouvoir bénéficier de l'avancement de l'implémentation des règles métier. L'exemple ci-dessous montre un exemple d'utilisation conjointe.
  public class MyClass {

    @BusinessRule(id="RG_0001", version="1.0")
    public void myMethod1() {
      // ...
    }

    @BusinessRule(id="RG_0016", version="1.0")
    @DevelopmentStatus(StatusType.DONE)
    public void myMethod2() {
      // ...
    }
}

Analyser les résultats

L'outil fait une analyse statique sur le code compilés (*.class). J'ai implémenté cette analyse en utilisant la librarie ASM qui permet de faire de l'analyse de Bytecode Java. L'utilisation d'une analyse statique depuis le Bytecode est plus complexe à mettre en oeuvre que de l'introspection (quoique...) mais elle présente surtout l'intérêt de pouvoir faire une analyse sans avoir à charger dynamiquement une classe. La classe peut donc très bien ne pas avoir ses classes liées chargées pour être analysée (ce qui est très utile lors de très gros projet et de Maven Dependency Hell...).

Une façon très simple de lancer l'outil, une fois installé, est de lancer la commande suivante : 

  mvn clean package -DskipTests com.dolphin:dolphin-maven-plugin:1.3:dolphin -DdolphinPrefix=com.mypackage.test
Le résultat de l'analyse est disponible dans le répertoire target/dolphin sous la forme d'un rapport HTML.

Le rapport HTML est une application HTML5 statique qui permet d'afficher une échelle du nombre de méthode analysées, ainsi que le status d'avancement de chaque méthode. Le tableau récapitulatif peut être trié par classe, par méthode, par règle ou par version. Il propose également une zone de recherche.
L'export XLS est également possible.

Intégration dans Jenkins 

L'intérêt est de pouvoir automatiser cette analyse et de l'intégrer dans Jenkins pour pouvoir disposer, de manière régulière et en quasi-temps réel, l'avancement.

Etant donné que Dolphin est disponible sous la forme d'un plugin Maven, il est tout à fait possible de l'intégrer à une construction Jenkins.

Voici un type de paramétrage pouvant être mis en place : 
Ce qui déclenche le Build : 
Scrutation de l'outil de gestion de version : H/20 * * * 1-5 
Build : 
Goals et options : 
  mvn clean package -DskipTests com.dolphin:dolphin-maven-plugin:1.3:dolphin -DdolphinPrefix=com.mypackage.test
Action à la suite de Build :
Archiver des artefacts : fichiers à archiver :
target/dolphin/**

C'est cette dernière étape qui va nous intéresser. Nous utilisons Jenkins comme "serveur Web", en mettant à disposition les fichiers HTML statiques directement accessible depuis ses constructions.
En cliquant sur index.html, on se rend compte que le résultat est accessible sur une URL du type :
http://MY_SERVER/jenkins/job/MY_JOB/BUILD_NUMBER/artifact/target/dolphin/index.html
On peut donc facilement, en gérant la rétention des constructions, garder une version de l'export par construction et ainsi garder un historique des différentes analyses Dolphin.

 L'intérêt pour le chef de projet est d'avoir une vision de la dernière analyse. Dans ce cas, on tire parti des URL Jenkins pour nous aider puisque Jenkins met à disposition les dernière construction sous un formalisme d'URL toujours identique, à savoir :;
http://MY_SERVER/jenkins/job/MY_JOB/lastSuccessfulBuild/artifact/target/dolphin/index.html
Ce lien peut ensuite être utilisé pour accéder rapidement aux résultats de dernière analyse, peu importe le numéro de construction utilisé par Jenkins, et notamment être utilisé directement depuis un tableau de bord par exemple.

samedi 21 septembre 2013

Jenkins & SVN : Afficher la révision comme numéro de build

Le numéro de build indiqué par défaut lors de la construction dans Jenkins est un numéro qui s'incrémente à chaque construction. Ce numéro - mis à part de nous indiquer à combien de construction nous sommes rendu - n'apporte pas plus d'information.


Ce qui serait utile, par contre, c'est de savoir rapidement à quelle version de source cette construction correspond afin de disposer d'une meilleure traçabilité entre Source SVN -> artefact Jenkins.
Aucun plugin ne permet de le faire actuellement, nous allons voir comment on peut cependant le mettre en place rapidement.

Retour sur les versions de SVN

Dans notre contexte, nous avons plusieurs projets disponibles sur un repository SVN. Chaque projet est donc sur un sous-répertoire depuis la racine du dépot. A chaque commit (peu importe sur quel projet), le numéro de révision du dépôt est incrémenté.
Ce numéro de révision est global : il permet de restituer l'état d'un repository à un révision donnée.
Pour chaque sous répertoire, nous disposons d'un second indicateur : Last Changed Revision qui indique le dernier numéro de révision qui à modifié le répertoire en cours

Nous pouvons récupérer ces informations depuis la ligne de commande en se positionnant sur un répertoire de source précédemment checkoutée :

$ svn info
Path: .
Working Copy Root Path: D:\projets\toto\source\
URL: http:/xxx/usvn/svn/toto/trunk
Repository Root: http://xxx/usvn/svn/toto
Repository UUID: a1ebbc07-6c76-4030-a489-aa0d2fd72fa2
Revision: 11372
Node Kind: directory
Schedule: normal
Last Changed Author: fdupont
Last Changed Rev: 11360
Last Changed Date: 2013-09-11 17:23:54 +0200 (mer., 11 sept. 2013)

Les informations qui nous intéressent apparaissent dans les champs "Revision" et "Last Changed Rev".

Prise en compte dans Jenkins

Pour la prise en compte dans Jenkins, il faudra ajouter le plugin Hudson Groovy builder

Dans la configuration du build, ajouter une Pre steps avec execution de script Groovy "System". Exécuter en tant que script "System" signifie que le script sera exécuté dans la même JVM que Jenkins, ce qui permet d'avoir la main sur les objets Jenkins. C'est ce qui va nous permettre de modifier le nom du build ainsi que sa description.

Les deux lignes suivantes sont les imports des packages jenkins.
  import hudson.model.*
  import hudson.util.*
Récupère l'instance du build courant
  def build = Thread.currentThread().executable
On récupère ensuite le workspace du build courant, c'est à dire le répertoire dans lequel les sources sont chéckoutée. Ce répertoire contient le répertoire .svn qui sera utilisé par la commande svn info.
  def workspace = build.getWorkspace()
En groovy, le moyen le plus simple d'exécuter une commande shell et de récupérer le résultat est de passer par une tâche Ant.
  def ant = new AntBuilder()

  ant.exec(executable: "svn", outputproperty: "output", dir: workspace){
    arg(line: "info")

  }
La sortie est récupérée depuis la variable "outputProperty" puis sert à alimenter la variable svnInfo.
  svnInfo = ant.project.getProperty("output")
On utilise ensuite des expression régulière pour récupérer le numéro de révision ainsi que le LCR (Last Changed Revision.
  def pattern = /Last\s+Changed\s+Rev:\s+(\d+)/
  def matcher = (svnInfo =~ pattern)
  def lcr = "Last changed revivion : <b>" + matcher[0][1] + "</b>"
  
  pattern = /Revision:\s+(\d+)/
  matcher = (svnInfo =~ pattern)
  def rev = "r" + matcher[0][1]
Le nom du build est ensuite modifié avec l'intitulé de la révision et la description est renseignée avec le LCR.
  build.setDisplayName(rev)
  build.setDescription(lcr)

Au complet, ça nous donne :
  import hudson.model.* 
  import hudson.util.*

  def build = Thread.currentThread().executable
  def workspace = build.getWorkspace()
  def ant = new AntBuilder() 

  ant.exec(executable: "svn", outputproperty: "output", dir: workspace){ 
    arg(line: "info") 
  }

  svnInfo = ant.project.getProperty("output")
  def pattern = /Last\s+Changed\s+Rev:\s+(\d+)/ 
  def matcher = (svnInfo =~ pattern)
  def lcr = "Last changed revivion : " + matcher[0][1] + ""

  pattern = /Revision:\s+(\d+)/ 
  matcher = (svnInfo =~ pattern)
  def rev = "r" + matcher[0][1]

  build.setDisplayName(rev)
  build.setDescription(lcr)


Lors de la prochaine construction, depuis la View, on verra bien apparaitre notre numéro de révision


Dans la vue Constructions, le LCR apparait en tant que description :




Note complémentaire : pour les ceux qui utilisent SVN depuis Windows, l'outil en ligne de commande est internationalisé et répondra donc en français. Pour restituer les sorties consoles en anglais, ajouter la variable d'environnement suivante :
  set LC_MESSAGES=en_US
L'article original : http://jayflowers.com/WordPress/?p=258