Kontinuierliche Integration mit Jenkins und Drupal 7

Im Rahmen des Knowledge-Labs am 2.9.2011 bei Cocomore habe ich skizziert, wie man die Jenkins einsetzen könnte, um kontinuierliche Integration für ein Drupal-basiertes Projekt umzusetzen. Die Bausteine umfassten Jenkins, ein Demo-Drupal-Projekt, dessen automatische Aktualisierung aus der Versionsverwaltung SVN und den dadurch automatisch angestoßenen Lauf von Simpletest. Die wichtigsten dafür nötigen Schritte möchte ich nun auch hier schildern.

Basisinstallation

Für die gängigen Linux-Distributionen gibt es fertige Jenkins-Pakete zum Herunterladen. So auch für das von mir genutzte Debian.  Das Jenkins-Projekt betreibt sogar ein Repositorium, das sich nahtlos in die Software-Verwaltung einfügt. Auf der Download-Seite sind die dazu nötigen Kommandos beschrieben. Damit ist dann die Installation des Grundsystems nur noch ein "apt-get install jenkins" entfernt.

Da ein Drupal-System getestet werden soll, benötigt man natürlich auf der Maschine noch einen Webserver (Apache), PHP und eine Datenbank (MySQL).

Da sich mit Ant sehr schön Aufgaben automatisieren lassen und es von Jenkins unterstützt wird, ist dessen Installation auch nützlich.

Konfiguration

Zunächst wird in Jenkins für das zu testende Projekt ein neuer Job angelegt. Für Ant-basierte Projekte ist die Option '"Free Style"-Softwareprojekt' geeignet.

Jenkins - Neuen Job anlegen

Auf der Konfigurationsseite gibt es zahlreiche Einstellmöglichkeiten, um den Job seinen Bedürfnissen anzupassen. So legt man dort z.B. das verwendete Versionskontrollsystem fest. CVS- und SVN-Unterstützung hat die Standardinstallation von Jenkins bereits an Bord, aber es lassen sich per Plugin zahlreiche andere Systeme wie Git, Bazaar oder Mercurial nachrüsten. In diesem Beispiel wird SVN verwendet.

Damit der Quellcode gefunden werden kann, gibt man die Repositoriums-URL (inklusive des Pfades) an. Außerdem entscheidet man hier, was einen neuen Build auslösen soll. Für ein einfaches Setup bietet es sich an, die Ausführung entweder zu einem festen Zeitpunkt loslaufen zu lassen, oder man lässt Jenkins regelmäßig auf Änderungen im Repository prüfen. Für letztere Variante habe ich mich entschieden und hier im Beispiel die Prüfung auf "alle zwei Minuten" festgelegt. Nützlich ist, dass Jenkins bei der Prüfung der Version nicht nur den "direkten" Projekt-Code einbezieht, sondern auch per svn:externals eingebundene externe Abhängigkeiten.

Jenkins - SVN-Konfiguration

Nachdem Jenkins nun weiß, wo der Code zu finden ist, muss man ihm noch sagen, was damit bei einem Build passieren soll. Wir haben uns für ein Ant-basiertes Projekt entschieden. Deshalb sind die einzelnen Schritte als Ant-Targets anzugeben, die nacheinander ausgeführt werden.

Jenkins - Build-Verfahren: Ant
 

Nun muss noch festgelegt werden, was mit den Ergebnissen des Builds geschehen soll. Wir werden Simpletest so konfigurieren, dass es seine Ausgaben im JUnit-XML-Format schreibt. Deshalb aktivieren wir das JUnit-Plugin und geben ihm mit, wo die Simpletest-Ausgabe zu finden ist.

Jenkins - Post-Build-Aktionen

Hier ist der relevante Auszug des Ant-Targets, das die simpletests laufen lässt. Es werden in diesem Beispiel alle Tests der Gruppe "Demo" ausgeführt:

   target name="run_simpletests">
  [...]
   <exec dir="${basedir}/htdocs"
    executable="php"
    failonerror="true">
    arg line="scripts/run-tests.sh --php /usr/bin/php --url http://demo.debiserv/
      $--xml {basedir}/build/logs/simpletest Demo"/>
   </exec>
  </target>

Im Beispiel wurde ein Dummy-Simpletest verwendet, der einfach zwischen "Test erfolgreich" und "Test fehlgeschlagen" hin- und hergeschaltet werden kann:

<?php
    
class DemoModuleTestCase extends DrupalWebTestCase {

      public static function
getInfo() {
       return array(
      
'name' => 'Demo Module tests',
      
'description' => 'Test the demo module.',
      
'group' => 'Demo',
        );
      }
   
      public function
testDummyTest() {
      
$value = true;
      
//$value = false;
      
$this->assertTrue($value, 'The value is true.');
      }
     }
?>

Jenkins - Build-VerlaufHier sieht man die Auswirkung zweier Test-Commits. Der erste provozierte, dass der Simpletest fehlschlägt. Jenkins hat die Änderung im SVN erkannt und den Build-Lauf #34 angestoßen.  Die gelbe Kugel zeigt an, dass der Build zwar durchgelaufen, bei den Tests aber ein Fehler aufgetreten ist. Ein nachfolgender Commit sorgte dann dafür, dass der Test wieder erfolgreich verlief. Die Änderung im SVN löste Build #35 aus. Die blaue Kugel zeigt an, dass Build und Tests erfolgreich waren.

Über aktuelle Statusänderungen des Projektes kann man sich per E-Mail oder RSS-Feed benachrichtigen lassen. Damit wird das Entwicklungsteam ohne unnötigen Zeitverzug von einem plötzlich auftretenden Testfehlschlag unterrichtet.

Fazit

Mit Jenkins lässt sich kontinuierliche Integration für ein Drupal-Projekt umsetzen. Es bietet sich an, die einzelnen Schritte als Ant-Targets zu formulieren. Diese können auch während der Entwicklung benutzt werden, so dass man diesen Automatisierungsaufwand nur einmal aufzubringen hat. Drupals eingebautes Testframework Simpletest lässt sich als Schritt im Projekt-Build integrieren und dessen Ausgaben mit JUnit-kompatiblen Postprocessing-Plugins weiterverarbeiten. Jenkins Benachrichtigungsfunktionen halten Entwickler auf dem aktuellen Stand über den Zustand des Projektes.  Mit etwas Konfiguration lässt sich so zu einer vollständigen Lösung kommen.

PS: Bei der Demo wurde das Thema Sicherheit und Authentifizierung ausgeklammert. Wie zu erwarten unterstützt Jenkins Nutzer und Rechtevergabe. Auf echten Installationen sollte deren Einrichtung natürlich Pflicht sein, selbst wenn das System im internen Netz steht.