Build am Donnerstag: Jenkins Continuous Build Server für PHP-Projekte

Jenkins ist ein erweiterbares, webbasiertes System zur kontinuierlichen Integration in agilen Softwareprojekten.“ (Danke für diese praktische Einleitung, Wikipedia!).
Ich habe das schnieke Jenkins-System gerade für ein PHP-basiertes Projekt eingerichtet, und zwar mit Apache Ant als Build-Tool, Git übernimmt das Source-Code-Management. Winstone wird als Servlet-Container schon mitgeliefert, andere Programme wie etwa Tomcat sind möglich, aber nicht nötig.
Eine genaue Anleitungen zum Einrichten samt Template gibt’s hier: Jenkins Job Template for PHP-Projects. Die dort zu findende Vorlage liefert für den ersten Jenkins-PHP-Job die gängigsten Einstellungen der Post-Built-Aktionen, Graphen etc.
Hier sei angemerkt, dass zwar ein Jenkins-Template-Plugin als solches existiert, das es allerdings nur erlaubt, einen Teil der Optionen zu übertragen – praktisch gänzlich unnötig, lassen sich bestehende Job-Ordner doch einfach kopieren, umbenennen oder zu anderen Jenkins-Installationen verschieben (anschließend die Konfiguration von Jenkins neu laden).
Für PHP-Projekte sind folgende Jenkins-Plugins interessant:Ein paar der Graphen
Checkstyle (verarbeitet PHP_CodeSniffer-Logdateien im Checkstyle-Format)
Clover PHP (verarbeitet PHPUnit Code-Coverage xml-Ausgabe)
DRY (verarbeitet phpcpd-Logdateien im PMD-CPD-Format)
HTML Publisher (z.B. zum veröffentlichen des PHPUnit code coverage report)
JDepend (verarbeitet PHP_Depend-Logdateien im JDepend Format)
Plot (verarbeitet phploc CSV-Ausgabe)
PMD (verarbeitet PHPMD-Logdateien im PMD-Format)
Violations (verarbeitet diverse Logdateien)
xUnit (verarbeitet PHPUnit-Logdateien im JUnit format)
Automation
Für die Steuerung legt man ein Ant-Build-Skript an, sowie die Konfigurationen/Rulesets für die einzelnen Tools (etwa für CodeSniffer – siehe unseren Artikel). So lassen sich Builds individuell schneidern, von Code Coverage, Dupliziertem Quelltext, bis hin zur Verfügbarkeit der Datenbank.
In unserem Fall fungiert Git zudem als Build-Trigger und startet bei neuen Versionen im Repository den Job – inklusive Benachrichtigung der Git-User bei einem Fehlschlag (per E-Mail, Jabber u.A.) oder Git Publisher bei Erfolg. Die Jobs lassen sich alternativ manuell oder per Script starten, zeitlich Planen und Ruheperioden einrichten.

Distributed Builds

Eine Jenkins-Installation kann als Master agieren und Builds auf Nodes (bzw. Slaves) laufen lassen, auf ein und demselben Rechner oder externen Systemen, egal ob nun Windows oder anderen Unixen, etwa Solaris.
Eine Jenkins-Installation auf dem Slave ist nicht nötig – der Master kopiert die nötigen Dateien nach der Einrichtung. Wohl aber sollte der Node über alle für den Build erforderlichen Tools, etwa CVS, Pear, PHP und PHP-Tools (PHPUnit etwa schreit nach PHP ab 5.2.7) sowie die Konfigurationsdateien (sofern diese nicht im Repository liegen) verfügen. Einige Programme wie Maven, Ant, JDKs und Git installiert Jenkins auf Wunsch automatisch, wobei sich verschiedene Arten einstellen lassen.
Jobs legt man auf dem Master an und weist diese entweder dediziert einem dieser „Dumb“-Slaves zu (wer es sucht: nennt sich „Beschränke wo dieses Projekt ausgeführt werden darf“) oder es werden automatisch die vorhandenen Build-Prozessoren bei anstehenden Jobs ausgelastet. D.h. ein Job wird immer komplett ausgelagert, einzelne Test zu verteilen geht leider nicht. Die Ergebnisse bestaunt man auf dem Master.
Bei meinem Versuchsaufbau greift Jenkins unter Debian auf einen CentOS-Slave per ssh zu. Statt per ssh ließe sich ein Node auch „headless“ per Command-Line oder Skript sowie Java Web Start (JNLP) steuern.
Pferdefuß in meinem Fall: die unterschiedlichen PHP-Versionen. Einige PHPUnit-Test, die auf dem Master (mit PHP 5.3) funktionieren, laufen nicht auf dem vorgesehenen Slave. Ergo Tests umschreiben, oder für die Zukunft vorher überlegen, wo diese laufen sollen 😉