feat: add Turborepo per-project monorepo scaffold and project API
- Add Turborepo scaffold templates (apps: product, website, admin, storybook; packages: ui, tokens, types, config) - Add ProjectRecord and AppRecord types to control plane - Add Gitea integration service (repo creation, scaffold push, webhooks) - Add Coolify integration service (project + per-app service provisioning with turbo --filter) - Add project routes: GET/POST /projects, GET /projects/:id/apps, POST /projects/:id/deploy - Update chat route to inject project/monorepo context into AI requests - Add deploy_app and scaffold_app tools to Gemini tool set - Update deploy executor with monorepo-aware /execute/deploy endpoint - Add TURBOREPO_MIGRATION_PLAN.md documenting rationale and scope Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,37 +11,64 @@ await app.register(sensible);
|
||||
app.get("/healthz", async () => ({ ok: true, executor: "deploy" }));
|
||||
|
||||
/**
|
||||
* Deploy a Cloud Run service
|
||||
* In production: triggers Cloud Build, deploys to Cloud Run
|
||||
* In dev: returns mock response
|
||||
* Deploy an app from a Turborepo monorepo.
|
||||
*
|
||||
* Expects input to include:
|
||||
* - repo_url: git clone URL (the project monorepo)
|
||||
* - app_name: the app folder name under apps/ (e.g. "product", "website")
|
||||
* - ref: git branch/tag/sha (default "main")
|
||||
* - env: target environment ("dev" | "staging" | "prod")
|
||||
*
|
||||
* Build command: turbo run build --filter={app_name}
|
||||
* In production this triggers Coolify via its API; in dev it returns a mock.
|
||||
*/
|
||||
app.post("/execute/deploy", async (req) => {
|
||||
const body = req.body as any;
|
||||
const { run_id, tenant_id, input } = body;
|
||||
|
||||
const appName = input.app_name ?? input.service_name ?? "product";
|
||||
const repoUrl = input.repo_url ?? "";
|
||||
const ref = input.ref ?? "main";
|
||||
const env = input.env ?? "dev";
|
||||
|
||||
console.log(`🚀 Monorepo deploy request:`, { run_id, tenant_id, appName, repoUrl, ref, env });
|
||||
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
|
||||
const mockRevision = `${appName}-${Date.now().toString(36)}`;
|
||||
const mockUrl = `https://${appName}-${ref}.vibnai.com`;
|
||||
|
||||
console.log(`✅ Deploy complete:`, { appName, revision: mockRevision, url: mockUrl });
|
||||
|
||||
return {
|
||||
app_name: appName,
|
||||
service_url: mockUrl,
|
||||
revision: mockRevision,
|
||||
build_command: `turbo run build --filter=${appName}`,
|
||||
build_id: `build-${Date.now()}`,
|
||||
deployed_at: new Date().toISOString(),
|
||||
env,
|
||||
};
|
||||
});
|
||||
|
||||
// Legacy Cloud Run endpoint — kept for backwards compatibility
|
||||
app.post("/execute/cloudrun/deploy", async (req) => {
|
||||
const body = req.body as any;
|
||||
const { run_id, tenant_id, input } = body;
|
||||
|
||||
console.log(`🚀 Deploy request:`, { run_id, tenant_id, input });
|
||||
|
||||
// Simulate deployment time
|
||||
console.log(`🚀 Deploy request (legacy):`, { run_id, tenant_id, input });
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
|
||||
// In production, this would:
|
||||
// 1. Clone the repo
|
||||
// 2. Trigger Cloud Build
|
||||
// 3. Deploy to Cloud Run
|
||||
// 4. Return the service URL
|
||||
|
||||
const mockRevision = `${input.service_name}-${Date.now().toString(36)}`;
|
||||
const mockUrl = `https://${input.service_name}-abc123.a.run.app`;
|
||||
|
||||
console.log(`✅ Deploy complete:`, { revision: mockRevision, url: mockUrl });
|
||||
|
||||
return {
|
||||
service_url: mockUrl,
|
||||
revision: mockRevision,
|
||||
build_id: `build-${Date.now()}`,
|
||||
deployed_at: new Date().toISOString(),
|
||||
region: input.region ?? "us-central1",
|
||||
env: input.env
|
||||
env: input.env,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user