feat(P03): multi-project support, NFR milestone versioning, phase context reset, install scripts (v0.3.0)

This commit is contained in:
CI
2026-05-29 15:13:45 +00:00
parent e4bb3a9970
commit ddf04792c7
57 changed files with 1748 additions and 59 deletions
+91
View File
@@ -56,6 +56,24 @@ describe("GitContext", () => {
});
});
describe("projectSlug", () => {
it("defaults to undefined", () => {
const ctx = new GitContext(repoDir);
expect(ctx.getProjectSlug()).toBeUndefined();
});
it("accepts project slug in constructor", () => {
const ctx = new GitContext(repoDir, "task-api");
expect(ctx.getProjectSlug()).toBe("task-api");
});
it("setProjectSlug updates slug", () => {
const ctx = new GitContext(repoDir);
ctx.setProjectSlug("auth-svc");
expect(ctx.getProjectSlug()).toBe("auth-svc");
});
});
describe("getRecentCommits", () => {
it("returns parsed commits with ci blocks", () => {
commit(repoDir, `docs(init): initialize project
@@ -187,5 +205,78 @@ lessons:
expect(milestoneBranches.length).toBeGreaterThanOrEqual(1);
expect(phaseBranches[0].phaseNumber).toBe(1);
});
it("strips project prefix when projectSlug is set", () => {
commit(repoDir, "initial");
execSync("git checkout -b task-api/phase/01-auth", { cwd: repoDir, stdio: "pipe" });
commit(repoDir, "feat: auth work");
const ctx = new GitContext(repoDir, "task-api");
const branches = ctx.getBranches();
const phaseBranches = branches.filter((b) => b.type === "phase");
expect(phaseBranches.length).toBeGreaterThanOrEqual(1);
expect(phaseBranches[0].phaseNumber).toBe(1);
expect(phaseBranches[0].name).toBe("task-api/phase/01-auth");
});
});
describe("detectProjectFromCommit", () => {
it("detects project from ci block project field", () => {
commit(repoDir, `feat(P01): task work
---ci---
phase: 1
milestone: v1.0
project: task-api
status: execute
---/ci---`);
const ctx = new GitContext(repoDir);
expect(ctx.detectProjectFromCommit()).toBe("task-api");
});
it("detects project from branch prefix", () => {
commit(repoDir, "initial");
execSync("git checkout -b auth-svc/phase/01-auth", { cwd: repoDir, stdio: "pipe" });
commit(repoDir, "feat: auth work");
const ctx = new GitContext(repoDir);
expect(ctx.detectProjectFromCommit()).toBe("auth-svc");
});
it("returns null when no project detected", () => {
commit(repoDir, "feat: some work");
const ctx = new GitContext(repoDir);
expect(ctx.detectProjectFromCommit()).toBeNull();
});
});
describe("isNfrMilestone", () => {
it("returns true when no feat commits exist", () => {
commit(repoDir, `chore(P01): cleanup
---ci---
phase: 1
milestone: v0.1.1
status: execute
---/ci---`);
const ctx = new GitContext(repoDir);
expect(ctx.isNfrMilestone()).toBe(true);
});
it("returns false when feat commits exist", () => {
commit(repoDir, `feat(P01): add feature
---ci---
phase: 1
milestone: v1.0
status: execute
---/ci---`);
const ctx = new GitContext(repoDir);
expect(ctx.isNfrMilestone()).toBe(false);
});
});
});