Der Butler für Ihr Projekt

Eine Einführung in die Continuous Integration mit Jenkins
Kommentare

Tag X ist gekommen: Der Tag der Auslieferung des Softwareprojekts. Alle Entwickler des Teams werfen ihre Softwarestände zusammen und kreuzen die Finger: Kompiliert das Projekt? Werden alle Tests „grün“? Oder stehen doch wieder Wochenendschichten an, um die verschiedenen Teile ihrer Software zusammenzupuzzeln?

Das oben beschriebene Szenario hat wohl jeder Entwickler schon erlebt. Wäre es nicht besser, jederzeit zu wissen, in welchem Zustand sich Ihr Softwareprojekt befindet? Stets in der Lage zu sein, eine Auslieferung erstellen zu können? Unabhängig zu sein von dem „alten Hasen“, der als einziger die Auslieferung erstellt? Sicherstellen zu können, dass immer alle relevanten Dateien im Versionskontrollsystem eingecheckt sind? Jenkins ist ein Continuous Integration Server und kann als Ihr Projektbutler all dies (und noch viel mehr) gewährleisten.

Was ist Continuous Integration?

Continuous Integration hat das Ziel, die Qualität der Software über permanente Integration ihrer einzelnen Bestandteile zu steigern. Statt die Software nur in sehr großen Zeitabständen kurz vor der Auslieferung zu erstellen, wird sie in kleinen Zyklen immer wieder erstellt und getestet. So können die Integrationsprobleme oder fehlerhafte Tests frühzeitig und nicht erst am Tag des Release erkannt werden. Durch die kleinen Deltas zwischen den einzelnen Builds sind Fehler wesentlich leichter zu finden und zu beheben.

Grundvoraussetzung für die kontinuierliche Integration ist, dass der Quellcode in einem Versionskontrollsystem verwaltet wird und die Entwickler ihre Arbeitsstände auch permanent in dieses zurückspielen. Typischerweise wird die Software nach jedem Commit, oder bei sehr zeitintensiven Builds zumindest regelmäßig mehrmals täglich, gebaut. Im Anschluss werden Tests und Codeanalysen durchgeführt. Abschließend wird die Software beispielsweise auf einem Stage-System bereitgestellt. Die Entwickler und, wenn gewünscht, weitere Beteiligte werden über den Build-Vorgang benachrichtigt und haben die Möglichkeit, sich Ergebnisse, Logs und Analysen anzuschauen.

So bekommen die Entwickler fehlerhafte Commits nicht erst durch die Kollegen mitgeteilt, sondern schon zeitnah durch die permanente Rückmeldung der „unabhängigen Kontrollinstanz“ Continuous Integration Server. Den Projektleitern und Kunden stehen, je nach Bedarf, stets aktuelle Informationen über den Entwicklungsstand oder ein aktuelles Testsystem zur Verfügung.

Jenkins, zu Ihren Diensten

Jenkins ist ein Open Source Continuous Integration Server. Er kann Ihnen genau diese immer wiederkehrenden Arbeiten abnehmen. Jenkins ist eine Webapplikation sowie Administration, und die Auswertung der Projekte erfolgt vollständig über den Browser. Er lässt sich schnell installieren, ist einfach zu konfigurieren und dank seiner Plug-in-Architektur sehr flexibel an eigene Bedürfnisse anpassbar.

Um mit Jenkins zu starten, lädt man zunächst die Jenkins-Server-Software von www.jenkins-ci.org herunter. Mit dem „Native Package Windows“ [1] wird Jenkins als Windows-Service installiert. Nach dem Abschluss der Installation ist Ihr neuer Projektdiener unter http://localhost:8080/ zu erreichen.

Jenkins vs. Hudson: Das Jenkins-Projekt ist nach einem Konflikt mit Oracle im Jahr 2011 als Fork aus dem Hudson-Projekt hervorgegangen. Der größere Teil der Entwicklergemeinde ist den Jenkins-Weg mitgegangen. Jenkins ist deshalb heute das deutlich aktiviere Projekt und somit dem mittlerweile zur Eclipse Foundation gehörenden Hudson vorzuziehen.

Jenkins konfigurieren

Neben der Basissoftware kann aus derzeit etwa 600 Plug-ins zur Konfiguration des eigenen Build-Prozesses gewählt werden. Um Jenkins im Visual-Studio-Umfeld einsetzen zu können, müssen einige dieser Plug-ins installiert werden. Nach Aufruf der Jenkins-Startseite (Abb. 1) erreichen Sie die Jenkins-Administration über Jenkins verwalten. Im Bereich Plugins verwalten befindet sich das Update-Center, das es ermöglicht, neue Plug-ins zu installieren sowie bereits installierte Plug-ins zu aktualisieren.

Abb. 1: Jenkins-Startbildschirm (Quelle: https://ci.jenkins-ci.org)

Empfehlenswerte Jenkins-Plug-ins

Green Balls

Eine blaue Markierung für einen erfolgreichen Build ist ungewöhnlich, hilft aber Menschen mit Rot-Grün-Sehschwäche. Green Balls markiert die Builds standardmäßig grün, Benutzer mit der Sehschwäche können auf Blau umstellen.

EnvInject-Plug-in

Setzt die Umgebungsvariablen für einen Job. Die Umgebungsvariablen können aus einer Datei geladen, als Key-Value-Paar angegeben oder per Skript erzeugt werden.

XUnit-Plug-in

Mit dem XUnit-Plug-in können die Ergebnisse verschiedener Testwerkzeuge in Jenkins angezeigt werden. Über eine XSLT-Transformation können auch selbstgeschriebene Werkzeuge angebunden werden.

Role-Strategy-Plug-in

Ermöglicht eine rollenbasierte Benutzerverwaltung.

Email-Ext-Plug-in

Ermöglicht eine umfassende Konfiguration von E-Mail-Benachrichtigungen basierend auf verschiedenen Build-Ereignissen.

Disk-Usage-Plug-in

Bietet einen Überblick über den verwendeten Festplattenplatz auf Master und Slaves.

Job-Configuration-History-Plug-in

Speichert die alten Jobkonfigurationen und bietet einen Vergleich der unterschiedlichen Versionen an.

Timestamper

Fügt der Konsolenausgabe einen Zeitstempel hinzu.

Continuous-Integration-Game-Plug-in

Ein Spiel zur Motivation: Für „gute“ Commits gibt es Pluspunkte, für „schlechte“ gibt es Minuspunkte.

Das erste Jenkins-Projekt

Um ein Softwareprojekt zu bauen, legt man im Jenkins zunächst einen so genannten Job an. Über den Link Neuen Job anlegen wählen Sie zunächst einen Namen für den ersten Build-Job („MyFirstProject“) und selektieren Free Style-Softwareprojekt bauen. Nach Klick auf OK wird die Konfigurationsseite des Jobs geladen. Nach dem Speichern kann der Job erstmals manuell über den Link Jetzt bauen ausgeführt werden. Die einzelnen Durchläufe eines Jobs werden Builds genannt. Der Job läuft durch und bekommt im Build-Verlauf eine farbige Markierung. Blau steht für einen erfolgreichen, Gelb für einen instabilen und Rot für einen fehlerhaften Build. Zusätzlich bietet die Wettermarkierung (Sonne, Wolken, Gewitter) einen Indikator für die allgemeine „Gesundheit“ des Jobs. Beeinflusst werden kann das Wetter z. B. durch die Build-Geschichte, Codemetriken oder Code-Coverage-Ergebnisse. Mit Klick auf den Build-Lauf werden die Details zu einem Lauf angezeigt.

Unterhalb des Installationsverzeichnisses wurde im Ordner workspace ein Ordner für den Job angelegt. Dieser Jobordner ist das Arbeitsverzeichnis für die im Folgenden auszuführenden Build-Skripte.

Den Job kontinuierlich bauen

Unter Source-Code-Management wird die zu verwendende Quellcodeverwaltung eingerichtet. Nach der Einrichtung der Quellcodeverwaltung und einem erneuten Start wird Jenkins die aus der Quellcodeverwaltung geladenen Dateien im Arbeitsverzeichnis des Jobs ablegen.

Um den Job nun kontinuierlich auszuführen, wird in der Konfiguration des Jobs ein Build-Auslöser hinzugefügt. Der Build soll alle fünf Minuten die Quellcodeverwaltung abfragen und den Job bei Bedarf ausführen. Die Konfiguration der Option Source Code Management System abfragen muss in der Cron-Syntax formuliert werden:

# Alle 5 Minuten 
*/5 * * * *
Eine Visual Studio Solution bauen

Um MSBuild aus Jenkins heraus ausführen zu können, muss msbuild.exe in der Path-Variable des Systems eingetragen sein oder MSBuild über Jenkins konfigurieren | MSBuild in Jenkins selbst eingerichtet werden.

Über Build-Schritt hinzufügen lässt sich nun auch eine Visual Studio Solution bauen. Als Build-File dient die .proj- oder .sln-Datei, die relativ zum Arbeitsverzeichnis angesprochen wird. Die Command Line Arguments sind wie bei einem herkömmlichen Kommandozeilenaufruf von MSBuild zu setzen. Nach dem erneuten Start des Builds kann das Log über die Konsolenausgabe analysiert werden. Über den Link Arbeitsbereich kann das Arbeitsverzeichnis des Jobs bequem im Browser angezeigt werden.

[ header = Eine Einführung in die Continuous Integration mit Jenkins – Teil 2 ]

Tests mit MSTest automatisiert durchführen

Im Anschluss an das Bauen der Software werden im Normalfall die erstellten Tests durchgeführt. Das Starten der Tests kann über einen Batch-Aufruf von mstest.exe realisiert werden. Um MSTest von der Kommandozeile zu starten, wird die VSMDI-Datei (hier MyFirstProject.vsmdi) verwendet, in der Visual Studio die Testmetadaten verwaltet. Die VSMDI-Datei muss eine Testliste (hier JenkinsTests) enthalten. Die Testliste wird in Visual Studio über den Testlisteneditor angelegt und mit den in Jenkins auszuführenden Tests gefüllt. Das Ergebnis der Tests wird in eine .trx-Datei (hier TestResults.trx) unterhalb des Ordners TestResults geschrieben.

Für eine fehlerfreie Ausführung von mstest.exe muss das Verzeichnis für die Testergebnisse existieren, die .trx-Ergebnisdatei darf noch nicht vorhanden sein:

rmdir /s /q %TESTRESULTS_PATH% md %TESTRESULTS_PATH%

Zur Verbesserung der Lesbarkeit wird nach dem Vorbereiten des Ergebnisverzeichnisses ein zusätzlicher Build-Schritt zum Aufruf von mstest.exe erstellt:

mstest.exe /testmetadata:%SOLUTION_PATH%MyFirstProject.vsmdi  /testlist:JenkinsTests  /resultsfile:"%TESTRESULTS_PATH%TestResults.trx"

Um die Testergebnisse in Jenkins anzuzeigen, wird eine post-build action hinzugefügt und das XUnit-Plug-in gewählt. Im entsprechenden Eingabefeld wird der Pfad zum .trx-File eingegeben:

${TESTRESULTS_PATH}TestResults.trx

Zusätzlich kann eingestellt werden, ob der Status des Builds ab einer bestimmten Anzahl fehlgeschlagener Tests gelb bzw. rot markiert wird.

Nachdem der Job erneut durchlaufen wurde, werden auf der Oberfläche zusätzliche Links zu den Testergebnissen des Laufs bzw. des Jobs angezeigt. Die Anzahl der durchlaufenen sowie fehlgeschlagenen Tests wird auch graphisch auf der Jobseite dargestellt.

Die Code Coverage in Jenkins anzeigen

Zur Anzeige der Code Coverage von MSTest in Jenkins muss leider etwas mehr Aufwand investiert werden. Nach Aktivierung der Code Coverage in Visual Studio (typischerweise über die local.testsettings) und einem Durchlauf der Testfälle legt Visual Studio im Verzeichnis TestResults TestResults _ZEITSTEMPELInRECHNERNAME eine Datei data.coverage an. Diese Datei enthält die Code-Coverage-Ergebnisse in einem proprietären Binärformat.

Da die Datei unterhalb des Pfads mit dem Zeitstempel nur schlecht in Jenkins weiterverarbeitet werden kann, wird eine Jenkins.testsettings angelegt. In den Jenkins.testsettings wird ein User-defined naming scheme (PrefixTest=TestResults, kein date-time timestamp) angelegt. Zusätzlich wird die Code Coverage aktiviert und die zu verwendenden Assemblies ausgewählt.

Mit Verwendung der jenkins.testsettings wird die data.coverage-Datei im Verzeichnis TestResultsTestResultsInRECHNERNAME erzeugt. Diese Datei kann in Jenkins zur Weiterverarbeitung verwendet werden.

Die Verwendung einer eigenen testsettings-Datei hat zusätzlich den Vorteil, dass Änderungen an der local.testsettings rückwirkungsfrei für den Jenkins-Lauf sind. Um die neu angelegte testsettings-Datei zu verwenden, wird diese als Parameter beim Aufruf von mstest.exe in der Konfiguration des Jenkins-Jobs hinzugefügt:

mstest.exe /testmetadata:%SOLUTION_PATH%MyFirstProject.vsmdi  /testlist:JenkinsTests  /testsettings:%SOLUTION_PATH%Jenkins.testsettings  /resultsfile:"%TESTRESULTS_PATH%TestResults.trx"

Es gibt derzeit kein Plug-in, um die MSTest Code Coverage in Jenkins anzuzeigen. Über eine Transformation der Coverage-Ergebnisse in ein für ein Jenkins-Plug-in lesbares Format können die Daten dennoch in Jenkins verfügbar gemacht werden. Als Zielformat eignet sich das EMMA-XML-Format. EMMA ist ein frei verfügbares Java-Code-Coverage-Tool, für das ein stabiles Jenkins-Plug-in verfügbar ist.

Ein entsprechender Konverter lässt sich schnell schreiben. Zunächst wird die Datei Microsoft.VisualStudio.Coverage.Analysis.dll aus der Visual-Studio-Installation in das für den Konverter angelegte Projekt kopiert und referenziert. Zusätzlich muss die Datei Microsoft.VisualStudio.Coverage.Symbols.dll in das bin Directory des Konverters kopiert werden (Listing 1).

Listing 1: Code-Coverage-Datei in XML umwandeln
private XmlDocument GetCoverageXml(String coverageFileFqn) {   XmlDocument coverageXmlDocument = new XmlDocument();   CoverageInfo coverage = CoverageInfo.CreateFromFile(coverageFileFqn);   DataSet data = coverage.BuildDataSet();   string coverageXml = data.GetXml();   coverageXmlDocument.LoadXml(coverageXml);   return coverageXmlDocument; }

Nachdem die Coverage-Informationen in XML vorliegen, können sie mittels einer XSLT-Transformation in das EMMA-Format umgewandelt werden (Listing 2). Das dafür benötigte XSLT-Stylesheet kann von der Jenkins-Webseite heruntergeladen werden [2].

Listing 2: Code-Coverage-XML in EMMA-XML transformieren
private void TransformToEmma(XmlDocument coverageXmlDoc, String targetFileFqn)  {   XslCompiledTransform coverage2EmmaXsl = new XslCompiledTransform();   XmlTextWriter writer = new XmlTextWriter(targetFileFqn, Encoding.Default);   coverage2EmmaXsl.Load(COVERAGE_TO_EMMA_XSLT);   coverage2EmmaXsl.Transform(coverageXmlDoc, null, writer);   writer.Flush();   writer.Close(); }

Nach der Transformation liegt die EMMA-Coverage im angegebenen Zielverzeichnis. In Jenkins wird nun für die Transformation ein Build-Schritt für den Batch-Aufruf des Konverters hinzugefügt:

md %BUILDRESULTS_PATH% %VSCOVERAGE_TO_EMMA_EXE% -c %TESTRESULTS_PATH%TestResultsIn%COMPUTERNAME%data.coverage -t %BUILDRESULTS_PATH%EmmaCoverage.xml

Zur Auswertung wird eine post-build action zum Jenkins-Job hinzugefügt, die die EMMA-Testabdeckung veröffentlicht. Neben dem Verweis auf die erzeugte EMMA-Coverage-Datei können verschiedene Einstellungen zum Health reporting vorgenommen werden. Abhängig von den erreichten Code-Coverage-Werten setzt Jenkins dann das „Wetter“ des Jobs:

${BUILDRESULTS_PATH}EmmaCoverage.xml

Nach einem erneuten Lauf werden für den gesamten Job sowie für den Build selbst die Code-Coverage-Statistiken graphisch und textuell ausgegeben.

Die Software auf einem Testsystem bereitstellen

Nachdem alle für das Projekt benötigten Build-Schritte abgeschlossen sind, wird das Projekt bei Bedarf auf einem Testsystem bereitgestellt. Soll die Bereitstellung nicht bei jedem Build erfolgen, empfiehlt es sich, einen zusätzlichen Job anzulegen und die Build-Schritte des allgemeineren Jobs wiederzuverwenden. Nach Installation des Template Project Plugin stehen in der Jobkonfiguration entsprechende Optionen zur Verfügung.

Die Projektbeteiligten benachrichtigen

Es sind verschiedene Plug-ins zur Benachrichtigung der Projektbeteiligten über die Ergebnisse der Build-Läufe verfügbar. Im Regelfall werden die an einem Build beteiligten Entwickler per E-Mail benachrichtigt, wenn der Build fehlschlägt oder repariert wurde. Um automatisierte Mails zu versenden, muss in den Jenkins-Einstellungen zunächst der SMTP-Server eingestellt werden.

Nachdem die post-build action E-Mail-Benachrichtigung zum Job hinzugefügt wurde, wird Getrennte E-Mails an diejenigen Anwender senden, welche den Build fehlschlagen ließen aktiviert, um alle Entwickler zu benachrichtigen, die am entsprechenden Build beteiligt waren. Der korrekte Versand der E-Mails kann nach einem erneuten Durchlauf auch in der Konsolenausgabe des Jobs überprüft werden.

Auswertung von proprietären Formaten

Um die Ergebnisse von selbstgeschriebenen Werkzeugen oder anderer proprietärer Formate, für die kein Jenkins-Plug-in vorhanden ist, in Jenkins anzuzeigen, sind XSLT-Transformationen in ein allgemeines Format ein mächtiges Werkzeug. Eine solche Transformation wurde bei der Umwandlung der Code-Coverage-Daten beschrieben. Diese Transformationen sind dem deutlich aufwendigeren Schreiben eigener Jenkins-Plug-ins vorzuziehen.

Verteiltes Bauen

Um Builds von Projekten auf verschiedenen Rechnern durchführen zu können, unterstützt Jenkins das Master-/Slave-Konzept. So kann eine Jenkins-Instanz (Master) viele Projekte verwalten, die auf unterschiedlichen Rechnern (Slaves) gebaut werden sollen. Dies kann zur Lastverteilung oder zur Bereitstellung verschiedener Umgebungen nötig sein. Dazu muss auf den Slave-Rechnern ein so genannter Slave-Agent gestartet werden, der über https mit dem Master kommuniziert. Die Verteilung der Projekte auf die Slaves kann über Keywords oder dedizierte Zuweisung erfolgen. Die Lastverteilung von anstehenden Jobs auf mehrere mögliche Slaves regelt Jenkins selbständig.

Ein Butler für viele Aufgaben

Die leichte Installation und Konfigurierbarkeit ermöglicht einen schnellen Einstieg in Jenkins und dank der verfügbaren Plug-ins lässt Jenkins sich zum zentralen Manager für unterschiedlichste wiederkehrende Aufgaben oder zur Überwachung von externen Jobs erweitern. Die Open-Source-Community, die hinter Jenkins steht, ist sehr aktiv und reagiert bei gemeldeten Fehlern umgehend. Mit Jenkins steht einfach ein hervorragendes Werkzeug zum kontinuierlichen Erstellen und Testen von Softwareprojekten zur Verfügung. Nach der Einführung der Continuous Integration und dem Werkzeug Jenkins sollte den freien Wochenenden für das Projektteam also nichts mehr im Weg stehen – auch kein wichtiges Release.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -