Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 20x 5x 5x | /**
* 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;
}
}
|