Release Engineering Release Engineering
Erneuertes Build-System für ModuleStudio

Freitag, 12. August 2016

Die Komponenten von ModuleStudio werden nun mit anderen Technologien gebaut. Statt Buckminster wird jetzt das Maven-basierte Tycho eingesetzt. Die Jenkins-Jobs wurden auf Pipelines umgestellt und unterstützen somit nun mehrere Branches.

Tycho für Features in mehreren Repositories

Im ersten Schritt habe ich daran gearbeitet, die Builds lokal mit Tycho zum Laufen zu kriegen. Eine Herausforderung dabei war es, die Builds für alle Komponenten, die in unterschiedlichen Git-Repositories liegen, mit möglichst wenig Redundanz zu beschreiben. Dies funktioniert über eine gemeinsame Root-POM, die im zentralen Produkt-Repository liegt. Dieses muß ohnehin allen Builds zusätzlich zum Repository der jeweiligen Komponente bekannt gemacht werden, da das Branding-Bundle von allen Features benötigt wird.

  1.  
  2.   <parent>
  3.     <groupid>de.guite.modulestudio</groupid>
  4.     <artifactid>de.guite.modulestudio.configuration</artifactid>
  5.     <version>1.0.0-SNAPSHOT</version>
  6.     <relativepath>../MostProduct/releng/de.guite.modulestudio.configuration/pom.xml</relativepath>
  7.   </parent>
  8.   <modules>
  9.     <module>../MostProduct/releng/de.guite.modulestudio.target</module>
  10.     <module>bundles</module>
  11.     <module>features</module>
  12.     <module>releng</module>
  13.   </modules>
  14.  

Unterschiede zwischen lokalen Builds und Jenkins wurden in der Root-POM mit zwei verschiedenen Profilen abgebildet:

  1.  
  2.   <profiles>
  3.     <profile>
  4.       <id>default</id>
  5.       <activation>
  6.         <activebydefault>true</activebydefault>
  7.       </activation>
  8.       <properties>
  9.         ...
  10.       </properties>
  11.     </profile>
  12.     <profile>
  13.       <id>build-server</id>
  14.       <activation>
  15.         <property>
  16.           <name>env.BUILD_NUMBER</name>
  17.         </property>
  18.       </activation>
  19.       <properties>
  20.         ...
  21.       </properties>
  22.     </profile>
  23.   </profiles>
  24.  

Das Profil build-server wird automatisch aktiviert, sobald die Umgebungsvariable BUILD_NUMBER vorhanden ist. Dies erspart die manuelle Angabe des Profils beim Maven-Aufruf.

Die zweite Hürde bestand darin, dass manche Komponenten von anderen abhängen. Die entsprechenden Builds müssen also zusätzlich zur normalen Target-Plattform die benötigten P2-Repositories zur Verfügung gestellt bekommen. Glücklicherweise erlaubt Tycho die Kombination aus Target-Datei und Repositories. In den parent-POM der jeweiligen Komponente mußte ich also lediglich die benötigten Repositories deklarieren:

  1.  
  2.   <repositories>
  3.     <repository>
  4.       <id>most-dsl</id>
  5.       <url>file://${dsl.repository}</url>
  6.       <layout>p2</layout>
  7.     </repository>
  8.     <repository>
  9.       <id>most-generator</id>
  10.       <url>file://${generator.repository}</url>
  11.       <layout>p2</layout>
  12.     </repository>
  13.   </repositories>
  14.  

Pipelines in Jenkins

Als nächstes stand die Beschreibung der Jenkins-Jobs mittels Groovy-Skripten auf dem Programm: im Hauptverzeichnis eines GIt-Repositories wird eine Datei namens Jenkinsfile hinterlegt. Diese erlaubt dann die automatische Ausführung eines Jenkins-Jobs, was auch die Grundlage für die Multibranch-Funktionalität ist: Jenkins scannt alle Branches und erstellt für jeden Branch (oder Pull Request) einen einzelnen untergeordneten Job. Möchte man beispielsweise in einem Feature Branch eine zusätzliche Post-Build-Aktion durchführen, wird dies automatisch im entsprechenden Job reflektiert und damit genauso wie der eigentliche Code getestet.

Die sehr gute Dokumentation führt dazu, dass die eigentlichen Builds recht schnell funktionieren. Als etwas hakeliger haben sich die zusätzlichen Aktionen wie die Publikation unterschiedlicher Reports herausgestellt. Etwaige Einstiegshürden können hier aber mit dem in Jenkins integrierten Snippet Generator reduziert werden, mit dem man sich den Groovy-Code für unterschiedliche Aktionen generieren kann.

Nachdem der erste Job soweit funktioniert hat, ging es anschließend darum, die für alle Komponenten gemeinsamen Schritte auszulagern, um sie wiederverwenden zu können. So bleiben die Jenkinsfile-Dateien in den unterschiedlichen Repositories schlank und frei von unnötigen Redundanzen. Mein erster Versuch dahingehend hat sich damit beschäftigt, dass Jenkins ein eigenes Git Repository für eine globale Bibliothek von Groovy-Funktionen anbietet. Dieser Ansatz hat mich aber nicht zufrieden gestellt. Vor allem wollte ich nicht, dass die Groovy-Skripte ganz woanders liegen als die übrigen Build-Artefakte. Abhilfe hat hier das Pipeline Remote Loader Plugin gebracht: damit kann man die Groovy-Dateien dynamisch aus einem beliebigen Git-Repository laden. So konnte ich sie im zentralen Produkt-Repo unterbringen.

Das Ergebnis kann sich sehen lassen: die Jenkinsfile-Dateien sind nun schön schlank und Änderungen können weitgehend zentral durchgeführt werden.

Aktueller Stand

Die eigentlichen Builds laufen nun alle sowohl lokal als auch auf dem CI-Server. Es sind allerdings noch diverse kleinere Tasks offen, vor allem im Bereich Deployment. Auch bei den Tests ist noch Einiges zu tun, zum Beispiel die Parallelisierung der Testausführung.

Grundsätzlich ist die neue Architektur aber deutlich einfacher zu warten als zuvor. Dank der Pipeline-Skripte werden nun auch die Job-Konfigurationen von Jenkins mit in Git versioniert. Und mit der Multibranch-Funktionalität ist ein wichtiger Schritt gemacht, insbesondere in Bezug auf die Verarbeitung von Pull Requests. Nicht zuletzt hat die Umstellung auf Tycho dafür gesorgt, dass ein Problem beim Start der Mac-Version von ModuleStudio nun gelöst ist.

Mittelfristig werden die Pipelines auch beim Zikula-Core eingeführt werden. Dies wird aktuell jedoch noch durch die fehlende Kompatibilität des Ant-Plugins verhindert.

 
^