Mit Shared Libraries lassen sich die Funktionen von Jenkins einfach erweitern. In diesem Artikel zeige ich euch, wie ihr eine Shared Library erstellen, einbinden und aufrufen könnt.

Für die Durchführung braucht ihr Jenkins. Wie ihr Jenkins installiert und einrichtet, könnt ihr hier nachschlagen.

Vorbereitung

Das Projekt erstellen

Eine Shared Library benötigt folgende Ordnerstruktur:

./
- resources/
- src/
- vars/

Der Ordner src sollte wie ein standard Java-Quellcodeverzeichnis aussehen. Der Pfad zu den hier hinterlegten Klassen wird in der Pipeline eingebunden.

resources steht für zusätzliche Resourcen zur Verfügung. Dies können beispielsweise Textdateien sein, welche Konstanten oder Standardtexte bereitstellen.

In vars werden die Groovy-Scripte hinterlegt. Diese Scripte werden mit dem Dateinamen und der Funktion aufgerufen. Das sehen wir uns gleich etwas genauer an.

Ein Script erstellen

Als Beispiel möchten wir eine Funktion erstellen, um eine E-Mail zu senden.

Hierfür legen wir die Datei mailhelper.groovy an. Der Name ist frei definierbar. Ihr könnt die Datei auch mail.groovy oder notification.groovy nennen. Der Name wird beim Aufrufen wichtig (siehe weiter unten).

Die Scripts werden in Groovy geschrieben. Somit muss auch die Groovy-Syntax verwendet werden. Eine Funktion sieht folgendermaßen aus:

def sendMessage(subject, message) {
  emailext recipientProviders: [developers()], 
           subject: "Jenkins - ${subject}",
           body: "${message}"
}

def sendMessage(subject, message) ist die Methodensignatur. Die Methode heißt sendMessage und wird mit zwei Parametern aufgerufen. emailext ist ein Plugin für Jenkins, welche den Versand von E-Mails unterstützt. Für den Betreff und Inhalt der E-Mail übergeben wir die Parameter der Funktion.

Hinweis: Damit der Versand korrekt funktioniert, müsst ihr das Plugin vorher konfigurieren (Jenkins verwalten > System konfigurieren > Extended E-mail Notification).

Wenn ihr eine Hilfedatei anlegt (hier: mailhelper.txt) wird euch diese auch in der Weboberfläche angezeigt. Die Datei muss immer auf .txt enden. Ihr könnt HTML-Tags verwenden, um den Inhalt zu formatieren.

Anzeigen der Syntaxhilfe in Jenkins

Das Beispielprojekt sollte in etwa folgendermaßen aussehen:

Ordnerstruktur des Beispielprojekts

Bereitstellen der Bibliothek

Um diese Bibliothek bereitzustellen, empfehle ich euch ein Git-Repository einzurichten. Dieses Repository muss von Jenkins erreichbar sein.
Da Git sehr weit verbreitet ist und viele bereits damit arbeiten gehe ich nicht genauer auf die Erstellung eines Repositories ein.

Ich verwende für mein Beispiel Github. Andere Anbieter wie Gitlab, Bitbucket oder ein Dateiverzeichnis kann verwendet werden.

Bibliothek einbinden

Jenkins konfigurieren

Zuerst müssen wir diese Bibliothek dem Buildserver bekannt machen. Hierzu öffnen wir die Einstellungen (Jenkins verwalten > System konfigurieren) und scrollen bis zum Eintrag von Global Pipeline Libraries.

Es sind nur wenige Einstellungen wichtig. Zum einen der Name. Unter diesem wird die Bibliothek in der Pipeline geladen.

Zudem kann eine Standardversion (Default version) ausgewählt werden. In meinem Fall steht dort ‚master‘, damit ich immer die aktuellste Version der Bibliothek verwende, sofern die Pipelines diese Version nicht überschreiben.
Diese Einstellung kann mit dem Haken ‚Allow default version to be overridden‘ geändert werden.

Weiter unten geben wir den Pfad zum Git-Repository an. Dies entspricht dem Pfad, den wir selbst für „git clone“ verwenden.

Verwenden in der Pipeline

Zuerst müssen wir die Bibliothek einbinden. Es gibt in den Einstellungen einen Haken für ‚Load implicitly‘. Dadurch wird die Bibliothek automatisch eingebunden.

Ich bin kein Fan davon, Abhängigkeiten zu verschleiern. Falls das Jenkinsfile auf einem neuen Buildserver ausgeführt wird, kann es lange dauern den Fehler zu finden. Vor allem bei komplexen Konfigurationen wird es schwierig den Fehler zu identifizieren.

Mit Hilfe von @Library('Name-der-Bibliothek') _ binden wir die Bibliothek in die Pipeline ein.

Wichtig: Der Name-der-Bibliothek muss identisch mit dem Namen sein, welcher in den Einstellungen definiert wurde. In meinem Fall ist es mbedded-default.

Bei einer Declarative Pipeline (siehe Codebeispiel weiter unten) brauchen wir einen script-Block, um die Funktion auszuführen. Bei einer Scripted Pipeline ist der Block nicht notwendig.

Folgendermaßen kann eine Pipeline aussehen, um eine E-Mail während eines bestimmten Schrittes zu senden:

@Library('mbedded-default') _
pipeline {
  agent any

  stages {
    stage ('Build') {
      steps {
        echo 'Build'
      }
    } 
    stage ('Test') {
      steps {
        echo 'Test'
        script {
          mailhelper.sendMessage('Test', 'Test wurde ausgeführt.')
        }
      }
    } 
  }
}

Der Post-Block bietet sich an, um Benachrichtigungen zu senden. Dieser wird ausgeführt, wenn der Build abgeschlossen wurde. Je nach Zustand (success, failure, etc). können verschiedene Aktionen zum Abschluss ausgeführt werden.

Eine Benachrichtigung bei erfolgreichem oder fehlerhaften Abschluss kann folgendermaßen aussehen:

@Library('mbedded-default') _
pipeline {
  agent any

  stages {
    stage ('Build') {
      steps {
        echo 'Build'
      }
    } 
    stage ('Test') {
      steps {
        echo 'Test'
      }
    } 
  }
  post {
    success {
      script {
        mailhelper.sendMessage('Build erfolgreich', 'Build wurde erfolgreich abgeschlossen.')
      }
    }
    failure {
      script {
        mailhelper.sendMessage('Build abgebrochen', 'Build wurde fehlerhaft beendet.')
      }
    }
  }
}

Hier wurde der Script unter post > success bzw. post > failure eingebunden. Dies hat zur Folge, dass das Ergebnis der Ausführung per Mail an die entsprechenden Entwickler gesendet wird.

Hinweis: Die Parameter (subject und message) dürfen nicht per Namen angegeben werden. Folgender Aufruf erzeugt einen Syntaxfehler und funktioniert nicht:

script {
  mailhelper.sendMessage(subject: 'Mein Betreff', message: 'Meine Nachricht')
}

Fazit

Wie ihr sehen konntet ist eine Shared Library recht schnell angelegt und eingerichtet. Mit Hilfe dieser Bibliotheken könnt ihr euch Hilfsfunktionen schreiben, um den Buildprozess zu vereinfachen oder Schritte zusammenzufassen.

Habt ihr schon mit Shared Libraries gearbeitet und wie sind eure Erfahrungen damit?


Bildnachweis: pxhere.com, jenkins.io/artwork/

Weiterführende Links: