Kai Ole Hartwig
6 Min. Lesezeit
Niedrig

pinup: Warum ich meinen Renovate-Runner durch ein Go-Binary ersetzt habe

Renovate hat bei mir über Jahre Merge-Requests für unsere Repositories geöffnet, zuletzt für rund 200. Zuverlässig, soweit man das sehen konnte. Trotzdem habe ich es im September abgelöst. Nicht wegen der Updates, die es gemacht hat. Sondern wegen der Updates, die es nicht gemacht hat, ohne es zu sagen.

Der Nachfolger heißt pinup. Ein statisches Go-Binary, das die vorhandene Renovate-Konfiguration liest, vor jeder Änderung einen Plan schreibt und für jedes zurückgehaltene Update den Grund nennt. Es ist Open Source, unter Apache-2.0.

01 — Renovate lief. Genau das war das Problem

Mein Setup war nicht klein. Sieben Scan-Partitionen im Stundentakt, eine Fast-Lane für eigene Releases, eine default.json mit 88 KB und 25 Custom Managern. Jeder Stundenlauf kostete 40 Minuten Wall-Zeit und 128 Runner-Minuten. Dazu kam ein Node-Sidecar für die apk-Datenquelle, die Renovate nicht kennt.

Teuer war aber etwas anderes. Die Fehler waren still. Eine automatische Migration der Konfiguration verpackte die fileMatch-Regexe doppelt. Danach lief kein einziger Custom Manager mehr. Eine Gruppenregel verglich den Composer-Namen, Renovate prüfte aber den internen Paketnamen. Die Gruppe griff also nie, und die Merge-Requests stritten sich um dieselbe composer.lock. Ein anderes Lock wurde ein Jahr lang gar nicht aktualisiert.

Keiner dieser Fehler hat einen roten Job erzeugt. Renovate war jedes Mal grün. Ich habe sie gefunden, weil erwartete Updates ausblieben, nicht weil mir etwas gemeldet wurde.

02 — Ein Plan vor dem ersten geschriebenen Byte

Renovate sagt, was es getan hat. Es sagt nicht, was es nicht getan hat und warum. Genau diese Lücke schließt pinup.

Jeder Lauf erzeugt zuerst einen maschinenlesbaren Plan. pinup whatif hört dort auf, pinup run macht weiter. Jedes zurückgehaltene Update trägt im Plan seinen Grund, die Regel, die es hält, und den Zeitpunkt, an dem die Sperre fällt.

 

lodash 4.17.20 -> 4.17.21  ready
redis 20.13.4 -> 28.1.0  dependencyDashboardApproval packageRules[3]

 

Die erste Zeile wird beim nächsten Lauf ein Branch. Die zweite sagt, welche Regel das Major-Update hält und wo sie steht. Mit --now rechnet pinup den Plan für einen anderen Zeitpunkt. So prüfe ich einen Zeitplan oder ein minimumReleaseAge, ohne darauf zu warten.

Was ein Versionslabel verschweigt

Zwei weitere Dinge sieht pinup, die mir vorher gefehlt haben. Ein Tag, dessen Digest sich geändert hat, ist kein Update. Bei latest ist das normal. Bei v2.10.0 wurde eine veröffentlichte Version überschrieben, und der Plan sagt, welcher Fall vorliegt.

Bei Helm-Charts fragt ein Analyzer, was sich wirklich geändert hat: die App-Version, weggefallene Values-Keys, Subcharts und die Images, die das Chart selbst setzt. Diese Images stehen in keiner Datei meines Repositories, also hätte sie sonst niemand gepinnt. Daraus entsteht ein Effective-Label neben dem deklarierten. Das strengere von beiden entscheidet über Automerge.

03 — Umstieg ohne eine geänderte Zeile Konfiguration

pinup liest die vorhandene renovate.json: extends, Presets, packageRules, Custom Regex Manager, Schedules, minimumReleaseAge, Lock-File-Maintenance, postUpgradeTasks, OSV-Alerts und das Dependency-Dashboard. pinup migrate zeigt Schlüssel für Schlüssel, was eine Konfiguration nutzt und was pinup davon unterstützt.

Branch-Namen und Titel der Merge-Requests sind dieselben wie bei Renovate. Offene Branches übernimmt pinup. Beim Wechsel entstand kein einziger doppelter Merge-Request.

Erst vergleichen, dann umschalten

Vor der Umstellung lief pinup im Shadow-Modus. Es verglich seine Pläne Lauf für Lauf mit den Merge-Requests, die Renovate offen hatte. Ein Kontroll-Repository, das bewusst abweichen muss, verhindert, dass sich der Vergleich selbst bestätigt. Erst als beide übereinstimmten, habe ich umgeschaltet.

Clean Room statt Fork

Renovate steht unter AGPL-3.0. Die Konfigurationssprache durfte ich übernehmen, den Code nicht lesen. pinup ist deshalb ein Clean-Room-Nachbau. Ich habe den gepinnten Renovate-Container ausgeführt und das Verhalten aus aufgezeichneten Ein- und Ausgabepaaren nachgebaut. Diese Paare sind heute die Testsuite. pinup selbst steht unter Apache-2.0, wie alle meine Go-Werkzeuge.

04 — Was sich gemessen geändert hat

Der Stundenlauf über alle Repositories braucht jetzt 10,6 statt 40 Minuten Wall-Zeit und 75 statt 128 Runner-Minuten. pinup hat keine Laufzeitumgebung und zwei Fremdabhängigkeiten. Der Node-Sidecar ist weg.

Wichtiger ist die Kette dahinter. Am 25. September habe ich sie einmal von Anfang bis Ende gemessen, an einem echten Release dieses Blogs:

Uhrzeit (UTC)Schritt
07:02Release des Blog-Pakets 3.23.0
07:03pinup öffnet den Merge-Request in der Website-App
07:10Merge-Request gemergt, App-Release folgt
07:19pinup öffnet die Deploy-MR in der GitOps-Konfiguration
07:48pinup merged die Deploy-MR
07:57Änderung live

Knapp eine Stunde vom Tag bis zur Produktion, ohne dass ich eingreifen musste. Ein zweites Release kam währenddessen nach. pinup hat die noch offene Deploy-MR darauf hochgezogen, statt eine zweite zu öffnen.

Häufige Fragen

Muss ich meine renovate.json für pinup anpassen?+

Nein. pinup liest die vorhandene Konfiguration so, wie sie ist. Vorher zeigt pinup migrate Schlüssel für Schlüssel, was die Konfiguration nutzt und was pinup davon unterstützt. Branch-Namen und Titel bleiben gleich, offene Branches werden übernommen.

Wie riskant ist der Umstieg von Renovate auf pinup?+

Er lässt sich in Stufen gehen. pinup whatif ändert nichts und braucht kein Token. Danach folgt ein --dry-run gegen ein echtes Projekt. Im Shadow-Modus vergleicht pinup seine Pläne mit den offenen Merge-Requests von Renovate. Umschalten lohnt sich erst, wenn beide übereinstimmen.

Läuft pinup auch mit GitHub?+

Die GitHub-Anbindung ist implementiert. Getestet ist sie gegen einen Nachbau der API und in einem Lesezugriff auf das eigene Repository. Ein erstes Produktions-Repository auf GitHub steht noch aus. Im Produktionsbetrieb läuft pinup bisher auf GitLab, dort über rund 200 Repositories.

Warum ist pinup kein Fork von Renovate?+

Renovate steht unter AGPL-3.0. Ein Fork hätte diese Lizenz geerbt. pinup ist ein Clean-Room-Nachbau: Das Verhalten wurde am gepinnten Renovate-Container beobachtet und aus aufgezeichneten Ein- und Ausgabepaaren nachgebaut. Kein Code wurde übernommen. Deshalb kann pinup unter Apache-2.0 stehen.

Fazit

pinup ersetzt nicht Renovates Konfigurationssprache, sondern seinen Runner. Die Regeln bleiben. Der Betrieb wird günstiger und vor allem ehrlicher: Wenn ein Update nicht kommt, steht im Plan, warum. Für mich war das der eigentliche Grund. Die gesparten Runner-Minuten sind der Bonus.

Code, Releases und Dokumentation liegen auf GitHub. Einen Überblick mit Quickstart gibt es auf der Projektseite zu pinup.

Ich stelle Ihren Renovate-Betrieb auf pinup um. Oder sage Ihnen, warum sich das für Ihr Setup nicht lohnt.

Konfigurations-Check mit pinup migrate, Shadow-Betrieb neben dem bestehenden Runner und ein Umstieg, bei dem kein Merge-Request doppelt entsteht.

Plattform-Betrieb statt Beratung auf Papier: Ich betreibe die Dependency-Automation auf Wunsch auch dauerhaft mit, inklusive der Regeln, die erklären, warum ein Update wartet.

Termin buchen →

Über den Autor

[Translate to English:] Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freelance DevSecOps consultant · OnlyOle Consulting

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.