name: Desktop Release # Builds the Quintodrome desktop app (Tauri) for macOS (.app/.dmg) and # Windows (.exe/.msi), bundling the Navidrome server as a sidecar, and # attaches the artifacts to the Gitea release on `v*` tags. # # Note: artifacts are unsigned (no Apple/Windows code-signing certs), so users # will hit Gatekeeper/SmartScreen prompts. on: push: tags: ["v*"] workflow_dispatch: concurrency: group: desktop-${{ github.ref }} cancel-in-progress: true jobs: build-desktop: name: Build desktop (${{ matrix.target }}) strategy: fail-fast: false matrix: include: - os: macos-latest target: aarch64-apple-darwin - os: macos-13 # Intel runner target: x86_64-apple-darwin - os: windows-latest target: x86_64-pc-windows-msvc runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 - name: Setup Node uses: actions/setup-node@v6 with: node-version: 24 cache: npm cache-dependency-path: ui/package-lock.json - name: Setup Go uses: actions/setup-go@v6 with: go-version-file: go.mod - name: Setup Rust uses: dtolnay/rust-toolchain@stable - name: Cache Rust build uses: Swatinem/rust-cache@v2 with: workspaces: desktop/src-tauri # Navidrome's sqlite_fts5 tag needs CGO, so on Windows we need a gcc. - name: Setup Windows CGO (mingw) if: runner.os == 'Windows' uses: msys2/setup-msys2@v2 with: msystem: MINGW64 install: mingw-w64-x86_64-gcc update: false - name: Add mingw to PATH if: runner.os == 'Windows' shell: bash run: echo "C:/msys64/mingw64/bin" >> $GITHUB_PATH - name: Build Navidrome web UI shell: bash run: | cd ui # --ignore-scripts skips the workbox postinstall (bin/update-workbox.sh), # a bash script that fails under cmd.exe on Windows. It's only needed # for the PWA service worker, which the desktop app doesn't use. npm ci --ignore-scripts npm run build - name: Build Navidrome server binary shell: bash run: | GIT_SHA=$(git rev-parse --short HEAD) if [[ "$GITHUB_REF" == refs/tags/* ]]; then GIT_TAG="${GITHUB_REF_NAME#v}" else GIT_TAG="dev" fi if [[ "$RUNNER_OS" == "Windows" ]]; then export CGO_ENABLED=1 OUTPUT="navidrome.exe" else OUTPUT="navidrome" fi go build \ -ldflags="-X github.com/navidrome/navidrome/consts.gitSha=$GIT_SHA -X github.com/navidrome/navidrome/consts.gitTag=$GIT_TAG" \ -tags=netgo,sqlite_fts5 \ -o "$OUTPUT" # Stage the sidecar under the target-triple name tauri expects. mkdir -p desktop/src-tauri/binaries if [[ "$RUNNER_OS" == "Windows" ]]; then cp navidrome.exe "desktop/src-tauri/binaries/navidrome-${{ matrix.target }}.exe" else cp navidrome "desktop/src-tauri/binaries/navidrome-${{ matrix.target }}" chmod +x "desktop/src-tauri/binaries/navidrome-${{ matrix.target }}" fi - name: Build Tauri app shell: bash run: | cd desktop npx --yes @tauri-apps/cli@2 build - name: Collect artifacts (macOS) if: runner.os == 'macOS' shell: bash run: | mkdir -p dist BUNDLE=desktop/src-tauri/target/release/bundle ditto -c -k --keepParent "$BUNDLE/macos/Quintodrome.app" "dist/Quintodrome-${{ matrix.target }}.app.zip" cp "$BUNDLE"/dmg/*.dmg dist/ 2>/dev/null || true ls -la dist - name: Collect artifacts (Windows) if: runner.os == 'Windows' shell: bash run: | mkdir -p dist BUNDLE=desktop/src-tauri/target/release/bundle cp "$BUNDLE"/nsis/*.exe dist/ 2>/dev/null || true cp "$BUNDLE"/msi/*.msi dist/ 2>/dev/null || true ls -la dist - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: desktop-${{ matrix.target }} path: dist/* retention-days: 7 release: name: Publish Gitea release needs: build-desktop if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v8 with: path: dist pattern: desktop-* merge-multiple: true - run: ls -R dist - name: Create release and upload assets env: TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail TAG="${GITHUB_REF_NAME#v}" RELEASE_ID=$(curl -sS -X POST "$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/releases" \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"draft\":false}" \ | jq -r '.id') for f in dist/*; do curl -sS -X POST "$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$(basename "$f")" \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary @"$f" done