Files
voculinux/tests/test_appimage_packaging.py
T
a37469c8d5 feat(ui): About page for this app, VocaHQ, and talk to us (#718)
* feat(ui): About page for this app, VocaHQ, and talk to us

Settings About now has three groups. Vocalinux keeps the existing icon,
version, AGPL-3.0, updater, and What's New. The website button opens
vocalinux.com.

Part of VocaHQ lists the family sites with PRODUCT.md status. Talk to us
opens GitHub issues, Discord, X, and email. Official Design marks from
VocaHQ/.github are vendored as-is and painted with iron-white ink.

* fix(ui): unique About Open names and pin Design SVG hashes

Open buttons on About still say Open. Each one now uses its tooltip as
the accessible name so a screen reader can tell vocahq.com from
vocalinux.com from Latest Release.

The Talk-to-us SVG test pins sha256 of the four official marks from
VocaHQ/.github 61c8eee.

* fix(ui): circular app icon and About source code link

The launcher and About header used the square teal fill. Switch
both to the circular family logo (voca-logo.svg). Website stays
vocalinux.com; Source code next to it opens the GitHub repo.

* fix(appimage): pin pywhispercpp to the version install.sh declares

* fix(appimage): pin pywhispercpp at both install sites

* test(docs): match AGENTS.md uv.lock wording

#727 dropped "unused until those phases land". The test still
looked for that line, so any PR that runs Python tests against
current main failed. Pin the current contract instead: uv.lock
is authoritative, and requirements/*.txt are not hand-edited.

---------

Co-authored-by: Sergey Silaev <hello@8am.dev>
2026-08-23 00:50:40 -07:00

89 lines
3.1 KiB
Python

"""Regression guards for AppImage packaging."""
import re
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
BUILD_SH = REPO_ROOT / "packaging" / "appimage" / "build.sh"
# Typelibs that must ship in the AppImage. xlib/Dbusmenu/GModule/fontconfig are
# transitive GIR deps — pruning them broke Gtk on openSUSE (#585).
REQUIRED_TYPELIBS = (
"Gtk-3.0",
"Gdk-3.0",
"xlib-2.0",
"GModule-2.0",
"Dbusmenu-0.4",
"fontconfig-2.0",
"Notify-0.7",
)
# Tray stacks are alternates (same order as tray_indicator.py).
INDICATOR_TYPELIBS = (
"AyatanaAppIndicator3-0.1",
"AyatanaAppindicator3-0.1",
"AppIndicator3-0.1",
)
def test_appimage_build_ships_transitive_typelibs():
text = BUILD_SH.read_text()
assert "TYPELIBS=(" in text
# Must not wipe linuxdeploy's typelib set down to a partial allowlist.
assert 'rm -rf "$APPDIR/usr/lib/girepository-1.0"' not in text
assert "keeping linuxdeploy extras" in text or "Ensuring required typelibs" in text
for typelib in REQUIRED_TYPELIBS:
assert typelib in text, f"missing typelib seed {typelib} in {BUILD_SH}"
for typelib in INDICATOR_TYPELIBS:
assert typelib in text, f"missing indicator typelib seed {typelib}"
assert "INDICATOR_TYPELIBS=" in text
assert "indicator_found" in text
assert "Need at least one of:" in text
def test_appimage_build_bundles_gi_runtime_libs():
text = BUILD_SH.read_text()
for lib in (
"libappindicator3.so.1",
"libayatana-appindicator3.so.1",
"libdbusmenu-glib.so.4",
"libdbusmenu-gtk3.so.4",
"libnotify.so.4",
):
assert lib in text, f"missing GI runtime lib {lib} in {BUILD_SH}"
def test_appimage_build_smokes_gi_without_host_typelibs():
text = BUILD_SH.read_text()
assert "smoke_gi_imports" in text
assert "unshare --user --mount" in text
def test_appimage_build_rebuilds_pywhispercpp_with_vulkan():
text = BUILD_SH.read_text()
assert "GGML_VULKAN=1" in text
assert "libggml-vulkan" in text
assert "VOCALINUX_APPIMAGE_REQUIRE_VULKAN" in text
assert "VOCALINUX_APPIMAGE_SKIP_VULKAN" in text
assert "rebuild_pywhispercpp_vulkan" in text
assert 'CC="${CC:-gcc}"' in text
assert 'CXX="${CXX:-g++}"' in text
def test_appimage_pins_pywhispercpp_to_the_installer_version():
"""An unpinned source build takes whatever PyPI published that day.
pywhispercpp 1.5.1 landed mid-review and failed to compile with Vulkan on
the runner, breaking both AppImage jobs while nothing in the repo changed.
"""
build = BUILD_SH.read_text(encoding="utf-8")
# Both installs: the bundle install resolves the wheel's dependency range and
# the Vulkan rebuild replaces it. Pinning one mixes two versions' libggml.
assert build.count("pywhispercpp==$PYWHISPERCPP_VERSION") == 2
assert 'PYWHISPERCPP_VERSION="$(sed' in build, "the pin must come from install.sh"
installer = (REPO_ROOT / "install.sh").read_text(encoding="utf-8")
assert re.search(
r'^PYWHISPERCPP_VERSION="\d+\.\d+\.\d+"', installer, re.M
), "install.sh no longer declares the version build.sh reads"