CI / pruefen (pull_request) Canceled after 0s
Die Faelle A und B beantworteten die Frage auf Ebene der Scopes, nicht auf Ebene der Aufrufe. Wer nachpruefen wollte, ob ein Recht wirklich noetig ist, musste die drei Clients selbst lesen. Jetzt steht in der README je System eine vollstaendige Tabelle: Aufruf, Zweck, benoetigtes Recht. Die Zuordnung bei GitHub folgt der offiziellen Berechtigungsuebersicht - dass /tags und /stats/commit_activity unter Metadata fallen und nicht unter Contents, ist nicht zu erraten. Fuer GitLab ist mit Quellenangabe belegt, dass es unterhalb von 'api' keinen Schreibzugriff auf Issues gibt. Ausserdem war offen, woher die Kommentare an den Issues stammen: Nebula schreibt keine. Der Schreibzugriff besteht aus genau zwei Aufrufen. Ein Test klopft dafuer die Clients ab - kaeme ein dritter dazu, wuerde die Empfehlung 'nimm ein lesendes Token' still falsch, ohne dass jemand einen Fehler saehe. Der Hinweis am Eingabefeld nannte Actions nicht, obwohl der CI-Zustand bei GitHub genau daran haengt. Refs #10
/** * Das README eines Repositories – gemeinsame Teile fuer alle drei Anbieter. * * Gezeigt wird es auf der Projektseite, damit man nicht ins Git wechseln * muss, nur um zu sehen, worum ein halbvergessenes Projekt eigentlich ging. */ export interface RepoReadme { /** Roher Markdown-Text. */ content: string; /** Dateiname im Repository, etwa "README.md". */ path: string; /** * Basis, gegen die relative Links im Text aufzuloesen sind – die * Web-Ansicht des Repositories im Verzeichnis des READMEs. */ baseUrl: string | null; /** Wurde am Deckel abgeschnitten? */ truncated: boolean; } /** * Hoechstlaenge. Ein README von einem Megabyte gibt es, und es waere in * einer Vorschau ohnehin unlesbar – abgeschnitten wird an einer * Zeilengrenze, damit kein halber Codeblock stehen bleibt. */ export const README_MAX_CHARS = 60_000; /** * Dateinamen, die als README gelten – in dieser Reihenfolge. Markdown zuerst, * weil nur das dargestellt werden kann; die uebrigen landen als Klartext in * einem Codeblock, was immer noch besser ist als nichts. */ const KANDIDATEN = [ "readme.md", "readme.markdown", "readme.mdown", "readme", "readme.txt", "readme.rst", ]; /** * Sucht aus einer Verzeichnisauflistung die README-Datei heraus. * Gross- und Kleinschreibung ist egal; die Reihenfolge oben entscheidet. */ export function pickReadme(namen: string[]): string | null { const klein = new Map(namen.map((name) => [name.toLowerCase(), name])); for (const kandidat of KANDIDATEN) { const treffer = klein.get(kandidat); if (treffer) return treffer; } return null; } /** Kuerzt am Deckel, aber an einer Zeilengrenze. */ export function capReadme(text: string): { content: string; truncated: boolean } { if (text.length <= README_MAX_CHARS) return { content: text, truncated: false }; const roh = text.slice(0, README_MAX_CHARS); const letzterUmbruch = roh.lastIndexOf("\n"); return { // Nur wenn der Umbruch nicht ganz am Anfang liegt – sonst bliebe fast // nichts uebrig. content: letzterUmbruch > README_MAX_CHARS / 2 ? roh.slice(0, letzterUmbruch) : roh, truncated: true, }; } /** * Dekodiert, was die Anbieter als base64 liefern. * * Bewusst ueber Buffer und nicht ueber atob: der Inhalt ist UTF-8, und atob * gaebe Bytes zurueck, aus denen Umlaute als Kauderwelsch herauskaemen. */ export function decodeBase64(value: string): string { return Buffer.from(value.replace(/\s/g, ""), "base64").toString("utf8"); }