import { describe, expect, test } from "bun:test" import { applyOverride, bumpVersion, detectComponentsFromFiles, inferBumpFromIntent, parseReleaseIntent, resolveComponentWarnings, } from "../src/release/components" describe("release component detection", () => { test("maps plugin-only changes to the matching plugin component", () => { const components = detectComponentsFromFiles([ "plugins/compound-engineering/skills/ce-plan/SKILL.md", ]) expect(components.get("compound-engineering")).toEqual([ "plugins/compound-engineering/skills/ce-plan/SKILL.md", ]) expect(components.get("cli")).toEqual([]) expect(components.get("coding-tutor")).toEqual([]) expect(components.get("marketplace")).toEqual([]) }) test("maps cli and plugin changes independently", () => { const components = detectComponentsFromFiles([ "src/commands/install.ts", "plugins/coding-tutor/.claude-plugin/plugin.json", ]) expect(components.get("cli")).toEqual(["src/commands/install.ts"]) expect(components.get("coding-tutor")).toEqual([ "plugins/coding-tutor/.claude-plugin/plugin.json", ]) }) test("maps claude marketplace metadata without bumping plugin components", () => { const components = detectComponentsFromFiles([".claude-plugin/marketplace.json"]) expect(components.get("marketplace")).toEqual([".claude-plugin/marketplace.json"]) expect(components.get("cursor-marketplace")).toEqual([]) expect(components.get("compound-engineering")).toEqual([]) expect(components.get("coding-tutor")).toEqual([]) }) test("maps cursor marketplace metadata to cursor-marketplace component", () => { const components = detectComponentsFromFiles([".cursor-plugin/marketplace.json"]) expect(components.get("cursor-marketplace")).toEqual([".cursor-plugin/marketplace.json"]) expect(components.get("marketplace")).toEqual([]) expect(components.get("compound-engineering")).toEqual([]) expect(components.get("coding-tutor")).toEqual([]) }) }) describe("release intent parsing", () => { test("parses conventional titles with optional scope and breaking marker", () => { const parsed = parseReleaseIntent("feat(coding-tutor)!: add tutor reset flow") expect(parsed.type).toBe("feat") expect(parsed.scope).toBe("coding-tutor") expect(parsed.breaking).toBe(true) expect(parsed.description).toBe("add tutor reset flow") }) test("supports conventional titles without scope", () => { const parsed = parseReleaseIntent("fix: adjust ce:plan-beta wording") expect(parsed.type).toBe("fix") expect(parsed.scope).toBeNull() expect(parsed.breaking).toBe(false) }) test("infers bump levels from parsed intent", () => { expect(inferBumpFromIntent(parseReleaseIntent("feat: add release preview"))).toBe("minor") expect(inferBumpFromIntent(parseReleaseIntent("fix: correct preview output"))).toBe("patch") expect(inferBumpFromIntent(parseReleaseIntent("docs: update requirements"))).toBeNull() expect(inferBumpFromIntent(parseReleaseIntent("refactor!: break compatibility"))).toBe("major") }) }) describe("override handling", () => { test("keeps inferred bump when override is auto", () => { expect(applyOverride("patch", "auto")).toBe("patch") }) test("promotes inferred bump when override is explicit", () => { expect(applyOverride("patch", "minor")).toBe("minor") expect(applyOverride(null, "major")).toBe("major") }) test("increments semver versions", () => { expect(bumpVersion("2.42.0", "patch")).toBe("2.42.1") expect(bumpVersion("2.42.0", "minor")).toBe("2.43.0") expect(bumpVersion("2.42.0", "major")).toBe("3.0.0") }) }) describe("scope mismatch warnings", () => { test("does not require scope when omitted", () => { const warnings = resolveComponentWarnings( parseReleaseIntent("fix: update ce plan copy"), ["compound-engineering"], ) expect(warnings).toEqual([]) }) test("warns when explicit scope contradicts detected files", () => { const warnings = resolveComponentWarnings( parseReleaseIntent("fix(cli): update coding tutor text"), ["coding-tutor"], ) expect(warnings[0]).toContain('Optional scope "cli" does not match') }) })