feat: add GitHub import flow, project delete fix, and analyze API
- Mirror GitHub repos to Gitea as-is on import (skip scaffold) - Auto-trigger ImportAnalyzer agent after successful mirror - Add POST/GET /api/projects/[projectId]/analyze route - Fix project delete button visibility (was permanently opacity:0) - Store isImport, importAnalysisStatus, importAnalysisJobId on projects Made-with: Cursor
This commit is contained in:
@@ -115,9 +115,28 @@ export async function POST(request: Request) {
|
||||
giteaCloneUrl = repo.clone_url;
|
||||
giteaSshUrl = repo.ssh_url;
|
||||
|
||||
// Push Turborepo monorepo scaffold as initial commit
|
||||
await pushTurborepoScaffold(GITEA_ADMIN_USER, repoName, slug, projectName);
|
||||
console.log(`[API] Turborepo scaffold pushed to ${giteaRepo}`);
|
||||
// If a GitHub repo was provided, mirror it as-is.
|
||||
// Otherwise push the default Turborepo scaffold.
|
||||
if (githubRepoUrl) {
|
||||
const agentRunnerUrl = process.env.AGENT_RUNNER_URL ?? 'http://localhost:3333';
|
||||
const mirrorRes = await fetch(`${agentRunnerUrl}/api/mirror`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
github_url: githubRepoUrl,
|
||||
gitea_repo: `${GITEA_ADMIN_USER}/${repoName}`,
|
||||
project_name: projectName,
|
||||
}),
|
||||
});
|
||||
if (!mirrorRes.ok) {
|
||||
const detail = await mirrorRes.text();
|
||||
throw new Error(`GitHub mirror failed: ${detail}`);
|
||||
}
|
||||
console.log(`[API] GitHub repo mirrored to ${giteaRepo}`);
|
||||
} else {
|
||||
await pushTurborepoScaffold(GITEA_ADMIN_USER, repoName, slug, projectName);
|
||||
console.log(`[API] Turborepo scaffold pushed to ${giteaRepo}`);
|
||||
}
|
||||
|
||||
// Register webhook — skip if one already points to this project
|
||||
const webhookUrl = `${APP_URL}/api/webhooks/gitea?projectId=${projectId}`;
|
||||
@@ -239,6 +258,10 @@ export async function POST(request: Request) {
|
||||
// Turborepo monorepo apps — each gets its own Coolify service
|
||||
turboVersion: '2.3.3',
|
||||
apps: provisionedApps,
|
||||
// Import metadata
|
||||
isImport: !!githubRepoUrl,
|
||||
importAnalysisStatus: githubRepoUrl ? 'pending' : null,
|
||||
importAnalysisJobId: null as string | null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
@@ -262,7 +285,40 @@ export async function POST(request: Request) {
|
||||
`, [JSON.stringify(projectId), firebaseUserId, workspacePath]);
|
||||
}
|
||||
|
||||
console.log('[API] Created project', projectId, slug, '| gitea:', giteaRepo ?? 'skipped');
|
||||
// ──────────────────────────────────────────────
|
||||
// 5. If this is an import, trigger the analysis agent
|
||||
// ──────────────────────────────────────────────
|
||||
let analysisJobId: string | null = null;
|
||||
if (githubRepoUrl && giteaRepo) {
|
||||
try {
|
||||
const agentRunnerUrl = process.env.AGENT_RUNNER_URL ?? 'http://localhost:3333';
|
||||
const jobRes = await fetch(`${agentRunnerUrl}/api/agent/run`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
agent: 'ImportAnalyzer',
|
||||
task: `Analyze this imported codebase (originally from ${githubRepoUrl}) and produce CODEBASE_MAP.md and MIGRATION_PLAN.md as described in your instructions.`,
|
||||
repo: giteaRepo,
|
||||
}),
|
||||
});
|
||||
if (jobRes.ok) {
|
||||
const jobData = await jobRes.json() as { jobId?: string };
|
||||
analysisJobId = jobData.jobId ?? null;
|
||||
// Store the job ID on the project record
|
||||
if (analysisJobId) {
|
||||
await query(
|
||||
`UPDATE fs_projects SET data = jsonb_set(jsonb_set(data, '{importAnalysisJobId}', $1::jsonb), '{importAnalysisStatus}', '"running"') WHERE id = $2`,
|
||||
[JSON.stringify(analysisJobId), projectId]
|
||||
);
|
||||
}
|
||||
console.log(`[API] Import analysis job started: ${analysisJobId}`);
|
||||
}
|
||||
} catch (analysisErr) {
|
||||
console.error('[API] Failed to start import analysis (non-fatal):', analysisErr);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[API] Created project', projectId, slug, '| gitea:', giteaRepo ?? 'skipped', '| import:', !!githubRepoUrl);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
@@ -275,6 +331,8 @@ export async function POST(request: Request) {
|
||||
giteaError: giteaError ?? undefined,
|
||||
theiaWorkspaceUrl,
|
||||
theiaError: theiaError ?? undefined,
|
||||
isImport: !!githubRepoUrl,
|
||||
analysisJobId: analysisJobId ?? undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[POST /api/projects/create] Error:', error);
|
||||
|
||||
Reference in New Issue
Block a user