desktop: publish betas to separate repo (#14376)

This commit is contained in:
Brendan Allan
2026-02-20 22:33:21 +08:00
committed by GitHub
parent 92ab4217c2
commit ce17f9dd94
7 changed files with 105 additions and 39 deletions

View File

@@ -41,6 +41,13 @@ jobs:
- uses: ./.github/actions/setup-bun - uses: ./.github/actions/setup-bun
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Install OpenCode - name: Install OpenCode
if: inputs.bump || inputs.version if: inputs.bump || inputs.version
run: bun i -g opencode-ai run: bun i -g opencode-ai
@@ -49,14 +56,16 @@ jobs:
run: | run: |
./script/version.ts ./script/version.ts
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ steps.committer.outputs.token }}
OPENCODE_BUMP: ${{ inputs.bump }} OPENCODE_BUMP: ${{ inputs.bump }}
OPENCODE_VERSION: ${{ inputs.version }} OPENCODE_VERSION: ${{ inputs.version }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GH_REPO: ${{ (github.ref_name == 'beta' && 'anomalyco/opencode-beta') || github.repository }}
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
release: ${{ steps.version.outputs.release }} release: ${{ steps.version.outputs.release }}
tag: ${{ steps.version.outputs.tag }} tag: ${{ steps.version.outputs.tag }}
repo: ${{ steps.version.outputs.repo }}
build-cli: build-cli:
needs: version needs: version
@@ -69,6 +78,13 @@ jobs:
- uses: ./.github/actions/setup-bun - uses: ./.github/actions/setup-bun
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Build - name: Build
id: build id: build
run: | run: |
@@ -76,7 +92,8 @@ jobs:
env: env:
OPENCODE_VERSION: ${{ needs.version.outputs.version }} OPENCODE_VERSION: ${{ needs.version.outputs.version }}
OPENCODE_RELEASE: ${{ needs.version.outputs.release }} OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
GH_TOKEN: ${{ github.token }} GH_REPO: ${{ needs.version.outputs.repo }}
GH_TOKEN: ${{ steps.committer.outputs.token }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@@ -189,6 +206,13 @@ jobs:
if: contains(matrix.settings.host, 'ubuntu') if: contains(matrix.settings.host, 'ubuntu')
run: cargo tauri --version run: cargo tauri --version
- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Build and upload artifacts - name: Build and upload artifacts
uses: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a uses: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a
timeout-minutes: 60 timeout-minutes: 60
@@ -196,14 +220,16 @@ jobs:
projectPath: packages/desktop projectPath: packages/desktop
uploadWorkflowArtifacts: true uploadWorkflowArtifacts: true
tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }} tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose args: --target ${{ matrix.settings.target }} --config ${{ (github.ref_name == 'beta' && './src-tauri/tauri.beta.conf.json') || './src-tauri/tauri.prod.conf.json' }} --verbose
updaterJsonPreferNsis: true updaterJsonPreferNsis: true
releaseId: ${{ needs.version.outputs.release }} releaseId: ${{ needs.version.outputs.release }}
tagName: ${{ needs.version.outputs.tag }} tagName: ${{ needs.version.outputs.tag }}
releaseDraft: true releaseDraft: true
releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext] releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext]
repo: ${{ (github.ref_name == 'beta' && 'opencode-beta') || '' }}
releaseCommitish: ${{ github.sha }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
@@ -280,4 +306,5 @@ jobs:
OPENCODE_RELEASE: ${{ needs.version.outputs.release }} OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
AUR_KEY: ${{ secrets.AUR_KEY }} AUR_KEY: ${{ secrets.AUR_KEY }}
GITHUB_TOKEN: ${{ steps.committer.outputs.token }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
GH_REPO: ${{ needs.version.outputs.repo }}
NPM_CONFIG_PROVENANCE: false NPM_CONFIG_PROVENANCE: false

View File

@@ -1,5 +1,5 @@
import { APIEvent } from "@solidjs/start" import type { APIEvent } from "@solidjs/start"
import { DownloadPlatform } from "./types" import type { DownloadPlatform } from "../types"
const assetNames: Record<string, string> = { const assetNames: Record<string, string> = {
"darwin-aarch64-dmg": "opencode-desktop-darwin-aarch64.dmg", "darwin-aarch64-dmg": "opencode-desktop-darwin-aarch64.dmg",
@@ -17,17 +17,20 @@ const downloadNames: Record<string, string> = {
"windows-x64-nsis": "OpenCode Desktop Installer.exe", "windows-x64-nsis": "OpenCode Desktop Installer.exe",
} satisfies { [K in DownloadPlatform]?: string } } satisfies { [K in DownloadPlatform]?: string }
export async function GET({ params: { platform } }: APIEvent) { export async function GET({ params: { platform, channel } }: APIEvent) {
const assetName = assetNames[platform] const assetName = assetNames[platform]
if (!assetName) return new Response("Not Found", { status: 404 }) if (!assetName) return new Response("Not Found", { status: 404 })
const resp = await fetch(`https://github.com/anomalyco/opencode/releases/latest/download/${assetName}`, { const resp = await fetch(
cf: { `https://github.com/anomalyco/${channel === "stable" ? "opencode" : "opencode-beta"}/releases/latest/download/${assetName}`,
// in case gh releases has rate limits {
cacheTtl: 60 * 5, cf: {
cacheEverything: true, // in case gh releases has rate limits
}, cacheTtl: 60 * 5,
} as any) cacheEverything: true,
},
} as any,
)
const downloadName = downloadNames[platform] const downloadName = downloadNames[platform]

View File

@@ -1,18 +1,18 @@
import "./index.css" import "./index.css"
import { Title, Meta } from "@solidjs/meta" import { Meta, Title } from "@solidjs/meta"
import { A, createAsync, query } from "@solidjs/router" import { A } from "@solidjs/router"
import { Header } from "~/component/header" import { createSignal, type JSX, onMount, Show } from "solid-js"
import { Footer } from "~/component/footer"
import { IconCopy, IconCheck } from "~/component/icon"
import { Faq } from "~/component/faq" import { Faq } from "~/component/faq"
import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png" import { Footer } from "~/component/footer"
import { Header } from "~/component/header"
import { IconCheck, IconCopy } from "~/component/icon"
import { Legal } from "~/component/legal" import { Legal } from "~/component/legal"
import { LocaleLinks } from "~/component/locale-links"
import { config } from "~/config" import { config } from "~/config"
import { createSignal, onMount, Show, JSX } from "solid-js"
import { DownloadPlatform } from "./types"
import { useI18n } from "~/context/i18n" import { useI18n } from "~/context/i18n"
import { useLanguage } from "~/context/language" import { useLanguage } from "~/context/language"
import { LocaleLinks } from "~/component/locale-links" import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png"
import type { DownloadPlatform } from "./types"
type OS = "macOS" | "Windows" | "Linux" | null type OS = "macOS" | "Windows" | "Linux" | null
@@ -40,8 +40,8 @@ function getDownloadPlatform(os: OS): DownloadPlatform {
} }
} }
function getDownloadHref(platform: DownloadPlatform) { function getDownloadHref(platform: DownloadPlatform, channel: "stable" | "beta" = "stable") {
return `/download/${platform}` return `/download/${channel}/${platform}`
} }
function IconDownload(props: JSX.SvgSVGAttributes<SVGSVGElement>) { function IconDownload(props: JSX.SvgSVGAttributes<SVGSVGElement>) {

View File

@@ -0,0 +1,21 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenCode Beta",
"identifier": "ai.opencode.desktop.beta",
"bundle": {
"createUpdaterArtifacts": true,
"linux": {
"rpm": {
"compression": {
"type": "none"
}
}
}
},
"plugins": {
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEYwMDM5Nzg5OUMzOUExMDQKUldRRW9UbWNpWmNEOENYT01CV0lhOXR1UFhpaXJsK1Z3aU9lZnNtNzE0TDROWVMwVW9XQnFOelkK",
"endpoints": ["https://github.com/anomalyco/opencode-beta/releases/latest/download/latest.json"]
}
}
}

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env bun #!/usr/bin/env bun
import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin"
import path from "path"
import fs from "fs"
import { $ } from "bun" import { $ } from "bun"
import fs from "fs"
import path from "path"
import { fileURLToPath } from "url" import { fileURLToPath } from "url"
import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin"
const __filename = fileURLToPath(import.meta.url) const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename) const __dirname = path.dirname(__filename)
@@ -12,8 +12,9 @@ const dir = path.resolve(__dirname, "..")
process.chdir(dir) process.chdir(dir)
import pkg from "../package.json"
import { Script } from "@opencode-ai/script" import { Script } from "@opencode-ai/script"
import pkg from "../package.json"
const modelsUrl = process.env.OPENCODE_MODELS_URL || "https://models.dev" const modelsUrl = process.env.OPENCODE_MODELS_URL || "https://models.dev"
// Fetch and generate models.dev snapshot // Fetch and generate models.dev snapshot
const modelsData = process.env.MODELS_DEV_API_JSON const modelsData = process.env.MODELS_DEV_API_JSON
@@ -26,7 +27,11 @@ await Bun.write(
console.log("Generated models-snapshot.ts") console.log("Generated models-snapshot.ts")
// Load migrations from migration directories // Load migrations from migration directories
const migrationDirs = (await fs.promises.readdir(path.join(dir, "migration"), { withFileTypes: true })) const migrationDirs = (
await fs.promises.readdir(path.join(dir, "migration"), {
withFileTypes: true,
})
)
.filter((entry) => entry.isDirectory() && /^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}/.test(entry.name)) .filter((entry) => entry.isDirectory() && /^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}/.test(entry.name))
.map((entry) => entry.name) .map((entry) => entry.name)
.sort() .sort()
@@ -171,7 +176,6 @@ for (const item of targets) {
compile: { compile: {
autoloadBunfig: false, autoloadBunfig: false,
autoloadDotenv: false, autoloadDotenv: false,
//@ts-ignore (bun types aren't up to date)
autoloadTsconfig: true, autoloadTsconfig: true,
autoloadPackageJson: true, autoloadPackageJson: true,
target: name.replace(pkg.name, "bun") as any, target: name.replace(pkg.name, "bun") as any,
@@ -214,7 +218,7 @@ if (Script.release) {
await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`) await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`)
} }
} }
await $`gh release upload v${Script.version} ./dist/*.zip ./dist/*.tar.gz --clobber` await $`gh release upload v${Script.version} ./dist/*.zip ./dist/*.tar.gz --clobber --repo ${process.env.GH_REPO}`
} }
export { binaries } export { binaries }

View File

@@ -57,13 +57,16 @@ await $`bun install`
await import(`../packages/sdk/js/script/build.ts`) await import(`../packages/sdk/js/script/build.ts`)
if (Script.release) { if (Script.release) {
await $`git commit -am "release: v${Script.version}"` if (!Script.preview) {
await $`git tag v${Script.version}` await $`git commit -am "release: v${Script.version}"`
await $`git fetch origin` await $`git tag v${Script.version}`
await $`git cherry-pick HEAD..origin/dev`.nothrow() await $`git fetch origin`
await $`git push origin HEAD --tags --no-verify --force-with-lease` await $`git cherry-pick HEAD..origin/dev`.nothrow()
await new Promise((resolve) => setTimeout(resolve, 5_000)) await $`git push origin HEAD --tags --no-verify --force-with-lease`
await $`gh release edit v${Script.version} --draft=false` await new Promise((resolve) => setTimeout(resolve, 5_000))
}
await $`gh release edit v${Script.version} --draft=false --repo ${process.env.GH_REPO}`
} }
console.log("\n=== cli ===\n") console.log("\n=== cli ===\n")

View File

@@ -17,8 +17,16 @@ if (!Script.preview) {
const release = await $`gh release view v${Script.version} --json tagName,databaseId`.json() 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") {
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()
output.push(`release=${release.databaseId}`)
output.push(`tag=${release.tagName}`)
} }
output.push(`repo=${process.env.GH_REPO}`)
if (process.env.GITHUB_OUTPUT) { if (process.env.GITHUB_OUTPUT) {
await Bun.write(process.env.GITHUB_OUTPUT, output.join("\n")) await Bun.write(process.env.GITHUB_OUTPUT, output.join("\n"))
} }