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
|
const MAX_DIFF_LINES = 300
|
||||||
|
|
||||||
function truncate(text: string, maxLines = 200): string {
|
function lineCount(text: string): number {
|
||||||
const lines = text.split("\n")
|
if (!text) return 0
|
||||||
if (lines.length <= maxLines) return text
|
return text.split("\n").length
|
||||||
return lines.slice(0, maxLines).join("\n") + `\n... (truncated, ${lines.length - maxLines} more lines)`
|
}
|
||||||
|
|
||||||
|
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) {
|
export async function action(branch: string) {
|
||||||
|
|
@ -59,9 +64,7 @@ export async function action(branch: string) {
|
||||||
const resolvable: typeof fileDiffs = []
|
const resolvable: typeof fileDiffs = []
|
||||||
const skipped: string[] = []
|
const skipped: string[] = []
|
||||||
for (const entry of fileDiffs) {
|
for (const entry of fileDiffs) {
|
||||||
const oursLines = entry.oursDiff ? entry.oursDiff.split("\n").length : 0
|
if (lineCount(entry.oursDiff) > MAX_DIFF_LINES || lineCount(entry.theirsDiff) > MAX_DIFF_LINES) {
|
||||||
const theirsLines = entry.theirsDiff ? entry.theirsDiff.split("\n").length : 0
|
|
||||||
if (oursLines > MAX_DIFF_LINES || theirsLines > MAX_DIFF_LINES) {
|
|
||||||
skipped.push(entry.file)
|
skipped.push(entry.file)
|
||||||
} else {
|
} else {
|
||||||
resolvable.push(entry)
|
resolvable.push(entry)
|
||||||
|
|
@ -69,27 +72,31 @@ export async function action(branch: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolvable.length === 0) {
|
if (resolvable.length === 0) {
|
||||||
await git.abortMerge(root)
|
|
||||||
spin.fail("All conflicts are too complex for auto-resolution")
|
spin.fail("All conflicts are too complex for auto-resolution")
|
||||||
console.log("\nThe following files need manual resolution:")
|
console.log("\nThe following files need manual resolution:")
|
||||||
for (const file of skipped) console.log(` - ${file}`)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const preamble = [
|
||||||
|
`## Merge Context`,
|
||||||
|
`Merging branch \`${branch}\` into \`${current}\``,
|
||||||
|
``,
|
||||||
|
`### Commits on \`${branch}\`:`,
|
||||||
|
(branchLog && truncate(branchLog, 50)) || "(no commits)",
|
||||||
|
``,
|
||||||
|
`### Overall changes on \`${branch}\`:`,
|
||||||
|
(branchDiffStat && truncate(branchDiffStat, 100)) || "(no changes)",
|
||||||
|
].join("\n")
|
||||||
|
|
||||||
for (const { file, oursDiff, theirsDiff } of resolvable) {
|
for (const { file, oursDiff, theirsDiff } of resolvable) {
|
||||||
spin.text = `Resolving ${file}`
|
spin.text = `Resolving ${file}`
|
||||||
|
|
||||||
const content = await Bun.file(join(root, file)).text()
|
const content = await Bun.file(join(root, file)).text()
|
||||||
|
|
||||||
const context = [
|
const context = [
|
||||||
`## Merge Context`,
|
preamble,
|
||||||
`Merging branch \`${branch}\` into \`${current}\``,
|
|
||||||
``,
|
|
||||||
`### Commits on \`${branch}\`:`,
|
|
||||||
(branchLog && truncate(branchLog, 50)) || "(no commits)",
|
|
||||||
``,
|
|
||||||
`### Overall changes on \`${branch}\`:`,
|
|
||||||
(branchDiffStat && truncate(branchDiffStat, 100)) || "(no changes)",
|
|
||||||
``,
|
``,
|
||||||
`---`,
|
`---`,
|
||||||
`## Conflicted File: ${file}`,
|
`## Conflicted File: ${file}`,
|
||||||
|
|
@ -121,7 +128,7 @@ export async function action(branch: string) {
|
||||||
spin.succeed(`Resolved ${resolvable.length} of ${conflicts.length} conflict(s)`)
|
spin.succeed(`Resolved ${resolvable.length} of ${conflicts.length} conflict(s)`)
|
||||||
console.log("\nThe following files are too complex for auto-resolution:")
|
console.log("\nThe following files are too complex for auto-resolution:")
|
||||||
for (const file of skipped) console.log(` - ${file}`)
|
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
|
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()
|
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> {
|
export async function commitLog(range: string, cwd: string): Promise<string> {
|
||||||
const result = await $`git log --oneline ${range}`.cwd(cwd).nothrow().quiet()
|
const result = await $`git log --oneline ${range}`.cwd(cwd).nothrow().quiet()
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) return ""
|
||||||
throw new Error(`Failed to get log for range "${range}"`)
|
|
||||||
}
|
|
||||||
return result.text().trim()
|
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> {
|
export async function diffStat(range: string, cwd: string): Promise<string> {
|
||||||
const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
|
const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) return ""
|
||||||
throw new Error(`Failed to get diff stat for range "${range}"`)
|
|
||||||
}
|
|
||||||
return result.text().trim()
|
return result.text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user