pr-rescue: liegengebliebene Pull Requests in fremden Repositories finden

Ein Kommandozeilenwerkzeug, das die eigenen Pull Requests in fremden Repositories danach sortiert, wer als Nächstes handeln muss, und die von einem Stale-Bot geschlossenen findet.

Das Problem

Pull Requests an fremde Projekte bleiben auf zwei Arten liegen. Manche warten auf den Autor (ein Merge-Konflikt, ein fehlschlagender Check, eine Frage aus dem Review), und der Autor bemerkt es nicht. Andere schließt ein Stale-Bot nach Wochen ohne Review, manchmal nachdem sie schon freigegeben waren. Die Benachrichtigungen von GitHub trennen diese Fälle nicht, und eine Schließung durch einen Bot sieht aus wie jede andere.

Über Stale-Bots wird immer wieder geklagt (Reaktionen Stand 2026-10-20):

Dashboards wie gh-dash zeigen offene Pull Requests an. Ein Werkzeug, das von Bots geschlossene Pull Requests findet oder für jeden offenen sagt, wer handeln muss, wurde nicht gefunden.

Wie es funktioniert

pr-rescue nutzt die Anmeldung der GitHub-CLI und einige GraphQL-Suchanfragen, um die offenen, geschlossenen und gemergten Pull Requests des Nutzers in fremden Repositories abzurufen. Es teilt sie in drei Gruppen ein:

  • Wartet auf dich: Merge-Konflikt, angeforderte Änderungen, fehlschlagende Checks, Entwurf oder ein unbeantworteter Kommentar einer Person seit dem letzten eigenen Commit. Dazu kommen Pull Requests, die ein Bot ohne Merge geschlossen hat, markiert mit APPROVED, wenn sie freigegeben waren, und mit dem Hinweis, ob der Branch noch existiert. Davon hängt ab, ob ein Reopen funktionieren kann.
  • Wartet auf die Maintainer: freigegeben, aber nicht gemergt, noch kein Review oder abgebrochene Checks, die einen Neustart brauchen, den ein Fork nicht auslösen kann, jeweils mit den Tagen ohne Aktivität.
  • Bereits erledigt: von Bots geschlossene Pull Requests, auf die ein späterer eigener Pull Request verweist, etwa mit "Replaces #123".

Pull Requests, die eine Person oder der Autor selbst geschlossen hat, fehlen in der Liste. Checks werden einzeln gelesen. Ein Status, der nur meldet, dass eine Deployment-Vorschau freigegeben werden muss (Vercels "Authorization required to deploy" bei Pull Requests aus Forks), zählt nicht als Fehler. Ein Gate-Job wie enforce-all-checks, der nur fehlschlägt, weil ein anderer Job abgebrochen wurde, wird nicht gesondert gemeldet. Fehlschlagende Checks stehen mit Namen in der Ausgabe.

Das ist die Beispielausgabe aus der README mit erfundenen Repository-Namen:

$ pr-rescue
Waiting on you (3)
  acme/router#5059  checks failing: test (3.11)  [open, 78d idle]
      Add retry budget to the proxy
      https://github.com/acme/router/pull/5059
  acme/sdk#1472  closed by github-actions, branch still exists: reopen or resubmit  [closed, 68d idle]
      fix(cli): pass keyword arguments to the start function
      https://github.com/acme/sdk/pull/1472
  acme/storage#9066  merge conflict  [open, 34d idle]
      feat: per-test repeat pass rate threshold
      https://github.com/acme/storage/pull/9066

Waiting on maintainers (2)
  acme/gateway#1638  approved, not merged  [open, 0d idle]
  ...

Already handled (1)
  acme/serving#5636  closed by github-actions, resubmitted as #6421  [closed, 60d idle]

--json gibt die Liste mit den Feldern waiting_on, reason, approved und idle_days aus.

Tests

Die Tests bauen Pull-Request-Datensätze in der Form, die die GraphQL-Abfrage liefert, und geben sie an die Klassifizierung. Abgedeckt sind von Bots geschlossene Pull Requests mit und ohne Branch oder Nachfolger, Schließungen durch eine Person, gemergte Pull Requests, die offenen Zustände und Kommentare von einer Person, einem Bot und dem Autor. Ein nachgebauter GitHub-Client liefert Ergebnisseiten für die drei Suchen. Damit prüft ein Test, dass Neueinreichungen verknüpft werden, die Ergebnisse sortiert sind und jede Anfrage die eigenen Repositories des Nutzers ausschließt. Vier Tests decken die Regeln für Checks ab: den Vercel-Status, einen abgebrochenen Job mit fehlschlagendem Gate-Job, einen Gate-Job, der allein fehlschlägt, und einen echten Fehler neben einem Abbruch. Die Tests greifen nicht aufs Netz zu. Das CI führt sie auf Python 3.10 bis 3.13 aus, prüft mit ruff und ruft --version und --help auf.

Grenzen

  • Bots werden am Kontotyp und an einer kurzen Liste bekannter Bot-Konten erkannt. Schließt eine Person Pull Requests über ein persönliches Konto, zählt sie als Person.
  • Ein Reopen kann trotzdem scheitern, wenn der Basis-Branch weitergezogen ist oder der Head-Branch per Force-Push überschrieben wurde. Ein neuer Pull Request, der den alten erwähnt, erscheint dann unter "Already handled".
  • Ein Check, der wegen eines externen Timeouts fehlschlägt, wird als fehlschlagend gemeldet. Das Werkzeug kann ihn nicht von einem Fehler unterscheiden, den die Änderung verursacht.
  • Die Suche von GitHub liefert höchstens 1000 Ergebnisse pro Anfrage.

Code und Installationsanleitung liegen unter github.com/Jwrede/pr-rescue.