mercredi 1 avril 2015

Accéder aux branches de merge des Pull-Request avec Atlassian Stash (git)

Les pull-requests sur Atlassian BitBucket server (Stash) permettant le code review génère des branches habituellement non utilisée.

Pour faire un checkout de ces branches il faut faire les modifications suivante :

Attention cette caractéristique est lié à votre server git et non pas directement à git.


Rechercher dans le fichier .git/config de votre repertoire git local la section suivante :


[remote "origin"]
  url = git@bitbucket.compagny:an/url/to/repository.git
  fetch = +refs/heads/*:refs/remotes/origin/*


Il est possible que vous soyez amener a modifier cette URL pour quelle corresponde aux paramètres de votre projet (dans le cas de BitBucket).

[remote "origin"]
  url = git@bitbucket.compagny:an/url/to/repository.git
  fetch = +refs/heads/*:refs/remotes/origin/*
  fetch = +refs/pull-requests/*:refs/remotes/origin/pull-requests/*

Si vous utilisez un serveur GitLab (et il faut bien sur adapter au reste de l'article)

[remote "origin"]
  url = git@gitlab.compagny:an/url/to/repository.git
  fetch = +refs/heads/*:refs/remotes/origin/*
  fetch = +refs/merge-requests/*:refs/remotes/origin/merge-requests/*


Pour verifier le bon fonctionne, il suffit de mettre à jour votre repos local à l'aide de :

$ git fetch origin --verbose --prune
From bitbucket.compagny:an/url/to/repository
 * [new ref] refs/pull-requests/42/from  -> origin/pull-requests/42/from
 * [new ref] refs/pull-requests/42/merge -> origin/pull-requests/42/merge
 * [new ref] refs/pull-requests/43/from  -> origin/pull-requests/43/from
 * [new ref] refs/pull-requests/43/merge -> origin/pull-requests/43/merge

...


Pour récupérer un Pull-Request particulier, il suffit de faire :

$ git checkout pull-requests/1000/from
Branch pull-requests/42/from set up to track remote branch pull-requests/42/from from origin.
Switched to a new branch 'pull-requests/42/from'



Pour faire la même chose sous jenkins, ce qui permet de vérifier que le merge (qui sera fait lorsque la PR sera validé) build correctement.

Par exemple pour le Pull-Request 248 :

La branche se nomme ainsi : origin/pull-requests/248/merge Dans le Job de jenkins, je suppose que l'on part d'un Job existant qui build une branche classique du projet. il faut alors configurer/modifier les 3 points suivant :

  • GIT/Repositories/Advanced.../Refspec/
    Mettre la valeur: +refs/pull-requests/*:refs/remotes/origin/pull-requests/*
  • GIT/Branches to build: Branch Specifier (blank for 'any')
    Mettre la valeur: refs/heads/pull-requests/248/merge
  • GIT/Additional Behaviours/Branch name
    Mettre la valeur: pull-requests/248/merge
La section SCM du fichier de configuration du Job sera du type :


<scm class="hudson.plugins.git.GitSCM" plugin="git@2.3.4">
     <configVersion>2</configVersion>
     <userRemoteConfigs>
         <hudson.plugins.git.UserRemoteConfig>
             <refspec>+refs/pull-requests/*:refs/remotes/origin/pull-requests/*</refspec>
             <url>ssh://git@bitbucket.compagny:/group/project.git</url>
         </hudson.plugins.git.UserRemoteConfig>
     </userRemoteConfigs>
     <branches>
         <hudson.plugins.git.BranchSpec>
             <name>refs/heads/pull-requests/248/merge</name>
         </hudson.plugins.git.BranchSpec>
     </branches>
     <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
     <browser class="hudson.plugins.git.browser.Stash">
         <url>https://bitbucket.compagny/projects/group/repos/project</url>
     </browser>
     <submoduleCfg class="list" />
     <extensions>
         <hudson.plugins.git.extensions.impl.LocalBranch>
             <localBranch>pull-requests/248/merge</localBranch>
         </hudson.plugins.git.extensions.impl.LocalBranch>
     </extensions>
 </scm>

Cet exemple suppose que vous utiliser un système permettant de créer dynamiquement des jobs Jenkins, il doit être adapter à votre système de build.

jeudi 12 septembre 2013

Options de rafraichissement d'une page dans Chrome

Options de rafraichissement d'une page dans Chrome

Voici une fonctionnalité très pratique pour les développeurs mais extrêmement bien caché de Chrome

Lorsque la fenêtre des outils développeur est active (F12), il faut appuyez sur le bouton d'actualisation sans le relâcher immédiatement, ou utiliser le bouton droit de votre sourie. Un menu déroulant s'affiche et vous propose trois méthodes pour rafraichissement la page courante :

  • Actualisation normale (Normal Reload): le cache sera utilisé comme habituellement, le navigateur ne rechargera les fichiers que s'il ne peut pas faire autrement. Cela concernant les fichiers JavaScript, les images, les fichiers texte, etc. Cette action correspond au classique raccourci clavier: F5.
  • Actualisation forcée (Hard Reload): Indique au navigateur de ne pas utiliser quoi que ce soit provenant du cache lors du premier chargement. Concrètement cela force le navigateur à télécharger à nouveau tous les fichiers JavaScript, image, fichier texte, etc. Cependant, si la page charge des ressources additionnelles plus tard via javascript ou des redirections, ces ressources proviendront du cache, lorsque cela sera possible. Raccourci clavier: CTRL + F5.
  • Vider le cache et effectuer une actualisation forcée (Empty Cache and Hard Reload): Dans ce mode, absolument rien ne viendra de la cache.

vendredi 9 août 2013

java.lang.IndexOutOfBoundsException: "Invalid index" lors de l'appel à la méthode JFileChooser.setCurrentDirectory( dir )

Une exception assez inattendue peut survenir lors de l'appel à la méthode setCurrentDirectory() sur une objet de type JFileChooser.

Exception in thread "xxx" java.lang.IndexOutOfBoundsException: Invalid index
 at javax.swing.DefaultRowSorter.convertRowIndexToModel(DefaultRowSorter.java:514)
 at sun.swing.FilePane$SortableListModel.getElementAt(FilePane.java:658)
 at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1360)
 at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(BasicListUI.java:1311)
 at javax.swing.plaf.basic.BasicListUI.getCellBounds(BasicListUI.java:952)
 at javax.swing.JList.getCellBounds(JList.java:1633)
 at javax.swing.JList.ensureIndexIsVisible(JList.java:1149)
 at sun.swing.FilePane.ensureIndexIsVisible(FilePane.java:1694)
 at sun.swing.FilePane.doDirectoryChanged(FilePane.java:1617)
 at sun.swing.FilePane.propertyChange(FilePane.java:1667)
 at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
 at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
 at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:263)
 at java.awt.Component.firePropertyChange(Component.java:8382)
 at javax.swing.JFileChooser.setCurrentDirectory(JFileChooser.java:581)
 at ...

A priori cela ressemble à un bug Swing, or il n'en est rien. Un article présent dans la base de bug de Sun, explique qu'il ne s'agit pas d'un bug, mais d'un problème de Thread.

Il est a noter que dans mon cas, qu'aucune erreur n'était visible tant que le code ne faisait pas appel à la méthode setCurrentDirectory().

Pour ceux qui sont pressés, je vous donne directement la recette de cuisine :
Il suffit de transformer le code qui initialise votre objet JFileChooser comme suit

Code initial :
JFileChooser jfc = ...
jfc.setFileSelectionMode( ... );
jfc.setCurrentDirectory( ... );
if( jfc.showOpenDialog( parent ) == JFileChooser.APPROVE_OPTION ){
 ...
 }

Code corrigé :
SwingUtilities.invokeLater( new Runnable() { @Override public void run() { JFileChooser jfc = ... jfc.setFileSelectionMode( ... ); jfc.setCurrentDirectory( ... ); if( jfc.showOpenDialog( parent ) == JFileChooser.APPROVE_OPTION ){ ... } } });

Comme l'explique, fort mal, l'article de Sun, l’initialisation doit se faire depuis l'"event dispatch thread", en français, depuis le thread de gestion des événements Swing.

Dans les programmes Swing, le thread d'initialisations n'ont pas pas grand chose à faire. Sa tâche principal étant de créer un objet Runnable qui initialise l'interface graphique. Cette tâche est mise dans la pile des tâche awt/swing, c'est depuis cet environnement que doit être exécuté les traitements lié à l'interface graphique.

Une fois l'interface graphique est créé, le programme est principalement contrôlé par les événements GUI, chacun qui provoque l'exécution d'une tâche courte sur l'"event dispatch thread". Le code d'application peut planifier des tâches de suppléments sur l'"event dispatch thread" a condition qu'ils se terminent rapidement, afin de ne pas interférer avec le traitement des événements ou un thread de travail (pour les tâches longue à traiter).

jeudi 30 mai 2013

[coup de gueule] L'informatique, la France et l'Europe...

Un petit coup de gueule suite à la lecture de l'article "L’étrange pacte de l’armée française avec Microsoft" sur le site du Vinvinteur qui reprend une série d'articles de PC INpact dont en particulier celui intitulé "Défense - nouveaux détails sur l’offre Open Bar de Microsoft".

Pour résumé très rapidement: L'armée Française est équipée 100% Micro$oft, cela s'étant fait sans aucun appel d'offre et bien que des rapports préconisait de ne pas prendre cette solution.

Comment expliquer cela ? La première raison est présente dans la tête de tout le monde, c'est que les personnes ayant milité pour cette solution, à défaut d'avoir fait un choix pertinent pour l'armée, on certainement fait un choix pertinent pour eux même.
Mais il y a une autre raison, c'est qu'il n'y a pas réellement de concurrent, en tous les cas, pas de concurrent en France, ni même en Europe et cela est à mon avis beaucoup plus grave.

Les dirigeants Français ont toujours eu une vision des technologies informatique à côté de la plaque. La raison, sans doute qu'aucun des grands décideurs n'a d’intérêt économique (personnel) dans l'éclosion d'une réel industrie dans ce secteur.
Rappelez-vous dans les années 1990, le rayonnement de la France était assuré par le minitel que tous le monde nous enviais, enfin, c'était le discours officiel, mais personne ne nous l'a acheté. L'article Wikipedia sur le minitel est d'ailleurs écrit dans cette parfaite vision d'une solution révolutionnaire que personne n'a compris, très loin de mon expérience de l'époque où j'utilisait sur le réseau FidoNet (Ce dernier document Wikipedia n'existe d'ailleurs pas en Français, il viendrais contredire le cocorico de la page minitel).

Pourtant à la même époque un nouveau système est en cours d'étude, il s'agit d'un protocole qui révolutionnera le monde : le protocole http. Cela vous rappel quelque chose ? Et oui, puisque c'est le protocole de communication du web. Mais où est né ce protocole ? C'est un britannique Tim Berners-Lee qui a écrit le premier serveur du Web, alors qu'il travaillait pour le CERN, c'est ensuite l'INRIA qui définira les bases du standard avant de passer la main au W3C.
Si Internet vient des Etats Unis, le Web vient d'Europe puisqu'il a été inventé au CERN (Organisation Européenne pour la Recherche Nucléaire), puis repris par l'INRIA ( Institut National de Recherche en Informatique et en Automatique [Fr]) et il est maintenant normalisé par le W3C.
Tout cela pour expliquer que ce n'est pas un problème de compétence technique, mais un vrai problème de compétence politique. Comment se fait-il qu'une technologie, aujourd'hui incontournable, issue de la coopération des pays Européen, n'a-t-elle pas permis aux pays Européen d'être leader sur cette technologie ? 

L'Europe et la France ne manque pas de compétence, mais à l'époque, la France en particulier, à travers France Telecom, défendait avant tout sa technologie révolutionnaire : le minitel. Ce n'est qu'en 2012 que le groupe France Telecom fermera ce service. Le minitel était une manne pour les fabriquant du minitel Matra, Alcatel et Philips (seule entreprise non française de ce consortium), un secteur non compétitif et contrôlé par l'état.

Ayant participé à la présentation à de grandes entreprises (TF1 en particulier) des concepts de site Web en 1996, je me rappel que le frein principal était le fait que ces entreprises ne pouvait pas facturer l'accès à leur site. Le minitel était alors une source de revenu garantis, puisque le temps de consultation était facturé, en effet le 36 15 TF1 rapportait alors 3,65 francs par consultation. Ils ne comprenaient pas la notion d'interactivité avec leurs clients (leurs téléspectateurs) et ne voyait en cela aucun débouché.

Ces entreprises ont bien sur revue lors copie depuis, mais nous avons pris un retard qui sera difficilement rattrapable.

Et pourtant des projets où la France est à la pointe, cela existe :
  • VLC est l'exemple parfait de ce que devrait être le "rayonnement de la France" : VLC media player était au début le client pour le projet VideoLAN qui avait pour but la création d'un logiciel permettant la diffusion de vidéos à travers un réseau informatique de l'École Centrale Paris. Il est aujourd'hui développé par des contributeurs du monde entier et est l'un des premiers lecteurs multimédias utilisé dans le monde. Imaginer ce qu'on pourrait faire si chaque grande école et chaque université mettais en place un projet de ce type, cela instaurerait de plus une compétition au meilleurs projet et serait une vitrine parfaite pour ces écoles.
  • DailyMotion, bien que cette entreprise peine à trouver sa place, elle est avant-gardiste et à su proposer son contenu a des formats standard (Flash étant un format propriétaire) dès 2009, utilisant entre autres le SVG, le Javascript et le HTML 5.
  • XnView est un gratuiciel de visualisation, de retouche et de conversion d’images. Développé par  un Français Pierre-Emmanuel Gougelet, c'est aujourd'hui devenu une suite de logiciels.
  • SPIP appartient à la famille nombreuses des sites à pages dynamiques que l’on désigne souvent par CMS
Cette liste, que ne se veut ni exhaustive, ni objective, présente une gamme de produits informatique très vaste développée dans des contextes totalement différent, souvent avec des fonds très limités. Elle a pour but de démontrer mon propos, à savoir, les compétences sont au rendez-vous : l'incompétence est au niveau des décideurs (politiques et chefs d'entreprises confondus).

Si des infrastructures et des financements était disponibles beaucoup d'autres projets pourrait voir le jour, et avec 1 700 000 € (fourchette basse du contrat de l'armée Française avec Micro$oft), il n'y a aucun doute que l'indépendance de l'armée pourrait être garantis. Au niveau Européen, la question ne se pose même pas, mais le mot Europe a été volé par financier qui ne voit ici qu'une manière de promouvoir leur doctrine libérale.

lundi 19 novembre 2012

Spécification JavaBean des trucs étranges

JavaBeans est une notion familière à tout développeur Java. A priori, il s'agit d'une classe, avec certaines propriétés et pour chacune de ces propriétés les méthodes getter et setter associées. Rien de bien compliqué donc.
Cependant, il arrive que nous ayant des surprise, et bien que les getter et setter aient été générés on découvre une erreur. Pourquoi lors l'exécution de l'application, celle-ci ne trouve pas un getter ou un setter d'une des propriété du bean ?

Et là on se rend compte que les spécifications JavaBean sont expliquées dans un petit document PDF de plus de 100 pages. Inévitablement, certaines des règles sont un peu bizarres et autant dire que rare sont les personnes qui ont regardée cette documentation.

Concrètement
Le nom des propriétés commence par une lettre minuscule au début du nom de la propriété, les méthodes JavaBean correspondantes (getter / setter) commences par get et set puis vient ensuite la première lettre en majuscule nom de la propriété.

Dans la plupart des cas cette règle est correcte.

Mais il arrive que l'on à traiter des noms des attributs non standard que certain problèmes se présentent. C'est typiquement le cas si votre code provient d'une génération automatisée de votre code.
Prenons un exemple, une chaîne provenant du C risque de vous produire l'attribut sName. Là, vous générez les méthodes getSName() et setSName(String nom).

Avec cet exemple, les framework tels que Struts, Hibernate, iBatis ou JSF ne seront pas résoudre l'accès à l'attribut sName.
En effet, dans un tel cas le getter et setter doivent avoir la forme suivante: getsName() et setsName(String nom).

Les propriétés et les règles d'accès

Type de la
propriété
Nom de la
propriété
getter setter
Doublexcoordinate public Double getXcoordinate() public void setXcoordinate(Double value)
DoublexCoordinate public Double getxCoordinate() public void setxCoordinate(Double value)
DoubleXCoordinate public Double getXCoordinate() public void setXCoordinate(Double value)
DoubleXcoordinateNon autoriséNon autorisé
Booleanstudent public Boolean getStudent() public void setStudent(Boolean value)
booleanstudent public boolean getStudent()
public boolean isStudent()
public void setStudent(boolean value)
Toto[]toto public Toto[] getToto()
public Toto getToto(int index)
public void setToto(Toto[] newArray)
public void setToto(int index, Toto item)

La Javadoc.

On peut s'inspirer de java.beans.Introspector, une classe permettant de récupérer la liste des propriétés présente sur une classe.

Method getter = new PropertyDescriptor(propertyName, beanClass).getReadMethod();

Voir également:

mardi 13 novembre 2012

Astuce JAVA, XML et expressions régulières

L'analyse de petits flux XML inséré dans une base de donnée par exemple n'est pas rare, la mise en place d'un parseur XML classique pour ce genre de traitement peut s'avérer inadapté.

Prenons le cas où l'on chercher à retrouver un texte entre 2 balises.

Attention, ce code n'est pas censé remplacé un parseur XML, il ne supporte pas en particulier le fait qu'un élément contienne un élément ayant le même nom.

jeudi 14 juin 2012

Portage C/Java: isalnum()vs isLetterOrDigit()

Le Code JAVA équivalent au code C

/* code C */
 
if( isalnum( c ) ) {
  // ... true ...
  }
else {
  // ... false ...
  }

est

// Eg. C / isalnum() Unix in JAVA
 
if( Character.isLetterOrDigit( c ) && (c < 128) ) {
  // ... true ...
  }
else {
  // ... false ...
  }

la seconde clause est souvent omise dans les documentations et les applications.