fix: source-aware repo extraction, Gitea readme/languages endpoints

Use CASE/source instead of COALESCE for repo name extraction — Gitea's
repo.name is the short name while full_name includes the owner prefix.
Fix Gitea README fetch to use /contents/README.md with base64 decoding
instead of the nonexistent /readme endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 16:18:40 +03:00
parent ba216580ea
commit 46ef63a68e
2 changed files with 45 additions and 25 deletions

View File

@@ -54,12 +54,19 @@ impl EventReader for PgStore {
AND ($2::timestamptz IS NULL OR occurred_at < $2)
AND ($3::text[] IS NULL OR source = ANY($3))
AND ($4::bool OR public = true)
AND ($6::text IS NULL OR COALESCE(
AND ($6::text IS NULL OR (CASE source
WHEN 'github' THEN COALESCE(
payload->'repo'->>'name',
payload->'repository'->>'full_name',
payload->>'_repo',
payload->>'product'
) = $6)
payload->'repository'->>'full_name'
)
WHEN 'gitea' THEN COALESCE(
payload->'repo'->>'full_name',
payload->'repo'->>'name'
)
WHEN 'hg' THEN payload->>'_repo'
WHEN 'bugzilla' THEN payload->>'product'
ELSE NULL
END) = $6)
ORDER BY occurred_at DESC
LIMIT $5
"#,
@@ -134,12 +141,19 @@ impl EventReader for PgStore {
MAX(occurred_at) AS last_activity
FROM (
SELECT source, occurred_at,
COALESCE(
CASE source
WHEN 'github' THEN COALESCE(
payload->'repo'->>'name',
payload->'repository'->>'full_name',
payload->>'_repo',
payload->>'product'
) AS repo,
payload->'repository'->>'full_name'
)
WHEN 'gitea' THEN COALESCE(
payload->'repo'->>'full_name',
payload->'repo'->>'name'
)
WHEN 'hg' THEN payload->>'_repo'
WHEN 'bugzilla' THEN payload->>'product'
ELSE NULL
END AS repo,
CASE source
WHEN 'github' THEN 'github.com'
WHEN 'gitea' THEN COALESCE(payload->>'_host', 'git.lair.cafe')

View File

@@ -102,21 +102,27 @@ export async function fetchProjects(): Promise<ProjectSummary[]> {
return resp.json();
}
/** Fetch repo README as rendered HTML or raw markdown. */
/** Fetch repo README as raw markdown. */
export async function fetchReadme(source: Source, host: string, repo: string): Promise<string | null> {
const baseUrl = source === 'github'
? `https://api.github.com/repos/${repo}/readme`
: source === 'gitea'
? `https://${host}/api/v1/repos/${repo}/readme`
: null;
if (!baseUrl) return null;
const resp = await fetch(baseUrl, {
if (source === 'github') {
const resp = await fetch(`https://api.github.com/repos/${repo}/readme`, {
headers: { 'Accept': 'application/vnd.github.raw+json' },
});
if (!resp.ok) return null;
return resp.text();
}
if (source === 'gitea') {
// Gitea returns JSON with base64-encoded content
const resp = await fetch(`https://${host}/api/v1/repos/${repo}/contents/README.md`);
if (!resp.ok) return null;
const data = await resp.json();
if (data.encoding === 'base64' && data.content) {
return atob(data.content);
}
return data.content ?? null;
}
return null;
}
/** Fetch repo languages as { language: bytes } map. */
export async function fetchLanguages(source: Source, host: string, repo: string): Promise<Record<string, number> | null> {