Fix Windows preview process leak, and make the nightly heavy tests able to fail honestly #140
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: CI Tests | |
| # Pulls the published dependency bundle + the whisper add-on (binary + small | |
| # model) and runs the Rust test suite plus the Flutter tests, EXCLUDING the | |
| # heavy full-encode integration tests (those run in nightly.yml via | |
| # `--tags heavy`). macOS is tested natively on both arm64 (macos-15) and x64 | |
| # (macos-15-intel); Windows on x64; Linux on x64 (ubuntu-24.04). | |
| on: | |
| push: | |
| branches: [main] | |
| paths-ignore: ['**.md', 'docs/**', 'licenses/**'] | |
| pull_request: | |
| paths-ignore: ['**.md', 'docs/**', 'licenses/**'] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-test-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| WHISPER_MODEL_URL: https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin | |
| jobs: | |
| macos: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: arm64 | |
| runner: macos-15 | |
| - arch: x64 | |
| runner: macos-15-intel # last native Intel image, available until ~Aug 2027 | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| # Point the Flutter ToolLocator/DependencyManager at the repo-root deps | |
| # (Platform.resolvedExecutable is the test runner under `flutter test`). | |
| VAPOURBOX_DEPS_DIR: ${{ github.workspace }}/deps/macos-${{ matrix.arch }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Resolve deps tag | |
| id: deps | |
| run: | | |
| TAG=$(python3 -c "import json;print(json.load(open('app/assets/deps-version.json'))['releaseTag'])") | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "ver=${TAG#deps-v}" >> "$GITHUB_OUTPUT" | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Download dependencies (${{ matrix.arch }}) | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VER="${{ steps.deps.outputs.ver }}" | |
| ZIP="VapourBox-deps-${VER}-macos-${{ matrix.arch }}.zip" | |
| mkdir -p deps/macos-${{ matrix.arch }} | |
| gh release download "${{ steps.deps.outputs.tag }}" --pattern "$ZIP" --dir . --clobber | |
| unzip -q -o "$ZIP" -d deps/macos-${{ matrix.arch }} | |
| rm -f "$ZIP" | |
| xattr -cr deps/macos-${{ matrix.arch }} 2>/dev/null || true | |
| # The whisper small model (~466 MB) is architecture-independent; cache it. | |
| - name: Cache whisper model | |
| uses: actions/cache@v5 | |
| with: | |
| path: .whisper-cache | |
| key: whisper-ggml-small-v1 | |
| - name: Provision whisper add-on | |
| run: | | |
| mkdir -p .whisper-cache addons/whisper/models | |
| if [ ! -f .whisper-cache/ggml-small.bin ]; then | |
| echo "Downloading whisper small model..." | |
| curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL" | |
| fi | |
| cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin | |
| # whisper-cli comes from the same Homebrew bottle the app downloads. | |
| brew install whisper-cpp | |
| BP="$(brew --prefix)" | |
| ln -sfn "$BP/opt/whisper-cpp/bin" addons/whisper/bin | |
| ln -sfn "$BP/opt/whisper-cpp/lib" addons/whisper/lib | |
| - name: Rust tests | |
| # Debug build: DependencyLocator's upward search then finds the repo-root | |
| # deps/ and addons/ (release mode looks under ~/Library). | |
| run: cd worker && cargo test -- --nocapture | |
| - name: Generate Dart serialization | |
| run: | | |
| cd app | |
| flutter pub get | |
| dart run build_runner build --delete-conflicting-outputs | |
| - name: Flutter tests | |
| # Excludes @Tags(['heavy']) — the full-encode integration tests, which | |
| # run in nightly.yml. The script-only integration tests + unit tests run here. | |
| run: cd app && flutter test --exclude-tags heavy | |
| windows: | |
| runs-on: windows-latest | |
| env: | |
| VAPOURBOX_DEPS_DIR: ${{ github.workspace }}/deps/windows-x64 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Resolve deps tag | |
| id: deps | |
| shell: bash | |
| run: | | |
| TAG=$(python -c "import json;print(json.load(open('app/assets/deps-version.json'))['releaseTag'])") | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "ver=${TAG#deps-v}" >> "$GITHUB_OUTPUT" | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Download dependencies (windows-x64) | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VER="${{ steps.deps.outputs.ver }}" | |
| ZIP="VapourBox-deps-${VER}-windows-x64.zip" | |
| mkdir -p deps/windows-x64 | |
| gh release download "${{ steps.deps.outputs.tag }}" --pattern "$ZIP" --dir . --clobber | |
| # The Windows deps zip uses backslash separators; 7-Zip handles that | |
| # (info-zip `unzip` warns and exits non-zero, tripping `set -e`). | |
| 7z x "$ZIP" -o"deps/windows-x64" -y >/dev/null | |
| rm -f "$ZIP" | |
| - name: Cache whisper model | |
| uses: actions/cache@v5 | |
| with: | |
| path: .whisper-cache | |
| key: whisper-ggml-small-v1 | |
| - name: Provision whisper add-on | |
| shell: bash | |
| run: | | |
| mkdir -p .whisper-cache addons/whisper/models | |
| if [ ! -f .whisper-cache/ggml-small.bin ]; then | |
| curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL" | |
| fi | |
| cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin | |
| curl -L -o /tmp/whisper-win.zip \ | |
| "https://github.com/ggml-org/whisper.cpp/releases/download/v1.8.3/whisper-bin-x64.zip" | |
| 7z x /tmp/whisper-win.zip -o/tmp/whisper-win -y >/dev/null | |
| # Flatten: DependencyLocator expects addons/whisper/whisper-cli.exe | |
| CLI=$(find /tmp/whisper-win -name "whisper-cli.exe" | head -1) | |
| cp "$(dirname "$CLI")"/*.exe addons/whisper/ 2>/dev/null || true | |
| cp "$(dirname "$CLI")"/*.dll addons/whisper/ 2>/dev/null || true | |
| ls addons/whisper/ | |
| - name: Rust tests | |
| run: cd worker && cargo test -- --nocapture | |
| - name: Generate Dart serialization | |
| run: | | |
| cd app | |
| flutter pub get | |
| dart run build_runner build --delete-conflicting-outputs | |
| - name: Flutter tests | |
| # Excludes @Tags(['heavy']) — the full-encode integration tests, which | |
| # run in nightly.yml. The script-only integration tests + unit tests run here. | |
| run: cd app && flutter test --exclude-tags heavy | |
| linux: | |
| runs-on: ubuntu-24.04 # must match the deps-build runner: those binaries | |
| # need its glibc, so an older runner cannot run them | |
| env: | |
| # Dart ToolLocator/DependencyManager honour this; the Rust locator does | |
| # not (it uses the XDG path), so we also symlink it below. | |
| VAPOURBOX_DEPS_DIR: ${{ github.workspace }}/deps/linux-x64 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang cmake ninja-build pkg-config \ | |
| libgtk-3-dev liblzma-dev unzip | |
| - name: Resolve deps tag | |
| id: deps | |
| run: | | |
| TAG=$(python3 -c "import json;print(json.load(open('app/assets/deps-version.json'))['releaseTag'])") | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "ver=${TAG#deps-v}" >> "$GITHUB_OUTPUT" | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Download dependencies (linux-x64) | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VER="${{ steps.deps.outputs.ver }}" | |
| ZIP="VapourBox-deps-${VER}-linux-x64.zip" | |
| mkdir -p deps/linux-x64 | |
| gh release download "${{ steps.deps.outputs.tag }}" --pattern "$ZIP" --dir . --clobber | |
| unzip -q -o "$ZIP" -d deps/linux-x64 | |
| rm -f "$ZIP" | |
| - name: Cache whisper model | |
| uses: actions/cache@v5 | |
| with: | |
| path: .whisper-cache | |
| key: whisper-ggml-small-v1 | |
| - name: Provision whisper add-on | |
| run: | | |
| mkdir -p .whisper-cache addons/whisper/models addons/whisper/bin | |
| if [ ! -f .whisper-cache/ggml-small.bin ]; then | |
| echo "Downloading whisper small model..." | |
| curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL" | |
| fi | |
| cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin | |
| # Download the same published whisper-cli the app fetches at runtime | |
| # (the linux-x64 source in whisper-addon.json), so the test exercises | |
| # the real add-on artifact + tar layout instead of building from | |
| # source. Mirrors the Windows job, which curls its release zip. | |
| WHISPER_URL=$(python3 -c "import json;print(json.load(open('app/assets/whisper-addon.json'))['binary']['platforms']['linux-x64']['url'])") | |
| echo "whisper-cli: $WHISPER_URL" | |
| curl -L -o /tmp/whisper-cli.tar.gz "$WHISPER_URL" | |
| tar xzf /tmp/whisper-cli.tar.gz -C addons/whisper # => addons/whisper/bin/whisper-cli | |
| chmod +x addons/whisper/bin/whisper-cli | |
| ls -la addons/whisper/bin addons/whisper/models | |
| - name: Stage deps/addons at XDG path for the Rust locator | |
| # The Rust DependencyLocator on Linux only looks under | |
| # ~/.local/share/VapourBox (no debug upward-search); the Dart tests use | |
| # the repo-root copy. Symlink so a single checkout satisfies both. | |
| run: | | |
| mkdir -p "$HOME/.local/share/VapourBox" | |
| ln -sfn "${{ github.workspace }}/deps" "$HOME/.local/share/VapourBox/deps" | |
| ln -sfn "${{ github.workspace }}/addons" "$HOME/.local/share/VapourBox/addons" | |
| - name: Rust tests | |
| run: cd worker && cargo test -- --nocapture | |
| - name: Generate Dart serialization | |
| run: | | |
| cd app | |
| flutter pub get | |
| dart run build_runner build --delete-conflicting-outputs | |
| - name: Flutter tests | |
| # Excludes @Tags(['heavy']) — the full-encode integration tests, which | |
| # run in nightly.yml. The script-only integration tests + unit tests run here. | |
| run: cd app && flutter test --exclude-tags heavy |