fix(FN-1455): initialize git during project registration
Fusion-Task-Id: FN-1455
This commit is contained in:
@@ -70,6 +70,7 @@ describe("ensureCwdProjectRegistered", () => {
|
||||
});
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(existsSync(join(cwd, ".git"))).toBe(true);
|
||||
expect(existsSync(join(cwd, ".fusion"))).toBe(true);
|
||||
expect(existsSync(join(cwd, ".fusion", "fusion.db"))).toBe(true);
|
||||
expect(ensureSpy).toHaveBeenCalledWith(
|
||||
@@ -156,6 +157,7 @@ describe("ensureCwdProjectRegistered", () => {
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("[serve] Failed to auto-register current project: boom"),
|
||||
);
|
||||
expect(readProjectIdentity(cwd)).toBeNull();
|
||||
|
||||
await central.close();
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { join } from "node:path";
|
||||
import { runInit } from "../init.js";
|
||||
import { exec } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import { GitRepositoryInitializationError } from "@fusion/core";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -158,6 +159,14 @@ describe("init command", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("propagates Git initialization failures instead of reporting local init success", async () => {
|
||||
const error = new GitRepositoryInitializationError(tempProjectDir, "git is not installed");
|
||||
mockEnsureProjectForPath.mockRejectedValueOnce(error);
|
||||
|
||||
await expect(runInit({ path: tempProjectDir })).rejects.toBe(error);
|
||||
expect(mockCentralClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should be idempotent - report already initialized", async () => {
|
||||
// First init
|
||||
await runInit({ path: tempProjectDir });
|
||||
@@ -358,7 +367,7 @@ describe("init command", () => {
|
||||
expect(Number(commitCount)).toBe(1);
|
||||
});
|
||||
|
||||
it("does not create git repository without --git and logs a hint", async () => {
|
||||
it("delegates registration without --git and does not log a manual git hint", async () => {
|
||||
const originalLog = console.log;
|
||||
const logs: string[] = [];
|
||||
console.log = (...args: unknown[]) => {
|
||||
@@ -372,6 +381,11 @@ describe("init command", () => {
|
||||
}
|
||||
|
||||
expect(existsSync(join(tempProjectDir, ".git"))).toBe(false);
|
||||
expect(logs.join("\n")).toContain("Not a git repository. Run 'fn init --git' to auto-initialize one.");
|
||||
expect(mockEnsureProjectForPath).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
path: tempProjectDir,
|
||||
}),
|
||||
);
|
||||
expect(logs.join("\n")).not.toContain("Not a git repository");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,7 +164,12 @@ describe("project commands", () => {
|
||||
const { runProjectAdd } = await import("../project.js");
|
||||
await runProjectAdd("demo", ".", { force: true });
|
||||
|
||||
expect(mockRegisterProject).toHaveBeenCalled();
|
||||
expect(mockEnsureProjectForPath).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: "demo",
|
||||
path: process.cwd(),
|
||||
}),
|
||||
);
|
||||
const lines = consoleSpy.mock.calls.map((call) => String(call[0]));
|
||||
expect(lines.some((line) => line.includes("Registered project 'demo'"))).toBe(true);
|
||||
expect(lines.some((line) => line.includes("Location:"))).toBe(true);
|
||||
@@ -339,9 +344,9 @@ describe("project commands", () => {
|
||||
expect(output).toContain("Completed: 10");
|
||||
});
|
||||
|
||||
it("validation exits on missing required args for runProjectAdd", async () => {
|
||||
it("validation exits on invalid project name for runProjectAdd", async () => {
|
||||
const { runProjectAdd } = await import("../project.js");
|
||||
await expect(runProjectAdd("", "/tmp")).rejects.toThrow("process.exit:1");
|
||||
await expect(runProjectAdd("bad name", "/tmp")).rejects.toThrow("process.exit:1");
|
||||
});
|
||||
|
||||
it("validation exits on missing required args for runProjectRemove", async () => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { promisify } from "node:util";
|
||||
const execAsync = promisify(exec);
|
||||
import {
|
||||
CentralCore,
|
||||
GitRepositoryInitializationError,
|
||||
QMD_INSTALL_COMMAND,
|
||||
isQmdAvailable,
|
||||
isValidSqliteDatabaseFile,
|
||||
@@ -105,12 +106,9 @@ export async function runInit(options: InitOptions = {}): Promise<void> {
|
||||
console.log(` ✓ Created .fusion/ directory`);
|
||||
}
|
||||
|
||||
const hasGitRepo = await isGitRepo(cwd);
|
||||
if (!hasGitRepo && options.git) {
|
||||
if (options.git && !(await isGitRepo(cwd))) {
|
||||
await initializeGitRepo(cwd);
|
||||
console.log(` ✓ Initialized git repository`);
|
||||
} else if (!hasGitRepo) {
|
||||
console.log(` ⚠ Not a git repository. Run 'fn init --git' to auto-initialize one.`);
|
||||
}
|
||||
|
||||
// Add local Fusion/Pi storage directories to .gitignore
|
||||
@@ -178,6 +176,10 @@ export async function runInit(options: InitOptions = {}): Promise<void> {
|
||||
|
||||
await central.close();
|
||||
} catch (err) {
|
||||
if (err instanceof GitRepositoryInitializationError) {
|
||||
await central.close();
|
||||
throw err;
|
||||
}
|
||||
// If central DB registration fails, still report success since local files are created
|
||||
console.log(` ⚠ Could not register in central database: ${(err as Error).message}`);
|
||||
console.log(`\n✓ Project initialized locally (central registration can be done later)`);
|
||||
|
||||
Reference in New Issue
Block a user