feat(P03): multi-project support, NFR milestone versioning, phase context reset, install scripts (v0.3.0)
This commit is contained in:
@@ -4,6 +4,9 @@ import {
|
||||
CommitEscalation,
|
||||
CommitRequirements,
|
||||
CommitCompoundMeta,
|
||||
parseCommitScope,
|
||||
formatCommitScope,
|
||||
CommitScope,
|
||||
} from "../types/commit-meta.js";
|
||||
import {
|
||||
extractCiBlock,
|
||||
@@ -112,6 +115,19 @@ escalations:
|
||||
|
||||
All tests pass. Awaiting deploy approval.`;
|
||||
|
||||
const SAMPLE_PROJECT_COMMIT = `feat(task-api/P01-01-02): create registration endpoint
|
||||
|
||||
---ci---
|
||||
phase: 1
|
||||
milestone: v1.0
|
||||
project: task-api
|
||||
plan: 01-01
|
||||
task: 01-01-02
|
||||
status: execute
|
||||
---/ci---
|
||||
|
||||
Registration endpoint for task-api project.`;
|
||||
|
||||
describe("extractCiBlock", () => {
|
||||
it("extracts ---ci--- block from commit message", () => {
|
||||
const block = extractCiBlock(SAMPLE_INIT_COMMIT);
|
||||
@@ -192,6 +208,14 @@ describe("parseCiBlock", () => {
|
||||
expect(meta.escalations![0].resolution).toBe("pending");
|
||||
});
|
||||
|
||||
it("parses project field", () => {
|
||||
const block = extractCiBlock(SAMPLE_PROJECT_COMMIT)!;
|
||||
const meta = parseCiBlock(block)!;
|
||||
expect(meta.project).toBe("task-api");
|
||||
expect(meta.phase).toBe(1);
|
||||
expect(meta.plan).toBe("01-01");
|
||||
});
|
||||
|
||||
it("returns null for empty block", () => {
|
||||
const meta = parseCiBlock("");
|
||||
expect(meta).toBeNull();
|
||||
@@ -249,4 +273,85 @@ describe("parseCommitMessage", () => {
|
||||
const parsed = parseCommitMessage("pqr678", SAMPLE_TASK_COMMIT);
|
||||
expect(parsed.body).toContain("POST /auth/register validates email and password");
|
||||
});
|
||||
|
||||
it("parses commit with project-prefixed scope", () => {
|
||||
const parsed = parseCommitMessage("stu901", SAMPLE_PROJECT_COMMIT);
|
||||
expect(parsed.type).toBe("feat");
|
||||
expect(parsed.scope).toBe("task-api/P01-01-02");
|
||||
expect(parsed.ci!.project).toBe("task-api");
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseCommitScope", () => {
|
||||
it("parses init scope", () => {
|
||||
const scope = parseCommitScope("init");
|
||||
expect(scope.isInit).toBe(true);
|
||||
expect(scope.phase).toBe(0);
|
||||
});
|
||||
|
||||
it("parses milestone scope", () => {
|
||||
const scope = parseCommitScope("milestone");
|
||||
expect(scope.isMilestone).toBe(true);
|
||||
expect(scope.phase).toBe(0);
|
||||
});
|
||||
|
||||
it("parses simple phase scope", () => {
|
||||
const scope = parseCommitScope("P01");
|
||||
expect(scope.phase).toBe(1);
|
||||
expect(scope.isInit).toBe(false);
|
||||
expect(scope.isMilestone).toBe(false);
|
||||
});
|
||||
|
||||
it("parses task scope with plan and task", () => {
|
||||
const scope = parseCommitScope("P01-01-02");
|
||||
expect(scope.phase).toBe(1);
|
||||
expect(scope.plan).toBe("01-01");
|
||||
expect(scope.task).toBe("01-01-02");
|
||||
});
|
||||
|
||||
it("parses project-prefixed scope", () => {
|
||||
const scope = parseCommitScope("task-api/P01-01-02");
|
||||
expect(scope.project).toBe("task-api");
|
||||
expect(scope.phase).toBe(1);
|
||||
expect(scope.plan).toBe("01-01");
|
||||
expect(scope.task).toBe("01-01-02");
|
||||
});
|
||||
|
||||
it("does not treat P-prefixed scope as project-prefixed", () => {
|
||||
const scope = parseCommitScope("P01-auth");
|
||||
expect(scope.project).toBeUndefined();
|
||||
expect(scope.phase).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatCommitScope", () => {
|
||||
it("formats init scope", () => {
|
||||
const scope: CommitScope = { phase: 0, isInit: true, isMilestone: false };
|
||||
expect(formatCommitScope(scope)).toBe("init");
|
||||
});
|
||||
|
||||
it("formats milestone scope", () => {
|
||||
const scope: CommitScope = { phase: 0, isInit: false, isMilestone: true };
|
||||
expect(formatCommitScope(scope)).toBe("milestone");
|
||||
});
|
||||
|
||||
it("formats simple phase scope", () => {
|
||||
const scope: CommitScope = { phase: 1, isInit: false, isMilestone: false };
|
||||
expect(formatCommitScope(scope)).toBe("P01");
|
||||
});
|
||||
|
||||
it("formats task scope", () => {
|
||||
const scope: CommitScope = { phase: 1, plan: "01-01", task: "01-01-02", isInit: false, isMilestone: false };
|
||||
expect(formatCommitScope(scope)).toBe("P01-01-02");
|
||||
});
|
||||
|
||||
it("formats project-prefixed scope", () => {
|
||||
const scope: CommitScope = { phase: 1, project: "task-api", plan: "01-01", task: "01-01-02", isInit: false, isMilestone: false };
|
||||
expect(formatCommitScope(scope)).toBe("task-api/P01-01-02");
|
||||
});
|
||||
|
||||
it("formats project-prefixed phase scope without plan/task", () => {
|
||||
const scope: CommitScope = { phase: 2, project: "auth-svc", isInit: false, isMilestone: false };
|
||||
expect(formatCommitScope(scope)).toBe("auth-svc/P02");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user