name: Release on: push: tags: - "v*" workflow_dispatch: inputs: version: description: "Release version (e.g., v1.0.0)" required: true type: string prerelease: description: "Mark as pre-release" required: false type: boolean default: false jobs: build-release: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Bun uses: ./.github/actions/setup-bun - name: Set up pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "20" cache: "pnpm" cache-dependency-path: | hosts/vscode-plugin/pnpm-lock.yaml - name: Set up Java uses: actions/setup-java@v4 with: distribution: "temurin" java-version: "21" - name: Determine version id: version run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT echo "prerelease=${{ github.event.inputs.prerelease }}" >> $GITHUB_OUTPUT else echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT if [[ "${GITHUB_REF#refs/tags/}" == *"-"* ]]; then echo "prerelease=true" >> $GITHUB_OUTPUT else echo "prerelease=false" >> $GITHUB_OUTPUT fi fi # version without leading 'v' for use as OPENCODE_VERSION VER="$(grep -oP '"version":\s*"\K[^"]+' packages/opencode/package.json)" echo "version_number=$VER" >> $GITHUB_OUTPUT - name: Build backend binaries run: ./hosts/scripts/build_opencode.sh env: OPENCODE_VERSION: ${{ steps.version.outputs.version_number }} - name: Install VSCode plugin dependencies (all) working-directory: hosts/vscode-plugin run: | if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile else npm ci fi - name: Compile VSCode plugin TypeScript working-directory: hosts/vscode-plugin run: | if [ -f pnpm-lock.yaml ]; then pnpm run compile:production else npm run compile:production fi - name: Package VSCode plugin (standard) from staging working-directory: hosts/vscode-plugin run: | STAGE_DIR="../tmp_opencode_vscode_stage" rm -rf "$STAGE_DIR" mkdir -p "$STAGE_DIR" # Copy minimal required files cp package.json "$STAGE_DIR/" cp -R out "$STAGE_DIR/out" cp -R resources "$STAGE_DIR/resources" # Exclude gui-only artifacts from standard build rm -rf "$STAGE_DIR/resources/webgui-app" [ -f README.md ] && cp README.md "$STAGE_DIR/" || true [ -f CHANGELOG.md ] && cp CHANGELOG.md "$STAGE_DIR/" || true [ -f ../../LICENSE ] && cp ../../LICENSE "$STAGE_DIR/" || true # Sanitize package.json: remove scripts and devDependencies node -e ' const fs=require("fs"); const path=require("path"); const pkgPath=path.resolve(process.cwd(), "../tmp_opencode_vscode_stage/package.json"); const pkg=JSON.parse(fs.readFileSync(pkgPath, "utf8")); delete pkg.scripts; delete pkg.devDependencies; fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); ' # Package from staging directory without touching dependencies ( cd "$STAGE_DIR" && npx -y @vscode/vsce package --no-dependencies --out "opencode-standard.vsix" ) # Move artifact back into plugin dir for later collection mv "$STAGE_DIR"/*.vsix . # Clean up staging rm -rf "$STAGE_DIR" - name: Build webgui for gui-only variant run: | # Use bun from repo root since this is a Bun workspace monorepo cd packages/opencode/webgui bun install --frozen-lockfile bun run build - name: Package VSCode plugin (gui-only) from staging working-directory: hosts/vscode-plugin run: | WEBGUI_DIST="../../packages/opencode/webgui-dist" if [ ! -d "$WEBGUI_DIST" ]; then echo "::error::webgui-dist not found at $WEBGUI_DIST" exit 1 fi STAGE_DIR="../tmp_opencode_vscode_gui_only_stage" rm -rf "$STAGE_DIR" mkdir -p "$STAGE_DIR" # Copy minimal required files — NO binaries cp package.json "$STAGE_DIR/" cp -R out "$STAGE_DIR/out" mkdir -p "$STAGE_DIR/resources" # Copy resources except bin/ for item in resources/*; do [ "$(basename "$item")" = "bin" ] && continue cp -R "$item" "$STAGE_DIR/resources/" done # Embed webgui-dist cp -R "$WEBGUI_DIST" "$STAGE_DIR/resources/webgui-app" [ -f README.md ] && cp README.md "$STAGE_DIR/" || true [ -f CHANGELOG.md ] && cp CHANGELOG.md "$STAGE_DIR/" || true [ -f ../../LICENSE ] && cp ../../LICENSE "$STAGE_DIR/" || true # Deep-merge gui-only overrides into package.json, remove scripts/devDependencies node -e ' const fs=require("fs"); const path=require("path"); function deep(t,s){for(const k of Object.keys(s)){const sv=s[k],tv=t[k];if(Array.isArray(sv)&&Array.isArray(tv)){for(let i=0;i /dev/null 2>&1; then echo "✓ VSCode extension (standard) found" else echo "✗ VSCode extension (standard) missing" fi # Check if VSCode gui-only extension exists if ls ./test-artifacts/opencode-vscode-gui-only-*.vsix 1> /dev/null 2>&1; then echo "✓ VSCode extension (gui-only) found" else echo "✗ VSCode extension (gui-only) missing" fi # Check if JetBrains standard plugin exists if ls ./test-artifacts/opencode-jetbrains-*.zip 1> /dev/null 2>&1 && ! ls ./test-artifacts/opencode-jetbrains-gui-only-*.zip 1> /dev/null 2>&1; then echo "✓ JetBrains plugin (standard) found" else echo "✗ JetBrains plugin (standard) missing" fi # Check if JetBrains gui-only plugin exists if ls ./test-artifacts/opencode-jetbrains-gui-only-*.zip 1> /dev/null 2>&1; then echo "✓ JetBrains plugin (gui-only) found" else echo "✗ JetBrains plugin (gui-only) missing" fi