All files / src/git project-clones.ts

25% Statements 3/12
100% Branches 0/0
50% Functions 1/2
25% Lines 3/12

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;
  }
}