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.
This commit is contained in:
Kit Langton 2026-04-17 22:37:37 -04:00
commit 421f891e6b
2 changed files with 12 additions and 41 deletions

View file

@ -7,7 +7,6 @@ import { fileURLToPath } from "url"
console.log("=== publishing ===\n") console.log("=== publishing ===\n")
const tag = `v${Script.version}` const tag = `v${Script.version}`
const release_commit = `release: ${tag}`
const pkgjsons = await Array.fromAsync( const pkgjsons = await Array.fromAsync(
new Bun.Glob("**/package.json").scan({ 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 return (await $`git diff --quiet && git diff --cached --quiet`.nothrow()).exitCode !== 0
} }
async function releaseTagReady() { async function releaseTagExists() {
const ref = await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow() return (await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow()).exitCode === 0
if (ref.exitCode !== 0) return false
return (await $`git log -1 --format=%s refs/tags/${tag}`.text()).trim() === release_commit
} }
async function prepareReleaseFiles() { async function prepareReleaseFiles() {
@ -47,18 +44,16 @@ async function prepareReleaseFiles() {
if (Script.release && !Script.preview) { if (Script.release && !Script.preview) {
await $`git fetch origin --tags` await $`git fetch origin --tags`
if (await releaseTagReady()) await $`git switch --detach refs/tags/${tag}` await $`git switch --detach`
else await $`git switch --detach`
} }
await prepareReleaseFiles() await prepareReleaseFiles()
if (Script.release && !Script.preview && !(await releaseTagReady())) { if (Script.release && !Script.preview) {
await $`git commit -am ${release_commit}` if (await releaseTagExists()) {
if ((await $`git rev-parse -q --verify refs/tags/${tag}`.nothrow()).exitCode === 0) { console.log(`release tag ${tag} already exists, skipping tag creation`)
await $`git tag -f ${tag}`
await $`git push origin refs/tags/${tag} --force --no-verify`
} else { } else {
await $`git commit -am "release: ${tag}"`
await $`git tag ${tag}` await $`git tag ${tag}`
await $`git push origin refs/tags/${tag} --no-verify` await $`git push origin refs/tags/${tag} --no-verify`
await new Promise((resolve) => setTimeout(resolve, 5_000)) await new Promise((resolve) => setTimeout(resolve, 5_000))

View file

@ -5,33 +5,6 @@ import { $ } from "bun"
const output = [`version=${Script.version}`] const output = [`version=${Script.version}`]
const sha = process.env.GITHUB_SHA ?? (await $`git rev-parse HEAD`.text()).trim() 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) { if (!Script.preview) {
await $`bun script/changelog.ts --to ${sha}`.cwd(process.cwd()) 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 dir = process.env.RUNNER_TEMP ?? "/tmp"
const notesFile = `${dir}/opencode-release-notes.txt` const notesFile = `${dir}/opencode-release-notes.txt`
await Bun.write(notesFile, body) 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(`release=${release.databaseId}`)
output.push(`tag=${release.tagName}`) output.push(`tag=${release.tagName}`)
} else if (Script.channel === "beta") { } 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(`release=${release.databaseId}`)
output.push(`tag=${release.tagName}`) output.push(`tag=${release.tagName}`)
} }