Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions packages/opencode/script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ import { fileURLToPath } from "url"
const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)

async function published(name: string, version: string) {
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
}

async function publish(dir: string, name: string, version: string) {
if (await published(name, version)) {
console.log(`already published ${name}@${version}`)
return
}
if (process.platform !== "win32") await $`chmod -R 755 .`.cwd(dir)
await $`bun pm pack`.cwd(dir)
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
}

const binaries: Record<string, string> = {}
for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) {
const pkg = await Bun.file(`./dist/${filepath}`).json()
Expand Down Expand Up @@ -40,14 +54,10 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write(
)

const tasks = Object.entries(binaries).map(async ([name]) => {
if (process.platform !== "win32") {
await $`chmod -R 755 .`.cwd(`./dist/${name}`)
}
await $`bun pm pack`.cwd(`./dist/${name}`)
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(`./dist/${name}`)
await publish(`./dist/${name}`, name, binaries[name])
})
await Promise.all(tasks)
await $`cd ./dist/${pkg.name} && bun pm pack && npm publish *.tgz --access public --tag ${Script.channel}`
await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version)

const image = "ghcr.io/anomalyco/opencode"
const platforms = "linux/amd64,linux/arm64"
Expand Down Expand Up @@ -104,6 +114,7 @@ if (!Script.preview) {
await Bun.file(`./dist/aur-${pkg}/PKGBUILD`).write(pkgbuild)
await $`cd ./dist/aur-${pkg} && makepkg --printsrcinfo > .SRCINFO`
await $`cd ./dist/aur-${pkg} && git add PKGBUILD .SRCINFO`
if ((await $`cd ./dist/aur-${pkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break
await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"`
await $`cd ./dist/aur-${pkg} && git push`
break
Expand Down Expand Up @@ -176,6 +187,8 @@ if (!Script.preview) {
await $`git clone ${tap} ./dist/homebrew-tap`
await Bun.file("./dist/homebrew-tap/opencode.rb").write(homebrewFormula)
await $`cd ./dist/homebrew-tap && git add opencode.rb`
await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`
await $`cd ./dist/homebrew-tap && git push`
if ((await $`cd ./dist/homebrew-tap && git diff --cached --quiet`.nothrow()).exitCode !== 0) {
await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`
await $`cd ./dist/homebrew-tap && git push`
}
}
12 changes: 11 additions & 1 deletion packages/plugin/script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@ import { fileURLToPath } from "url"
const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)

async function published(name: string, version: string) {
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
}

await $`bun tsc`
const pkg = await import("../package.json").then((m) => m.default)
const pkg = await import("../package.json").then(
(m) => m.default as { name: string; version: string; exports: Record<string, string> },
)
const original = JSON.parse(JSON.stringify(pkg))
if (await published(pkg.name, pkg.version)) {
console.log(`already published ${pkg.name}@${pkg.version}`)
process.exit(0)
}
for (const [key, value] of Object.entries(pkg.exports)) {
const file = value.replace("./src/", "./dist/").replace(".ts", "")
// @ts-ignore
Expand Down
37 changes: 24 additions & 13 deletions packages/sdk/js/script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,35 @@ import { fileURLToPath } from "url"
const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)

async function published(name: string, version: string) {
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
}

const pkg = (await import("../package.json").then((m) => m.default)) as {
exports: Record<string, string | object>
name: string
version: string
exports: Record<string, unknown>
}
const original = JSON.parse(JSON.stringify(pkg))
function transformExports(exports: Record<string, string | object>) {
for (const [key, value] of Object.entries(exports)) {
if (typeof value === "object" && value !== null) {
transformExports(value as Record<string, string | object>)
} else if (typeof value === "string") {
const file = value.replace("./src/", "./dist/").replace(".ts", "")
exports[key] = {
import: file + ".js",
types: file + ".d.ts",
function transformExports(exports: Record<string, unknown>) {
return Object.fromEntries(
Object.entries(exports).map(([key, value]) => {
if (typeof value === "string") {
const file = value.replace("./src/", "./dist/").replace(".ts", "")
return [key, { import: file + ".js", types: file + ".d.ts" }]
}
}
}
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
return [key, transformExports(value)]
}
return [key, value]
}),
)
}
if (await published(pkg.name, pkg.version)) {
console.log(`already published ${pkg.name}@${pkg.version}`)
process.exit(0)
}
transformExports(pkg.exports)
pkg.exports = transformExports(pkg.exports)
await Bun.write("package.json", JSON.stringify(pkg, null, 2))
await $`bun pm pack`
await $`npm publish *.tgz --tag ${Script.channel} --access public`
Expand Down
91 changes: 66 additions & 25 deletions script/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,63 @@ 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({
absolute: true,
}),
).then((arr) => arr.filter((x) => !x.includes("node_modules") && !x.includes("dist")))

for (const file of pkgjsons) {
let pkg = await Bun.file(file).text()
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${Script.version}"`)
console.log("updated:", file)
await Bun.file(file).write(pkg)
}

const extensionToml = fileURLToPath(new URL("../packages/extensions/zed/extension.toml", import.meta.url))
let toml = await Bun.file(extensionToml).text()
toml = toml.replace(/^version = "[^"]+"/m, `version = "${Script.version}"`)
toml = toml.replaceAll(/releases\/download\/v[^/]+\//g, `releases/download/v${Script.version}/`)
console.log("updated:", extensionToml)
await Bun.file(extensionToml).write(toml)

await $`bun install`
await import(`../packages/sdk/js/script/build.ts`)
async function hasChanges() {
return (await $`git diff --quiet && git diff --cached --quiet`.nothrow()).exitCode !== 0
}

if (Script.release) {
if (!Script.preview) {
await $`git commit -am "release: v${Script.version}"`
await $`git tag v${Script.version}`
await $`git fetch origin`
await $`git cherry-pick HEAD..origin/dev`.nothrow()
await $`git push origin HEAD --tags --no-verify --force-with-lease`
await new Promise((resolve) => setTimeout(resolve, 5_000))
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 prepareReleaseFiles() {
for (const file of pkgjsons) {
let pkg = await Bun.file(file).text()
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${Script.version}"`)
console.log("updated:", file)
await Bun.file(file).write(pkg)
}

await import(`../packages/desktop/scripts/finalize-latest-json.ts`)
await import(`../packages/desktop-electron/scripts/finalize-latest-yml.ts`)
let toml = await Bun.file(extensionToml).text()
toml = toml.replace(/^version = "[^"]+"/m, `version = "${Script.version}"`)
toml = toml.replaceAll(/releases\/download\/v[^/]+\//g, `releases/download/v${Script.version}/`)
console.log("updated:", extensionToml)
await Bun.file(extensionToml).write(toml)

await $`bun install`
await $`./packages/sdk/js/script/build.ts`
}

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 $`gh release edit v${Script.version} --draft=false --repo ${process.env.GH_REPO}`
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`
} else {
await $`git tag ${tag}`
await $`git push origin refs/tags/${tag} --no-verify`
await new Promise((resolve) => setTimeout(resolve, 5_000))
}
}

console.log("\n=== cli ===\n")
Expand All @@ -54,5 +74,26 @@ await import(`../packages/sdk/js/script/publish.ts`)
console.log("\n=== plugin ===\n")
await import(`../packages/plugin/script/publish.ts`)

if (Script.release) {
await import(`../packages/desktop/scripts/finalize-latest-json.ts`)
await import(`../packages/desktop-electron/scripts/finalize-latest-yml.ts`)
}

if (Script.release && !Script.preview) {
await $`git fetch origin`
await $`git checkout -B dev origin/dev`
await prepareReleaseFiles()
if (await hasChanges()) {
await $`git commit -am "sync release versions for v${Script.version}"`
await $`git push origin HEAD:dev --no-verify`
} else {
console.log(`dev already synced for ${tag}`)
}
}

if (Script.release) {
await $`gh release edit ${tag} --draft=false --repo ${process.env.GH_REPO}`
}

const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)
36 changes: 30 additions & 6 deletions script/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,36 @@ import { Script } from "@opencode-ai/script"
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) {
const sha = process.env.GITHUB_SHA ?? (await $`git rev-parse HEAD`.text()).trim()
await $`bun script/changelog.ts --to ${sha}`.cwd(process.cwd())
const file = `${process.cwd()}/UPCOMING_CHANGELOG.md`
const body = await Bun.file(file)
Expand All @@ -15,14 +42,11 @@ if (!Script.preview) {
const dir = process.env.RUNNER_TEMP ?? "/tmp"
const notesFile = `${dir}/opencode-release-notes.txt`
await Bun.write(notesFile, body)
await $`gh release create v${Script.version} -d --title "v${Script.version}" --notes-file ${notesFile}`
const release = await $`gh release view v${Script.version} --json tagName,databaseId`.json()
const release = await ensureRelease(notesFile)
output.push(`release=${release.databaseId}`)
output.push(`tag=${release.tagName}`)
} else if (Script.channel === "beta") {
await $`gh release create v${Script.version} -d --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()
const release = await ensureRelease()
output.push(`release=${release.databaseId}`)
output.push(`tag=${release.tagName}`)
}
Expand Down
Loading