diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index 9d29724d86a..7783100911e 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -1,6 +1,10 @@ name: "Setup Bun" description: "Setup Bun with caching and install dependencies" inputs: + bun-version: + description: "Bun version to install instead of the root packageManager version" + required: false + default: "" install-flags: description: "Additional flags to pass to 'bun install'" required: false @@ -20,19 +24,22 @@ runs: shell: bash run: | if [ "$RUNNER_ARCH" = "X64" ]; then - V=$(node -p "require('./package.json').packageManager.split('@')[1]") + V="${{ inputs.bun-version }}" + if [ -z "$V" ]; then V=$(node -p "require('./package.json').packageManager.split('@')[1]"); fi + TAG=$([ "$V" = "canary" ] && echo "canary" || echo "bun-v${V}") case "$RUNNER_OS" in macOS) OS=darwin ;; Linux) OS=linux ;; Windows) OS=windows ;; esac - echo "url=https://github.com/oven-sh/bun/releases/download/bun-v${V}/bun-${OS}-x64-baseline.zip" >> "$GITHUB_OUTPUT" + echo "url=https://github.com/oven-sh/bun/releases/download/${TAG}/bun-${OS}-x64-baseline.zip" >> "$GITHUB_OUTPUT" fi - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: - bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }} + bun-version: ${{ !steps.bun-url.outputs.url && inputs.bun-version || '' }} + bun-version-file: ${{ !steps.bun-url.outputs.url && !inputs.bun-version && 'package.json' || '' }} bun-download-url: ${{ steps.bun-url.outputs.url }} - name: Get cache directory diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e88bc8c0877..c903426458c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -81,6 +81,8 @@ jobs: fetch-tags: true - uses: ./.github/actions/setup-bun + with: + bun-version: canary # Bun 1.4 until its stable release is published - name: Setup git committer id: committer @@ -102,6 +104,7 @@ jobs: id: build run: ./packages/cli/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }} env: + BUN_COMPILE_RELEASE: canary OPENCODE_VERSION: ${{ needs.version.outputs.version }} OPENCODE_RELEASE: ${{ needs.version.outputs.release }} GH_REPO: ${{ needs.version.outputs.repo }} diff --git a/packages/cli/script/build.ts b/packages/cli/script/build.ts index 9452c30a66f..1c272a39d6b 100755 --- a/packages/cli/script/build.ts +++ b/packages/cli/script/build.ts @@ -1,7 +1,7 @@ #!/usr/bin/env bun import { $ } from "bun" -import { rm } from "fs/promises" +import { mkdir, rm } from "fs/promises" import path from "path" import { Script } from "@opencode-ai/script" import { createSolidTransformPlugin } from "@opentui/solid/bun-plugin" @@ -99,6 +99,7 @@ for (const item of targets) { } const target = targetName(item) const name = target.replace(binary, "cli") + const executablePath = await compileExecutable(item) console.log(`building ${name}`) const result = await Bun.build({ entrypoints: ["./src/index.ts"], @@ -115,6 +116,7 @@ for (const item of targets) { autoloadTsconfig: true, autoloadPackageJson: true, target: target.replace(binary, "bun") as Bun.Build.CompileTarget, + executablePath, outfile: path.join(outdir, name, "bin", binary), execArgv: [`--user-agent=${binary}/${Script.version}`, "--use-system-ca", "--"], windows: {}, @@ -154,6 +156,28 @@ for (const item of targets) { await verifyArtifact(path.join(outdir, name)) } +async function compileExecutable(item: (typeof allTargets)[number]) { + const release = process.env.BUN_COMPILE_RELEASE + if (!release) return + + const platform = item.os === "win32" ? "windows" : item.os + const name = ["bun", platform, item.arch, item.abi, item.avx2 === false ? "baseline" : undefined] + .filter(Boolean) + .join("-") + const cache = path.join(outdir, ".bun", release) + const executable = path.join(cache, name, item.os === "win32" ? "bun.exe" : "bun") + if (await Bun.file(executable).exists()) return executable + + await mkdir(cache, { recursive: true }) + const archive = path.join(cache, `${name}.zip`) + const response = await fetch(`https://github.com/oven-sh/bun/releases/download/${release}/${name}.zip`) + if (!response.ok) throw new Error(`Failed to download ${name} from Bun release ${release}: ${response.status}`) + await Bun.write(archive, response) + await $`unzip -oq ${archive} -d ${cache}` + await rm(archive) + return executable +} + function targetName(item: (typeof allTargets)[number]) { return [ binary,