🏡 index : ironmagma/quintodrome.git

name: Desktop Release

# Builds the Quintodrome desktop app (Tauri) for macOS (.app/.dmg),
# Windows (.exe/.msi) and Linux (.flatpak/.snap, x86_64 + aarch64), bundling
# the Navidrome server as a sidecar, and attaches the artifacts to the GitHub
# release on `v*` tags.
#
# Note: artifacts are not signed with Apple/Windows certs (macOS builds are only
# ad-hoc signed), 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-15-intel # Intel runner (macos-13 was retired)
            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

  build-linux:
    name: Build Linux (${{ matrix.arch }})
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-24.04
            arch: x86_64
          - os: ubuntu-24.04-arm
            arch: aarch64
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6

      - name: Build
        uses: ./.github/actions/build-linux
        with:
          arch: ${{ matrix.arch }}
          upload-artifact: true

  release:
    name: Publish GitHub release
    needs:
      - build-desktop
      - build-linux
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/download-artifact@v8
        with:
          path: dist
          pattern: desktop-*
          merge-multiple: true

      - run: ls -R dist

      - name: Upload to GitHub release
        uses: softprops/action-gh-release@v2
        with:
          files: dist/*
          generate_release_notes: true
          body: |
            ### macOS: "Quintodrome is damaged and can't be opened"

            The app isn't signed with an Apple Developer ID, so macOS blocks downloaded copies. After moving it to `/Applications`, run:

            ```sh
            xattr -dr com.apple.quarantine /Applications/Quintodrome.app
            codesign --force --deep -s - /Applications/Quintodrome.app
            ```