v0.9.5 #431
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g., v1.2.3). If provided, will checkout and release this tag regardless of current branch." | |
| required: false | |
| type: string | |
| permissions: | |
| contents: write # Required for electron-builder to upload release assets | |
| id-token: write # Required for GCP workload identity authentication (Windows code signing) | |
| env: | |
| RELEASE_TAG: ${{ inputs.tag || github.event.release.tag_name || github.ref_name }} | |
| jobs: | |
| preflight: | |
| name: Validate release target | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Ensure release tag context | |
| run: | | |
| if [ -z "$RELEASE_TAG" ]; then | |
| echo "::error::RELEASE_TAG is empty. Ensure this workflow runs on a release event or refs/tags/* ref." | |
| exit 1 | |
| fi | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| if [ -n "${{ inputs.tag }}" ]; then | |
| echo "workflow_dispatch with explicit tag input: ${{ inputs.tag }}" | |
| elif [[ "$GITHUB_REF" != refs/tags/* ]]; then | |
| echo "::error::workflow_dispatch runs must either provide a 'tag' input or target a tag ref. Current ref: $GITHUB_REF" | |
| exit 1 | |
| fi | |
| fi | |
| echo "Publishing tag $RELEASE_TAG" | |
| build-macos: | |
| name: Build and Release macOS | |
| needs: preflight | |
| runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-15' || 'macos-latest' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| fetch-depth: 0 # Required for git describe to find tags | |
| - uses: ./.github/actions/setup-mux | |
| - name: Build application | |
| run: bun run build | |
| - name: Setup code signing | |
| run: ./scripts/setup-macos-signing.sh | |
| env: | |
| MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} | |
| MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }} | |
| AC_APIKEY_P8_BASE64: ${{ secrets.AC_APIKEY_P8_BASE64 }} | |
| AC_APIKEY_ID: ${{ secrets.AC_APIKEY_ID }} | |
| AC_APIKEY_ISSUER_ID: ${{ secrets.AC_APIKEY_ISSUER_ID }} | |
| - name: Package and publish for macOS | |
| run: make dist-mac-release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build-linux: | |
| name: Build and Release Linux | |
| needs: preflight | |
| runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| fetch-depth: 0 # Required for git describe to find tags | |
| - uses: ./.github/actions/setup-mux | |
| - name: Build application | |
| run: bun run build | |
| - name: Package and publish for Linux | |
| run: bun x electron-builder --linux --publish always | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build-vscode-extension: | |
| name: Build and Release VS Code Extension | |
| needs: preflight | |
| runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| fetch-depth: 0 # Required for git describe to find tags | |
| - uses: ./.github/actions/setup-mux | |
| - uses: ./.github/actions/build-vscode-extension | |
| - name: Wait for GitHub release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| for attempt in $(seq 1 30); do | |
| if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then | |
| echo "Release $RELEASE_TAG is available" | |
| exit 0 | |
| fi | |
| echo "Release $RELEASE_TAG not found yet (attempt $attempt/30); waiting 10s..." | |
| sleep 10 | |
| done | |
| echo "::error::Timed out waiting for release $RELEASE_TAG" | |
| exit 1 | |
| - name: Upload VS Code extension to release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release upload "$RELEASE_TAG" \ | |
| vscode/mux-*.vsix \ | |
| --clobber | |
| - name: Publish to VS Code Marketplace | |
| working-directory: vscode | |
| env: | |
| VSCE_PAT: ${{ secrets.VSCE_PAT }} | |
| run: | | |
| if [ -z "$VSCE_PAT" ]; then | |
| echo "VSCE_PAT secret is not set; skipping VS Code Marketplace publish." | |
| exit 0 | |
| fi | |
| bunx vsce publish -p "$VSCE_PAT" | |
| build-windows: | |
| name: Build and Release Windows | |
| needs: preflight | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup-mux | |
| - name: Add MSYS2 make to PATH | |
| shell: pwsh | |
| run: | | |
| # MSYS2 is pre-installed on Windows runners, just needs to be in PATH | |
| # Install make via pacman (faster than choco) | |
| C:\msys64\usr\bin\pacman.exe -S --noconfirm make | |
| echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| - name: Verify tools | |
| shell: bash | |
| run: | | |
| make --version | |
| bun --version | |
| magick --version | head -1 | |
| - name: Build application | |
| run: bun run build | |
| # Setup Java for jsign (EV code signing with GCP KMS) | |
| - name: Setup Java | |
| uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 | |
| with: | |
| distribution: "zulu" | |
| java-version: "11.0" | |
| - name: Authenticate to Google Cloud | |
| id: gcloud_auth | |
| if: ${{ vars.GCP_WORKLOAD_ID_PROVIDER != '' }} | |
| uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8 | |
| with: | |
| workload_identity_provider: ${{ vars.GCP_WORKLOAD_ID_PROVIDER }} | |
| service_account: ${{ vars.GCP_SERVICE_ACCOUNT }} | |
| token_format: "access_token" | |
| - name: Setup code signing | |
| shell: pwsh | |
| run: | | |
| if (-not $env:EV_SIGNING_CERT) { | |
| Write-Host "⚠️ No Windows code signing certificate provided - building unsigned" | |
| exit 0 | |
| } | |
| # Save EV certificate to temp file | |
| $certPath = Join-Path $env:TEMP "ev_cert.pem" | |
| Set-Content -Path $certPath -Value $env:EV_SIGNING_CERT | |
| Add-Content -Path $env:GITHUB_ENV -Value "EV_CERTIFICATE_PATH=$certPath" | |
| # Download jsign | |
| $jsignPath = Join-Path $env:TEMP "jsign-6.0.jar" | |
| Invoke-WebRequest -Uri "https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar" -OutFile $jsignPath | |
| Add-Content -Path $env:GITHUB_ENV -Value "JSIGN_PATH=$jsignPath" | |
| Write-Host "✅ Windows EV code signing configured" | |
| env: | |
| EV_SIGNING_CERT: ${{ secrets.EV_SIGNING_CERT }} | |
| - name: Package and publish for Windows (.exe) | |
| run: bun x electron-builder --win --publish always | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # EV signing environment variables (used by custom sign script if configured) | |
| EV_KEYSTORE: ${{ vars.EV_KEYSTORE }} | |
| EV_KEY: ${{ vars.EV_KEY }} | |
| EV_TSA_URL: ${{ vars.EV_TSA_URL }} | |
| GCLOUD_ACCESS_TOKEN: ${{ steps.gcloud_auth.outputs.access_token }} | |
| - name: Upload Windows artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-release | |
| path: | | |
| release/*.exe | |
| release/*.exe.blockmap | |
| if-no-files-found: error | |
| notify-discord: | |
| name: Notify Discord | |
| runs-on: ubuntu-latest | |
| needs: [build-macos, build-linux, build-windows, build-vscode-extension] | |
| # Only notify on actual releases, not manual workflow runs | |
| if: github.event_name == 'release' | |
| steps: | |
| - name: Send release notification to Discord | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| RELEASE_NAME: ${{ github.event.release.name }} | |
| RELEASE_URL: ${{ github.event.release.html_url }} | |
| RELEASE_BODY: ${{ github.event.release.body }} | |
| REPO_NAME: ${{ github.repository }} | |
| run: | | |
| # Truncate body so we don't blow up Discord | |
| BODY="${RELEASE_BODY}" | |
| if [ ${#BODY} -gt 1500 ]; then | |
| BODY="${BODY:0:1500}..." | |
| fi | |
| # Build JSON payload with proper escaping via jq | |
| jq -n \ | |
| --arg title "New release: ${RELEASE_NAME:-$RELEASE_TAG}" \ | |
| --arg url "$RELEASE_URL" \ | |
| --arg body "$BODY" \ | |
| --arg repo "$REPO_NAME" \ | |
| '{ | |
| username: "GitHub Releases", | |
| embeds: [{ | |
| title: $title, | |
| url: $url, | |
| description: $body, | |
| footer: { text: $repo } | |
| }] | |
| }' > payload.json | |
| # Send to Discord | |
| curl -X POST \ | |
| -H "Content-Type: application/json" \ | |
| -d @payload.json \ | |
| "$DISCORD_WEBHOOK_URL" |