fix: handle Gitea 409 on project create by linking to existing repo

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-19 17:16:24 -08:00
parent aeedc76a18
commit f4ab70822c

View File

@@ -3,7 +3,7 @@ import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth/authOptions'; import { authOptions } from '@/lib/auth/authOptions';
import { query } from '@/lib/db-postgres'; import { query } from '@/lib/db-postgres';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { createRepo, createWebhook, GITEA_ADMIN_USER_EXPORT } from '@/lib/gitea'; import { createRepo, createWebhook, getRepo, listWebhooks, GITEA_ADMIN_USER_EXPORT } from '@/lib/gitea';
import { provisionTheiaWorkspace } from '@/lib/cloud-run-workspace'; import { provisionTheiaWorkspace } from '@/lib/cloud-run-workspace';
import type { ProjectPhaseData, ProjectPhaseScores } from '@/lib/types/project-artifacts'; import type { ProjectPhaseData, ProjectPhaseScores } from '@/lib/types/project-artifacts';
@@ -67,23 +67,45 @@ export async function POST(request: Request) {
try { try {
const repoName = slug; // e.g. "taskmaster" const repoName = slug; // e.g. "taskmaster"
const repo = await createRepo(repoName, { let repo;
description: `${projectName} — managed by Vibn`,
private: true, try {
auto_init: true, repo = await createRepo(repoName, {
}); description: `${projectName} — managed by Vibn`,
private: true,
auto_init: true,
});
console.log(`[API] Gitea repo created: ${GITEA_ADMIN_USER}/${repoName}`);
} catch (createErr) {
const msg = createErr instanceof Error ? createErr.message : String(createErr);
// 409 = repo already exists — link to it instead of failing
if (msg.includes('409')) {
console.log(`[API] Gitea repo already exists, linking to ${GITEA_ADMIN_USER}/${repoName}`);
repo = await getRepo(GITEA_ADMIN_USER, repoName);
if (!repo) throw new Error(`Repo ${repoName} exists but could not be fetched`);
} else {
throw createErr;
}
}
giteaRepo = repo.full_name; // e.g. "mark/taskmaster" giteaRepo = repo.full_name; // e.g. "mark/taskmaster"
giteaRepoUrl = repo.html_url; // e.g. "https://git.vibnai.com/mark/taskmaster" giteaRepoUrl = repo.html_url; // e.g. "https://git.vibnai.com/mark/taskmaster"
giteaCloneUrl = repo.clone_url; giteaCloneUrl = repo.clone_url;
giteaSshUrl = repo.ssh_url; giteaSshUrl = repo.ssh_url;
// 2. Register webhook on the repo pointing back to Vibn // Register webhook — skip if one already points to this project
const webhookUrl = `${APP_URL}/api/webhooks/gitea?projectId=${projectId}`; const webhookUrl = `${APP_URL}/api/webhooks/gitea?projectId=${projectId}`;
const hook = await createWebhook(GITEA_ADMIN_USER, repoName, webhookUrl, GITEA_WEBHOOK_SECRET); const existingHooks = await listWebhooks(GITEA_ADMIN_USER, repoName).catch(() => []);
giteaWebhookId = hook.id; const alreadyHooked = existingHooks.some(h => h.config.url.includes(projectId));
console.log(`[API] Gitea repo created: ${giteaRepo}, webhook: ${giteaWebhookId}`); if (!alreadyHooked) {
const hook = await createWebhook(GITEA_ADMIN_USER, repoName, webhookUrl, GITEA_WEBHOOK_SECRET);
giteaWebhookId = hook.id;
console.log(`[API] Webhook registered: ${giteaRepo}, id: ${giteaWebhookId}`);
} else {
giteaWebhookId = existingHooks.find(h => h.config.url.includes(projectId))?.id ?? null;
console.log(`[API] Webhook already exists for ${giteaRepo}`);
}
} catch (err) { } catch (err) {
// Non-fatal — log and continue. Project is still created. // Non-fatal — log and continue. Project is still created.
giteaError = err instanceof Error ? err.message : String(err); giteaError = err instanceof Error ? err.message : String(err);