From 4f70cb1c8bba7ec4824e80b2efef27050f5868a1 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Mon, 27 Jul 2026 04:23:31 +0300 Subject: [PATCH 1/2] feat(ci): publish Linux AppImage on GitHub Releases Add scripts/linux/build_appimage.sh and attach Querya-Desktop-{ver}-linux.AppImage alongside the portable zip. Closes #382 Co-authored-by: Cursor --- .github/workflows/release.yml | 20 +++++++-- .gitignore | 4 ++ docs/tags-and-releases.md | 15 ++++++- scripts/linux/build_appimage.sh | 75 +++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 6 deletions(-) create mode 100755 scripts/linux/build_appimage.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 57e05ec2..7f8f924f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,15 +119,20 @@ jobs: - name: Build Linux (release) run: flutter build linux --release - - name: Zip Linux artifact + - name: Zip Linux artifact (portable) run: | cd build/linux/x64/release/bundle zip -r "${GITHUB_WORKSPACE}/Querya-Desktop-${{ steps.version.outputs.version }}-linux.zip" . + - name: Build Linux AppImage (installable) + run: ./scripts/linux/build_appimage.sh + - uses: actions/upload-artifact@v4 with: name: bundle-linux - path: Querya-Desktop-${{ steps.version.outputs.version }}-linux.zip + path: | + Querya-Desktop-${{ steps.version.outputs.version }}-linux.zip + Querya-Desktop-${{ steps.version.outputs.version }}-linux.AppImage if-no-files-found: error build-macos: @@ -241,10 +246,11 @@ jobs: run: | set -euo pipefail mkdir -p dist - find artifacts -name '*.zip' -exec mv -t dist/ {} + + find artifacts \( -name '*.zip' -o -name '*.AppImage' \) -exec mv -t dist/ {} + test "$(find dist -name '*.zip' | wc -l)" -eq 3 + test "$(find dist -name '*.AppImage' | wc -l)" -eq 1 cd dist - sha256sum *.zip | tee SHA256SUMS.txt + sha256sum *.zip *.AppImage | tee SHA256SUMS.txt - name: Build release notes from CHANGELOG.md run: | @@ -256,10 +262,15 @@ jobs: echo "---" echo "" echo "### Downloads" + echo "" + echo "#### Portable (zip — run from folder)" echo "- **Linux**: \`Querya-Desktop-${VERSION}-linux.zip\`" echo "- **Windows**: \`Querya-Desktop-${VERSION}-windows.zip\`" echo "- **macOS**: \`Querya-Desktop-${VERSION}-macos.zip\` (signed, notarized and stapled \`.app\` when Apple Developer secrets are configured; otherwise unsigned)" echo "" + echo "#### Installable" + echo "- **Linux AppImage**: \`Querya-Desktop-${VERSION}-linux.AppImage\` (\`chmod +x\` then run)" + echo "" echo "Verify checksums: \`SHA256SUMS.txt\`" echo "" echo "### Build info" @@ -285,6 +296,7 @@ jobs: fail_on_unmatched_files: true files: | dist/*.zip + dist/*.AppImage dist/SHA256SUMS.txt env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index dfdc4895..4738764b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,7 @@ coverage/ *.exe design-front/ docker/sqlite/data/ + +# Local packaging outputs +Querya-Desktop-*.AppImage +Querya-Desktop-*.zip diff --git a/docs/tags-and-releases.md b/docs/tags-and-releases.md index 362912c6..85543e71 100644 --- a/docs/tags-and-releases.md +++ b/docs/tags-and-releases.md @@ -22,8 +22,19 @@ ## Что внутри релиза -- Имена архивов: `Querya-Desktop-X.Y.Z-linux.zip`, `Querya-Desktop-X.Y.Z-windows.zip`, `Querya-Desktop-X.Y.Z-macos.zip` (внутри неподписанный `.app`). -- Версия для имён и тега — **semver из pubspec**; build `+N` попадает в текст релиза как **полный pubspec version**. +### Portable + +- `Querya-Desktop-X.Y.Z-linux.zip`, `…-windows.zip`, `…-macos.zip` (Flutter bundles / `.app`) + +### Installable (Linux) + +- `Querya-Desktop-X.Y.Z-linux.AppImage` — built by [`scripts/linux/build_appimage.sh`](../scripts/linux/build_appimage.sh) in Release CI (`chmod +x` then run) + +Also attached: `SHA256SUMS.txt` (all artifacts). + +Версия для имён и тега — **semver из pubspec**; build `+N` попадает в текст релиза как **полный pubspec version**. + +Другие installable форматы (Windows setup, deb/rpm/Flatpak): epic [#379](https://github.com/QueryaHub/Querya-Desktop/issues/379). ## Changelog в GitHub Release diff --git a/scripts/linux/build_appimage.sh b/scripts/linux/build_appimage.sh new file mode 100755 index 00000000..0f974619 --- /dev/null +++ b/scripts/linux/build_appimage.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Build Querya-Desktop-*.AppImage from a Flutter linux release bundle. +# +# Usage: +# ./scripts/linux/build_appimage.sh [bundle_dir] [output_appimage] +# +# Defaults: +# bundle_dir = build/linux/x64/release/bundle +# output = Querya-Desktop--linux.AppImage +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +BUNDLE="${1:-$ROOT/build/linux/x64/release/bundle}" +BINARY_NAME="querya_desktop" +ICON_SRC="$ROOT/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" + +if [[ ! -d "$BUNDLE" ]]; then + echo "error: Flutter linux bundle not found: $BUNDLE" >&2 + echo "Run: flutter build linux --release" >&2 + exit 1 +fi +if [[ ! -x "$BUNDLE/$BINARY_NAME" ]]; then + echo "error: missing executable: $BUNDLE/$BINARY_NAME" >&2 + exit 1 +fi +if [[ ! -f "$ICON_SRC" ]]; then + echo "error: icon not found: $ICON_SRC" >&2 + exit 1 +fi + +VERSION="$(grep '^version:' "$ROOT/pubspec.yaml" | sed 's/^version: //; s/+.*//')" +OUT="${2:-$ROOT/Querya-Desktop-${VERSION}-linux.AppImage}" + +WORKDIR="$(mktemp -d "${TMPDIR:-/tmp}/querya-appimage.XXXXXX")" +cleanup() { rm -rf "$WORKDIR"; } +trap cleanup EXIT + +APPDIR="$WORKDIR/AppDir" +mkdir -p "$APPDIR" +cp -a "$BUNDLE"/. "$APPDIR/" + +cp "$ICON_SRC" "$APPDIR/${BINARY_NAME}.png" + +cat > "$APPDIR/${BINARY_NAME}.desktop" < "$APPDIR/AppRun" <<'EOF' +#!/bin/bash +set -euo pipefail +HERE="$(dirname "$(readlink -f "$0")")" +export LD_LIBRARY_PATH="${HERE}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +cd "$HERE" +exec "$HERE/querya_desktop" "$@" +EOF +chmod +x "$APPDIR/AppRun" "$APPDIR/$BINARY_NAME" + +TOOL="$WORKDIR/appimagetool" +# Prefer type-2 continuous tool; --appimage-extract-and-run avoids FUSE on CI. +curl -fsSL -o "$TOOL" \ + "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage" +chmod +x "$TOOL" + +ARCH=x86_64 "$TOOL" --appimage-extract-and-run "$APPDIR" "$OUT" +chmod +x "$OUT" +echo "Wrote $OUT" From 06e4bb2790443a7ec017964d32cdd04bed1b6751 Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Mon, 27 Jul 2026 04:28:24 +0300 Subject: [PATCH 2/2] feat(ci): publish Windows Inno Setup installer on Releases Add packaging/windows/querya.iss and attach Querya-Desktop-{ver}-windows-setup.exe next to the portable zip. Closes #383 Co-authored-by: Cursor --- .github/workflows/release.yml | 36 ++++++++++++++++++++---- .gitignore | 1 + docs/tags-and-releases.md | 9 ++++-- packaging/windows/querya.iss | 53 +++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 packaging/windows/querya.iss diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f8942885..a2bd3b19 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,16 +74,32 @@ jobs: - name: Build Windows (release) run: flutter build windows --release - - name: Zip Windows artifact + - name: Zip Windows artifact (portable) run: | $v = "${{ steps.version.outputs.version }}" $dir = "build\windows\x64\runner\Release" Compress-Archive -Path "$dir\*" -DestinationPath "Querya-Desktop-$v-windows.zip" + - name: Install Inno Setup + run: choco install innosetup --no-progress -y + + - name: Build Windows setup.exe (installable) + shell: pwsh + run: | + $v = "${{ steps.version.outputs.version }}" + $iscc = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe" + if (!(Test-Path $iscc)) { throw "ISCC not found at $iscc" } + & $iscc "/DMyAppVersion=$v" "packaging\windows\querya.iss" + $setup = "dist-windows\Querya-Desktop-$v-windows-setup.exe" + if (!(Test-Path $setup)) { throw "Setup not produced: $setup" } + Copy-Item $setup "Querya-Desktop-$v-windows-setup.exe" + - uses: actions/upload-artifact@v4 with: name: bundle-windows - path: Querya-Desktop-${{ steps.version.outputs.version }}-windows.zip + path: | + Querya-Desktop-${{ steps.version.outputs.version }}-windows.zip + Querya-Desktop-${{ steps.version.outputs.version }}-windows-setup.exe if-no-files-found: error build-linux: @@ -241,10 +257,12 @@ jobs: run: | set -euo pipefail mkdir -p dist - find artifacts -name '*.zip' -exec mv -t dist/ {} + + find artifacts \( -name '*.zip' -o -name '*.AppImage' -o -name '*-windows-setup.exe' \) \ + -exec mv -t dist/ {} + test "$(find dist -name '*.zip' | wc -l)" -eq 3 + test "$(find dist -name '*-windows-setup.exe' | wc -l)" -eq 1 cd dist - sha256sum *.zip | tee SHA256SUMS.txt + sha256sum *.* | tee SHA256SUMS.txt - name: Build release notes from CHANGELOG.md run: | @@ -265,7 +283,10 @@ jobs: echo "Optional USB-style profile: set \`QUERYA_PORTABLE=1\` or create a \`QueryaData/\` folder next to the binary (see docs/packaging.md)." echo "" echo "#### Installable" - echo "_AppImage / Windows setup / distro packages — tracked in epic #379; not attached to this release yet._" + echo "- **Windows setup**: \`Querya-Desktop-${VERSION}-windows-setup.exe\` (Inno Setup)" + if [[ -f "dist/Querya-Desktop-${VERSION}-linux.AppImage" ]]; then + echo "- **Linux AppImage**: \`Querya-Desktop-${VERSION}-linux.AppImage\`" + fi echo "" echo "Verify checksums: \`SHA256SUMS.txt\`" echo "" @@ -289,9 +310,12 @@ jobs: tag_name: ${{ steps.rel.outputs.tag }} name: Querya Desktop ${{ needs.build-windows.outputs.version }} body_path: release-notes.md - fail_on_unmatched_files: true + # AppImage may be absent until the Linux AppImage job lands (#382). + fail_on_unmatched_files: false files: | dist/*.zip + dist/*.AppImage + dist/*-windows-setup.exe dist/SHA256SUMS.txt env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index dfdc4895..8f0ddfd2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,5 +39,6 @@ coverage/ *.so *.dll *.exe +dist-windows/ design-front/ docker/sqlite/data/ diff --git a/docs/tags-and-releases.md b/docs/tags-and-releases.md index 70e03bf3..45e5a883 100644 --- a/docs/tags-and-releases.md +++ b/docs/tags-and-releases.md @@ -37,9 +37,14 @@ Профиль по умолчанию всё равно в OS app-support; USB-style data → [packaging.md](packaging.md) (`QUERYA_PORTABLE` / `QueryaData/`). -### Installable channel (planned) +### Installable channel -Отдельные артефакты (AppImage, Windows setup, deb/rpm/Flatpak) — epic [#379](https://github.com/QueryaHub/Querya-Desktop/issues/379). Пока в Release публикуются только portable zip выше. +| Artifact | Notes | +|----------|--------| +| `Querya-Desktop-X.Y.Z-windows-setup.exe` | Inno Setup (`packaging/windows/querya.iss`) | +| `Querya-Desktop-X.Y.Z-linux.AppImage` | When Linux AppImage CI is merged (#382) | + +Другие форматы (deb/rpm/Flatpak): [#386](https://github.com/QueryaHub/Querya-Desktop/issues/386) / epic [#379](https://github.com/QueryaHub/Querya-Desktop/issues/379). ## Changelog в GitHub Release diff --git a/packaging/windows/querya.iss b/packaging/windows/querya.iss new file mode 100644 index 00000000..ea2113d9 --- /dev/null +++ b/packaging/windows/querya.iss @@ -0,0 +1,53 @@ +; Inno Setup script for Querya Desktop (Windows installable channel). +; Compile from repo root after `flutter build windows --release`: +; ISCC /DMyAppVersion=0.4.11 packaging\windows\querya.iss + +#ifndef MyAppVersion + #define MyAppVersion "0.0.0" +#endif + +#define MyAppName "Querya Desktop" +#define MyAppPublisher "QueryaHub" +#define MyAppExeName "querya_desktop.exe" +#define MyAppSourceDir "..\..\build\windows\x64\runner\Release" + +[Setup] +; Stable AppId — do not change across releases (controls uninstall / upgrades). +AppId={{A7C3E2F1-9B4D-4E8A-8F2C-1D5E6A7B8C9D} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL=https://github.com/QueryaHub/Querya-Desktop +DefaultDirName={autopf}\Querya Desktop +DefaultGroupName=Querya Desktop +DisableProgramGroupPage=yes +LicenseFile= +OutputDir=..\..\dist-windows +OutputBaseFilename=Querya-Desktop-{#MyAppVersion}-windows-setup +SetupIconFile=..\..\windows\runner\resources\app_icon.ico +Compression=lzma +SolidCompression=yes +WizardStyle=modern +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=dialog +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible +UninstallDisplayIcon={app}\{#MyAppExeName} +CloseApplications=yes +RestartApplications=no + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent