From eb8031b126b01299767228361ce2930812fd0ada Mon Sep 17 00:00:00 2001 From: mrleo1nid <43583385+mrleo1nid@users.noreply.github.com> Date: Thu, 22 Oct 2026 00:43:16 +0300 Subject: [PATCH] ci(release): cross-compile Windows NSIS on the Linux runner Co-authored-by: Cursor --- .gitea/workflows/ci-desktop.yml | 2 +- .gitea/workflows/release.yml | 131 +++++++++++++++----------------- apps/desktop/package.json | 1 + docs/desktop.md | 2 +- 4 files changed, 65 insertions(+), 71 deletions(-) diff --git a/.gitea/workflows/ci-desktop.yml b/.gitea/workflows/ci-desktop.yml index 8472ace..1114ec1 100644 --- a/.gitea/workflows/ci-desktop.yml +++ b/.gitea/workflows/ci-desktop.yml @@ -1,5 +1,5 @@ # Rust-часть десктопа: прокси и проверки URL. Установщики — в release.yml -# (Linux на ubuntu-latest, Windows NSIS на windows-latest). +# (Linux AppImage/deb и Windows NSIS через cargo-xwin на ubuntu-latest). name: ci / desktop on: diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8bd56e4..153b1bb 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,6 +1,7 @@ # Релиз по тегу vMAJOR.MINOR.PATCH[-rc.N]: Gitea Release с заметками → APK, Linux и Windows. # Релиз создаётся сразу (статусы Android/десктоп — «собирается»); сборки докладывают файлы # и переписывают статус: собран / не удалась (scripts/release.mjs). +# Один Ubuntu-раннер: сначала APK, потом десктоп (Linux native + Windows через cargo-xwin). # Docker-образы не публикуются: сервер собирает их сам из клонированного репозитория (deploy/update.sh). # # Секреты (Settings → Actions → Secrets): @@ -198,10 +199,13 @@ jobs: if: cancelled() run: node scripts/release.mjs android cancelled - desktop-linux: - name: desktop (Linux в релиз) - needs: release - timeout-minutes: 60 + # После Android: на одном хосте параллельный Tauri + Gradle валит раннер. + # Windows NSIS — cargo-xwin + makensis на этом же Ubuntu (виндового раннера нет). + desktop: + name: desktop (Linux и Windows в релиз) + needs: [release, android] + if: always() && needs.release.result == 'success' + timeout-minutes: 90 runs-on: ubuntu-latest defaults: run: @@ -215,10 +219,14 @@ jobs: VERSION: ${{ needs.release.outputs.version }} APPIMAGE_EXTRACT_AND_RUN: "1" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + CARGO_BUILD_JOBS: "2" + XWIN_CACHE_DIR: /opt/ci-cache/xwin steps: - uses: actions/checkout@v4 - name: Статус в релизе — собирается - run: node scripts/release.mjs desktop linux building + run: | + node scripts/release.mjs desktop linux building + node scripts/release.mjs desktop windows building - name: Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal @@ -227,7 +235,8 @@ jobs: sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file \ libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev \ - libdbus-1-dev libsecret-1-dev patchelf libfuse2 + libdbus-1-dev libsecret-1-dev patchelf libfuse2 \ + nsis lld llvm clang - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm } @@ -237,10 +246,12 @@ jobs: ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db + ~/.cargo/bin/cargo-xwin key: cargo-desktop-${{ hashFiles('apps/desktop/src-tauri/Cargo.toml') }} restore-keys: cargo-desktop- - run: pnpm install --frozen-lockfile - name: Сборка AppImage и deb + id: linux working-directory: apps/desktop run: | set -euo pipefail @@ -254,7 +265,9 @@ jobs: cp "$f" "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-linux.deb" done ls -lh "$GITHUB_WORKSPACE"/pipu-music-${PIPU_VERSION}-linux.* - - name: Файлы в релиз + rm -rf src-tauri/target/release + - name: Linux в релиз + id: linux-upload run: | set -euo pipefail files=() @@ -266,72 +279,52 @@ jobs: exit 1 fi node scripts/release.mjs desktop linux success "${files[@]}" - - name: Статус в релизе — сборка не удалась - if: failure() - run: node scripts/release.mjs desktop linux failure - - name: Статус в релизе — сборка отменена - if: cancelled() - run: node scripts/release.mjs desktop linux cancelled - - # Нужен act_runner с меткой windows-latest (Windows + MSVC Build Tools + WebView2). - # Без такого раннера job останется в очереди; Tauri не кросс-компилирует NSIS с Linux. - desktop-windows: - name: desktop (Windows в релиз) - needs: release - timeout-minutes: 60 - runs-on: windows-latest - defaults: - run: - shell: pwsh - env: - PIPU_VERSION: ${{ needs.release.outputs.version }} - GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }} - GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }} - PUBLIC_URL: ${{ vars.PUBLIC_URL || 'https://gitea.hsrv.site' }} - TAG: ${{ github.ref_name }} - VERSION: ${{ needs.release.outputs.version }} - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 - with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm } - - name: Статус в релизе — собирается - run: node scripts/release.mjs desktop windows building - - uses: ilammy/msvc-dev-cmd@v1 - - name: Rust + - name: Windows toolchain + if: ${{ !cancelled() }} run: | - $init = Join-Path $env:TEMP 'rustup-init.exe' - Invoke-WebRequest -Uri 'https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe' -OutFile $init - & $init -y --default-toolchain stable --profile minimal --default-host x86_64-pc-windows-msvc --no-modify-path - Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\.cargo\bin" - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git/db - key: cargo-desktop-windows-${{ hashFiles('apps/desktop/src-tauri/Cargo.toml') }} - restore-keys: cargo-desktop-windows- - - run: pnpm install --frozen-lockfile + set -euo pipefail + rustup target add x86_64-pc-windows-msvc + if ! command -v cargo-xwin >/dev/null; then + cargo install --locked cargo-xwin + fi + if [ ! -d /opt/ci-cache ]; then + echo "XWIN_CACHE_DIR=$HOME/.cache/xwin" >> "$GITHUB_ENV" + mkdir -p "$HOME/.cache/xwin" + else + mkdir -p /opt/ci-cache/xwin + fi - name: Сборка NSIS + id: win + if: ${{ !cancelled() }} working-directory: apps/desktop run: | - pnpm bundle:windows - $bundle = Join-Path (Get-Location) 'src-tauri/target/release/bundle/nsis' - $src = Get-ChildItem -Path $bundle -Filter '*-setup.exe' | Select-Object -First 1 - if (-not $src) { throw "нет NSIS setup.exe после сборки в $bundle" } - $dest = Join-Path $env:GITHUB_WORKSPACE "pipu-music-$env:PIPU_VERSION-windows-setup.exe" - Copy-Item $src.FullName $dest - Get-Item $dest | Format-List Name, Length - - name: Файл в релиз - run: | - $file = "pipu-music-$env:PIPU_VERSION-windows-setup.exe" - if (-not (Test-Path $file)) { throw "нет $file после сборки" } - node scripts/release.mjs desktop windows success $file - - name: Статус в релизе — сборка не удалась - if: failure() + set -euo pipefail + pnpm bundle:windows:cross + bundle=src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis + shopt -s nullglob + copied= + for f in "$bundle"/*-setup.exe; do + cp "$f" "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-windows-setup.exe" + copied=1 + done + if [ -z "$copied" ]; then + echo "::error::нет NSIS setup.exe после сборки в $bundle" + ls -la "$bundle" || true + exit 1 + fi + ls -lh "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-windows-setup.exe" + - name: Windows в релиз + id: win-upload + if: ${{ !cancelled() && steps.win.outcome == 'success' }} + run: node scripts/release.mjs desktop windows success "pipu-music-${PIPU_VERSION}-windows-setup.exe" + - name: Статус Linux — сборка не удалась + if: failure() && steps.linux-upload.outcome != 'success' + run: node scripts/release.mjs desktop linux failure + - name: Статус Windows — сборка не удалась + if: failure() && steps.win-upload.outcome != 'success' run: node scripts/release.mjs desktop windows failure - name: Статус в релизе — сборка отменена if: cancelled() - run: node scripts/release.mjs desktop windows cancelled + run: | + node scripts/release.mjs desktop linux cancelled + node scripts/release.mjs desktop windows cancelled diff --git a/apps/desktop/package.json b/apps/desktop/package.json index b3d1994..eb172cf 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -8,6 +8,7 @@ "bundle": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json", "bundle:linux": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --bundles appimage,deb", "bundle:windows": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --bundles nsis", + "bundle:windows:cross": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis", "tauri": "tauri", "icons": "tauri icon ../web/public/favicon.svg" }, diff --git a/docs/desktop.md b/docs/desktop.md index 423bae3..7186398 100644 --- a/docs/desktop.md +++ b/docs/desktop.md @@ -14,4 +14,4 @@ pnpm --filter @pipu/desktop bundle На Windows получается NSIS-установщик, на Linux — AppImage, deb и rpm. Зависимости Linux: WebKitGTK 4.1, AppIndicator, libsecret, GStreamer. -Релиз по тегу прикладывает Linux AppImage/`.deb` (`pipu-music-<версия>-linux.*`) и Windows NSIS (`pipu-music-<версия>-windows-setup.exe`). Windows-job в `release.yml` ждёт act_runner с меткой `windows-latest` (MSVC + WebView2). Страница `/download` на сервере отдаёт те файлы, что есть в последнем релизе Gitea. +Релиз по тегу собирает всё на Linux-раннере: AppImage/`.deb` и Windows NSIS через `cargo-xwin` (`pipu-music-<версия>-windows-setup.exe`). Подпись Windows-установщика на Linux нет. Страница `/download` на сервере отдаёт те файлы, что есть в последнем релизе Gitea.