feat(git): README des Repositories holen
Erspart den Wechsel ins Git, nur um zu sehen, worum ein halbvergessenes Projekt eigentlich ging. GitHub hat einen eigenen Endpunkt, der jede Schreibweise findet - ein Aufruf genuegt. GitLab und Gitea kennen keinen; dort wird erst das Wurzelverzeichnis aufgelistet und dann die gefundene Datei geholt. Erkannt werden README.md und die ueblichen Varianten, Gross- und Kleinschreibung egal; Markdown hat Vorrang, weil nur das wirklich dargestellt werden kann. Geholt wird hoechstens einmal am Tag, wie der Kalender, und mit eigenem Zeitstempel: schlaegt das eine fehl, soll das andere nicht mit blockiert werden. Bei 60 000 Zeichen wird abgeschnitten, aber an einer Zeilengrenze - sonst bliebe womoeglich ein halber Codeblock stehen. Dekodiert wird ueber Buffer und nicht ueber atob, sonst kaemen Umlaute als Kauderwelsch heraus. Kein README ist eine Auskunft, kein Fehlschlag: der Zeitstempel wird dann trotzdem gesetzt, damit nicht jeder Abgleich erneut sucht. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+44
-2
@@ -58,9 +58,10 @@ export async function syncRepository(repositoryId: string): Promise<SyncResult>
|
||||
try {
|
||||
const data = await client.fetchRepo(ref);
|
||||
await persistSnapshot(repository, data);
|
||||
// Erst nach dem Snapshot: die Zeile muss existieren, bevor der Kalender
|
||||
// hineingeschrieben werden kann.
|
||||
// Erst nach dem Snapshot: die Zeile muss existieren, bevor Kalender und
|
||||
// README hineingeschrieben werden koennen.
|
||||
await maybeRefreshCalendar(repository.id, client, ref);
|
||||
await maybeRefreshReadme(repository.id, client, ref);
|
||||
// Nach dem Speichern, damit die Meldung den neuen Stand sieht.
|
||||
await notifyAfterSync(repository.id);
|
||||
return {
|
||||
@@ -196,6 +197,47 @@ async function maybeRefreshCalendar(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt das README – wie der Kalender hoechstens einmal am Tag.
|
||||
*
|
||||
* Ein eigener Zeitstempel und nicht der des Kalenders: schlaegt das eine
|
||||
* fehl, soll das andere nicht mit blockiert werden.
|
||||
*/
|
||||
async function maybeRefreshReadme(
|
||||
repositoryId: string,
|
||||
client: GitClient,
|
||||
ref: { owner: string; name: string },
|
||||
): Promise<void> {
|
||||
try {
|
||||
const snapshot = await prisma.repoSnapshot.findUnique({
|
||||
where: { repositoryId },
|
||||
select: { readmeAt: true },
|
||||
});
|
||||
|
||||
const zuletzt = snapshot?.readmeAt?.getTime() ?? 0;
|
||||
if (Date.now() - zuletzt < CALENDAR_TTL_MS) return;
|
||||
|
||||
const readme = await client.fetchReadme(ref);
|
||||
|
||||
// Kein README im Repository: das ist eine Auskunft, kein Fehlschlag.
|
||||
// Der Zeitstempel wird gesetzt, damit nicht jeder Abgleich erneut sucht,
|
||||
// und ein etwaiger alter Stand verschwindet.
|
||||
await prisma.repoSnapshot.update({
|
||||
where: { repositoryId },
|
||||
data: {
|
||||
readme: readme?.content ?? null,
|
||||
readmePath: readme?.path ?? null,
|
||||
readmeBaseUrl: readme?.baseUrl ?? null,
|
||||
readmeAt: new Date(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// Wie beim Kalender: Beiwerk. Ohne Zeitstempel versucht es der naechste
|
||||
// Durchgang von selbst wieder.
|
||||
console.error("[nebula] README konnte nicht geholt werden:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Owner/Name aus den Feldern oder ersatzweise aus der URL bestimmen. */
|
||||
export function resolveRepoRef(
|
||||
repository: Pick<Repository, "repoOwner" | "repoName" | "repoUrl">,
|
||||
|
||||
Reference in New Issue
Block a user