refactor merge: extract lineCount helper, hoist preamble, and gracefully handle git errors
This commit is contained in:
parent
c6b6f52b1f
commit
376f918a66
|
|
@ -8,10 +8,15 @@ import { action as closeAction } from "./close.ts"
|
|||
|
||||
const MAX_DIFF_LINES = 300
|
||||
|
||||
function truncate(text: string, maxLines = 200): string {
|
||||
const lines = text.split("\n")
|
||||
if (lines.length <= maxLines) return text
|
||||
return lines.slice(0, maxLines).join("\n") + `\n... (truncated, ${lines.length - maxLines} more lines)`
|
||||
function lineCount(text: string): number {
|
||||
if (!text) return 0
|
||||
return text.split("\n").length
|
||||
}
|
||||
|
||||
function truncate(text: string, maxLines = MAX_DIFF_LINES): string {
|
||||
const count = lineCount(text)
|
||||
if (count <= maxLines) return text
|
||||
return text.split("\n").slice(0, maxLines).join("\n") + `\n... (truncated, ${count - maxLines} more lines)`
|
||||
}
|
||||
|
||||
export async function action(branch: string) {
|
||||
|
|
@ -59,9 +64,7 @@ export async function action(branch: string) {
|
|||
const resolvable: typeof fileDiffs = []
|
||||
const skipped: string[] = []
|
||||
for (const entry of fileDiffs) {
|
||||
const oursLines = entry.oursDiff ? entry.oursDiff.split("\n").length : 0
|
||||
const theirsLines = entry.theirsDiff ? entry.theirsDiff.split("\n").length : 0
|
||||
if (oursLines > MAX_DIFF_LINES || theirsLines > MAX_DIFF_LINES) {
|
||||
if (lineCount(entry.oursDiff) > MAX_DIFF_LINES || lineCount(entry.theirsDiff) > MAX_DIFF_LINES) {
|
||||
skipped.push(entry.file)
|
||||
} else {
|
||||
resolvable.push(entry)
|
||||
|
|
@ -69,19 +72,14 @@ export async function action(branch: string) {
|
|||
}
|
||||
|
||||
if (resolvable.length === 0) {
|
||||
await git.abortMerge(root)
|
||||
spin.fail("All conflicts are too complex for auto-resolution")
|
||||
console.log("\nThe following files need manual resolution:")
|
||||
for (const file of skipped) console.log(` - ${file}`)
|
||||
process.exit(1)
|
||||
console.log("\nResolve them manually, then run: git add <files> && git commit --no-edit")
|
||||
return
|
||||
}
|
||||
|
||||
for (const { file, oursDiff, theirsDiff } of resolvable) {
|
||||
spin.text = `Resolving ${file}`
|
||||
|
||||
const content = await Bun.file(join(root, file)).text()
|
||||
|
||||
const context = [
|
||||
const preamble = [
|
||||
`## Merge Context`,
|
||||
`Merging branch \`${branch}\` into \`${current}\``,
|
||||
``,
|
||||
|
|
@ -90,6 +88,15 @@ export async function action(branch: string) {
|
|||
``,
|
||||
`### Overall changes on \`${branch}\`:`,
|
||||
(branchDiffStat && truncate(branchDiffStat, 100)) || "(no changes)",
|
||||
].join("\n")
|
||||
|
||||
for (const { file, oursDiff, theirsDiff } of resolvable) {
|
||||
spin.text = `Resolving ${file}`
|
||||
|
||||
const content = await Bun.file(join(root, file)).text()
|
||||
|
||||
const context = [
|
||||
preamble,
|
||||
``,
|
||||
`---`,
|
||||
`## Conflicted File: ${file}`,
|
||||
|
|
@ -121,7 +128,7 @@ export async function action(branch: string) {
|
|||
spin.succeed(`Resolved ${resolvable.length} of ${conflicts.length} conflict(s)`)
|
||||
console.log("\nThe following files are too complex for auto-resolution:")
|
||||
for (const file of skipped) console.log(` - ${file}`)
|
||||
console.log("\nResolve them manually, then run: git commit --no-edit")
|
||||
console.log("\nResolve them manually, then run: git add <files> && git commit --no-edit")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
12
src/git.ts
12
src/git.ts
|
|
@ -135,21 +135,17 @@ export async function mergeBase(ref1: string, ref2: string, cwd: string): Promis
|
|||
return result.text().trim()
|
||||
}
|
||||
|
||||
/** Get a one-line-per-commit log for a revision range. */
|
||||
/** Get a one-line-per-commit log for a revision range. Returns empty string on failure. */
|
||||
export async function commitLog(range: string, cwd: string): Promise<string> {
|
||||
const result = await $`git log --oneline ${range}`.cwd(cwd).nothrow().quiet()
|
||||
if (result.exitCode !== 0) {
|
||||
throw new Error(`Failed to get log for range "${range}"`)
|
||||
}
|
||||
if (result.exitCode !== 0) return ""
|
||||
return result.text().trim()
|
||||
}
|
||||
|
||||
/** Get a diff stat summary for a revision range. */
|
||||
/** Get a diff stat summary for a revision range. Returns empty string on failure. */
|
||||
export async function diffStat(range: string, cwd: string): Promise<string> {
|
||||
const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
|
||||
if (result.exitCode !== 0) {
|
||||
throw new Error(`Failed to get diff stat for range "${range}"`)
|
||||
}
|
||||
if (result.exitCode !== 0) return ""
|
||||
return result.text().trim()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user