Sonntagabend letzter Woche war AutoBrew auf Version 2.3.0. Montag früh hatte ich eine klare Liste mit acht Features, die ich unbedingt in 2.4 haben wollte. Samstag war v2.4.0 live — und zwischendrin hatte ich einen Signing-Kampf mit Xcode und GitHub Actions, den ich so nicht erwartet hatte. Das ist die ehrliche Erzählung davon, was diese Woche in meiner macOS-App-Entwicklung passiert ist.
AutoBrew v2.4: Was sich für Nutzer ändert
Automatische Snapshots vor jedem Upgrade
Das ist das Feature, das die App einen Sprung nach vorne macht. Bisher hat AutoBrew Homebrew-Casks automatisch aktualisiert — aber wenn ein Update kaputt war, gab es keinen einfachen Weg zurück. V2.4 löst das: Jedes Mal, bevor AutoBrew ein Cask automatisch aktualisiert, legt die App einen Snapshot der App-Daten des Nutzers an. Geht das Update schief, reicht ein Klick in der neuen Update-History-Ansicht, um den Stand von vorher wiederherzustellen.
Technisch läuft das über die bestehende AppSnapshotEngine, die ich jetzt tief in den Upgrade-Flow eingehängt habe. Der Snapshot passiert vor dem eigentlichen brew upgrade-Aufruf, synchron, bevor das Cask-Binary angerührt wird. Die Update-History-Ansicht ist ein neuer Sidebar-Eintrag in BrewStore, der die abgeschlossenen Auto-Upgrades newest-first auflistet — mit Status-Icons pro Cask, die ein dedizierter Parser aus dem brew upgrade-Output extrahiert. Das klingt trivial. Ist es nicht. Brew schreibt seinen Output in einer Mischung aus Fortschritts-Zeilen, Warnungen und tatsächlichen Ergebnissen, die sich je nach Cask und Homebrew-Version leicht unterscheiden. Ich habe den Parser dreimal umgebaut, bis er zuverlässig zwischen “erfolgreich”, “fehlgeschlagen” und “unklar” unterscheiden konnte.
Selektives Wiederherstellen und der Snapshot-Diff-Viewer
Was nützt ein Snapshot, wenn man beim Wiederherstellen alles oder nichts zurückbekommt? Ich wollte granularer sein. V2.4 erlaubt es, einzelne Komponenten eines Snapshots gezielt zurückzuspielen — Preferences separat von Caches, Caches separat von Application-Support-Daten. Der Nutzer sieht, was in welcher Komponente steckt, und entscheidet selbst.
Dazu kommt der Snapshot-Diff-Viewer: ein direkter Vergleich zwischen zwei Snapshots. Man sieht auf einen Blick, welche Dateien sich zwischen dem Stand vor dem Upgrade und dem Stand danach verändert haben. Das ist besonders nützlich, wenn man verstehen will, warum eine App nach dem Update anders verhält — ohne blind wiederherstellen zu müssen. Für die Implementierung greife ich auf FileManager-Enumerationen beider Snapshot-Verzeichnisse zurück und diffiere die Pfade und Datei-Checksums. Die Darstellung passiert in einer simplen SwiftUI-List mit farbcodierten Zeilen. Nichts Spektakuläres technisch, aber der Nutzwert ist real.
Das schlanke CLI per URL-Scheme
Ein Feature, das ich schon länger im Kopf hatte: ein Kommandozeilen-Werkzeug, das AutoBrew-Aktionen auslösen kann, ohne selbst ein vollständiges macOS-App-Bundle mit eigenem Signing-Profil zu sein. Die Lösung ist so simpel wie elegant. Das CLI ist ein schlankes Binary, das Befehle als URL-Scheme-Aufrufe an die laufende AutoBrew-App delegiert. autobrew upgrade firefox wird intern zu einem autobrew://upgrade?cask=firefox-URL-Aufruf — die App empfängt ihn, führt die Aktion aus, und das CLI wartet auf die Antwort. Das Binary selbst braucht kein eigenes Provisioning-Profil, weil es kein eigenständiges App-Bundle ist. Es ist ein Tool. Das Signing-Modell von Apple unterscheidet hier, und das ist einer der Punkte, an dem ich diese Woche auf eine harte Kante gestoßen bin — dazu gleich mehr.
Changelog-Vorschau in den Pending Approvals
AutoBrew hat einen Approval-Modus: Upgrades werden nicht automatisch installiert, sondern dem Nutzer zur Genehmigung vorgelegt. Bisher sah man dabei nur Cask-Name und neue Versionsnummer. Das reicht nicht. V2.4 holt die GitHub-Release-Notes direkt in die Pending-Approvals-Ansicht. Man sieht, was sich in einem Update geändert hat, bevor man auf “Installieren” klickt. Die Implementierung ist ein einfacher GitHub-API-Aufruf gegen api.github.com/repos/{owner}/{repo}/releases/tags/{version}, gecacht in BrewStore, damit nicht bei jedem View-Aufruf eine Anfrage rausgeht.
Das gefällt mir gut. Es ist das erste Feature in AutoBrew, das Daten von außerhalb des lokalen Systems zieht — und es fühlt sich richtig an, weil es einen echten Engpass löst: Man wollte wissen, was ein Update bringt, bevor man es freigibt.
Orphan-Cleanup und brew doctor
Zwei kleinere, aber nützliche Ergänzungen: brew autoremove ist jetzt direkt aus BrewStore heraus aufrufbar. Homebrew hinterlässt nach Upgrades und Deinstallationen regelmäßig verwaiste Dependencies. Statt manuell im Terminal aufzuräumen, gibt es jetzt einen Button. Und brew doctor-Output wird geparst und als Health-Sektion angezeigt — Warnungen und Probleme, strukturiert lesbar, nicht als roher Terminal-Dump. Beides klingt nach Kleinkram. Für jemanden, der AutoBrew als primäres Homebrew-Interface nutzt, ist es das Komplettgefühl, das vorher noch gefehlt hat.
Externer Snapshot-Speicher via Security-Scoped Bookmarks
Wer Snapshots nicht im Standard-App-Support-Verzeichnis haben will — zum Beispiel weil dort Speicherplatz knapp ist oder weil man Snapshots auf eine externe SSD auslagern möchte — kann jetzt einen eigenen Speicherort wählen. Die App merkt sich den Zugriff über einen Security-Scoped Bookmark, den macOS für genau diesen Zweck bereitstellt. Der Nutzer wählt einmal einen Ordner per Open-Panel, die App speichert den Bookmark in UserDefaults, und ab diesem Moment landet jeder neue Snapshot dort. Kein erneuter Dialog, kein Berechtigungsverlust nach einem Neustart. Das war konzeptuell einfach, hat aber in der Praxis zwei Iterationen gebraucht, weil ich beim ersten Anlauf den Bookmark zu früh im App-Lifecycle aufgelöst habe — nach einem Neustart war der Scope nicht mehr aktiv und der Schreibvorgang schlug lautlos fehl. Stille Fehler sind die schlimmsten.
Der Signing-Kampf: Warum ich heute dreimal denselben CI-Job gemergt habe
Apples Code-Signing-Modell ist und bleibt nervig. Diese Woche hat es mich einen halben Tag gekostet.
Das Problem: Ich wollte die CI-Pipeline auf eine wiederverwendbare GitHub-Actions-Workflow-Bibliothek umstellen — marcelrgberger/ci-open-source@v1 — die ich für meine öffentlichen Projekte pflege. Der erste Versuch lief mit automatischem Signing, was Xcode Cloud vorbehalten ist und auf normalen GitHub-Runnern nicht zuverlässig funktioniert. Der zweite Versuch verwendete mein wiederverwendbares Workflow-Setup mit ci-open-source, scheiterte aber daran, dass das CLI-Helper-Binary einen Provisioning-Profile-Specifier im Build-Setting hatte — was für Command-Line-Tools schlicht verboten ist. Tools sind kein App-Bundle, Apple erlaubt dort keine Profile.
Am Ende bin ich zurück auf Manual-Signing mit explizitem Profil-Bezeichner gegangen, habe den Profil-Specifier aus dem CLI-Target entfernt, und das redundante keychain-password-Secret gestrichen, weil match-password das seit Version 1.3.0 abdeckt. Drei Merges, ein Revert, ein halber Tag. Das Ergebnis ist jetzt sauberer als vor dem Chaos — aber ich wäre lieber direkt dort angekommen.
Was ich mitnehme: Wenn man in einer macOS-App ein Command-Line-Tool als separates Target hat, muss das Signing-Setup der beiden Targets von Anfang an getrennt gedacht werden. Das App-Bundle braucht ein Provisioning-Profil. Das CLI-Tool nicht. Xcode macht den Unterschied nicht automatisch, und wenn man es nicht explizit setzt, knallt es irgendwann in der CI — und meistens zu einem unpassenden Moment.
Was als nächstes kommt
Die Retry-Logik für fehlgeschlagene Upgrades ist bereits drin: automatische Wiederholungsversuche nach einer Stunde, vier Stunden und zwölf Stunden, bevor ein Upgrade als dauerhaft gescheitert markiert wird. Das ist eine kleine Sache, die im Alltag einen Unterschied macht — ein Update schlägt oft fehl, weil das Netzwerk kurz weg war oder ein Prozess blockiert hat, nicht weil das Paket kaputt ist.
Cask-Kollektionen sind ebenfalls in v2.4: Casks zu benannten Gruppen zusammenfassen und per Klick als Gruppe installieren oder deinstallieren. Das ist der Anfang einer Migrations-Funktion — Mac neu aufsetzen, Kollektion importieren, fertig.
Wenn du überlegst, eine native macOS-App für dein Unternehmen entwickeln zu lassen — sei es für interne Werkzeuge, Automatisierung oder als eigenständiges Produkt — ist AutoBrew ein gutes Beispiel dafür, wie ich arbeite: feature by feature, öffentlich, mit ehrlicher Dokumentation der Rückschläge. Was ich für AutoBrew baue, baue ich mit demselben Anspruch für Kunden. Schau dir meine Leistungen an oder schreib mir direkt.
AutoBrew v2.4.0 ist auf GitHub verfügbar — DMG herunterladen, in Applications ziehen, fertig.