refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt standard monorepo conventions (apps/ for runnable apps, packages/ for reusable libraries). Update all config files, shared package imports, test fixtures, and documentation to reflect new paths. Key fixes: - Update workspace config to ["apps/*", "packages/*"] - Update tsconfig.json rootDir/include for apps/server/ - Add apps/web/** to vitest exclude list - Update drizzle.config.ts schema path - Fix ensure-schema.ts migration path detection (3 levels up in dev, 2 levels up in dist) - Fix tests/integration/cli-server.test.ts import paths - Update packages/shared imports to apps/server/ paths - Update all docs/ files with new paths
This commit is contained in:
48
apps/server/git/project-clones.ts
Normal file
48
apps/server/git/project-clones.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Project Clone Management
|
||||
*
|
||||
* Ensures project repositories are cloned into the repos/ directory.
|
||||
* These base clones are used as the source for git worktrees.
|
||||
*/
|
||||
|
||||
import { join } from 'node:path';
|
||||
import { access } from 'node:fs/promises';
|
||||
import { cloneProject } from './clone.js';
|
||||
import { createModuleLogger } from '../logger/index.js';
|
||||
|
||||
const log = createModuleLogger('git');
|
||||
|
||||
/**
|
||||
* Derive the canonical clone directory for a project (relative to workspace root).
|
||||
* Convention: repos/<sanitizedName>-<id>/
|
||||
*/
|
||||
export function getProjectCloneDir(projectName: string, projectId: string): string {
|
||||
const sanitized = projectName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
||||
return join('repos', `${sanitized}-${projectId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a project's git repository is cloned to the workspace.
|
||||
* Uses the canonical path: <workspaceRoot>/repos/<sanitizedName>-<id>/
|
||||
*
|
||||
* @param project - Project with id, name, and url
|
||||
* @param workspaceRoot - Absolute path to the workspace root
|
||||
* @returns Absolute path to the clone directory
|
||||
*/
|
||||
export async function ensureProjectClone(
|
||||
project: { id: string; name: string; url: string },
|
||||
workspaceRoot: string,
|
||||
): Promise<string> {
|
||||
const relPath = getProjectCloneDir(project.name, project.id);
|
||||
const clonePath = join(workspaceRoot, relPath);
|
||||
|
||||
try {
|
||||
await access(clonePath);
|
||||
log.debug({ project: project.name, clonePath }, 'project clone already exists');
|
||||
return clonePath;
|
||||
} catch {
|
||||
log.info({ project: project.name, url: project.url, clonePath }, 'cloning project for first time');
|
||||
await cloneProject(project.url, clonePath);
|
||||
return clonePath;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user