Pour développer un add-on sur le produit Atlassian JIRA, la mise en place d’un environnement de développement confortable et productif peut être long. Une bonne connaissance sur Java et surtout maven peut être un pré-requis indispensable même si la documentation JIRA en anglais est relativement complète. L’objectif de ce billet est de présenter certains problèmes rencontrés et de donner les solutions.
Pour commencer un plugin, il est recommandé de compiler et d’exécuter un premier tutorial. Cela permet de vérifier que l’environnement de développement est bien configuré sur un add-on de référence fournit par Atlassian.
Attention JIRA en très gourmand, prévoir :
Pour installer le SDK JIRA, on peut lire la documentation officielle
Ce SDK encapsule le binaire maven en incluant un repository maven avec quelques dépendances. Le repository maven local du SDK est incomplet, quelques centaines de MO et 30 - 60 minutes de téléchargement sont à prévoir.
Le SDK JIRA encapsule les commandes maven standard (atlas-clean pour mvn clean, atlas-run pour mvn tomcat7:run par exemple), on peut oublier temporairement la commande “mvn” même si les notions qui sont derrière sont les mêmes.
Pour commencer, explorer le SDK JIRA est un bon début pour comprendre ce qu’il contient.
Il faudra certainement quelques configurations en plus par rapport à la documentation officielle si vous êtes dans un contexte “entreprise”. Sur le poste d’un développeur java, maven est souvent déjà installé avec un settings.xml propre à la machine du développeur. Par exemple, celui-ci contient des informations sur le proxy d’entreprise.
Après avoir installé le SDK, la commande suivante permet de connaître la configuration réellement utilisée :
atlas-version
ATLAS Version: 5.0.13
ATLAS Home: /usr/share/atlassian-plugin-sdk-5.0.13
ATLAS Scripts: /usr/share/atlassian-plugin-sdk-5.0.13/bin
ATLAS Maven Home: /usr/share/atlassian-plugin-sdk-5.0.13/apache-maven-3.2.1
Executing: /usr/share/atlassian-plugin-sdk-5.0.13/apache-maven-3.2.1/bin/mvn --version -gs /usr/share/atlassian-plugin-sdk-5.0.13/apache-maven-3.2.1/conf/settings.xml
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256M; support was removed in 8.0
Apache Maven 3.2.1 (ea8b2b07643dbb1b84b6d16e1f08391b666bc1e9; 2014-02-14T18:37:52+01:00)
Maven home: /usr/share/atlassian-plugin-sdk-5.0.13/apache-maven-3.2.1
Java version: 1.8.0_25, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre
Default locale: fr_FR, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.3", arch: "x86_64", family: "mac"
Si rien n’a été changé, il utilise le binaire maven et le settings.xml présent dans le SDK. Cette configuration ne sera certainement pas suffisante dans un contexte “entreprise” car une configuration spécifique est nécessaire pour télécharger les dépendances maven du fait des règles de sécurité. On peut donc préciser le settings.xml de la façon suivante :
atlas-version -gs $TONHOME/.m2/settings.xml
Il faudra dans ce cas ajouter les options présentes dans le settings.xml du SDK en renseignant les informations liées aux repositories maven. Pour ne pas impacter le build des autres projets, un profile JIRA peut être mis en place :
<profile>
<id>JIRA</id>
<repositories>
<repository>
<id>atlassian-public</id>
<url>https://maven.atlassian.com/repository/public</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>
<repository>
<id>atlassian-plugin-sdk</id>
<url>file://${env.ATLAS_HOME}/repository</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>atlassian-public</id>
<url>https://maven.atlassian.com/repository/public</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<updatePolicy>never</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>atlassian-plugin-sdk</id>
<url>file://${env.ATLAS_HOME}/repository</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<properties>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</properties>
</profile>
La commande complète pour utiliser la nouvelle configuration maven est la suivante :
atlas-debug -gs ~/.m2/settings.xml -P JIRA
Dans les entreprises, il est courant d’avoir un repository maven permettant entre autre de :
On a besoin d’ajouter les repositories Atlassian dans le repository d’entreprise pour permettre à tous les développeurs d’avoir la même configuration et au Jenkins de fonctionner.
En fonction de la configuration du repository d’entreprise, on peut avoir l’erreur suivante sur la dépendance
<groupId>asm</groupId>
<artifactId>asm-all</artifactId>
<version>3.0</version>
Le log de l’erreur :
Failed to transfer file: http://dsi.eutelsat.fr/artifactory/repo
/asm/asm-all/20070324/asm-all-20070324.pom'. Return code is: 409 , Re
asonPhrase:Conflict. -> [Help 1]
Le problème vient du fait que le composant a pour version 20070324 dans le nom du fichier et non 3.0 . Il faut dans ce cas désactiver les vérifications sur les dépendances dans le repository d’entreprise. Pour Artifactory c’est l’option Suppress POM Consistency Check
Voici les explications d’Artifactory sur le sujet.
JIRA utilise avec beaucoup de succès la technologie OSGI pour installer à chaud (sans redémarrer le serveur) et isoler les plugins (classpath différent). Cette technologie offre aussi au développeur la possibilité de compiler et de redéployer le plugin sans redémarrer le serveur JIRA. Le temps de redéploiement sera alors entièrement dépendant de la taille du plugin.
Fastdev est activée quand on lance la commande atlas-debug.
Celui-ci permet de :
Cette fonctionnalité est présente dans une barre en bas du navigateur qu’il faut déplier :
Les fonctionnalités fastdev :
Problème rencontré :
J’ai eu le problème suivant sur le rechargement à chaud du plugin avec la version 5.0.13 de AMPS :
[INFO] Scanning for projects...
[WARNING] The POM for org.apache.maven.plugins:maven-compiler-plugin:jar:5.0.13 is missing, no dependency information available
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.759 s
[INFO] Finished at: 2015-06-05T16:47:07+01:00
[INFO] Final Memory: 13M/226M
[INFO] ------------------------------------------------------------------------
[ERROR] Plugin org.apache.maven.plugins:maven-compiler-plugin:5.0.13 or one of its dependencies could not be resolved: Failure to find org.apache.maven.plugins:maven-compiler-plugin:jar:5.0.13 in https://maven.atlassian.com/repository/public was cached in the local repository, resolution will not be reattempted until the update interval of atlassian-public has elapsed or updates are forced -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginResolutionException
Ma question et mon contournement sont disponibles ici
Les tests unitaires avec des mocks autour de l’API Jira sont relativement facile à mettre en place. Le code du plugin s’interface avec les APIs en utilisant la classe ComponentAccessor qui fournit le service. Mocker ComponentAccessor permettra d’intercepter les APIs que l’on veut simuler dans nos tests.
Les tests d’IHM “à la selenium” sont possible pour les plus courageux.
Les tests sur les interfaces métiers sont comme souvent les plus maintenables et pertinents surtout sur un plugin JIRA où l’objectif est de faire le moins de code possible en utilisant les APIs au maximum. Tester en simulant les APIs sera long, l’environnement de tests JIRA nous offre la possibilité de créer des tests métiers pertinents. Comment faire ?
Les services métiers du plugin doivent être déclarés dans un composant JIRA qui permettra de séparer le modèle de la vue (pattern MVC).
Dans le atlassian-plugin.xml, il faut ajouter le composant comme ceci :
<component key="AppsonicAgeAnalysisComponentComponent"
name="Appsonic aged balance component" i18n-name-key="appsonic-age-analysis-component.name"
class="com.appsonic.jira.ageAnalysis.component.AgeAnalysisComponentImpl" public="true">
<interface>com.appsonic.jira.ageAnalysis.component.AgeAnalysisComponent</interface>
</component>
les tests ressemblent alors à cela :
@RunWith(AtlassianPluginsTestRunner.class)
public class AgeAnalysisComponentWithFilterWiredTest {
private final AgeAnalysisComponent ageAnalysisComponent;
public AgeAnalysisComponentWithFilterWiredTest(AgeAnalysisComponent ageAnalysisComponent) {
this.ageAnalysisComponent = ageAnalysisComponent;
}
@Test
public void testGetWorkflowByIssue() throws SearchException {
Assert.assertFalse(ageAnalysisComponent.getWorkflowByIssue(null).isEmpty());
}
}
L’annotation @RunWith(AtlassianPluginsTestRunner.class) indique qu’on utilisera les tests fonctionnels dans un serveur JIRA. On peut exécuter le tutorial officiel pour se lancer.
Si on souhaite tester sur des projets JIRA contenant des demandes avec un workflow spécifique, par exemple, on peut injecter des données avant de lancer les tests de la façon suivante :
Le pom.xml ressemble à cela :
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jira-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<productDataPath>${basedir}/src/test/resources/generated-test-resources.zip</productDataPath>
<useFastdevCli>false</useFastdevCli>
<testGroups>
<testGroup>
<id>wired-integration</id>
<productIds>
<productId>jira</productId>
</productIds>
<includes>
<include>it/**/*WiredTest.java</include>
</includes>
</testGroup>
<testGroup>
<id>traditional-integration</id>
<productIds>
<productId>jira</productId>
</productIds>
<includes>
<include>it/**/*TrdTest.java</include>
</includes>
</testGroup>
</testGroups>
</configuration>
</plugin>
Pour exécuter des insertions en base, le mieux est de créer un projet sur chaque scenario. De cette façon les tests se lanceront à la suite, sans avoir à purger les données insérées (procédure de rollback)
Fastdev permet de voir le résultat des tests métiers et de les exécuter unitairement directement dans JIRA :
Voici la liste des tests avec une interface plutôt convainquante :
La commande atlas-debug ajoute automatiquement les paramètres permettant de prendre le contrôle de la JVM à distance.
Très pratique pour débuguer son code et les tests métiers dans un environnement JIRA avec son IDE préféré.
Ici la configuration avec intellij :
L’API JIRA est documentée à l’aide d’une javadoc.
Avoir le code source JIRA sera très vite indispensable après le “hello word” pour comprendre les APIs JIRA.
Jira n’est pas open source, les sources sont téléchargeables sur le compte “licence Atlassian” disponible uniquement pour les développeurs qui ont acheté la version de JIRA correspondante (pas disponible sur l’abonnement cloud de JIRA).
Impossible d’avoir le code source sans licence, même avec un petit mail sympa, Atlassian ne veut pas.
Pour que l’IDE java du développeur puisse voir les sources sans avoir à les attacher à la main, il faut remplir le repository maven local ou le repository d’entreprise en utilisant le script fournit dans le zip des sources.
Et on a encore du travail car il va falloir :
Le script va compiler tous les projets JIRA et associer les sources dans le repository maven local.
Il n’y aura plus qu’a faire “download source” dans l’IDE pour avoir les sources associées aux jars jira et recommencer l’opération à chaque nouvelle version de JIRA.
Problèmes rencontrés :
mvn install:install-file -DgroupId=javax.activation -DartifactId=activation -Dversion=1.0.2 -Dpackaging=jar -Dfile=activation-1.0.2.jar -Dmaven.repo.local=SOURCE_JIRA/atlassian-jira-6.4-m14-source/localrepo
Comme on peut le constater, cette opération est longue et fastidieuse, je n’inclus plus les sources dans mon projet JIRA depuis le dernier debugueur intellij qui est capable de rendre lisible le bytecode java (fabuleux outil au passage, bravo JetBrains). En revanche, j’ai toujours un projet jira sous le coude pour m’inspirer du code.
Comme vous avez pu le lire, écrire un add-on Jira n’est pas aussi simple qu’on pourrait le penser. N’hésitez pas à laisser un commentaire sur ce billet si vous avez besoin d’aide ou me contacter.
Et vous pouvez aussi tester mon plugin JIRA “balance agée” en mettant des étoiles sur le store, ça me fera plaisir :)
Antoine