Herunterladen - Atlassian User Group München

Werbung
Entwicklung eines JIRA Gadgets
Ein generisches
Balkendiagramm
15.09.2011, Atlassian User Group
Leo von Klenze, Alexander Arth
1
Motivation
JIRA Überblick
JIRA für das Beschwerdemanagement
Auswertungen mit JIRA
2
Entwicklung von Gadgets
3
Komponenten eines JIRA Gadgets
Definition des Plugins: atlassian-plugin.xml
Definition des Gadgets: gadget.xml
Nutzen der REST API
4
Testen des Plugins und Validierung
Automatisierte Tests
Validierung von Benutzereingaben
5
Das fertige Balkendiagramm Plugin
6
Zum Schluss
Motivation
Motivation
JIRA Überblick
Motivation
JIRA Überblick
�
Bugtracker von Atlassian (http://www.atlassian.com/JIRA)
�
�
Einfach zu bedienen (für den Benutzer)
�
Umfangreich zu konfigurieren (seit 4.4 etwas übersichtlicher �)
Motivation
JIRA für das Beschwerdemanagement
�
Eigener Workflow
�
Eigene Felder (Eigenschaften eines Tickets)
�
Verwendung im Fachbereich
�
Auswertungen notwendig
In diesem Fall über Eingangsmonat und Herkunft
Motivation
Auswertungen mit JIRA
�
Auswertungen basieren auf Filtern
Auswahl von Tickets mit bestimmten Eigenschaften
�
Verschiedene visuelle Darstellungen von Filtern möglich
Motivation
Auswertungen mit JIRA
�
Auswertungen basieren auf Filtern
Auswahl von Tickets mit bestimmten Eigenschaften
�
Verschiedene visuelle Darstellungen von Filtern möglich
Motivation
Auswertungen mit JIRA
�
Auswertungen basieren auf Filtern
Auswahl von Tickets mit bestimmten Eigenschaften
�
Verschiedene visuelle Darstellungen von Filtern möglich
Motivation
Ziel der Auswertung
Motivation
Ziel der Auswertung
Motivation
Berichte vs. Gadgets
�
Es gibt in JIRA sogenannte Berichte zur Auswertung
�
Allerdings nur wenige vordefinierte Berichte
�
Konfiguration muss jedesmal neu ausgewählt werden (Filter/Typ)
�
Gute Druckansicht
Motivation
Berichte vs. Gadgets
�
Gadgets sind sofort auf der Startseite sichtbar
�
Pro Startseite sind mehrere Gadgets möglich
�
Gadgets merken sich ihre Konfiguration
�
Zur Zeit keine gute “out-of-the-box”-Druckansicht
Motivation
Auswertungen mit Gadgets
�
Knapp 30 vordefinierte Gadgets
�
Nur wenige Gadgets, die Auswertungen auf eigenen Feldern ermöglichen
�
Problem: oft an spezielle JIRA-Felder gebunden, z.B. “Erstellt vs. Erledigt”
�
In diesem Fall benötigt: gestapeltes Balkendiagramm (Monat, Herkunft)
Lösung: eigenes Gadget entwickeln �
Entwicklung von Gadgets
Entwicklung von Gadgets
Allgemeine Vorteile von Gadgets
�
Sofortige Präsenz auf Startseite
�
Anpassbarkeit
�
Interaktivität
�
Cross Plattform Einsetzbarkeit (⇒ Open Social Api)
Entwicklung von Gadgets
Tools, Techniken und Sprachen
�
Build Tools (Maven)
�
Konfiguration: XML
�
Frontend: HTML, CSS
�
Backend: JavaScript, AJAX, Java
Komponenten eines JIRA Gadgets
Komponenten eines JIRA Gadgets
atlassian-plugin.xml
�
Plugin Beschreibung
�
Definition von Plugin Komponenten
Komponenten eines JIRA Gadgets
atlassian-plugin.xml
�
Plugin Beschreibung
�
Definition von Plugin Komponenten
<g a d g e t key=” b a r c h a r t ” l o c a t i o n= ”com/ t n g t e c h / j i r a / p l u g i n s /
g a d g e t / b a r c h a r t −g a d g e t . xml ” />
< r e s t key=” r e s t −r e s o u r c e s ” p at h=” / j i r a −r e s t ” v e r s i o n=” 1 . 0 ”>
< d e s c r i p t i o n> S t e l l t d i e nö t i g e n REST R e s o u r c e n f ü r d a s
Gadget b e r e i t</ d e s c r i p t i o n>
</ r e s t>
Komponenten eines JIRA Gadgets
Aufbau der gadget.xml
�
Allgemeine Beschreibung des Gadgets
�
Benötigte Module
�
User Authentifizierung
�
Einstellungsvariablen
�
HTML und JavaScript Code für zwei Ansichten
–
Konfiguration → Descriptor
–
Ergebnisansicht → View
Komponenten eines JIRA Gadgets
Aufbau der gadget.xml
�
Allgemeine Beschreibung des Gadgets
�
Benötigte Module
�
User Authentifizierung
�
Einstellungsvariablen
�
HTML und JavaScript Code für zwei Ansichten
–
Konfiguration → Descriptor
–
Ergebnisansicht → View
⇒ Funktionierendes Beispiel aus Vorlage ist sinnvoll. Tutorials von Atlassian
funktionieren nicht mehr richtig mit aktuellen Versionen!
Komponenten eines JIRA Gadgets
Aufbau der gadget.xml [1]
<Module>
<M o d u l e P r e f s t i t l e =” B a l k e n d i a g r a m m ” a u t h o r=”TNG”
d e s c r i p t i o n=” E i n g e n e r i s c h e s B a l k e n d i a g r a m m . ”>
<R e q u i r e f e a t u r e=” o a u t h p o p u p ” />
....
#o a u t h
</ M o d u l e P r e f s>
<U s e r P r e f name=” i s C o n f i g u r e d ” d a t a t y p e=” h i d d e n ”
d e f a u l t v a l u e=” f a l s e ” />
....
<Content t y p e=” h t m l ”><! [CDATA[
#r e q u i r e R e s o u r c e ( ” com . a t l a s s i a n . g a d g e t s . p u b l i s h e r : a j s −
gadgets ”)
....
#i n c l u d e R e s o u r c e s ( )
Komponenten eines JIRA Gadgets
Aufbau der gadget.xml [2]
< s c r i p t t y p e=” t e x t / j a v a s c r i p t ”>
( function () {
v a r g a d g e t = AJS . Gadget ( {
b a s e U r l : ” ATLASSIAN BASE URL ” ,
u se Oa ut h : ”/ r e s t / g a d g e t / 1 . 0 / c u r r e n t U s e r ” ,
config : { descriptor : function ( args ) { . . . . } } ,
view : { template : function ( args ) { . . . . } }
}) ;
}) ( ) ;
</ s c r i p t >
]] >
</Content>
</Module>
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: descriptor [1]
descriptor : function ( args ) {
v a r p r o j e c t O r F i l t e r P i c k e r = AJS . t h i s . f i e l d s .
projectOrFilterPicker ( this , ” p r oj ect O r F ilt e r Id ” , args .
options ) ;
return { f i e l d s : [
projectOrFilterPicker ,
{
userpref : ” axisField ”,
l a b e l : ” x−Achse : ” ,
d e s c r i p t i o n : ” F e l d f ü r Werte d e r x−Achse . ” ,
type : ” s e l e c t ” ,
s e l e c t e d : t h i s . g e t P r e f (” a x i s F i e l d ”) ,
options : args . a x i s F i e l d . fieldNames
},
AJS . t h i s . f i e l d s . n o w C o n f i g u r e d ( )
] };
},
....
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: Möglichkeiten
�
Vorgefertigte Konfigurationsfelder, z.B. projectOrFilterPicker
�
Selbstgebaute Optionen aus Standardtypen, z.B. type=“select“
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: Möglichkeiten
�
Vorgefertigte Konfigurationsfelder, z.B. projectOrFilterPicker
�
Selbstgebaute Optionen aus Standardtypen, z.B. type=“select“
Vor- und Nachteile
�
Es gibt keine Seite mit allen Möglichkeiten
�
Einheitliche Namensgebung ermöglicht erfolgreiches Raten,
z.B. filterPicker oder type=“text“
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: Möglichkeiten
�
Vorgefertigte Konfigurationsfelder, z.B. projectOrFilterPicker
�
Selbstgebaute Optionen aus Standardtypen, z.B. type=“select“
Vor- und Nachteile
�
Es gibt keine Seite mit allen Möglichkeiten
�
Einheitliche Namensgebung ermöglicht erfolgreiches Raten,
z.B. filterPicker oder type=“text“
�
Erzeugter HTML Code nicht perfekt → Checkbox geht im IE nicht!
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: descriptor [2]
descriptor : function ( args ) {
....
,
args : [{
key : ” a x i s F i e l d ” ,
ajaxOptions : function () {
return {
u r l : ”/ r e s t / j i r a −r e s t / 1 . 0 / B a r C h a r t C o n f i g u r a t i o n /
LookupCustomFields ”
};
}
}]
}
Komponenten eines JIRA Gadgets
Gadgetkonfiguration: descriptor [2]
descriptor : function ( args ) {
....
,
args : [{
key : ” a x i s F i e l d ” ,
ajaxOptions : function () {
return {
u r l : ”/ r e s t / j i r a −r e s t / 1 . 0 / B a r C h a r t C o n f i g u r a t i o n /
LookupCustomFields ”
};
}
}]
}
View wird analog definiert und modifiziert DOM direkt
Komponenten eines JIRA Gadgets
Java-REST-Klasse
@Path ( ” / B a r C h a r t C o n f i g u r a t i o n ” )
@ P r o d u c e s ( { MediaType . APPLICATION JSON } )
public class BarChartGadgetConfiguration {
public BarChartGadgetConfiguration (
J i r a A u t h e n t i c a t i o n C o n t e x t jAC , . . . . ) { . . . . }
@GET
@Path ( ” / L o o k u p C u s t o m F i e l d s ” )
p u b l i c Response lookupCustomFieldNames ( ) {
try {
F i e l d L i s t f i e l d L i s t = getFieldList () ;
r e t u r n R e s p o n s e . ok ( f i e l d L i s t ) . b u i l d ( ) ;
}
catch ( RuntimeException e ) {
r e t u r n Response . s e r v e r E r r o r ( ) . b u i l d ( ) ;
}
}
....
}
Komponenten eines JIRA Gadgets
FieldList-Klasse
�
Objekt in Response beliebig
Komponenten eines JIRA Gadgets
FieldList-Klasse
�
Objekt in Response beliebig
�
Muss aber in Klassendefinition annotiert sein!
�
⇒ Einfache Response Objekte wie Response.ok(”Hello World”) funktionieren
nicht!
Komponenten eines JIRA Gadgets
FieldList-Klasse
�
Objekt in Response beliebig
�
Muss aber in Klassendefinition annotiert sein!
�
⇒ Einfache Response Objekte wie Response.ok(”Hello World”) funktionieren
nicht!
@XmlRootElement
public class FieldList {
@XmlElement
p u b l i c L i s t <Map<S t r i n g , S t r i n g >> f i e l d N a m e s ;
p u b l i c F i e l d L i s t (Map<Long , S t r i n g > f i e l d I n f o s ) {
// f i e l d N a m e s b e f ü l l e n
}
}
Komponenten eines JIRA Gadgets
Stolpersteine im Java Code
�
Exceptions im Java Code
⇒ Try Catch um Rest Aufruf und Response.serverError()
Komponenten eines JIRA Gadgets
Stolpersteine im Java Code
�
Exceptions im Java Code
⇒ Try Catch um Rest Aufruf und Response.serverError()
�
Rest Klassen werden als Singleton instanziiert
⇒ Threadsafe programmieren! (ThreadLocal)
Komponenten eines JIRA Gadgets
Stolpersteine im Java Code
�
Exceptions im Java Code
⇒ Try Catch um Rest Aufruf und Response.serverError()
�
Rest Klassen werden als Singleton instanziiert
⇒ Threadsafe programmieren! (ThreadLocal)
�
Standardeinstellung bzgl. Caching der REST Aufrufe varriiert
⇒ new CacheControl().setNoCache(true) an Response anhängen
Testen des Plugins und Validierung
Testen des Plugins und Validierung
Unit- und Integrationstests
�
Testing Framework: JUnit
�
Mocking Framework: Mockito
�
Momentan 88 Unit Tests und 1 Integrations Test (Stand 15.9.)
�
Automatisiertes Laden der Testdaten für manuelles Testen der GUI
Testen des Plugins und Validierung
Wieso nur 1 Integrationstest?
�
Code Design: Code Coverage durch Unit Tests ca 71%
�
JIRA API bietet FuncTestCase Klasse als GUI Tester
�
Problem: Gadgets liegen in iFrames ⇒ DOM versteckt
Testen des Plugins und Validierung
Wieso nur 1 Integrationstest?
�
Code Design: Code Coverage durch Unit Tests ca 71%
�
JIRA API bietet FuncTestCase Klasse als GUI Tester
�
Problem: Gadgets liegen in iFrames ⇒ DOM versteckt
�
Mocken der kompletten JIRA-API komplex, aber möglich
⇒ Erstellen einer Klasse JiraUtils, die durchgereicht wird und als einzige
Schnittstelle zur Jira API dient
Testen des Plugins und Validierung
Validierung von Benutzereingaben
Javascript:
�
Validierung von Texteingaben
Testen des Plugins und Validierung
Validierung von Benutzereingaben
Javascript:
�
Validierung von Texteingaben
Java:
�
Setzen einer Flag, wenn die Konfiguration geändert wird
�
Weitergeben von Flag und User Input an Java-Klasse
�
Validierung z.B. ob gewähltes Custom Field korrekt unterstützt wird
�
Behandlung der Ergebnisse über window.alert()
Das fertige Balkendiagramm Plugin
Das fertige Balkendiagramm Plugin
Konfiguration
Das fertige Balkendiagramm Plugin
Das Balkendiagramm
Zum Schluss
Hinweise
�
Atlassian JIRA: http://www.atlassian.com/software/jira/
�
Dashboard einrichten: http://confluence.atlassian.com/display/
JIRA/Customising+the+Dashboard
�
JIRA Developer Documentation (Atlassian SDK, Plugin Guide, . . . )
http://confluence.atlassian.com/display/JIRADEV/JIRA+
Developer+Documentation
�
Das Plugin wird gerade im Atlassian-Plugin-Exchange veröffentlicht
Vielen Dank für die Aufmerksamkeit!
Herunterladen