feat(git): Adapter fuer GitHub, GitLab und Gitea

Ein gemeinsames Interface (GitClient) mit drei Implementierungen. Jeder
Adapter liefert dieselbe normalisierte Struktur, sodass die Oberflaeche die
Unterschiede der APIs nicht kennen muss:

- GitHub  – REST v3, Bearer-Token, funktioniert auch mit Enterprise (/api/v3).
            open_issues_count enthaelt dort PRs, das wird herausgerechnet.
- GitLab  – API v4, PRIVATE-TOKEN, Projekte ueber den URL-kodierten Pfad,
            damit verschachtelte Gruppen funktionieren.
- Gitea   – API v1, token-Header, deckt auch Forgejo ab.

Geholt werden Repo-Eckdaten, Branches, Tags, Commits, Releases, Sprachen und
offene PRs/MRs. Die Teilabfragen laufen parallel; eine fehlschlagende Liste
bricht den restlichen Sync nicht ab.

Weiteres:
- http.ts uebersetzt HTTP-Status in verstaendliche Meldungen (401 Token,
  403 Scopes/Rate-Limit, 404 Pfad) und erzwingt ein Timeout.
- parseRepoUrl versteht https-, ssh- und GitLab-Weboberflaechen-URLs.
- meta.ts haelt die Provider-Metadaten frei von node:crypto, damit
  Client-Komponenten sie importieren koennen.
- sync.ts schreibt das Ergebnis als Snapshot und vermerkt Fehler am Projekt,
  statt eine Ausnahme bis in die Seite durchzureichen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-25 19:33:50 +02:00
co-authored by Claude Opus 5
parent c9e09a2762
commit 9ea6bb8d36
8 changed files with 1146 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
import type { ProviderKind } from "./types";
/**
* Reine Metadaten zu den Git-Systemen – bewusst frei von Node-Imports,
* damit dieses Modul auch in Client-Komponenten benutzt werden kann.
*/
export const PROVIDER_META: Record<
ProviderKind,
{ label: string; defaultBaseUrl: string; tokenHelp: string; docsUrl: string }
> = {
GITHUB: {
label: "GitHub",
defaultBaseUrl: "https://github.com",
tokenHelp:
"Fine-grained Token mit Lesezugriff auf Contents, Metadata, Issues und Pull Requests.",
docsUrl: "https://github.com/settings/tokens",
},
GITLAB: {
label: "GitLab",
defaultBaseUrl: "https://gitlab.com",
tokenHelp: "Personal Access Token mit Scope 'read_api' (bzw. 'read_repository').",
docsUrl: "https://gitlab.com/-/user_settings/personal_access_tokens",
},
GITEA: {
label: "Gitea / Forgejo",
defaultBaseUrl: "https://git.example.com",
tokenHelp: "Access Token mit Leserechten auf repository, issue und user.",
docsUrl: "https://docs.gitea.com/development/api-usage",
},
};
export function guessProvider(host: string): ProviderKind {
const lower = host.toLowerCase();
if (lower.includes("github")) return "GITHUB";
if (lower.includes("gitlab")) return "GITLAB";
return "GITEA";
}