// Git helpers for branch validation and commit operations import { execSync } from "child_process" export function getCurrentBranch(cwd = process.cwd()): string { return execSync("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf-8" }).trim() } export function isClean(cwd = process.cwd()): boolean { const status = execSync("git status --porcelain", { cwd, encoding: "utf-8" }).trim() return status === "" } export function commitFile(path: string, message: string, cwd = process.cwd()): void { execSync(`git add ${path}`, { cwd }) execSync(`git commit -m ${JSON.stringify(message)}`, { cwd }) } export function commitFileWithBody(path: string, header: string, body: string, cwd = process.cwd()): void { execSync(`git add ${path}`, { cwd }) const msg = `${header}\n\n${body}` execSync(`git commit -m ${JSON.stringify(msg)}`, { cwd }) } export function branchExists(branch: string, cwd = process.cwd()): boolean { try { execSync(`git rev-parse --verify ${branch}`, { cwd, stdio: "pipe" }) return true } catch { return false } } // Parse the issue branch name into type and ID export function parseIssueBranch(branch: string): { type: string; id: number } | null { const match = branch.match(/^(feature|bugfix|hotfix)\/(\d+)$/) if (!match) return null return { type: match[1], id: Number(match[2]) } } export interface GitCommit { hash: string subject: string body: string } // Get commits on current branch since it diverged from a base branch export function getCommitsSinceDiverge(base = "develop", cwd = process.cwd()): GitCommit[] { return parseGitLog(`${base}..HEAD`, cwd) } // Get commits from a ref spec (e.g. HEAD~3..HEAD) export function getCommitsFromRef(refSpec: string, cwd = process.cwd()): GitCommit[] { return parseGitLog(refSpec, cwd) } // Get all commits on a branch export function getAllCommits(branch: string, cwd = process.cwd()): GitCommit[] { return parseGitLog(branch, cwd) } function parseGitLog(range: string, cwd: string): GitCommit[] { const SEP = "---COMMIT-SEP---" const format = `%H%n%s%n%b%n${SEP}` let output: string try { output = execSync( `git log ${range} --format=${JSON.stringify(format)}`, { cwd, encoding: "utf-8" } ) } catch { return [] } const commits: GitCommit[] = [] const entries = output.split(SEP).filter(e => e.trim()) for (const entry of entries) { const lines = entry.trim().split("\n") if (lines.length < 2) continue commits.push({ hash: lines[0], subject: lines[1], body: lines.slice(2).join("\n").trim(), }) } return commits } // Check if a commit subject is a todo transition export function parseTodoTransition(subject: string): { issueId: number; status: string } | null { const match = subject.match(/^todo\((\d+)\):\s*(\S+)/) if (!match) return null return { issueId: Number(match[1]), status: match[2] } }