Entwicklung eines JIRA Gadgets Ein generisches Balkendiagramm
Transcrição
Entwicklung eines JIRA Gadgets Ein generisches Balkendiagramm
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!