perf(desktop): ship a .deb instead of an 80MB AppImage
ci / api / api (push) Successful in 50s
ci / db / db (push) Successful in 50s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Failing after 49s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m13s
ci / ts / ts (packages + web) (push) Canceled after 2m4s
ci / desktop / rust (desktop proxy) (push) Successful in 5m33s
release / release (версия и заметки) (push) Successful in 9s
release / android (APK в релиз) (push) Failing after 4m6s
release / desktop (Linux и Windows в релиз) (push) Successful in 17m20s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mrleo1nidandCursor committed 2026-10-22 08:26:50 +03:00
1 parent 73ad61e7a5
commit 83b604437c
14 files changed
+27 -34

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
# Rust-часть десктопа: прокси и проверки URL. Установщики — в release.yml # Rust-часть десктопа: прокси и проверки URL. Установщики — в release.yml
# (Linux AppImage/deb и Windows NSIS через cargo-xwin на ubuntu-latest). # (Linux .deb и Windows NSIS через cargo-xwin на ubuntu-latest).
name: ci / desktop name: ci / desktop
on: on:
+7 -14
View File
@@ -217,7 +217,6 @@ jobs:
PUBLIC_URL: ${{ vars.PUBLIC_URL || 'https://gitea.hsrv.site' }} PUBLIC_URL: ${{ vars.PUBLIC_URL || 'https://gitea.hsrv.site' }}
TAG: ${{ github.ref_name }} TAG: ${{ github.ref_name }}
VERSION: ${{ needs.release.outputs.version }} VERSION: ${{ needs.release.outputs.version }}
APPIMAGE_EXTRACT_AND_RUN: "1"
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
CARGO_BUILD_JOBS: "2" CARGO_BUILD_JOBS: "2"
XWIN_CACHE_DIR: /opt/ci-cache/xwin XWIN_CACHE_DIR: /opt/ci-cache/xwin
@@ -235,7 +234,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file \ sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file \
libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev \ libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev \
libdbus-1-dev libsecret-1-dev patchelf libfuse2 \ libdbus-1-dev libsecret-1-dev patchelf \
nsis lld llvm clang nsis lld llvm clang
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
@@ -250,7 +249,7 @@ jobs:
key: cargo-desktop-${{ hashFiles('apps/desktop/src-tauri/Cargo.toml') }} key: cargo-desktop-${{ hashFiles('apps/desktop/src-tauri/Cargo.toml') }}
restore-keys: cargo-desktop- restore-keys: cargo-desktop-
- run: pnpm install --frozen-lockfile - run: pnpm install --frozen-lockfile
- name: Сборка AppImage и deb - name: Сборка deb
id: linux id: linux
working-directory: apps/desktop working-directory: apps/desktop
run: | run: |
@@ -258,27 +257,21 @@ jobs:
pnpm bundle:linux pnpm bundle:linux
bundle=src-tauri/target/release/bundle bundle=src-tauri/target/release/bundle
shopt -s nullglob shopt -s nullglob
for f in "$bundle"/appimage/*.AppImage; do
cp "$f" "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-linux.AppImage"
done
for f in "$bundle"/deb/*.deb; do for f in "$bundle"/deb/*.deb; do
cp "$f" "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-linux.deb" cp "$f" "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-linux.deb"
done done
ls -lh "$GITHUB_WORKSPACE"/pipu-music-${PIPU_VERSION}-linux.* ls -lh "$GITHUB_WORKSPACE/pipu-music-${PIPU_VERSION}-linux.deb"
rm -rf src-tauri/target/release rm -rf src-tauri/target/release
- name: Linux в релиз - name: Linux в релиз
id: linux-upload id: linux-upload
run: | run: |
set -euo pipefail set -euo pipefail
files=() f="pipu-music-${PIPU_VERSION}-linux.deb"
for f in pipu-music-${PIPU_VERSION}-linux.AppImage pipu-music-${PIPU_VERSION}-linux.deb; do if [ ! -f "$f" ]; then
[ -f "$f" ] && files+=("$f") echo "::error::нет $f после сборки"
done
if [ ${#files[@]} -eq 0 ]; then
echo "::error::нет AppImage и deb после сборки"
exit 1 exit 1
fi fi
node scripts/release.mjs desktop linux success "${files[@]}" node scripts/release.mjs desktop linux success "$f"
- name: Windows toolchain - name: Windows toolchain
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
run: | run: |
+1 -1
View File
@@ -1549,7 +1549,7 @@ paths:
security: [] # публично: страница /download без входа security: [] # публично: страница /download без входа
summary: Клиенты последнего релиза (Android и десктоп) summary: Клиенты последнего релиза (Android и десктоп)
description: | description: |
Тот же релиз Gitea, что и для Android: APK, установщик Windows, AppImage/deb, DMG. Тот же релиз Gitea, что и для Android: APK, установщик Windows, .deb, DMG.
Нет настроек Gitea или файлов клиентов — `404 app.update_unavailable`. Нет настроек Gitea или файлов клиентов — `404 app.update_unavailable`.
responses: responses:
"200": "200":
+1 -1
View File
@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"dev": "tauri dev", "dev": "tauri dev",
"bundle": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json", "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:linux": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --bundles deb",
"bundle:windows": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --bundles nsis", "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", "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", "tauri": "tauri",
+1 -1
View File
@@ -123,7 +123,7 @@ export function fakeApi(initial: FakeUser[]) {
notes_md: '', notes_md: '',
clients: [ clients: [
{ client: 'windows', filename: 'pipu-music_1.3.0_x64-setup.exe', size: 20_000_000, download_url: '/api/v1/app/download/windows/1.3.0' }, { client: 'windows', filename: 'pipu-music_1.3.0_x64-setup.exe', size: 20_000_000, download_url: '/api/v1/app/download/windows/1.3.0' },
{ client: 'linux', filename: 'pipu-music_1.3.0_amd64.AppImage', size: 18_000_000, download_url: '/api/v1/app/download/linux/1.3.0' }, { client: 'linux', filename: 'pipu-music_1.3.0_amd64.deb', size: 4_000_000, download_url: '/api/v1/app/download/linux/1.3.0' },
{ client: 'macos', filename: 'pipu-music_1.3.0_aarch64.dmg', size: 22_000_000, download_url: '/api/v1/app/download/macos/1.3.0' }, { client: 'macos', filename: 'pipu-music_1.3.0_aarch64.dmg', size: 22_000_000, download_url: '/api/v1/app/download/macos/1.3.0' },
{ client: 'android', filename: 'pipu-music-1.3.0.apk', size: 12_000_000, sha256: 'ab'.repeat(32), download_url: '/api/v1/app/download/android/1.3.0' }, { client: 'android', filename: 'pipu-music-1.3.0.apk', size: 12_000_000, sha256: 'ab'.repeat(32), download_url: '/api/v1/app/download/android/1.3.0' },
], ],
+1 -1
View File
@@ -104,7 +104,7 @@
Android-приложение обновляется само: при запуске оно сверяется с сервером и предлагает новый APK. Android-приложение обновляется само: при запуске оно сверяется с сервером и предлагает новый APK.
Раздать приложение — ссылка `https://<ваш-домен>/download` (без входа; `/android` перенаправляет сюда): Раздать приложение — ссылка `https://<ваш-домен>/download` (без входа; `/android` перенаправляет сюда):
сборка под систему посетителя, остальные платформы ниже, адрес сервера для копирования и короткая инструкция. сборка под систему посетителя, остальные платформы ниже, адрес сервера для копирования и короткая инструкция.
APK, Linux (AppImage, deb) и Windows (NSIS) прикладываются к релизу Gitea автоматически. Та же страница — внизу экрана входа APK, Linux (`.deb`) и Windows (NSIS) прикладываются к релизу Gitea автоматически. Та же страница — внизу экрана входа
и в меню профиля. и в меню профиля.
## 7. Наблюдение ## 7. Наблюдение
+2 -2
View File
@@ -12,6 +12,6 @@ pnpm --filter @pipu/desktop dev
pnpm --filter @pipu/desktop bundle pnpm --filter @pipu/desktop bundle
``` ```
На Windows получается NSIS-установщик, на Linux — AppImage, deb и rpm. Зависимости Linux: WebKitGTK 4.1, AppIndicator, libsecret, GStreamer (плеер идёт через WebKit, в AppImage GStreamer не упаковываем — иначе файл раздувается на десятки мегабайт). На Windows получается NSIS-установщик (~3 МБ). На Linux в релиз идёт только `.deb` (~4 МБ): AppImage тащит WebKitGTK и раздувается до ~80 МБ. Зависимости пакета: WebKitGTK 4.1, AppIndicator, libsecret, GStreamer.
Релиз по тегу собирает всё на Linux-раннере: AppImage/`.deb` и Windows NSIS через `cargo-xwin` (`pipu-music-<версия>-windows-setup.exe`). Подпись Windows-установщика на Linux нет. Страница `/download` на сервере отдаёт те файлы, что есть в последнем релизе Gitea. Релиз по тегу собирает Linux `.deb` и Windows NSIS через `cargo-xwin` (`pipu-music-<версия>-windows-setup.exe`). Подпись Windows-установщика на Linux нет. Страница `/download` на сервере отдаёт те файлы, что есть в последнем релизе Gitea.
+1 -1
View File
@@ -1336,7 +1336,7 @@ export interface paths {
}; };
/** /**
* Клиенты последнего релиза (Android и десктоп) * Клиенты последнего релиза (Android и десктоп)
* @description Тот же релиз Gitea, что и для Android: APK, установщик Windows, AppImage/deb, DMG. * @description Тот же релиз Gitea, что и для Android: APK, установщик Windows, .deb, DMG.
* Нет настроек Gitea или файлов клиентов — `404 app.update_unavailable`. * Нет настроек Gitea или файлов клиентов — `404 app.update_unavailable`.
*/ */
get: operations["getAppClients"]; get: operations["getAppClients"];
+2 -2
View File
@@ -35,7 +35,7 @@
"download": { "download": {
"android": "Download APK", "android": "Download APK",
"windows": "Download for Windows", "windows": "Download for Windows",
"linux": "Download AppImage", "linux": "Download .deb",
"macos": "Download for macOS" "macos": "Download for macOS"
}, },
"version": "version {{version}}", "version": "version {{version}}",
@@ -43,7 +43,7 @@
"step_install": { "step_install": {
"android": "Open the downloaded file. If Android asks, allow installs from this source.", "android": "Open the downloaded file. If Android asks, allow installs from this source.",
"windows": "Run the installer and follow the steps. pipu will appear in the Start menu.", "windows": "Run the installer and follow the steps. pipu will appear in the Start menu.",
"linux": "Make the file executable and open it. For a .deb, install the package.", "linux": "Install the package: sudo apt install ./pipu-music-….deb. Needs WebKitGTK 4.1 and GStreamer.",
"macos": "Open the disk image and drag pipu into Applications." "macos": "Open the disk image and drag pipu into Applications."
}, },
"step_server": "Launch pipu and enter the server address:", "step_server": "Launch pipu and enter the server address:",
+2 -2
View File
@@ -35,7 +35,7 @@
"download": { "download": {
"android": "Скачать APK", "android": "Скачать APK",
"windows": "Скачать для Windows", "windows": "Скачать для Windows",
"linux": "Скачать AppImage", "linux": "Скачать .deb",
"macos": "Скачать для macOS" "macos": "Скачать для macOS"
}, },
"version": "версия {{version}}", "version": "версия {{version}}",
@@ -43,7 +43,7 @@
"step_install": { "step_install": {
"android": "Откройте скачанный файл. Если Android спросит — разрешите установку из этого источника.", "android": "Откройте скачанный файл. Если Android спросит — разрешите установку из этого источника.",
"windows": "Запустите установщик и следуйте шагам. pipu появится в меню Пуск.", "windows": "Запустите установщик и следуйте шагам. pipu появится в меню Пуск.",
"linux": "Сделайте файл исполняемым и откройте его. Для .deb — установите пакет.", "linux": "Установите пакет: sudo apt install ./pipu-music-….deb. Нужны WebKitGTK 4.1 и GStreamer.",
"macos": "Откройте образ и перетащите pipu в Программы." "macos": "Откройте образ и перетащите pipu в Программы."
}, },
"step_server": "Запустите pipu и введите адрес сервера:", "step_server": "Запустите pipu и введите адрес сервера:",
+2 -2
View File
@@ -85,7 +85,7 @@ export function renderAndroidStatus({ status, runUrl, versionCode, apk, signing
/** Блок статуса сборки десктопа в тексте релиза (отдельный для linux и windows). */ /** Блок статуса сборки десктопа в тексте релиза (отдельный для linux и windows). */
export function renderDesktopStatus({ platform, status, runUrl, files }) { export function renderDesktopStatus({ platform, status, runUrl, files }) {
const label = platform === 'windows' ? 'Windows' : 'Linux'; const label = platform === 'windows' ? 'Windows' : 'Linux';
const pending = platform === 'windows' ? 'NSIS-установщик' : 'AppImage и .deb'; const pending = platform === 'windows' ? 'NSIS-установщик' : '.deb';
const lines = const lines =
status === 'success' status === 'success'
? [ ? [
@@ -185,7 +185,7 @@ export function renderNotes({
'', '',
`- **Android:** \`pipu-music-${version}.apk\` — откройте на телефоне; Android попросит разрешить установку из этого источника.`, `- **Android:** \`pipu-music-${version}.apk\` — откройте на телефоне; Android попросит разрешить установку из этого источника.`,
`- **Windows:** \`pipu-music-${version}-windows-setup.exe\`.`, `- **Windows:** \`pipu-music-${version}-windows-setup.exe\`.`,
`- **Linux:** \`pipu-music-${version}-linux.AppImage\` (сделайте исполняемым) или \`.deb\`.`, `- **Linux:** \`pipu-music-${version}-linux.deb\` — \`sudo apt install ./pipu-music-${version}-linux.deb\` (нужны WebKitGTK 4.1 и GStreamer).`,
`- **Проверка APK:** \`sha256sum pipu-music-${version}.apk\` должен совпасть с \`pipu-music-${version}.apk.sha256\`.`, `- **Проверка APK:** \`sha256sum pipu-music-${version}.apk\` должен совпасть с \`pipu-music-${version}.apk.sha256\`.`,
'', '',
`Первая установка сервера — [инструкция](${repoUrl}/src/tag/${tag}/docs/install-guide.md).`, `Первая установка сервера — [инструкция](${repoUrl}/src/tag/${tag}/docs/install-guide.md).`,
+3 -3
View File
@@ -89,9 +89,9 @@ test('desktop status blocks', () => {
const ok = renderDesktopStatus({ const ok = renderDesktopStatus({
platform: 'linux', platform: 'linux',
status: 'success', status: 'success',
files: [{ name: 'pipu-music-1.4.0-linux.AppImage', size: 40 * 1024 * 1024 }], files: [{ name: 'pipu-music-1.4.0-linux.deb', size: 4 * 1024 * 1024 }],
}); });
assert.match(ok, /`pipu-music-1\.4\.0-linux\.AppImage` \(40,0 МБ\)/); assert.match(ok, /`pipu-music-1\.4\.0-linux\.deb` \(4,0 МБ\)/);
assert.equal(replaceDesktopStatus(`a\n\n${building}\n\nb`, 'linux', ok).includes(building), false); assert.equal(replaceDesktopStatus(`a\n\n${building}\n\nb`, 'linux', ok).includes(building), false);
const winBuilding = renderDesktopStatus({ platform: 'windows', status: 'building', runUrl: 'https://run' }); const winBuilding = renderDesktopStatus({ platform: 'windows', status: 'building', runUrl: 'https://run' });
@@ -126,7 +126,7 @@ test('release notes', () => {
assert.match(notes, /"version":"0\.2\.0"/); assert.match(notes, /"version":"0\.2\.0"/);
assert.match(notes, /pipu-music-0\.2\.0\.apk/); assert.match(notes, /pipu-music-0\.2\.0\.apk/);
assert.match(notes, /pipu-music-0\.2\.0-windows-setup\.exe/); assert.match(notes, /pipu-music-0\.2\.0-windows-setup\.exe/);
assert.match(notes, /pipu-music-0\.2\.0-linux\.AppImage/); assert.match(notes, /pipu-music-0\.2\.0-linux\.deb/);
assert.match(notes, /src\/tag\/v0\.2\.0\/docs\/install-guide\.md/); assert.match(notes, /src\/tag\/v0\.2\.0\/docs\/install-guide\.md/);
assert.doesNotMatch(notes, /Предварительная версия/); assert.doesNotMatch(notes, /Предварительная версия/);
}); });
+2 -2
View File
@@ -161,9 +161,9 @@ func assetRank(kind, name string) int {
return 1 return 1
case "linux": case "linux":
switch { switch {
case strings.HasSuffix(n, ".appimage"):
return 3
case strings.HasSuffix(n, ".deb"): case strings.HasSuffix(n, ".deb"):
return 3
case strings.HasSuffix(n, ".rpm"):
return 2 return 2
default: default:
return 1 return 1
@@ -28,7 +28,7 @@ func TestPickClientFiles(t *testing.T) {
assert.Equal(t, "pipu-music-1.3.0.apk", files["android"].Name) assert.Equal(t, "pipu-music-1.3.0.apk", files["android"].Name)
assert.Equal(t, "https://gitea/sum", files["android"].ChecksumURL) assert.Equal(t, "https://gitea/sum", files["android"].ChecksumURL)
assert.Equal(t, "pipu-music_1.3.0_x64-setup.exe", files["windows"].Name) assert.Equal(t, "pipu-music_1.3.0_x64-setup.exe", files["windows"].Name)
assert.Equal(t, "pipu-music_1.3.0_amd64.AppImage", files["linux"].Name) assert.Equal(t, "pipu-music_1.3.0_amd64.deb", files["linux"].Name)
assert.Equal(t, "pipu-music_1.3.0_aarch64.dmg", files["macos"].Name) assert.Equal(t, "pipu-music_1.3.0_aarch64.dmg", files["macos"].Name)
} }