import { mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; import type { PrismaClient } from "./client.js"; import { InvalidProjectWorkspacePathError, normalizeProjectWorkspacePath, resolveProjectWorkspaceDirectory, wireProjectWorkspace, } from "./project-workspace.js"; vi.mock("@rakazo/core/git-checkout", () => ({ readGitCheckout: vi.fn(async () => ({ present: true, remoteUrl: "https://github.com/example/demo.git", defaultBranch: "main", headCommit: "abc123", dirty: false, dirtyPaths: [], })), })); describe("project workspace wiring", () => { const roots: string[] = []; afterEach(() => { for (const root of roots.splice(0)) { rmSync(root, { recursive: true, force: true }); } }); function tempDir(prefix: string) { const root = mkdtempSync(path.join(tmpdir(), prefix)); roots.push(root); return root; } it("normalizes absolute workspace paths", () => { const root = tempDir("project-workspace-normalize-"); expect(normalizeProjectWorkspacePath(root)).toBe(path.resolve(root)); }); it("rejects missing folders", async () => { const missing = path.join(tmpdir(), `missing-${Date.now()}`); await expect(resolveProjectWorkspaceDirectory(missing)).rejects.toBeInstanceOf( InvalidProjectWorkspacePathError, ); }); it("resolves a symlinked folder to the real folder behind it", async () => { const root = tempDir("project-workspace-symlink-"); const real = path.join(root, "real"); mkdirSync(real); symlinkSync(real, path.join(root, "link")); expect(await resolveProjectWorkspaceDirectory(path.join(root, "link"))).toBe( realpathSync(real), ); }); it("persists workspace and git metadata on the space", async () => { const root = tempDir("project-workspace-wire-"); mkdirSync(path.join(root, ".git")); const updates: Array> = []; const prisma = { space: { update: vi.fn(async ({ data }: { data: Record }) => { updates.push(data); }), }, }; const wired = await wireProjectWorkspace(prisma as unknown as Pick, { spaceId: "space-1", workspacePath: await resolveProjectWorkspaceDirectory(root), }); expect(wired.path).toBe(realpathSync(root)); expect(wired.git).toEqual({ remoteUrl: "https://github.com/example/demo.git", defaultBranch: "main", headCommit: "abc123", dirty: false, dirtyPaths: [], }); expect(updates[0]).toMatchObject({ workspacePath: realpathSync(root), gitRemoteUrl: "https://github.com/example/demo.git", gitDefaultBranch: "main", gitHeadCommit: "abc123", }); }); });