• Learning Friday
  • Software-Modernisierung

{Renovate and then…}

Updates nerven dich? Mit Renovate und OpenRewrite kannst du Quarkus- und Angular-Updates fast vollständig automatisieren. Weniger manueller Aufwand, mehr Fokus auf das Wesentliche – entdecke, wie du Zeit sparst und deine Software fit für die Zukunft machst! 🚀

Einführung

Im Rahmen unseres Jagdthemas Software-Modernisierung spielt die automatisierte Aktualisierung von Software eine große Rolle. Bei gepardec haben wir uns zum Ziel gesetzt, diese Prozesse so effizient wie möglich zu gestalten. Mit dem Projekt „Renovate and then…“ wollten wir den Grundstein für unsere Automatisierungsstrategie legen.

Renovate ist bei uns kein Unbekannter. Es wird bereits erfolgreich bei einigen Kund:innen eingesetzt. Doch diesmal wollten wir einen Schritt weitergehen: die Kombination von Renovate mit OpenRewrite, um nicht nur Versions-Updates zu automatisieren, sondern auch die notwendigen Codeänderungen gleich mitzunehmen.

Was ist Renovate?

Renovate ist ein Open-Source-Tool, das Entwickler:innen hilft, ihre Software-Abhängigkeiten auf dem neuesten Stand zu halten. Es erstellt automatisch Pull Requests für Updates, sodass Entwickler:innen nicht mehr manuell nach neuen Versionen suchen müssen. Unterstützt werden eine Vielzahl von Paketmanagern, und die Konfiguration kann sehr detailliert an die spezifischen Bedürfnisse eines Projekts angepasst werden. Durch die Automatisierung von Abhängigkeitsupdates können Teams Sicherheitslücken minimieren und von den neuesten Features und Optimierungen profitieren.

Die Herausforderung

Renovate allein führt lediglich Versions-Upgrades durch, macht aber keine Codeänderungen. Ein klassisches Beispiel ist das Upgrade von Quarkus 2 auf Quarkus 3, bei dem der Namespace von javax.* zu jakarta.* geändert werden muss. Zum Glück bietet Quarkus ein OpenRewrite-Recipe, das diese Anpassung vornimmt.

Unsere Herausforderung bestand darin, Renovate und OpenRewrite so zu kombinieren, dass die Änderungen automatisch in den Pull Request aufgenommen werden. Unser Ziel war die automatisierte Aktualisierung einer Quarkus- und einer Angular-App. Beide Frameworks bieten Tools für Updates auf neuere Versionen:

Der Knackpunkt war, diese Tools mit den von Renovate zur Verfügung gestellten Konfigurationen (postUpgradeTasks) auszuführen.

Leider bringen die postUpgradeTasks einige Nachteile mit sich:

Aufwendige Konfiguration: Die Konfiguration der postUpgradeTasks ist etwas umständlich. Ein Kommando kann nur verwendet werden, wenn es zuerst erlaubt wird. Dazu gibt es den Parameter allowedPostUpgradeCommands.Zusätzlich müssen aber auch alle Parameter in der richtigen Reihenfolge angegeben werden.

Zudem müssen Umgebungsvariablen, die in einem postUpgradeTask verwendet werden sollen,  nochmal definiert werden:

Schwierigkeiten beim Debugging: Das Debuggen der postUpgradeTasks gestaltet sich kompliziert. Der Renovate-Log ist sehr umfangreich, und die Ausgaben der postUpgradeTasks sind nur schwer zu finden. Im Log selbst werden JSON und normale Logausgaben vermischt. Die Logs der postUpgradeTasks werden nur im Debug-Log-Level ausgegeben. In unserem Beispiel mit GitHub-Actions, welche JSON Logs formatiert darstellt, hatte dieses Log ca. 30000 Zeilen. 

Diese Nachteile machen die Nutzung von postUpgradeTasks nicht nur zeitaufwendig, sondern auch fehleranfällig und unübersichtlich.

Quarkus

Für unser Quarkus-Projekt klappte die Integration von Renovate und OpenRewrite reibungslos. Ein kleines Problem trat jedoch auf: Für den Befehl quarkus update musste die alte Version in der pom.xml bestehen bleiben, während Renovate diese bereits auf die neue Version angehoben hatte.

Unsere Lösung bestand darin, die Version vor dem Skriptaufruf zurückzusetzen und danach das Skript auszuführen. So konnte Renovate einen Pull Request mit allen notwendigen Versions- und Codeänderungen erstellen, der erfolgreich gebaut und gemerged werden konnte.

Angular

Anders als Quarkus verwendet Angular nicht OpenRewrite für automatisierte Migrationen, sondern die hauseigenen Angular Schematics. So werden Migrationen für Upgrades von Major Versionen angeboten. Da diese aber immer nur von einer Version auf die nächste upgraden können, erstellt Renovate in unserem Fall per Major-Sprung einen Pull Request.

Die Angular Schematics ließen sich nicht “nahtlos” in Renovate einbinden. Unter Renovate werden Versionsinkremente zwangsweise vor den postUpgradeTasks durchgeführt und das Projekt gebaut. Da bei den meisten neuen Major-Versionen von Angular auch zwangsweise andere Third-Party Dependencies außerhalb des @angular-Scopes upgegraded werden müssen (Stichwort: peerDependencies in package.json), schlägt der initiale Build nach dem Upgrade fehl, was widerum dazu führt, dass das durch Renovate initiierte Versionsupgrade fehlschlägt. Die postUpgradeTasks werden allerdings trotzdem ausgeführt und wir erhalten aufgrund der darin ausgeführten Angular Schematics letztendlich einen Pull Request mit einem validen, migrierten Zustand.

Fazit und Ausblick

Unser Projekt hat gezeigt, dass es möglich ist, Versions-Updates weitgehend zu automatisieren und damit den Entwicklern viel Zeit und Mühe zu ersparen. Allerdings ist eine vollständige Automatisierung nicht möglich. 

Wie auch Quarkus in ihrer Dokumentation beschreibt: “Although these recipes update many migration items, they do not cover all the items detailed in the Migration Guides.”

Für die Zukunft planen wir, diese Automatisierung weiter zu optimieren und eigene OpenRewrite-Recipes zu entwickeln. Wir freuen uns darauf, unsere Fähigkeiten weiter auszubauen und innovative Lösungen für die Herausforderungen der Softwaremodernisierung zu finden.

geschrieben von:
Christoph, Marko
WordPress Cookie Plugin von Real Cookie Banner