fix(cli): replace cherry-pick with rebase + retry in publish push

Keep the original order (push before publish) to preserve the safe
failure mode, but replace the cherry-pick with rebase and add a
3-attempt retry loop to shrink the race window.
This commit is contained in:
kiloconnect[bot]
2026-04-21 14:23:50 +00:00
parent 835350fedd
commit 42524dbf64
+25 -32
View File
@@ -90,11 +90,33 @@ await $`bun install`
await import(`../packages/sdk/js/script/build.ts`)
if (Script.release) {
// kilocode_change start - commit and tag the release locally; the push to
// origin is deferred until after all package publishing to minimise the
// window in which a concurrent merge to main could cause a race condition.
// kilocode_change start - commit, tag, and push with rebase + retry to handle
// concurrent merges to main. Rebase (instead of cherry-pick) handles
// overlapping file changes cleanly, and the retry loop covers the narrow
// window between fetch and push where another commit could land.
await $`git commit -am "release: v${Script.version}"`
await $`git tag v${Script.version}`
const retries = 3
for (let i = 1; i <= retries; i++) {
await $`git fetch origin main`
const rebase = await $`git rebase origin/main`.nothrow()
if (rebase.exitCode !== 0) {
console.error(`rebase failed (attempt ${i}/${retries}), aborting rebase`)
await $`git rebase --abort`.nothrow()
if (i === retries)
throw new Error("failed to rebase release commit onto origin/main after " + retries + " attempts")
await new Promise((r) => setTimeout(r, 3_000))
continue
}
const push = await $`git push origin HEAD:main --tags --no-verify --force-with-lease`.nothrow()
if (push.exitCode === 0) {
console.log("release commit pushed successfully")
break
}
console.warn(`push rejected (attempt ${i}/${retries}), retrying...`)
if (i === retries) throw new Error("failed to push release commit after " + retries + " attempts")
await new Promise((r) => setTimeout(r, 3_000))
}
// kilocode_change end
// kilocode_change start
@@ -138,35 +160,6 @@ await import(`../packages/kilo-vscode/script/publish.ts`)
const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)
// kilocode_change start - push the release commit to origin after all packages
// are published. Rebasing (instead of cherry-picking) on top of origin/main
// handles concurrent merges cleanly. A retry loop covers the narrow window
// between fetch and push where another commit could land.
if (Script.release) {
const retries = 3
for (let i = 1; i <= retries; i++) {
await $`git fetch origin main`
const rebase = await $`git rebase origin/main`.nothrow()
if (rebase.exitCode !== 0) {
console.error(`rebase failed (attempt ${i}/${retries}), aborting rebase`)
await $`git rebase --abort`.nothrow()
if (i === retries)
throw new Error("failed to rebase release commit onto origin/main after " + retries + " attempts")
await new Promise((r) => setTimeout(r, 3_000))
continue
}
const push = await $`git push origin HEAD:main --tags --no-verify --force-with-lease`.nothrow()
if (push.exitCode === 0) {
console.log("release commit pushed successfully")
break
}
console.warn(`push rejected (attempt ${i}/${retries}), retrying...`)
if (i === retries) throw new Error("failed to push release commit after " + retries + " attempts")
await new Promise((r) => setTimeout(r, 3_000))
}
}
// kilocode_change end
// kilocode_change start - extract latest changelog section for release notes
function extractLatestSection(changelog: string): string {
if (!changelog) return ""