feat(git): offene PRs und Issues, CI-Status und Commit-Aktivitaet

Bisher standen nur Zahlen da. Jetzt kommen die Inhalte mit.

Pull Requests und Issues: bis zu 50 offene je Liste, mit Nummer, Titel,
Autor, Alter, Labels und Link. Bei GitHub und Gitea liefert der
Issue-Endpunkt auch Pull Requests mit - die werden herausgefiltert.

CI-Status des letzten Laufs auf dem Default-Branch:
- GitHub ueber actions/runs; dort sind Lauf-Status und Ergebnis getrennt und
  werden auf einen Wert zusammengefuehrt
- GitLab ueber pipelines
- Gitea ueber den kombinierten Commit-Status. Das deckt Gitea Actions und
  externe Systeme wie Woodpecker gleichermassen ab - ein reiner
  Actions-Endpunkt existiert auf aelteren Instanzen nicht.

Commit-Aktivitaet als Balkenreihe. Berechnet aus den ohnehin geholten
Commits (jetzt 100 statt 15, angezeigt bleiben 15) statt ueber eigene
Statistik-Endpunkte: die gibt es nicht bei allen drei Systemen, und bei
GitHub antworten sie beim ersten Aufruf mit 202 und ohne Daten.

Beim Testen gegen gitlab-runner fiel auf, dass alle 100 Commits in die
letzten 30 Tage fielen - die frueheren Tage haetten faelschlich Null
gezeigt, obwohl wir ueber sie nichts wissen. Die Kurve wird deshalb auf den
tatsaechlich belegten Zeitraum gekuerzt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-26 01:04:19 +02:00
co-authored by Claude Opus 5
parent 4bb600bb06
commit 03ce74faa2
13 changed files with 823 additions and 49 deletions
+8
View File
@@ -117,6 +117,14 @@ async function persistSnapshot(projectId: string, data: RepoSnapshotData) {
commits: data.commits as unknown as object,
releases: data.releases as unknown as object,
languages: data.languages as unknown as object,
pullRequests: data.pullRequests as unknown as object,
issues: data.issues as unknown as object,
commitActivity: data.commitActivity as unknown as object,
ciState: data.ci?.state ?? null,
ciName: data.ci?.name ?? null,
ciBranch: data.ci?.branch ?? null,
ciUrl: data.ci?.url ?? null,
ciFinishedAt: data.ci?.finishedAt ? new Date(data.ci.finishedAt) : null,
pushedAt: data.pushedAt ? new Date(data.pushedAt) : null,
fetchedAt: new Date(),
};