Mit diesem Artikel stellen wir eine Lösung vor, mit der sich ein beliebiger Jenkins-Job starten lässt, sobald in JIRA eine neue Version freigegeben wird. Mit der Verknüpfung zwischen dem Release-Management in Jira und einem automatischen Deployment verbinden damit mehrere Vorteile:

  • die Release-Entscheidung obliegt dem Projektmanager
  • automatisches Deployment garantiert einen erfolgreichen Prozess bzw. einen definierten Abbruch im Fehlerfall
  • jedes Deployment wird zusammen mit den passenden Tickets in JIRA sauber dokumentiert

jira-release-buttonZum Einsatz kommen JIRA in der Version 6.4 und Jenkins in der Version 2.19. Die Lösung ist, soweit möglich mit dem neuen Pipeline Konzept von Jenkins umgesetzt. Dies erlaubt es den größten Teil der Konfiguration von Jenkins als Code in einem Source Code Repository (z. B. GIT) zu verwalten. Das ist deswegen erstrebenswert, weil so eine Historie der Konfiguration gespeichert wird und auch ähnliche Projekte schneller konfiguriert werden können, als über die Jenkins Web-UI.

Grundsätzlicher Ablauf

Zunächst wird beim Release einer neuen Version in JIRA ein Webhook auf eine bestimmte URL auf der Jenkinsinstanz aufgerufen. Dadurch wird ein zu erstellender Job (JIRA Release Job) ausgeführt, der detaillierte Daten zum JIRA Release und Project über die Web API abruft und aufgrund dieser Informationen entsprechende weitere Build-Jobs mit etwaigen Parametern starten kann. In der folgenden Abbildung ist der grundsätzliche Ablauf des Prozesses dargestellt:

Jira Webhook zum Starten eines Jenkins Builds

JIRA Webhook

Webhooks können bei JIRA als System Administrator unter dem Punkt „System“ -> „Advanced“ / „Erweitert“ -> WebHooks verwaltet werden. Über die Schaltfläche „Create a WebHook“ / „Einen Webhook erstellen“ oben rechts gelangt man zu einem umfangreichen Formular. Dort muss zuerst ein Name („Jenkins Release Version“) für den Webhook vergeben werden. Im URL-Feld wird ein Link nach folgendem Muster angegeben werden:

https://<user>:<password>@jenkins.example.com/buildByToken/buildWithParameters?job=jira-release-version&token=<TOKEN>&VERSION_ID=${version.id}&PROJECT_ID=${project.id}

webhooks-in-jiraDabei muss neben Benutzername und Passwort für die Basic Authentication Methode und der Domain zu Jenkins auch der TOKEN ersetzt werden. TOKEN ist ein zu erstellender zufälliger String der sicherstellen soll, dass Jobs nur durch autorisierte Systeme gestartet werden können. Die Autorisierung ist dahingehend redundant, da durch die nötige Benutzerauthentifizierung sowieso verhindert wird, dass Unbefugte Jobs starten können. Es scheint jedoch keine andere Möglichkeit zu geben, einen Jenkins-Job von außen zu starten, ohne ein Sicherheitstoken anzugeben.

Der job-Parameter der URL legt den Build-Job fest der durch den Aufruf angestoßen wird. Der Wert muss entsprechend angepasst werden, falls im weiteren Verlauf der Name des Jenkins-Jobs anders gewählt wird. Die verbleibenden zwei Parameter VERSION_ID und PROJEKT_ID enthalten Platzhalter, die von JIRA beim Veröffentlichen einer Version beim Aufruf des Webhooks mit den entsprechenden Werten ersetzt werden.

Unter der Überschrift „Ereignisse“ / „Events“ befindet sich eine Reihe von Checkboxen, die den Auslösezeitpunkt des Webhooks festlegen. Dort muss unter „Projetbezogene Ereignisse“ / „Project related events“ -> „Version“ der Punkt „veröffentlicht“ / „released“ angeklickt werden.

Nicht in die Irre treiben lassen darf man sich durch die Filterbox unter der Überschrift „Vorgangsbezogene Ereignisse“ / „Issue related events“. Dort können JQL (JIRA Query Language) Filter-Ausdrücke eingetragen werden, die das Auslösen des Webhooks auf z.B. bestimmte Projekte begrenzen. Leider haben diese JQL-Ausdrücke bei projektbezogenen Ereignissen keine Wirkung. Dies ist einer der Hauptgründe, warum im Verlauf des Artikels ein expliziter Dispatch-Job in Jenkins angelegt wird, der dann die eigentlichen Build-Jobs auslöst.

Nachdem alle Einstellungen festgelegt sind, wird der Webhook in JIRA abschließend gespeichert.

JIRA Release Job

Der zweite wesentliche Teil ist der JIRA Release Job, der in Jenkins konfiguriert wird.

Bevor hier ins Detail gegangen wird, müssen folgende Jenkins-Plugins installiert werden;

  • HTTP Request Plugin (v 1.8.12)
  • Build Authorization Token Root Plugin (v 1.4)

Als nächstes muss ein neuer Pipeline Job angelegt werden. Der gewählte Name ist in diesem Beispiel „jira-release-version“. Falls ein anderer gewählt werden soll, muss entsprechend der Parameter job in der Webhook URL im vorangegangenen Abschnitt angepasst werden. Neben dem Groovy-Build-Script muss manuell auch noch der Build-Trigger eingestellt werden. Dieser befindet sich im Abschnitt „Build Triggers“ und heißt „Builds von außerhalb starten (z.B. skriptgesteuert)“. Nach dem Anklicken der Checkbox ist noch der Authentifizierungstoken einzutragen. Dieser muss identisch mit dem in Wert TOKEN aus dem vorherigen Abschnitt sein.

import groovy.json.JsonOutput

import groovy.json.JsonSlurperClassic

properties([parameters([string(defaultValue: '', description: 'Version ID from JIRA', name: 'VERSION_ID'), string(defaultValue: '', description: 'Project ID from JIRA', name: 'PROJECT_ID')]), pipelineTriggers([])])

node {

stage ('Get Version Name') {

echo "JIRA version id: ${env.VERSION_ID}"

def versionResponse = httpRequest authentication: 'Jenkins Crowd User', url: "https://jira.example.de/rest/api/2/version/${env.VERSION_ID}", validResponseCodes: '200'

echo JsonOutput.prettyPrint(versionResponse.content)

env.VERSION_NAME = new JsonSlurperClassic().parseText(versionResponse.content)["name"]

echo "JIRA version name: ${env.VERSION_NAME}"

}

stage ('Get Project Name and Key') {

echo "JIRA project id: ${env.PROJECT_ID}"

def projectResponse = httpRequest authentication: 'Jenkins Crowd User', url: "https://jira.example.de/rest/api/2/project/${env.PROJECT_ID}", validResponseCodes: '200'

echo JsonOutput.prettyPrint(projectResponse.content)

env.PROJECT_NAME = new JsonSlurperClassic().parseText(projectResponse.content)["name"]

env.PROJECT_KEY = new JsonSlurperClassic().parseText(projectResponse.content)["key"]

echo "JIRA project name: ${env.PROJECT_NAME}"

echo "JIRA project key: ${env.PROJECT_KEY}"

}

stage ('Start Project') {

if ('TEST' == env.PROJECT_KEY) {

build job: 'test-version-script', parameters: [string(name: 'VERSION_NAME', value: env.VERSION_NAME)], wait: false

}

}

}


Das Build Skript aus dem Listing startet mit zwei Import-Anweisungen. Diese werden benötigt um JSON zu verarbeiten, das im Verlauf des Jobs geparst und ausgegeben wird. Die folgende Properties- Anweisung konfiguriert zwei Buildparameter, VERSION_ID und PROJECT_ID, die vom Webhook beim Aufruf befüllt werden.

Die ersten beiden Stages des Scripts haben einen ähnlichen Aufbau. Mit den numerischen Werten, die mit den Parameter VERSION_ID und PROJECT_ID dem Jenkins-Job übergeben werden, kann die API von JIRA abgefragt werden und somit unter anderem der Versionsname an nachfolgende Build-Jobs übergeben werden sowie der Projekt-Schlüssel als einfaches Unterscheidungskriterium für die Selektion des nachfolgenden Build-Jobs bestimmt werden. Zwar werden mit dem Webhook der mittels POST an Jenkins geschickt wird auch ein JSON Body übertragen, dem Autor ist jedoch kein Weg bekannt diesen innerhalb des Builds auszulesen. Daher wurde der Weg gewählt, die JIRA API anzufragen.

Der Eintrag für den authentication Parameter der httpRequest Methode muss zuvor in der globalen Jenkinskonfiguration unter dem Abschnitt „Http Request“ -> „Basic/Digest Authentication“ eingestellt werden. Über den Parameter validResponseCodes lassen sich die HTTP Request Codes einschränken, die der Build als erfolgreiche akzeptiert. In diesem Fall scheint eine Einschränkung auf 200 OK sinnvoll. Die abgefragten Werte werden nach dem Parsing zu den Umgebungsvariablen des Jobs hinzugefügt (VERSION_NAME, PROJECT_KEY, PROJECT_NAME).

Die letzte Job-Stage verwendet die zuvor abgefragten Werte und entscheidet anhand des unveränderlichen JIRA Projektschlüssel welcher Folgebuild angestoßen werden soll. Eine Übergabe von Parametern ist dabei möglich

Der wait Parameter des build Befehls legt fest, ob Jenkins auf das Ergebnis des nachfolgenden Builds warten soll und dessen Buildstatus in den Build mit einbinden soll oder den Build lediglich anstößt. Aus unserer Sicht soll sich jedoch der Dispatch-Job den angestoßenen Build nicht zu Eigen machen und daher nicht auf seine Beendigung warten.

Fazit

Für die eigentlich einfach erscheinende Aufgabe einen bestimmten Jenkins-Job beim Freigeben einer Version in JIRA anzustoßen, wird durch einige Stolpersteine in JIRA und Jenkins und dessen Plugins schnell ein komplexer Prozess. Dieser Artikel hat einen Weg aufgezeigt, wie sich die Klippen umschiffen lassen und damit das gewünschte Ergebnis erzielen lässt.

Über den Autor