mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-28 02:04:41 +00:00
Fixes an issue where GitHub artifact downloads could strip executable bits from binaries, causing Docker builds to fail when using unpacked dist files directly rather than published tarballs. The chmod now runs before the publish check to guarantee binaries are executable.
196 lines
7 KiB
TypeScript
Executable file
196 lines
7 KiB
TypeScript
Executable file
#!/usr/bin/env bun
|
|
import { $ } from "bun"
|
|
import pkg from "../package.json"
|
|
import { Script } from "@opencode-ai/script"
|
|
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) {
|
|
// GitHub artifact downloads can drop the executable bit, and Docker uses the
|
|
// unpacked dist binaries directly rather than the published tarball.
|
|
if (process.platform !== "win32") await $`chmod -R 755 .`.cwd(dir)
|
|
if (await published(name, version)) {
|
|
console.log(`already published ${name}@${version}`)
|
|
return
|
|
}
|
|
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()
|
|
binaries[pkg.name] = pkg.version
|
|
}
|
|
console.log("binaries", binaries)
|
|
const version = Object.values(binaries)[0]
|
|
|
|
await $`mkdir -p ./dist/${pkg.name}`
|
|
await $`cp -r ./bin ./dist/${pkg.name}/bin`
|
|
await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs`
|
|
await Bun.file(`./dist/${pkg.name}/LICENSE`).write(await Bun.file("../../LICENSE").text())
|
|
|
|
await Bun.file(`./dist/${pkg.name}/package.json`).write(
|
|
JSON.stringify(
|
|
{
|
|
name: pkg.name + "-ai",
|
|
bin: {
|
|
[pkg.name]: `./bin/${pkg.name}`,
|
|
},
|
|
scripts: {
|
|
postinstall: "bun ./postinstall.mjs || node ./postinstall.mjs",
|
|
},
|
|
version: version,
|
|
license: pkg.license,
|
|
optionalDependencies: binaries,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
)
|
|
|
|
const tasks = Object.entries(binaries).map(async ([name]) => {
|
|
await publish(`./dist/${name}`, name, binaries[name])
|
|
})
|
|
await Promise.all(tasks)
|
|
await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version)
|
|
|
|
const image = "ghcr.io/anomalyco/opencode"
|
|
const platforms = "linux/amd64,linux/arm64"
|
|
const tags = [`${image}:${version}`, `${image}:${Script.channel}`]
|
|
const tagFlags = tags.flatMap((t) => ["-t", t])
|
|
await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
|
|
|
|
// registries
|
|
if (!Script.preview) {
|
|
// Calculate SHA values
|
|
const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
|
|
|
|
const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2)
|
|
|
|
// arch
|
|
const binaryPkgbuild = [
|
|
"# Maintainer: dax",
|
|
"# Maintainer: adam",
|
|
"",
|
|
"pkgname='opencode-bin'",
|
|
`pkgver=${pkgver}`,
|
|
`_subver=${_subver}`,
|
|
"options=('!debug' '!strip')",
|
|
"pkgrel=1",
|
|
"pkgdesc='The AI coding agent built for the terminal.'",
|
|
"url='https://github.com/anomalyco/opencode'",
|
|
"arch=('aarch64' 'x86_64')",
|
|
"license=('MIT')",
|
|
"provides=('opencode')",
|
|
"conflicts=('opencode')",
|
|
"depends=('ripgrep')",
|
|
"",
|
|
`source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`,
|
|
`sha256sums_aarch64=('${arm64Sha}')`,
|
|
|
|
`source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`,
|
|
`sha256sums_x86_64=('${x64Sha}')`,
|
|
"",
|
|
"package() {",
|
|
' install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"',
|
|
"}",
|
|
"",
|
|
].join("\n")
|
|
|
|
for (const [pkg, pkgbuild] of [["opencode-bin", binaryPkgbuild]]) {
|
|
for (let i = 0; i < 30; i++) {
|
|
try {
|
|
await $`rm -rf ./dist/aur-${pkg}`
|
|
await $`git clone ssh://aur@aur.archlinux.org/${pkg}.git ./dist/aur-${pkg}`
|
|
await $`cd ./dist/aur-${pkg} && git checkout master`
|
|
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
|
|
} catch {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// Homebrew formula
|
|
const homebrewFormula = [
|
|
"# typed: false",
|
|
"# frozen_string_literal: true",
|
|
"",
|
|
"# This file was generated by GoReleaser. DO NOT EDIT.",
|
|
"class Opencode < Formula",
|
|
` desc "The AI coding agent built for the terminal."`,
|
|
` homepage "https://github.com/anomalyco/opencode"`,
|
|
` version "${Script.version.split("-")[0]}"`,
|
|
"",
|
|
` depends_on "ripgrep"`,
|
|
"",
|
|
" on_macos do",
|
|
" if Hardware::CPU.intel?",
|
|
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`,
|
|
` sha256 "${macX64Sha}"`,
|
|
"",
|
|
" def install",
|
|
' bin.install "opencode"',
|
|
" end",
|
|
" end",
|
|
" if Hardware::CPU.arm?",
|
|
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`,
|
|
` sha256 "${macArm64Sha}"`,
|
|
"",
|
|
" def install",
|
|
' bin.install "opencode"',
|
|
" end",
|
|
" end",
|
|
" end",
|
|
"",
|
|
" on_linux do",
|
|
" if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",
|
|
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`,
|
|
` sha256 "${x64Sha}"`,
|
|
" def install",
|
|
' bin.install "opencode"',
|
|
" end",
|
|
" end",
|
|
" if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",
|
|
` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`,
|
|
` sha256 "${arm64Sha}"`,
|
|
" def install",
|
|
' bin.install "opencode"',
|
|
" end",
|
|
" end",
|
|
" end",
|
|
"end",
|
|
"",
|
|
"",
|
|
].join("\n")
|
|
|
|
const token = process.env.GITHUB_TOKEN
|
|
if (!token) {
|
|
console.error("GITHUB_TOKEN is required to update homebrew tap")
|
|
process.exit(1)
|
|
}
|
|
const tap = `https://x-access-token:${token}@github.com/anomalyco/homebrew-tap.git`
|
|
await $`rm -rf ./dist/homebrew-tap`
|
|
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`
|
|
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`
|
|
}
|
|
}
|