#!/usr/bin/env bun
import { Script } from "@opencode-ai/script"
import { $ } from "bun"
import { Effect } from "effect"
import { fileURLToPath } from "url"
console.log("=== publishing ===\n")
const tag = `v${Script.version}`
const pkgjsons = await Array.fromAsync(
new Bun.Glob("**/package.json").scan({
absolute: true,
}),
).then((arr) => arr.filter((x) => !x.includes("node_modules") && !x.includes("dist")))
const extensionToml = fileURLToPath(new URL("../packages/extensions/zed/extension.toml", import.meta.url))
const readText = (path: string) => Effect.promise(() => Bun.file(path).text())
const writeText = (path: string, value: string) => Effect.promise(() => Bun.write(path, value))
const shell = (run: () => Promise) => Effect.promise(run)
const log = (message: string) => Effect.sync(() => console.log(message))
const hasChanges = shell(() => $`git diff --quiet && git diff --cached --quiet`.nothrow()).pipe(
Effect.map((result) => result.exitCode !== 0),
)
const releaseTagExists = shell(() => $`git rev-parse -q --verify refs/tags/${tag}`.nothrow()).pipe(
Effect.map((result) => result.exitCode === 0),
)
const prepareReleaseFiles = Effect.gen(function* () {
yield* Effect.forEach(pkgjsons, (file) =>
Effect.gen(function* () {
const next = (yield* readText(file)).replaceAll(/"version": "[^"]+"/g, `"version": "${Script.version}"`)
yield* log(`updated: ${file}`)
yield* writeText(file, next)
}),
)
const nextToml = (yield* readText(extensionToml))
.replace(/^version = "[^"]+"/m, `version = "${Script.version}"`)
.replaceAll(/releases\/download\/v[^/]+\//g, `releases/download/v${Script.version}/`)
yield* log(`updated: ${extensionToml}`)
yield* writeText(extensionToml, nextToml)
yield* shell(() => $`bun install`)
yield* shell(() => $`./packages/sdk/js/script/build.ts`)
})
const program = Effect.gen(function* () {
if (Script.release && !Script.preview) {
yield* shell(() => $`git fetch origin --tags`)
yield* shell(() => $`git switch --detach`)
}
yield* prepareReleaseFiles
if (Script.release && !Script.preview) {
if (yield* releaseTagExists) yield* log(`release tag ${tag} already exists, skipping tag creation`)
else {
yield* shell(() => $`git commit -am "release: ${tag}"`)
yield* shell(() => $`git tag ${tag}`)
yield* shell(() => $`git push origin refs/tags/${tag} --no-verify`)
yield* shell(() => new Promise((resolve) => setTimeout(resolve, 5_000)))
}
}
yield* log("\n=== cli ===\n")
yield* shell(() => import(`../packages/opencode/script/publish.ts`))
yield* log("\n=== sdk ===\n")
yield* shell(() => import(`../packages/sdk/js/script/publish.ts`))
yield* log("\n=== plugin ===\n")
yield* shell(() => import(`../packages/plugin/script/publish.ts`))
if (Script.release) {
yield* shell(() => import(`../packages/desktop/scripts/finalize-latest-json.ts`))
yield* shell(() => import(`../packages/desktop-electron/scripts/finalize-latest-yml.ts`))
}
if (Script.release && !Script.preview) {
yield* shell(() => $`git fetch origin`)
yield* shell(() => $`git checkout -B dev origin/dev`)
yield* prepareReleaseFiles
if (yield* hasChanges) {
yield* shell(() => $`git commit -am "sync release versions for v${Script.version}"`)
yield* shell(() => $`git push origin HEAD:dev --no-verify`)
} else yield* log(`dev already synced for ${tag}`)
}
if (Script.release) yield* shell(() => $`gh release edit ${tag} --draft=false --repo ${process.env.GH_REPO}`)
})
await Effect.runPromise(program)
const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)