Testbare Jenkins Shared Pipelines
Ist dein Pipeline Code getestet? Fliegen die Exceptions immer erst zur Laufzeit, weil ein Groovy Syntax Fehler vorliegt? Verziehen deine Kollegen voller Abscheu das Gesicht, wenn du “Pipeline Code” sagst? Say no more!
--
Von Bernhard, Software Engineer @comsysto
Einleitung
Wir nutzen Jenkins in mehreren Projekten und haben uns eine Shared Jenkins Pipeline aufgebaut. Bisher konnten wir unseren Pipeline Code nie wirklich lokal testen, es hat immer erst im eigentlichen Jenkins Job geknallt. Diesen Umstand wollten wir schleunigst ändern und haben uns damit beschäftigt, wie man testbaren Pipeline Code produzieren kann. Dieser BlogPost gibt dabei die Grundzüge unseres Ansatzes wieder.
UnitTests für Pipeline Code
Wir wollten folgendes erreichen:
- Jenkins Befehle mocken (sh, withCredentials, echo …)
- Ein Helper ruft keine anderen Helper auf (Separation of Concerns)
- Jeder Helper hat einen UnitTest
- Ein UnitTest mocked Jenkins und prüft (assert) die vom Helper produzierten shell-calls.
Unser Shared Pipeline Setup sieht dabei wie folgt aus:
Demo: Shared Pipeline mit GitHelper
Wir wollen zur Demonstration einen simplen GitHelper programmieren, der uns die Arbeit mit GIT erleichtert.
Das ganze Demo-Projekt seht ihr auf GitHub:
Wir binden die Demo Shared Pipeline in Jenkins als Globale Pipeline Library ein. Globale Pipelines laufen außerhalb der Sandbox und ermöglichen so einiges mehr an Funktionen als ge-sandboxte Pipelines.
Wir wollen unsere Library später unter der ID “comsysto” abrufen können und konfigurieren sie wie folgt:
Somit können wir unsere Library wie folgt in einem Jenkinsfile eines Pipeline-Jobs nutzen:
Credentials in Jenkins einrichten
Wir wollen mit unserem GitHelper und mithilfe von GitHub Personal Access Tokens private GitHub Repositories clonen können. Dafür legen wir uns ein UsernameAndPassword Credential mit dem Token als Passwort an.
Wir haben später in der Pipeline Zugriff auf die Zugangsdaten über die ID github-credentials-1. Credentials können wie folgt genutzt werden, was aber der GitHelper für uns übernehmen wird:
Einen Pipeline Job einrichten
Wir richten einen Pipeline Job ein, um unsere Pipeline zu testen. Als Randnotiz sei gesagt, dass wir neben den UnitTests auch für jeden Helper einen eigenen Integration-Test-Pipeline-Job haben.
Wir tragen folgenden Pipeline Code ein:
Dieser nutzt unsere globale comsysto-Library und den GitHelper. Man sieht, dass wir die credentials anhand der ID übergeben sowie Repository-Owner und Repository-name. Es wird also das private Repository https://github.com/comsysto/test-jenkins-private-repository gecloned.
Lässt man den Job laufen, sieht das Ergebnis so aus:
GitHelper und cloneGitHubRepository()
Unser GitHelper sieht wie folgt aus:
Der Dazugehörige Unit Test instanziiert den GitHelper sowie einen Jenkins Mock welcher alle Jenkins API Calls mocked.
Der Jenkins Mock ist dabei recht simpel aufgebaut. Aktuell mockt er nur env, sh() und withCredentials().
Die Unit Tests können wir wie folgt ausführen:
groovy -cp src/ src/com/comsysto/pipeline/test/GitHelperTest.groovy
Natürlich muss die Groovy SDK installiert sein. Wenn man alles richtig gemacht hat, laufen alle Tests sauber durch. Das @Grab() sorgt ggf. für eine etwas längere Wartezeit, da erst das JAR heruntergeladen werden muss.
Fazit
Wir können unsere Jenkins Library lokal testen. Und wissen daher früh, wenn etwas nicht funktioniert. Durch weitere Integration Test Pipeline Jobs pro Helper kann man die Testabdeckung noch weiter erhöhen. Wir sind mit unserem Ansatz sehr zufrieden und werden immer weiter daran feilen.
Originally published at comsystoreply.de.