Fix-Bot und Selbstheilung¶
Was ein Repository selbst repariert: die Befunde, die ein Befehl beheben kann, Tests, die einmal scheitern, Prüfungen, die abbrechen, Releases und Bots, die fehlschlagen.
Fix-Bot¶
Eine Prüfung, die scheitert, behebt, was ein Befehl beheben kann, etwa das Format des Codes, Leerzeichen am Zeilenende und Zeilenenden, die Regeln von markdownlint und die Seiten in einer Spalte: Der Bot committet die Behebungen als einen Commit auf einen Branch des Repositorys, auch einen von Renovate, schlägt sie an einem Pull Request aus einem Fork an ihren Zeilen vor und hält einen Pull Request mit den Behebungen von main, der sich selbst merged; python3 .github/blueprint.py fix run macht dieselben Behebungen auf deinem Rechner.
Womit: autofix in .github/checks.toml, after-checks.yml.
Pull Requests reparieren sich selbst¶
Erst beheben, dann erklären: Was ein Befehl an einer gescheiterten Prüfung beheben kann, behebt der Pull Request selbst, auch ein Pull Request von Renovate, und main ebenso.
- Die Prüfung behebt: Jede Erklärung in
.github/checks.tomlsagt inautofix, welche Befehle beheben, was ihre Prüfung findet, oder warum kein Befehl das kann; ein Test des Blueprints scheitert an einer, die es nicht sagt. Scheitert eine Prüfung, führt ihr Job diese Befehle auf dem Head des Pull Requests aus, mit den Werkzeugen, die er schon installiert hat: die Textdateien, die Seiten in einer Spalte, die Version des Release-Bots, Ruff, php-cs-fixer oder Biome und eine Lock-Datei von Composer oder npm, die ihr Werkzeug ablehnt, mit der kleinsten Änderung neu geschrieben, fürscripts/check.sh, markdownlint für das Markdown. Er behält die Dateien, die sie geändert haben, als Artefakt. - Ein Commit auf einem Branch des Repositorys: Sobald die Prüfungen des Commits, die beheben, fertig sind, committet der Fix-Bot alle ihre Behebungen als einen Commit auf den Branch, als die Release-App, mit ihrem Sign-off, und die Prüfungen laufen erneut; der Kommentar des PR-Coachs nennt die Dateien. Das klappt auch auf den Branches von Renovate und den anderen Bots, sodass ein Update eines Formatierers grün bleibt und sich selbst merged.
- Vorschläge an einem Fork: Kein Bot pusht in einen Fork, deshalb schlägt der Bot die Behebungen an ihren Zeilen des Pull Requests vor, höchstens zehn in einem Review und keinen zweimal; Commit suggestion übernimmt einen. Eine Behebung, die kein Vorschlag zeigen kann, etwa Zeilenenden, nennt ihre Datei, und der PR-Coach den Befehl.
- main repariert sich selbst: Scheitert eine Prüfung von
mainmit Behebungen, hält sie ein Pull Request vonbot/self-heal, der sich selbst merged, sobald jede Prüfung besteht; der Bot schließt ihn, sobaldmainkeine mehr braucht, und ein Fehler des Bots hält ein Issue offen. - Sicher mit jedem Pull Request: Der Bot führt nichts eines Pull Requests mit einem Token aus, das schreiben darf. Er nimmt die Behebungen als Daten, mit
blueprint.pyvonmain, und lässt nur Textdateien durch, die der Commit schon hat, unter einfachen Pfaden, außerhalb von.gitund der Workflows. Er committet höchstens zweimal hintereinander (einmal mehr für einen Check, der später endet), nie ein drittes Mal, und ein Pull Request mit dem Labelno-bot-fixesbekommt keinen Commit. - Auf deinem Rechner:
python3 .github/blueprint.py fix runführt die Befehle jedes Schritts vonscripts/check.shaus,python3 .github/blueprint.py fix textbehebt nur die Textdateien, undpython3 .github/blueprint.py fix versionschreibt die Version des Release-Bots dorthin zurück, wo eine Hand sie geändert hat.
Wackelige Tests¶
Ein Testlauf, der fehlschlägt oder dessen Job sein Zeitlimit erreicht, führt seine fehlgeschlagenen Jobs einmal neu aus, außer dieselben Jobs sind schon für den Commit davor gescheitert; ein Job, der dann besteht, wird in einem Issue als wackelig gemeldet, mit dem Schritt, dem Test und dem Fehler, die gescheitert sind, und das Issue zählt, wie oft jeder Job und Test gewackelt hat.
Womit: after-checks.yml.
Abgebrochene Prüfungen¶
Die schnellen Prüfungen laufen einmal für jeden Commit, sodass kein Lauf für einen anderen Commit sie abbricht; ein Lauf einer längeren vorgeschriebenen Prüfung für den neuesten Commit eines Pull Requests, den ein verspäteter Lauf für einen älteren Commit abgebrochen hat, startet von selbst neu, statt den Merge zu blockieren; ein neuerer Push auf main bricht die Tests und Scanner des Pushes davor ab, und ihr Lauf für den neuesten Commit von main startet ebenfalls neu, wenn ein verspäteter Lauf ihn abgebrochen hat.
Womit: after-checks.yml.
Gescheiterte Releases¶
Das Release eines Merges, das scheitert, etwa am Push seines Tags, den GitHub für einen Moment ablehnt, führt seine fehlgeschlagenen Jobs von selbst einmal neu aus, dort, wo sie stehen geblieben sind.
Womit: after-checks.yml.
Wenn eine Prüfung scheitert oder abbricht¶
Eine Prüfung, die ein Runner, eine Website oder GitHub für einen Moment scheitern lässt oder die ein Wettlauf zweier Läufe abbricht, braucht niemanden: Die Bots nach den Prüfungen führen sie einmal neu aus und lassen nur rot, was aus einem Grund scheitert.
- Ein Download, der hängt, beginnt neu, bevor ein Bot nötig ist: Jeder Download der Website ohne eigene Grenze, etwa einer des Social-Plugins, bekommt 10 Sekunden für die Verbindung und 30 für jeden nächsten Teil der Datei, und jeder Download beginnt zweimal neu. In den Variants weicht ein Setup von uv, das nicht binnen zwei Minuten endet, einem zweiten aus den Releases von uv auf GitHub, und ein Container, dessen Image nicht herunterzuladen war, startet neu. Nur was bei jedem Versuch scheitert, lässt seinen Schritt scheitern (Entscheidung 0061 der Entscheidungen).
- Einmal, nicht immer wieder: Der Bot für wackelige Tests führt die fehlgeschlagenen Jobs des ersten Versuchs eines Testlaufs einmal neu aus, ebenso der Bot für gescheiterte Releases mit einem Release, das ein Merge gestartet hat; ein Release, das du schon neu ausführst, gehört dir, und der Bot lässt es in Ruhe; der Bot für abgebrochene Prüfungen startet einen Lauf höchstens zweimal. Ein Job, den GitHub an seinem Zeitlimit stoppt, endet abgebrochen, nicht fehlgeschlagen, und läuft ebenfalls einmal neu. Ein Lauf, den du oder ein neuerer Lauf abgebrochen hat, bleibt abgebrochen, auch wenn ein Job, der auf die anderen wartet, deshalb fehlgeschlagen ist.
- Ein Fehler, der sich wiederholt, ist echt: Wenn dieselben Jobs schon für den Commit davor auf demselben Branch gescheitert sind, nachdem sie einmal neu liefen, laufen sie nicht noch einmal, damit ein kaputter Test keinen Runner umsonst beschäftigt.
- Das Issue der wackeligen Tests bekommt für jeden Lauf, der beim Neustart bestanden hat, einen Kommentar mit einer Tabelle: jeden Job, der zuerst fehlgeschlagen ist, mit einem Link zu seinem Log, den Schritt, der gescheitert ist, die Tests, die pytest im Log nennt, und den ersten Fehler. Seine Beschreibung zählt, wie oft jeder Job und Test gewackelt hat, und verlinkt den Lauf, in dem er es zuletzt getan hat, den neuesten zuerst, sodass der Test, der am meisten wackelt, auffällt, ohne jeden Kommentar zu lesen.
- Tests, die pytest nicht ausführt, etwa die Browsertests eines Docker E2E, nennen den gescheiterten Test ebenfalls, mit
copier update --data "test_marker=Browser step:": Schreibt das Log eines solchen Jobs diesen Text vor den Namen jedes Tests oder Schritts, sobald er beginnt, nennt der Bot den, den das Log vor dem Fehlschlag zuletzt nennt, im gescheiterten Schritt des Jobs und im gescheiterten Worker, und nimmt die erste Exception danach als Fehler, wenn keine Annotation einen nennt. - Was das Issue von einem Pull Request zeigt: Ein Name oder eine Zeile eines Logs steht dort als reiner Code, sodass ein Pull Request damit weder die Tabelle beenden noch jemanden erwähnen kann, und den Branch eines Forks, den er benennt, wie er will, nennt es nicht.
- Die schnellen Prüfungen laufen einmal für jeden Commit: Titel und Changelog, Dependency Review, Secret Scan, Bereichs-Labels und Website. Ein verspäteter Lauf für einen älteren Commit, etwa einer, den eine Änderung des Release-Pull-Requests startet, während release-please in ihn pusht, bricht sie für den neuesten Commit nicht mehr ab. Die Prüfungen, die Minuten dauern, Tests, Lint, CodeQL und die Varianten, brechen den Lauf für einen älteren Commit weiter ab; einen Wettlauf dort repariert der Bot für abgebrochene Prüfungen.
- Ein neuerer Push auf
mainbricht die Prüfungen des Pushes davor ab: Die Tests, CodeQL, die Link-Prüfung, OSV-Scanner und die Prüfung der Workflow-Sicherheit vonmainsagen nur, wie es ummainsteht, und das sagt der Lauf des neueren Commits auch, also hören sie auf, wie in einem Pull Request, und überlassen ihre Runner den Läufen, auf die es ankommt. Die Website, das Release und die Bots, die committen oder GitHub ändern, beenden, was sie begonnen haben, und einen Lauf nach Zeitplan oder von Hand bricht kein Push ab. Hat ein verspäteter Lauf für einen älteren Commit den Lauf für den neuesten Commit vonmainabgebrochen, startet ihn der Bot für abgebrochene Prüfungen neu, sodass die Coverage vonmain, die Alerts des Code Scannings und der Fix-Bot immer seinen neuesten Commit sehen (Entscheidung 0076 der Entscheidungen). - Weitere Test-Workflows eines Repositorys, etwa visuelle Tests, kommen mit
copier update --data "test_workflows=Visual check, Screenshot bot"zur CI und zu Docker E2E dazu. - Die Link-Prüfung eines Pull Requests liest die Dokumente, die er ändert, und alle Dokumente, wenn er die Regeln ändert oder eine Datei verschiebt oder löscht, auf die ein Dokument verlinken kann. lychee behält die Antworten der Websites einen Tag lang und fragt bei einem Link, der gescheitert ist, erneut nach, sodass eine Website, die für einen Moment nicht erreichbar ist, nur die Pull Requests scheitern lässt, die auf sie verlinken.
Wenn ein Bot fehlschlägt¶
Ein Bot oder ein geplanter Workflow, der auf main fehlschlägt, führt seine fehlgeschlagenen Jobs einmal neu aus, wo ein zweiter Versuch bestehen kann, und hält sonst ein Issue pro Workflow offen, mit den fehlgeschlagenen Jobs, ihren Schritten und ihren ersten Fehlern, das der nächste bestandene Lauf schließt; jede Nacht ein Blick auf den letzten Lauf jedes Workflows, auch der des Projekts, der einen Workflow startet, dessen Zeitplan GitHub verpasst oder abgeschaltet hat; wo ein Renovate-Workflow läuft, ein Issue mit den Warnungen und Fehlern von Renovate.
Womit: bot-health.yml, blueprint.py bot-health.
GitHub schickt den Fehlschlag eines geplanten Laufs nur an den, der seinen Zeitplan zuletzt geändert hat, und den eines anderen Laufs an den, der ihn gestartet hat, in diesen Repositorys meist die Release-App: Ein roter Bot zeigte sich nur im Actions-Tab, so wie Findings, Mutation und Renovate tagelang fehlschlugen. Der Bot für den Zustand der Bots (bot-health.yml) macht aus jedem solchen Fehlschlag ein Issue und schließt es, sobald der Bot wieder besteht.
- Ein Issue pro Workflow, mit einem Titel wie Findings fails on main und den Labels
bot-failureundmaintenance. Es nennt den letzten fehlgeschlagenen Lauf, seinen Versuch und seinen Auslöser und eine Tabelle der fehlgeschlagenen Jobs mit dem Schritt, der fehlschlug, und dem ersten Fehler eines jeden, aus den Annotationen des Laufs. Ein späterer Fehlschlag an derselben Stelle aktualisiert es nur, ohne Benachrichtigung; ein Fehlschlag in einem anderen Job oder Schritt fügt einen Kommentar hinzu. Der nächste Lauf, der besteht, schließt es mit einem Link auf diesen Lauf. - Ein zweiter Versuch nur, wo er bestehen kann: Ein erster Fehlschlag führt seine fehlgeschlagenen Jobs einmal neu aus, wie es der Bot für wackelige Tests bei den Tests tut, außer ein anderer Bot hat das schon getan. Findings, das fehlschlägt, solange ein Alarm offen ist, Mutation, das Stunden braucht, um dasselbe noch einmal zu messen, und die Property-Tests und das Fuzzing, die an einer Eingabe fehlschlugen, die sie gefunden haben, werden sofort gemeldet. Ein Lauf, den GitHub nicht starten konnte, weil seine Workflow-Datei ungültig ist, ebenso.
- Welche Läufe zählen: die der Bots und geplanten Workflows, die
bot-health.ymlaufzählt, auf dem Standardbranch, von einem Zeitplan, einem Push, einem Start von Hand oder einem anderen Workflow, nie von einem Pull Request oder einem Fork. Die Prüfungen, die in Pull Requests laufen, etwa die CI, die Website oder CodeQL, und die Workflows des Projekts zählen im nächtlichen Blick, der den letzten beendeten Lauf jedes Workflows auf dem Standardbranch nimmt, sodass keiner ihrer Läufe für einen Pull Request einen Lauf des Bots startet. Einem Lauf, den das Ende einer Prüfung eines Pull Requests startet, wie bei After the checks, gibt GitHub ebenfalls den Standardbranch, deshalb zählt der nächtliche Blick bei einem solchen Workflow nur dessen andere Läufe. Der Workflow Diagrams, Newest Python und Next runner halten je ein eigenes Issue. - Verpasste Zeitpläne: GitHub führt einen Zeitplan zu Stoßzeiten verspätet aus, manchmal gar nicht, und schaltet die Zeitpläne eines Repositorys nach 60 Tagen ohne Aktivität ab. Jede Nacht startet ein Workflow von Hand, dessen letzter Lauf älter ist als die letzte Zeit seines Zeitplans, die sechs Stunden oder länger her ist, höchstens vier pro Nacht, damit die Pull Requests ihre Runner behalten; Findings, Issue lifecycle und der Issue assistant sync des Blueprints starten mit abgeschaltetem
dry_run, wie ihr Zeitplan sie ausführt. Einen Zeitplan, den GitHub abgeschaltet hat, schaltet der Bot wieder ein. - Die Probleme von Renovate: Renovate, das im Blueprint für die Repositorys seines Eigentümers läuft und in einem Repository jedes anderen Eigentümers für dieses, protokolliert eine Lock-Datei, die es nicht lesen kann, als Warnung, ohne fehlzuschlagen. Der Renovate-Workflow hält ein Issue, Renovate logs problems, mit den Warnungen und Fehlern seines letzten Laufs, der welche hatte, nach Repository, und schließt es nach drei Läufen in Folge ohne eines. Ein öffentliches Issue nennt nur öffentliche Repositorys.
- Der Bot liest Läufe, Jobs und Annotationen und schreibt Issues mit dem
GITHUB_TOKENseines Jobs, und er checkt nur den Standardbranch aus, nie den Code eines Pull Requests. Ein Repository, dessen.github/labels.toml, die dem Projekt gehört, keinbot-failurehat, bekommt das Label vom Bot; trag es in die Datei ein, damit Farbe und Beschreibung an einem Ort bleiben.