Beliebte Suchanfragen

Cloud Native

DevOps

IT-Security

Agile Methoden

Java

//

Automatische Dependency-Updates mit Renovate

17.4.2023 | 5 Minuten Lesezeit

Bei der Softwareentwicklung ist es sinnvoll, bereits bestehende Funktionen wiederzuverwenden. Das spart Zeit und es wird unwahrscheinlicher, auf Probleme zu stoßen, die andere bereits gelöst haben. Funktionen können aus diesem Grund in Libraries gebündelt werden. Solche Libraries findet man in Repositories, aus denen man sie mit Paketmanagern beziehen und in die eigene Anwendung installieren kann. Durch die Nutzung von Libraries kommt man schneller und damit kostengünstiger zu einem Ergebnis und muss dabei nicht auf Qualität verzichten. Hierfür ist es jedoch auch notwendig, die verwendeten Libraries sorgfältig auszuwählen, um die eigenen Qualitätsansprüche sicherzustellen.

Libraries stehen außerdem nicht still, sondern werden kontinuierlich weiterentwickelt. Aus diesem Grund werden sie mit einer Versionsnummer im Repository veröffentlicht und von einem Paketmanager in einer bestimmten Version (meistens der aktuellsten) in der eigenen Anwendung installiert. Wird eine neue Version veröffentlicht, kann dies folgende Gründe haben:

  • Sicherheit
    Sicherheitslücken werden immer wieder gefunden und müssen geschlossen werden. Selbst bekannte und viel genutzte Bibliotheken weisen Sicherheitslücken auf, wie die Bibliothek Log4j gezeigt hat.
  • Performance
    Oft lassen sich Funktionen in ihrer Performance optimieren, sodass sie schneller laufen oder weniger Ressourcen (CPU, Speicher) benötigen.
  • Features
    Neue Features kommen zur Software hinzu, um näher an das verfolgte Ziel zu gelangen. Genauso können Features entfernt werden, weil sie durch neue ersetzt oder nicht mehr benötigt werden.

Eine Anwendung beinhaltet heutzutage schnell einige Dutzend Bibliotheken, auch Dependencies genannt. Diese veröffentlichen regelmäßig neue Versionen, zum Teil mehrmals pro Woche. Das liegt oft auch daran, dass Dependencies selbst wiederum Dependencies verwenden und so ein Abhängigkeitsbaum entsteht, der einer Anwendung in JavaScript schnell über 1000 Bibliotheken hinzufügt.

Um zeitnah von den Vorteilen einer neuen Version zu profitieren, sollten Dependencies regelmäßig geupdatet werden. Auch gilt, umso älter Dependencies sind, desto aufwendiger wird es, diese auf die aktuelle Version zu updaten.

Das liegt daran, dass das Changelog wächst und die Wahrscheinlichkeit für Breaking Changes zunimmt. Um Fehler, die durch Breaking Changes auftreten können, aufzudecken, sollten mit jedem Update Regressionstests durchgeführt werden.

Automatisierung der Depency-Updates mit Renovate

Renovate ist ein Tool, welches das Updaten der Dependencies übernehmen kann. Dabei lässt es sich sehr einfach in CI-Pipelines integrieren. Renovate unterstützt viele Sprachen und Plattformen zur Codeverwaltung.

Funktionsweise

Wenn Renovate eine neue Version einer Dependency findet, wird ein neuer Branch angelegt und die Version dort geupdatet. Danach laufen die konfigurierten Pipeline-Jobs auf diesem Branch. Diese sollten unter anderem Regressionstests enthalten, die testen, ob die Anwendung auch unter der neuen Version weiterhin funktioniert wie erwartet. Neben dem Branch erstellt Renovate einen Merge-Request auf den Haupt-Branch. In dem Merge-Request zeigt Renovate die Änderungen aus dem Changelog der Dependency an. Entscheidet man sich, eine Dependency zu updaten, kann der Merge-Request geschlossen werden und das Update fließt so in die Anwendung ein. Eine Einstellmöglichkeit erlaubt, dass Änderungen nach erfolgreich gelaufener Pipeline automatisch gemerget werden. Dies sollte nur geschehen, wenn die Anwendung mit ausreichend Tests versehen ist. Neben den Merge-Requests gibt es noch einen Issue, der als Dashboard den Zustand aller Dependencies anzeigt. Mit dem Dashboard lassen sich auch Freigabeprozesse für bestimmte Updates einrichten. Wie zum Beispiel Major Updates, spezielle Dependencies oder für alle Updates.

Einrichtung in GitLab: Aufsetzen des RenovateBot

Access Token

Es gibt verschiedene Wege, wie Renovate auf ein Repository oder mehrere Repositories zugreifen kann. Wenn man Renovate nur für ein Repository benutzen will, reicht ein GitLab-Accesstoken mit api- und write_repository-Zugriff. Soll sich Renovate um mehrere Repositories kümmern, empfiehlt es sich, einen Renovate-Benutzer in GitLab anzulegen und diesen als Member (Maintainer oder Developer) den relevanten Projekten hinzuzufügen. Diese Variante wird im folgenden Beispiel verwendet.

.gitlab-ci.yml

Dazu wird ein neues Repository renovate angelegt, welches in der .gitlab-ci.yml folgenden Renovate-Job enthält:

1stages:
2  - renovate
3
4renovate:
5  image: renovate/renovate:slim
6  stage: renovate
7  variables:
8    RENOVATE_PLATFORM: gitlab
9    RENOVATE_ENDPOINT: $CI_API_V4_URL
10    RENOVATE_AUTODISCOVER: "true"
11    RENOVATE_BINARY_SOURCE: install
12    LOG_LEVEL: debug
13  tags:
14    - docker
15  only:
16    - schedules
17  script:
18    - renovate $RENOVATE_EXTRA_FLAGS

In diesem Beispiel läuft Renovate in einem Docker-Container, welcher von einem GitLab Runner (Docker executor) gestartet wird.

Damit der Job laufen kann, werden folgende Environment-Variablen benötigt:

  • RENOVATE_TOKEN (CI/CD Variable)
    Hierfür wird für den Renovate-User ein Access Token angelegt, welcher api- und write_repository- Zugriff für GitLab erhält. Der api-Zugriff wird benötigt, damit Renovate den Dependency-Issue updaten, sowie Merge-Requests anlegen kann. Der write_repository-Zugriff wird benötigt, damit Dependency Files (z. B. package.json) geupdatet werden können.
  • GITHUB_COM_TOKEN (CI/CD Variable)
    Hier wird ein readonly-GitHub-Access-Token eines beliebigen GitHub-Accounts benötigt, um Release Notes für die auf GitHub veröffentlichten Dependencies zu laden.
  • RENOVATE_PLATFORM (.gitlab-ci.yml)
    Hier wird angegeben, dass Renovate mit GitLab läuft.
  • RENOVATE_ENDPOINT (.gitlab-ci.yml)
    Hier wird die API-URL von GitLab angegeben. Diese kann aus der von GitLab gesetzten Umgebungsvariable CI_API_V4_URL bezogen werden.
  • RENOVATE_AUTODISCOVER (.gitlab-ci.yml)
    Dieses Flag gibt an, dass Renovate automatisch alle Repositories, auf die es Zugriff hat, nach Dependencies durchsuchen soll.
  • RENOVATE_BINARY_SOURCE (.gitlab-ci.yml)
    Damit installiert sich Renovate “third-party tools”, die es benötigt, um Updates durchführen zu können, z. B npm, yarn, …

Es gibt noch viele weitere Einstellungsmöglichkeiten, die über diese Basiskonfiguration hinausgehen.

Scheduling

In der .gitlab-ci.yml ist unter only angegeben, dass Renovate über einen GitLab-Pipeline-Schedule gestartet wird. Dieser wird im nächsten Schritt angelegt:

Über das Interval Pattern wird angegeben, wie oft Renovate laufen soll. Es gibt keine allgemeine Empfehlung, wie oft dies geschehen sollte. Läuft es zu oft und gibt es sehr viele Dependency-Updates, kann es den normalen Entwicklungsprozess stören. Aus diesem Grund empfiehlt es sich, Renovate außerhalb der üblichen Arbeitszeiten laufen zu lassen. Renovate sollte aber auch nicht zu selten laufen, da das Mergen eines Update-Branches mit anschließendem Rebase eines anderen Update-Branches nicht in einem Durchlauf erfolgt.

Damit ist die allgemeine Basiskonfiguration von Renovate für eine GitLab-Instanz abgeschlossen.

Projektkonfiguration

Um Renovate in einem Repository zu aktivieren, genügt es, den Renovate-Nutzer als Maintainer oder Developer dem Repository hinzuzufügen. Da die Umgebungsvariable Autodiscover im Renovate-Job auf true gesetzt ist, wird Renovate beim nächsten Durchlauf das Repository automatisch finden und analysieren. Zudem ist es sinnvoll, im Projekt eine renovate.json Datei anzulegen, in der die Konfiguration für das Repository ergänzt werden kann.

1{
2  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3  "extends": ["config:base", ":pinAllExceptPeerDependencies"],
4  "packageRules": [
5    {
6      "matchUpdateTypes": ["minor", "patch"],
7      "automerge": true
8    }
9  ]
10}

In der extends-Property werden sinnvolle Presets angegeben. Mit :pinAllExceptPeerDependencies werden alle Dependencies auf eine feste Version in der package.json-Datei festgeschrieben. Oft schreibt z. B. npm die Versionsnummer mit einem Carret Range in die package.json. Dies ist aber nicht mehr nötig, da Renovate immer für die aktuelle Version sorgt.

Daneben wird noch eine PackageRule angelegt, die dafür sorgt, dass alle Minor- und Patch-Updates automatisch gemerget werden, wenn die Pipeline mit den Tests durchgelaufen ist.

Fazit

Renovate kann mit wenig Konfiguration schnell eingesetzt werden, um Dependencies regelmäßig zu updaten. Damit automatisiert es regelmäßig auftretende Aufgaben und hilft, die Anwendung immer aktuell zu halten. Dies trägt zum fehlerfreien und zuverlässigen Betrieb der Anwendung bei und steigert damit die Wertschöpfung.

Beitrag teilen

Gefällt mir

14

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.