Bump version: 0.4.2 → 0.4.3 #117
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: | |
| workflow_dispatch: | |
| push: | |
| tags: | |
| - "v*" | |
| jobs: | |
| release: | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: "macos-latest" | |
| args: "--target aarch64-apple-darwin" | |
| python-version: "3.12" | |
| backend: "mlx" | |
| - platform: "macos-15-intel" | |
| args: "--target x86_64-apple-darwin" | |
| python-version: "3.12" | |
| backend: "pytorch" | |
| - platform: "windows-latest" | |
| args: "" | |
| python-version: "3.12" | |
| backend: "pytorch" | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Ubuntu runners ship with ~14 GB free; pip + PyInstaller + torch can | |
| # peak well above that during the build. Reclaim ~25 GB by pruning | |
| # preinstalled toolchains we don't use. This is what likely tripped | |
| # the March 2026 Linux release attempts (see commit 103e98b | |
| # "github runners suck") — not a code issue, a disk-pressure one. | |
| - name: Free up disk space (ubuntu) | |
| if: contains(matrix.platform, 'ubuntu') || contains(matrix.platform, 'namespace') | |
| # Pinned to v1.3.1 (SHA) — this job runs with contents: write and | |
| # handles signing secrets later, so we don't want a floating ref. | |
| uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be | |
| with: | |
| tool-cache: false | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| # large-packages: true would `apt-get remove '^llvm-.*'`, which | |
| # cascade-removes reverse deps that won't be pulled back in by the | |
| # `llvm-dev` install below. The other flags already free ~20 GB, | |
| # enough for the Python + torch + PyInstaller build. | |
| large-packages: false | |
| swap-storage: true | |
| - name: Install dependencies (ubuntu only) | |
| if: contains(matrix.platform, 'ubuntu') || contains(matrix.platform, 'namespace') | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf llvm-dev libasound2-dev | |
| - name: Install LLVM (macOS) | |
| if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' | |
| run: | | |
| brew install llvm@20 | |
| echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH | |
| echo "LLVM_CONFIG=$(brew --prefix llvm@20)/bin/llvm-config" >> $GITHUB_ENV | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: "pip" | |
| - name: Install CPU-only PyTorch (Linux) | |
| if: contains(matrix.platform, 'ubuntu') || contains(matrix.platform, 'namespace') | |
| run: | | |
| pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pyinstaller | |
| pip install -r backend/requirements.txt | |
| pip install --no-deps chatterbox-tts | |
| pip install --no-deps hume-tada | |
| - name: Install MLX dependencies (Apple Silicon only) | |
| if: matrix.backend == 'mlx' | |
| run: | | |
| pip install -r backend/requirements-mlx.txt | |
| # mlx-audio>=0.3.1 and mlx-lm>=0.31.1 both declare transformers>=5.x, | |
| # which conflicts with our 4.57.x cap. The runtime APIs we use work | |
| # fine on transformers 4.57.x in practice (verified in dev), so install | |
| # them --no-deps. mlx-audio's other runtime deps (huggingface_hub, | |
| # librosa, numpy, numba, pyloudnorm) are already in requirements.txt; | |
| # miniaudio is in requirements-mlx.txt (needed by mlx_audio.stt, | |
| # not transitively pulled by anything else — see issue #505); the | |
| # rest (sounddevice, protobuf, sentencepiece, pyyaml, jinja2) are | |
| # pulled in by other engines. | |
| pip install --no-deps mlx-lm==0.31.1 | |
| pip install --no-deps mlx-audio==0.4.1 | |
| - name: Build Python server (Linux/macOS) | |
| if: matrix.platform != 'windows-latest' | |
| run: | | |
| chmod +x scripts/build-server.sh | |
| ./scripts/build-server.sh | |
| - name: Build Python server (Windows) | |
| if: matrix.platform == 'windows-latest' | |
| shell: bash | |
| run: | | |
| cd backend | |
| python build_binary.py | |
| # Get platform tuple | |
| PLATFORM=$(rustc --print host-tuple) | |
| # Create binaries directory | |
| mkdir -p ../tauri/src-tauri/binaries | |
| # Copy with platform suffix | |
| cp dist/voicebox-server.exe ../tauri/src-tauri/binaries/voicebox-server-${PLATFORM}.exe | |
| echo "Built voicebox-server-${PLATFORM}.exe" | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ (matrix.platform == 'macos-latest' && 'aarch64-apple-darwin') || (matrix.platform == 'macos-15-intel' && 'x86_64-apple-darwin') || '' }} | |
| - name: Rust cache | |
| uses: swatinem/rust-cache@v2 | |
| with: | |
| workspaces: "./tauri/src-tauri -> target" | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Install Apple API key | |
| if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' | |
| run: | | |
| mkdir -p ~/.appstoreconnect/private_keys/ | |
| cd ~/.appstoreconnect/private_keys/ | |
| echo ${{ secrets.APPLE_API_KEY_BASE64 }} >> AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 | |
| base64 --decode -i AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 -o AuthKey_${{ secrets.APPLE_API_KEY }}.p8 | |
| rm AuthKey_${{ secrets.APPLE_API_KEY }}.p8.base64 | |
| - name: Install Codesigning Certificate | |
| if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' | |
| uses: apple-actions/import-codesign-certs@v3 | |
| with: | |
| p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} | |
| p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| - name: Disk / environment snapshot (pre-bundle debug) | |
| if: contains(matrix.platform, 'ubuntu') || contains(matrix.platform, 'namespace') | |
| run: | | |
| echo "=== df -h ===" | |
| df -h | |
| echo "=== free -h ===" | |
| free -h | |
| echo "=== Rust / Cargo ===" | |
| rustc --version | |
| cargo --version | |
| echo "=== Bun ===" | |
| bun --version | |
| echo "=== Tauri CLI ===" | |
| cd tauri && bun run tauri --version | |
| - name: Extract release notes from CHANGELOG.md | |
| id: changelog | |
| shell: bash | |
| run: | | |
| # Get the version from the tag (strip leading 'v') | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| # Extract the section for this version from CHANGELOG.md | |
| # Matches from "## [X.Y.Z]" until the next "## [" heading | |
| NOTES=$(sed -n "/^## \[${VERSION}\]/,/^## \[/{/^## \[${VERSION}\]/d;/^## \[/d;p;}" CHANGELOG.md) | |
| # Fall back to a placeholder if the version isn't in the changelog | |
| if [ -z "$(echo "$NOTES" | tr -d '[:space:]')" ]; then | |
| NOTES="See the assets below to download and install this version." | |
| fi | |
| # Use multiline output syntax | |
| { | |
| echo "notes<<CHANGELOG_EOF" | |
| echo "$NOTES" | |
| echo "CHANGELOG_EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| # Linux hang watchdog: previous releases silently wedged inside tauri | |
| # bundling (possibly linuxdeploy/AppImage download, possibly cargo link). | |
| # Cap the step at 30 min so we get logs instead of waiting out the 6hr | |
| # job timeout. Other platforms historically complete in ~25 min, so 45 | |
| # is comfortable. | |
| - uses: tauri-apps/tauri-action@v0.6 | |
| timeout-minutes: ${{ (contains(matrix.platform, 'ubuntu') || contains(matrix.platform, 'namespace')) && 30 || 45 }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| APPLE_PROVIDER_SHORT_NAME: ${{ secrets.APPLE_PROVIDER_SHORT_NAME }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| # Stream subprocess stdout/stderr so the hang is visible in logs. | |
| CARGO_TERM_VERBOSE: "true" | |
| RUST_BACKTRACE: "1" | |
| with: | |
| projectPath: tauri | |
| tagName: v__VERSION__ | |
| releaseName: "voicebox v__VERSION__" | |
| releaseBody: ${{ steps.changelog.outputs.notes }} | |
| releaseDraft: true | |
| prerelease: false | |
| args: ${{ matrix.args }} | |
| includeUpdaterJson: true | |
| # Tauri's bundler signs the .app and notarizes it, but the .dmg wrapper | |
| # ships unnotarized. Gatekeeper rejects that on macOS 15 Sequoia (caught | |
| # by Homebrew Cask CI) and causes "app isn't signed" dialogs on older | |
| # Intel Macs when Apple's notarization servers are slow (see issue #509). | |
| # Submit the .dmg to notarytool, staple the ticket, and overwrite the | |
| # release asset uploaded by tauri-action. | |
| - name: Notarize and staple DMG (macOS) | |
| if: matrix.platform == 'macos-latest' || matrix.platform == 'macos-15-intel' | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| KEY_PATH="$HOME/.appstoreconnect/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8" | |
| TARGET=$(echo "${{ matrix.args }}" | sed -n 's/.*--target \([a-z0-9_-]*\).*/\1/p') | |
| DMG_DIR="tauri/src-tauri/target/${TARGET}/release/bundle/dmg" | |
| # Match the release tag tauri-action resolved from tauri.conf.json's | |
| # version field; GITHUB_REF_NAME is a branch name under workflow_dispatch. | |
| RELEASE_TAG="v$(jq -r '.version' tauri/src-tauri/tauri.conf.json)" | |
| shopt -s nullglob | |
| dmgs=("${DMG_DIR}"/*.dmg) | |
| if [ ${#dmgs[@]} -eq 0 ]; then | |
| echo "::error::No DMGs found in ${DMG_DIR} — tauri bundler output path may have changed" | |
| exit 1 | |
| fi | |
| for dmg in "${dmgs[@]}"; do | |
| echo "::group::Notarize $(basename "$dmg")" | |
| xcrun notarytool submit "$dmg" \ | |
| --key "$KEY_PATH" \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_ISSUER" \ | |
| --wait --timeout 20m | |
| xcrun stapler staple "$dmg" | |
| spctl -a -t open --context context:primary-signature -vv "$dmg" | |
| gh release upload "${RELEASE_TAG}" "$dmg" --clobber \ | |
| --repo "${GITHUB_REPOSITORY}" | |
| echo "::endgroup::" | |
| done | |
| build-cuda-windows: | |
| runs-on: windows-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| cache: "pip" | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pyinstaller | |
| pip install -r backend/requirements.txt | |
| pip install --no-deps chatterbox-tts | |
| pip install --no-deps hume-tada | |
| - name: Install PyTorch with CUDA 12.8 | |
| run: | | |
| pip install torch --index-url https://download.pytorch.org/whl/cu128 --force-reinstall --no-deps | |
| pip install torchaudio --index-url https://download.pytorch.org/whl/cu128 --force-reinstall --no-deps | |
| - name: Verify CUDA support in torch | |
| run: | | |
| python -c "import torch; print(f'CUDA available in build: {torch.cuda.is_available()}'); print(f'CUDA version: {torch.version.cuda}')" | |
| - name: Build CUDA server binary (onedir) | |
| shell: bash | |
| working-directory: backend | |
| env: | |
| # Include Blackwell (sm_120) via PTX forward compatibility. | |
| # Pre-built PyTorch cu128 wheels ship native kernels for sm_80/86/89/90 | |
| # but not sm_120. Setting this env var causes torch.utils.cpp_extension | |
| # (and any JIT-compiled kernels) to target Blackwell GPUs as well. | |
| TORCH_CUDA_ARCH_LIST: "8.0;8.6;8.9;9.0;12.0+PTX" | |
| run: python build_binary.py --cuda | |
| - name: Package into server core + CUDA libs archives | |
| shell: bash | |
| run: | | |
| python scripts/package_cuda.py \ | |
| backend/dist/voicebox-server-cuda/ \ | |
| --output release-assets/ \ | |
| --cuda-libs-version cu128-v1 \ | |
| --torch-compat ">=2.7.0,<2.11.0" | |
| - name: Upload archives to GitHub Release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| release-assets/voicebox-server-cuda.tar.gz | |
| release-assets/voicebox-server-cuda.tar.gz.sha256 | |
| release-assets/cuda-libs-cu128-v1.tar.gz | |
| release-assets/cuda-libs-cu128-v1.tar.gz.sha256 | |
| release-assets/cuda-libs.json | |
| draft: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload onedir as workflow artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: voicebox-server-cuda-windows | |
| path: backend/dist/voicebox-server-cuda/ | |
| retention-days: 7 |