mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-29 03:44:06 +08:00
fix(upstream): preserve compatibility tree overlays
This commit is contained in:
@@ -551,10 +551,17 @@ async function main() {
|
||||
await git.stageAll()
|
||||
const compatMessage = `refactor: kilo compat for ${targetVersion.tag}`
|
||||
if (prior) {
|
||||
const tree = await git.writeTree()
|
||||
const transformed = await git.writeTree()
|
||||
const tree = await git.overlayCompatTree({
|
||||
previous: prior.commit,
|
||||
upstream: prior.upstream,
|
||||
target: targetVersion.commit,
|
||||
transformed,
|
||||
extra: [".opencode-version"],
|
||||
})
|
||||
const commit = await git.createCommit(tree, compatMessage, prior.commit)
|
||||
await git.updateBranch(opencodeBranch, commit)
|
||||
await git.checkout(opencodeBranch)
|
||||
await $`git reset --hard ${commit}`.quiet()
|
||||
} else {
|
||||
await git.commit(compatMessage)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getCommitHash,
|
||||
getCommitParents,
|
||||
isAncestor,
|
||||
overlayCompatTree,
|
||||
recordAncestor,
|
||||
updateBranch,
|
||||
writeTree,
|
||||
@@ -108,3 +109,42 @@ test("finds previous compatibility commit when upstream tags diverge", async ()
|
||||
expect(found?.upstream).toBe(side)
|
||||
expect(found?.commit).not.toBe(ancient)
|
||||
})
|
||||
|
||||
test("compatibility tree preserves Kilo paths unchanged upstream", async () => {
|
||||
await Bun.write("shared.txt", "opencode A\n")
|
||||
await Bun.write("unchanged.txt", "opencode unchanged\n")
|
||||
await Bun.write("removed.txt", "remove me\n")
|
||||
const old = await commit("release: v1.0.0")
|
||||
|
||||
await Bun.write("shared.txt", "opencode B\n")
|
||||
await Bun.write("added.txt", "opencode added\n")
|
||||
await rm("removed.txt")
|
||||
const target = await commit("release: v1.0.1")
|
||||
|
||||
await $`git checkout -b main ${old}`.quiet()
|
||||
await Bun.write("shared.txt", "kilo A\n")
|
||||
await Bun.write("unchanged.txt", "kilo marker\n")
|
||||
await Bun.write("kilo-only.txt", "keep me\n")
|
||||
const previous = await commit("refactor: kilo compat for v1.0.0")
|
||||
|
||||
await $`git checkout --detach ${target}`.quiet()
|
||||
await Bun.write("shared.txt", "kilo B\n")
|
||||
await Bun.write("added.txt", "kilo added\n")
|
||||
await Bun.write(".opencode-version", "v1.0.1\n")
|
||||
await $`git add -A`.quiet()
|
||||
const transformed = await writeTree()
|
||||
const tree = await overlayCompatTree({
|
||||
previous,
|
||||
upstream: old,
|
||||
target,
|
||||
transformed,
|
||||
extra: [".opencode-version"],
|
||||
})
|
||||
|
||||
expect(await $`git show ${`${tree}:shared.txt`}`.text()).toBe("kilo B\n")
|
||||
expect(await $`git show ${`${tree}:added.txt`}`.text()).toBe("kilo added\n")
|
||||
expect(await $`git show ${`${tree}:unchanged.txt`}`.text()).toBe("kilo marker\n")
|
||||
expect(await $`git show ${`${tree}:kilo-only.txt`}`.text()).toBe("keep me\n")
|
||||
expect(await $`git show ${`${tree}:.opencode-version`}`.text()).toBe("v1.0.1\n")
|
||||
expect((await $`git cat-file -e ${`${tree}:removed.txt`}`.quiet().nothrow()).exitCode).not.toBe(0)
|
||||
})
|
||||
|
||||
@@ -206,6 +206,48 @@ export async function writeTree(): Promise<string> {
|
||||
return result.trim()
|
||||
}
|
||||
|
||||
function chunks<T>(items: T[], size = 200): T[][] {
|
||||
return Array.from({ length: Math.ceil(items.length / size) }, (_, idx) => items.slice(idx * size, (idx + 1) * size))
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay transformed upstream changes onto the previous compatibility tree.
|
||||
* Paths unchanged upstream keep their prior Kilo content, including Kilo-only
|
||||
* files and marker-bearing shared files.
|
||||
*/
|
||||
export async function overlayCompatTree(input: {
|
||||
previous: string
|
||||
upstream: string
|
||||
target: string
|
||||
transformed: string
|
||||
extra?: string[]
|
||||
}): Promise<string> {
|
||||
const diff = await $`git diff --name-only -z ${input.upstream} ${input.target}`.quiet().nothrow()
|
||||
if (diff.exitCode !== 0) throw new Error(`Failed to list upstream changes: ${diff.stderr.toString()}`)
|
||||
|
||||
const paths = Array.from(
|
||||
new Set([
|
||||
...diff.stdout
|
||||
.toString()
|
||||
.split("\0")
|
||||
.filter((path) => path.length > 0),
|
||||
...(input.extra ?? []),
|
||||
]),
|
||||
)
|
||||
const keep: string[] = []
|
||||
const remove: string[] = []
|
||||
for (const path of paths) {
|
||||
const result = await $`git cat-file -e ${`${input.transformed}:${path}`}`.quiet().nothrow()
|
||||
if (result.exitCode === 0) keep.push(path)
|
||||
else remove.push(path)
|
||||
}
|
||||
|
||||
await $`git read-tree ${input.previous}`.quiet()
|
||||
for (const batch of chunks(keep)) await $`git checkout ${input.transformed} -- ${batch}`.quiet()
|
||||
for (const batch of chunks(remove)) await $`git update-index --force-remove -- ${batch}`.quiet()
|
||||
return writeTree()
|
||||
}
|
||||
|
||||
export async function createCommit(tree: string, message: string, parent: string): Promise<string> {
|
||||
const result = await $`git commit-tree ${tree} -p ${parent} -m ${message}`.text()
|
||||
return result.trim()
|
||||
|
||||
Reference in New Issue
Block a user