Besser, öfter, mehr

Continuous Integration mit Git, Gerrit und Jenkins

Stephan Wagner und Marcus Handte

Kontinuierliche Integration ist ein Entwicklungsprozess, bei dem die zu entwickelnde Software in kurzen Abständen regelmäßig integriert, übersetzt, installiert und getestet wird. Dazu wird die Entwicklung in Arbeitsschritten mit geringem Umfang durchgeführt, und jeder Softwareentwickler integriert seine Änderungen fortlaufend in den primären Entwicklungszweig. Dadurch werden Probleme frühzeitig erkannt, und die Software kann kontinuierlich optimiert werden. Um den zusätzlichen Aufwand für ein Entwicklerteam zu minimieren, ist eine geeignete Werkzeugunterstützung unerlässlich. Wie sich eine effektive Unterstützung durch die Kombination der Open-Source-Werkzeuge Git, Gerrit und Jenkins realisieren lässt, wird im Folgenden beschrieben.

Eclipse Magazin

Der Artikel „Besser, öfter, mehr“ von Stephan Wagner und Marcus Handte ist erstmalig erschienen im

Eclipse Magazin 5.2012

Das Prinzip der Kontinuierlichen Integration ist spätestens seit ihrer Erwähnung Anfang des Jahrtausends als Bestandteil des Extreme Programming allgemein bekannt. Die Idee dahinter ist denkbar einfach: Es geht darum, kleine zusammenhängende Änderungen umzusetzen, sie zu prüfen und dann schnellstmöglich mit dem Hauptzweig der Entwicklung zu integrieren, um sie anderen Entwicklern zugänglich zu machen. In der Praxis ist jedoch zu beobachten, dass eben dieser klare Ablauf nicht konsequent umgesetzt wird. So wird häufig als einziges unterstützendes Werkzeug ein Versionsverwaltungssystem eingesetzt und lediglich zum Verteilen der Änderungen am Projekt genutzt. Schlecht strukturierter oder fehlerhafter Quelltext kann daher leicht in den Hauptzweig der Entwicklung übertragen werden. Ebenso können Änderungen an einem Modul unkontrolliert zu Fehlern in anderen Modulen führen.

Zwang zur Struktur

Durch die Planung eines festen Ablaufs für die Integration einer Änderung kann die Arbeitsweise unterschiedlicher Entwickler vereinheitlicht werden. Abbildung 1 zeigt einen möglichen Ablauf, der die Grundlage für diesen Artikel bildet. Zuerst wird die lokale Kopie der Software vom Entwickler auf den neuesten Stand gebracht. Daraufhin werden die entsprechenden Änderungen umgesetzt. Sobald die Programmierung abgeschlossen ist, werden die Änderungen mithilfe von Modultests auf Funktionstüchtigkeit geprüft. Sind alle lokal auftretenden Fehler behoben, wird die Änderung an einen Integrationsserver übertragen. Auf diesem wird die gesamte Software in einer vordefinierten Umgebung übersetzt, installiert und mittels Integrationstests geprüft. Treten dabei Fehler auf, müssen sie vom Entwickler behoben werden, und die gesamte Prozedur wird wiederholt. Sobald die Integrationstests erfolgreich abgeschlossen wurden, werden weitere Entwickler des Teams über die Änderung informiert. Die Entwickler prüfen die Änderung manuell im Rahmen eines Code-Reviews. Die dabei gefundenen Schwächen werden zusammen mit Kommentaren der Gutachter zurück an den Entwickler übergeben, der sie umsetzt und den Prozess erneut startet. Sind alle Fehler behoben und die Kommentare der Gutachter eingearbeitet, wird die Änderung dem Hauptentwicklungszweig hinzugefügt.

Abb. 1: Möglicher Ablauf einer Integration

Die Vorteile eines solchen Ablaufs liegen auf der Hand: Fehler können noch vor der Weitergabe einer Änderung behoben, Integrationsprobleme frühzeitig erkannt und strukturell unterschiedliche Herangehensweisen der Teammitglieder harmonisiert werden. Über diese direkten Auswirkungen hinaus hat ein solches Vorgehen jedoch weitere günstige Effekte: Durch die direkte Antwort der Testsysteme auf die eingestellten Änderungen werden Entwickler in positiver Weise dazu angehalten, die fertiggestellte Änderung gründlich zu prüfen. Zudem macht ein interner Review-Prozess den einzelnen Entwicklern bewusst, dass ihr Quelltext auch von den Kollegen gelesen wird. So wird automatisch vermehrt auf den eigenen Programmierstil und die Qualität der Dokumentation geachtet.

Um den zusätzlichen Aufwand dieses Ablaufs für das Entwicklerteam zu minimieren, ist eine geeignete Werkzeugunterstützung unerlässlich. Während wiederholbare lokale Tests durch die üblichen Werkzeuge wie Apache Maven und JUnit in einfacher Weise automatisiert werden können, erfordern die weiteren Schritte der kontinuierlichen Integration eine serverseitige Unterstützung, die den Ablauf in jedem Schritt nicht nur einfordert, sondern auch unterstützt. Eine solche Unterstützung lässt sich durch die Kombination der Open-Source-Werkzeuge Git, Gerrit und Jenkins kostengünstig realisieren.

Bei Git handelt es sich um ein weit verbreitetes Versionsverwaltungssystem, das ursprünglich für die Arbeit an Linux entwickelt wurde. Im Gegensatz zu vergleichbaren Systemen wie etwa Subversion sind alle Arbeitskopien vollständige Kopien des primären Repositories. Das ermöglicht lokales Arbeiten, ohne eine regelmäßige Kommunikation mit einem Server vorauszusetzen. So kann der Entwickler auf seinem eigenen Repository neue Entwicklungszweige (Branches) erzeugen, darauf arbeiten und später die einzelnen Änderungen (Commits) an den Hauptzweig der Entwicklung übertragen.

Jenkins ist eine Java-basierte Webanwendung, die in der Lage ist, unter Zuhilfenahme verschiedener Plug-ins selbst komplexere Softwaresysteme zu übersetzen, zu installieren und zu testen. Weiterhin ist Jenkins in der Lage, mittels statischer Metriken den Quellcode zu analysieren. Im Rahmen dieses Artikels wird jedoch lediglich die Nutzung von Jenkins zur automatischen Validierung der Änderungen beschrieben. Weiterführende Informationen zur Codeanalyse befinden sich online unter [1].

Das dritte Werkzeug ist ebenfalls eine Java-basierte Webanwendung namens Gerrit. Sie ermöglicht manuelle Prüfungen einzelner Commits im Rahmen von Code-Reviews. Dazu verwaltet Gerrit die primäre Kopie des Git Repositories und regelt die lesenden und schreibenden Zugriffe der Entwickler.

Installation

Die Installation der Werkzeuge ist simpel, weshalb an dieser Stelle vorwiegend auf einige Erweiterungen eingegangen werden soll, mit deren Hilfe ihre Integration verbessert werden kann. Git kann als native Anwendung unter verschiedenen Betriebssystemen installiert werden. Da Git auf die Entwicklung von Linux zurückgeht, bieten nahezu alle Linux-Distributionen entsprechende Pakete an. Für die Nutzung unter Windows eignet sich zum Beispiel Msysgit in Kombination mit der grafischen Oberfläche TortoiseGit, die beide über Windows Installer installiert werden können. Weitere Details befinden sich unter [2].

Sowohl bei Jenkins als auch bei Gerrit handelt es sich um Java-basierte Webanwendungen, die einen Webserver mit Servlet-Container voraussetzen. Beide Anwendungen bringen standardmäßig ihre eigenen Container mit und regeln die Rechteverwaltung eigenständig. Damit können erste Experimente mit beiden Systemen problemlos auf jedem Rechner mit Java Virtual Machine durchgeführt werden. In einer Produktionsumgebung ist jedoch in der Regel eine Integration mit der bestehenden Infrastruktur sinnvoll. Hierzu können beide Systeme zum Beispiel auf Apache Tomcat installiert werden, und die Rechteverwaltung kann an eine bestehende LDAP-Quelle angebunden werden. Weiterhin besteht die Option, über das Proxy-Modul des Apache-Webservers den Zugriff auf die Anwendungen auch von außerhalb des Unternehmensnetzwerks zu ermöglichen.

Die Installation von Jenkins ist unkompliziert. Auf einem bereits eingerichteten Tomcat reicht es aus, das Web Application Archive (.war) herunterzuladen und in das Tomcat-eigene webapp-Verzeichnis zu verschieben. Nach diesem Schritt kann die restliche Konfiguration im Browser durchgeführt werden. Als Erweiterung bietet sich für den Einsatz im Unternehmen die Anbindung an einen vorhandenen LDAP-Server an. Diese kann im Menü JENKINS VERWALTEN | SYSTEM KONFIGURIEREN aktiviert und konfiguriert werden. Auch lassen sich in diesem Menü sämtliche globalen Optionen setzen.

Zusätzlich werden zwei weitere Plug-ins für das System benötigt, die unter JENKINS VERWALTEN | PLUGINS VERWALTEN installiert werden können: zum einen das Git-Plug-in [3], das die grundlegende Unterstützung für Git kapselt, zum anderen das Gerrit-Trigger-Plug-in [4], das Jenkins über Änderungen in einem von Gerrit verwalteten Git Repository informiert und im Anschluss vordefinierte Aktionen auslösen kann.

Für die Installation von Gerrit ist es zunächst unumgänglich, das System im beigefügten Servlet-Container zu starten, um dabei die grundlegende Konfiguration zu initialisieren. Hierfür bietet es sich an, der projekteigenen Dokumentation unter [5] zu folgen. Nach Abschluss der Installation kann auch diese Applikation in den Tomcat-Server verschoben werden. Dazu müssen jedoch einige Bibliotheken innerhalb der Tomcat-Umgebung installiert werden. Zu diesen zählen beispielsweise die Treiber für die Datenbankanbindung. Wer unkompliziert alle von Gerrit benötigten Bibliotheken bereitstellen möchte, kann sämtliche .jar-Dateien aus $gerrit_home/lib in das lib-Verzeichnis der Tomcat-Installation kopieren. Des Weiteren muss die Verbindung zur Datenbank in Tomcat konfiguriert werden. Die Konfigurationsdatei context.xml muss dazu wie in Listing 1 ergänzt werden.

Listing 1

Geschrieben von
Stephan Wagner und Marcus Handte
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.