Technik

Veröffentlicht am 2. Oktober 2020

Listener mit Scriptrunner für Jira

In diesem Beitrag möchte ich euch anhand eines kleinen Beispiels für eine Automatisierung die Funktionsweise eines benutzerdefinierten Listener in Scriptrunner für Jira näher bringen. Zusätzlich zu den aus Jira bereits bekannten Funktionalitäten, wie z.B. Postfunctions, können Listener ereignisgesteuert sowohl mitgelieferte, vordefinierte Funktionen als auch komplett selbstdefinierte Aufgaben automatisiert ausgeführt werden.

Die Aufgabe

Für diesen Beitrag stellen wir uns vor, dass die Projektleitung eines Software-Projektes die Anforderung gestellt hat, dass für Vorgänge automatisch ein Fälligkeitsdatum in 2 Tagen ab heute gesetzt wird, sobald die Priorität auf die höchste Stufe gesetzt wird. Dies sollen und wollen wir mit Scriptrunner für Jira umsetzen.

Hierzu implementieren wir einen Listener, der immer dann reagiert, wenn ein Vorgang aktualisiert wird. Dieser Listener muss dann folgendes abarbeiten:

Listener in Scriptrunner

Wir erreichen Scriptrunner wie immer über einen Klick auf das Einstellungssymbol rechts oben auf jeder Seite in Jira und einen anschließenden Klick auf „Apps verwalten“.

Hier wählen wir den Eintrag „Listeners“ aus

Auf der rechten Seite sehen wir nun diverse Listener-Typen zur Auswahl.

Die meisten dieser Listener sind vordefiniert und von Scriptrunner mitgeliefert. Diese können für typische Aufgaben verwendet und meist auch den persönlichen Bedürfnissen anpassbare Aufgaben erledigen.

Für unsere Aufgabe wollen wir einen eigenen, neuen Listener implementieren, also wählen wir den obersten Punkt „Custom listener“ aus.

Basiskonfiguration des Listeners

Nun sehen wir die Basis-Eingabemaske eines Listener.

BezeichnungFunktion
NoteHier können und sollten wir den Listener näher beschreiben. Das ist wichtig, um später in der Auflistung aller Listener im System den gesuchten leichter wiederzufinden.
Project(s)Hier müssen wir auswählen, in welchen Projekten der Listender aktiv ist.
EventsHier definieren wir, bei welchen Events der Listener aktiv werden soll.
ScriptHier werden wir später den Groovy-Code für den Listener implementieren. Alternativ kann auch eine Datei angegeben werden, welche den Code enthält.

Anmerkung zum Link „Show snippets“:

Ein Klick öffnet eine scrollbare Liste, die per Mausklick vorgefertigte Code-Snippets in die Script-Box einfügt, um die Erstellung von Scripten zu vereinfachen. Wir werden das für unser Script nicht benutzen.

Zuerst werden wir nun die Basisdaten unseres Scriptes eingeben und auswählen:

Wichtig ist hier neben der korrekten Angabe des oder der Projekte, in denen der Listener aktiv sein soll, vor allem die korrekte Auswahl des oder der Events, bei denen der Listener ausgeführt wird. In unserem Fall das Event „Issue Updated“, welche beim Aktualisieren eines Vorganges ausgelöst wird.

Im nächsten Schritt machen wir uns an die Implementierung der eigentlichen Logik.

Das Script für den Listener

Nötige Bausteine

Im eigentlichen Script machen wir uns an die Abarbeitung der einzelnen Schritte aus dem Flussdiagramm.

Zunächst prüfen wir, ob die aktuelle Änderung des Vorganges eine Änderung der Priorität beinhaltet.

event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "priority"}

Inhaltlich wird in die im Event (in unserem Falle „Issue Updated“) nachgesehen, ob in der Liste der geänderten Felder das Feld „priority“ (Priorität) enthalten ist.

Gab es eine Änderung der Priorität, liefert der Ausdruck den Wert TRUE zurück.

Im nächsten Schritt überprüfen wir, ob die Priorität den höchsten Wert hat. Hier ist zu beachten, hierzu holen wir uns den Vorgang in der Form „MutableIssue“, in der wir ihn auch bearbeiten können. Dies ist notwendig, um auch Systemfelder per Script ändern zu können. Danach greifen wir auf das Feld der Priorität zu:

MutableIssue mutableIssue = issue
def priorityField = mutableIssue.priority.name

Nun können wir überprüfen, ob die Priorität die höchste ist:

if (priorityField.equals("Highest"))

Somit haben wir an dieser Stelle alle Informationen, die wir benötigen, um zu wissen ob wir das Fälligkeitsdatum anpassen müssen.

Nun benötigen wir noch die Änderung des Fälligkeitsdatums. Hierzu erzeugen wir einfach einen Wert vom Typ Calendar, in welchem wir einfach zum aktuellen Datum zwei Tage hinzuaddieren:

Calendar newDueDate = Calendar.getInstance()
newDueDate.setTime (new Date())
newDueDate.add(Calendar.DATE, 2)

Abschließend können wir das neue Fälligkeitsdatum setzen und diese Änderung speichern. Hierbei ist zu beachten, dass das Systemfeld „DueDate“ (Fälligeitsdatum) am einfachsten im Java-Format „Timestamp“ geschrieben werden kann:

def dueTimestamp = new Timestamp(newDueDate.getTimeInMillis())    
mutableIssue.setDueDate(dueTimestamp)

Die Speicherung des neuen Fälligkeitsdatums erfolgt über folgenden Aufruf:

issueManager.updateIssue(user, mutableIssue, EventDispatchOption.DO_NOT_DISPATCH, false)

Wichtig hierbei ist, dass Die EventDisptachOption „DO_NOT_DISPATCH“ genutzt wird, da sonst wiederum ein neuer Event vom Typ „Issue Updated“ ausgelöst wird, der an dieser Stelle nicht mehr notwendig ist.

Vollständiges Script

Hier folgt nun das vollständige Script für unseren Listener:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue
import java.sql.Timestamp
//Definition Basis-Parameter
def issueManager = ComponentAccessor.getIssueManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
// Fälligkeitsdatum geändert?
def change = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == "priority"}
// bei Änderung weiterer Ablauf
if (change) {
    // hole den änderbaren Vorgang und das Prioritätsfeld
    MutableIssue mutableIssue = issue
    def priorityField = mutableIssue.priority.name
    // höchste Priorität gesetzt?
    if (priorityField.equals("Highest")) {
        // neues Fälligkeitsdatum berechnen
        Calendar newDueDate = Calendar.getInstance()
        newDueDate.setTime(new Date())
        newDueDate.add(Calendar.DATE, 2)
        // neues Fälligkeitdatum setzen
    	def dueTimestamp = new Timestamp(newDueDate.getTimeInMillis())    
    	mutableIssue.setDueDate(dueTimestamp)
    	// Änderungen am Vorgang speichern
    	issueManager.updateIssue(user, mutableIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
    }
}

Fertiger Listener

Mit einem Klick auf „Add“ wird der Listener nun gespeichert und ist in der Listen-Ansicht der Scriptrunner-Listener verfügbar.

In der Listenansicht werden die Listener primär mit der Bezeichnung Ihres Typs angezeigt. Hier könnt Ihr nun sehen, warum das Ausfüllen des Feldes „Note“ beim Listener so wichtig ist. Außerdem ist auf den ersten Blick ersichtlich, für welche Projekte der Listener konfiguriert wurde und Ihr bekommt einen Überblick in die Historie der letzten Ausführungen.

Über die Schaltfläche „Aktion“ hat Ihr zudem die Möglichkeit, den Listener zu bearbeiten, zu deaktivieren oder zu löschen.

Was du noch wissen musst

Beachtet bitte, dass der erstellte Listender nur auf Aktualisierungen eines Vorganges reagiert. Soll die ursprüngliche Anforderung z.B. schon bei der initialen Erstellung eines Vorganges greifen, so könnte hierfür entweder ein eigener Listener per Scriptrunner erstellt werden oder man bedient sich der Funktionalität einer Postfunction. Hierzu wird es in zukünftigen Blog-Beiträgen bei uns weitere Informationen geben.


Hat Euch dieser Beitrag gefallen? Habt Ihr Anregungen oder Kritik? Hinterlasst uns einen Kommentar.


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Weitere Themen