From 421f891e6be1f897cd8c12b2ca1d5ced666eb4ee Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 17 Apr 2026 22:37:37 -0400 Subject: [PATCH] refactor(release): simplify detached publish flow Keep the detached release commit and retry-safe package publishes, but drop the draft and tag reuse logic so the release workflow stays focused on preventing dev rewrites while syncing version files back onto the latest dev tip. --- script/publish.ts | 19 +++++++------------ script/version.ts | 34 +++++----------------------------- 2 files changed, 12 insertions(+), 41 deletions(-) diff --git a/script/publish.ts b/script/publish.ts index 994d0bf2c1..6cd244e0e6 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -7,7 +7,6 @@ import { fileURLToPath } from "url" console.log("=== publishing ===\n") const tag = `v${Script.version}` -const release_commit = `release: ${tag}` const pkgjsons = await Array.fromAsync( new Bun.Glob("**/package.json").scan({ @@ -21,10 +20,8 @@ async function hasChanges() { return (await $`git diff --quiet && git diff --cached --quiet`.nothrow()).exitCode !== 0 } -async function releaseTagReady() { - const ref = await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow() - if (ref.exitCode !== 0) return false - return (await $`git log -1 --format=%s refs/tags/${tag}`.text()).trim() === release_commit +async function releaseTagExists() { + return (await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow()).exitCode === 0 } async function prepareReleaseFiles() { @@ -47,18 +44,16 @@ async function prepareReleaseFiles() { if (Script.release && !Script.preview) { await $`git fetch origin --tags` - if (await releaseTagReady()) await $`git switch --detach refs/tags/${tag}` - else await $`git switch --detach` + await $`git switch --detach` } await prepareReleaseFiles() -if (Script.release && !Script.preview && !(await releaseTagReady())) { - await $`git commit -am ${release_commit}` - if ((await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow()).exitCode === 0) { - await $`git tag -f ${tag}` - await $`git push origin refs/tags/${tag} --force --no-verify` +if (Script.release && !Script.preview) { + if (await releaseTagExists()) { + console.log(`release tag ${tag} already exists, skipping tag creation`) } else { + await $`git commit -am "release: ${tag}"` await $`git tag ${tag}` await $`git push origin refs/tags/${tag} --no-verify` await new Promise((resolve) => setTimeout(resolve, 5_000)) diff --git a/script/version.ts b/script/version.ts index c2dbd6c189..c1ad021b69 100755 --- a/script/version.ts +++ b/script/version.ts @@ -5,33 +5,6 @@ import { $ } from "bun" const output = [`version=${Script.version}`] const sha = process.env.GITHUB_SHA ?? (await $`git rev-parse HEAD`.text()).trim() -const repo = process.env.GH_REPO - -async function releaseView() { - if (repo) return await $`gh release view v${Script.version} --json tagName,databaseId --repo ${repo}`.json() - return await $`gh release view v${Script.version} --json tagName,databaseId`.json() -} - -async function ensureRelease(notesFile?: string) { - const existing = repo - ? await $`gh release view v${Script.version} --json tagName,databaseId --repo ${repo}`.nothrow() - : await $`gh release view v${Script.version} --json tagName,databaseId`.nothrow() - if (existing.exitCode === 0) return await releaseView() - if (notesFile) { - if (repo) { - await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}" --notes-file ${notesFile} --repo ${repo}` - return await releaseView() - } - await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}" --notes-file ${notesFile}` - return await releaseView() - } - if (repo) { - await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}" --repo ${repo}` - return await releaseView() - } - await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}"` - return await releaseView() -} if (!Script.preview) { await $`bun script/changelog.ts --to ${sha}`.cwd(process.cwd()) @@ -42,11 +15,14 @@ if (!Script.preview) { const dir = process.env.RUNNER_TEMP ?? "/tmp" const notesFile = `${dir}/opencode-release-notes.txt` await Bun.write(notesFile, body) - const release = await ensureRelease(notesFile) + await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}" --notes-file ${notesFile}` + const release = await $`gh release view v${Script.version} --json tagName,databaseId`.json() output.push(`release=${release.databaseId}`) output.push(`tag=${release.tagName}`) } else if (Script.channel === "beta") { - const release = await ensureRelease() + await $`gh release create v${Script.version} -d --target ${sha} --title "v${Script.version}" --repo ${process.env.GH_REPO}` + const release = + await $`gh release view v${Script.version} --json tagName,databaseId --repo ${process.env.GH_REPO}`.json() output.push(`release=${release.databaseId}`) output.push(`tag=${release.tagName}`) }