init
This commit is contained in:
commit
932d4ad420
46 changed files with 5800 additions and 0 deletions
95
lib/git.ts
Normal file
95
lib/git.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// 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] }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue