From 57b41d520150fc3ad219e186eb568fcb2f1ad31f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 14:56:35 +0000 Subject: [PATCH] ci: run the suite where a GNOME 50 desktop is, not where it isn't MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI has been red on main since the v2 rebuild started — six runs, every one of them for the environment rather than for the code. The ubuntu job could not pass in any configuration, and it took three separate experiments to establish that: * as it stands, `import gi` fails and pytest aborts during collection. apt puts PyGObject in /usr/lib/python3/dist-packages, for the runner's own python3; the venv is built from actions/setup-python, whose --system-site-packages points at the tool-cache tree instead. The 22 "skipped" in that same line were the Gio-backed tests skipping for the same reason, so the tier was proving far less than the log suggested. * give the venv PyGObject and 44 tests fail: 19 of them are every settings write being skipped with "your desktop session wasn't running", because there is no session bus on a CI runner. * add a private session bus and 14 remain, all of them the runner being a 2024 desktop: ubuntu-24.04 ships gsettings-desktop-schemas 46, which has no `accent-color` key and no org.gnome.shell, so every bundled Look plans zero add-ons. The archlinux container already had the right userspace and the session bus; it was only missing packages. So the split moves: the container runs the whole suite (`-m "not sandbox"`, both tiers), and ubuntu keeps the two things that genuinely need no desktop — ruff and the packaging tests. Also in the container's package list, which is what its own ten failures were about: gsettings-desktop-schemas, gnome-settings-daemon, mutter and gnome-shell for the schemas the pages read; gnome-desktop-4 for the GnomeDesktop-4.0 typelib the thumbnailer needs; gnome-backgrounds for the wallpaper catalogue the Wallpaper page scans; desktop-file-utils and appstream so the packaging tests do not skip themselves there. release.yml had the same broken pre-flight, so a v2.0.0 tag would have failed before it built anything. Its "Test before shipping" step is now the same container job, and the wheel build waits on it. Two test modules import gi at module scope under `pytestmark = pytest.mark.gtk`, but a marker deselects after collection, so -m "not gtk" never got the chance. They now carry the importorskip guard the other gi-dependent modules already use: on a machine with no PyGObject they skip instead of aborting the run. Verified both ways — the abort reproduces without the guard, collection is clean with it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0165p9a9fF1VfbWaQEGD7yYW --- .github/workflows/ci.yml | 74 ++++++++++++++++++++++------------ .github/workflows/release.yml | 46 ++++++++++++++++----- tests/unit/test_applyrunner.py | 5 +++ tests/unit/test_window.py | 5 +++ 4 files changed, 94 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a520eec..4a99a68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,8 @@ concurrency: # READ THIS BEFORE TRUSTING A GREEN TICK. # # What CI proves is strictly LESS than what `./verify.sh --full` proves on a -# real machine. Green here means: the code lints, the pure-Python tier passes, -# the packaging is well-formed, and the widgets build under GTK 4 / libadwaita. +# real machine. Green here means: the code lints, the packaging is well-formed, +# and the suite passes against a GNOME 50 userspace with a private session bus. # # It does NOT prove any of the following, all of which only the local canonical # check covers: @@ -27,61 +27,85 @@ concurrency: # * that the machine this was built on came out unchanged (F16). # A change that is green here and has not been through ./verify.sh --full is # unverified. See docs/testing.md. +# +# WHY THE WHOLE SUITE RUNS IN THE ARCH CONTAINER AND NOT ON THE UBUNTU RUNNER. +# It was split the other way until the v2 rebuild, and the unit half could not +# pass there for three separate reasons, none of them about the code: +# * with no PyGObject the page modules will not import, and the tests that +# read a setting through GioBackend have nothing to read it with; +# * with PyGObject but no session bus, every settings write is skipped with +# "your desktop session wasn't running" — 19 failures that say nothing; +# * with both, ubuntu-24.04's gsettings-desktop-schemas is GNOME 46, which +# has no `accent-color` key and no org.gnome.shell, so a further 14 fail +# for being a 2024 desktop rather than a 2026 one. +# The container is the machine gtheme targets. The ubuntu job keeps the two +# things that genuinely do not need a desktop: the linter and the packaging. jobs: - lint-and-unit: - name: ruff + unit tests + lint-and-packaging: + name: ruff + packaging runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - # F10: core/ may import Gio/GLib (a guard test forbids Gtk/Adw there), so - # the unit tier needs PyGObject with the GLib typelib. libglib2.0-bin - # provides glib-compile-schemas, which the settings-backend tests use to - # build a throwaway schema. The last three are what the packaging tests - # check the launcher entry, the store listing and the icons with — without - # them those tests skip themselves and prove nothing. - - name: Install GLib bindings and the packaging checkers + # These three are what the packaging tests check the launcher entry, the + # store listing and the icons with — without them those tests skip + # themselves and prove nothing. No PyGObject here on purpose: nothing in + # this job may need a desktop. + - name: Install the packaging checkers run: | sudo apt-get update - sudo apt-get install -y python3-gi gir1.2-glib-2.0 libglib2.0-bin \ - desktop-file-utils appstream librsvg2-bin + sudo apt-get install -y desktop-file-utils appstream librsvg2-bin - name: Install gtheme run: | - python -m venv --system-site-packages .venv + python -m venv .venv .venv/bin/python -m pip install --upgrade pip .venv/bin/python -m pip install -e '.[dev]' - name: ruff run: .venv/bin/ruff check . - - name: pytest - # Ubuntu runners ship libadwaita 1.5; gtheme targets 1.9. No Adw code - # may run here — that is the archlinux job's task. The unit tier - # includes tests/unit/test_packaging_*.py, which builds a real wheel - # and looks inside it. - run: .venv/bin/python -m pytest -q -m "not gtk and not sandbox" + - name: pytest — packaging only + # Builds a real wheel and looks inside it, validates the .desktop file + # and the metainfo, and checks what install.sh would put where. + run: | + .venv/bin/python -m pytest -q \ + tests/unit/test_packaging_wheel.py \ + tests/unit/test_packaging_desktop.py \ + tests/unit/test_packaging_install.py - gtk: - name: GTK/libadwaita tests (Arch container) + tests: + name: the suite (Arch container, GNOME 50) runs-on: ubuntu-latest container: archlinux:latest steps: + # The GNOME lines are not decoration. Without them ten tests fail for the + # container rather than for the code: the schemas the pages read + # (org.gnome.shell, org.gnome.mutter, the settings-daemon plugins), the + # GnomeDesktop-4.0 typelib the thumbnailer needs, and the wallpaper + # catalogue under /usr/share/gnome-background-properties. - name: Install system packages run: | pacman -Syu --noconfirm \ python python-gobject gtk4 libadwaita glib2 dconf libsoup3 \ + gsettings-desktop-schemas gnome-desktop-4 gnome-settings-daemon \ + mutter gnome-shell gnome-backgrounds \ + desktop-file-utils appstream \ python-pip python-hatchling dbus git - uses: actions/checkout@v4 - name: Install gtheme run: | python -m venv --system-site-packages .venv .venv/bin/python -m pip install -e '.[dev]' - - name: pytest -m gtk + - name: pytest # gtk4-broadwayd is an offscreen GDK backend: no X server, no # compositor, no Xvfb needed. dbus-run-session gives the tests a - # private session bus so nothing reaches a real one. + # private session bus so nothing reaches a real one — and so that the + # transaction tests have a session to write into at all. + # + # -m "not sandbox" is both tiers at once: the sandbox tier is the only + # one this file refuses to run, and pyproject already deselects it. run: | gtk4-broadwayd :5 & sleep 2 GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 \ - dbus-run-session -- .venv/bin/python -m pytest -q -m gtk + dbus-run-session -- .venv/bin/python -m pytest -q -m "not sandbox" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68a2170..b9bd60d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,36 @@ permissions: contents: read jobs: + # Nothing ships that the suite has not passed on, and the suite needs a + # GNOME 50 userspace and a session bus to mean anything — see the long note + # at the top of ci.yml. This is that job, and the wheel waits for it. + tests: + name: the suite (Arch container, GNOME 50) + runs-on: ubuntu-latest + container: archlinux:latest + steps: + - name: Install system packages + run: | + pacman -Syu --noconfirm \ + python python-gobject gtk4 libadwaita glib2 dconf libsoup3 \ + gsettings-desktop-schemas gnome-desktop-4 gnome-settings-daemon \ + mutter gnome-shell gnome-backgrounds \ + desktop-file-utils appstream \ + python-pip python-hatchling dbus git + - uses: actions/checkout@v4 + - name: Install gtheme + run: | + python -m venv --system-site-packages .venv + .venv/bin/python -m pip install -e '.[dev]' + - name: Test before shipping + run: | + gtk4-broadwayd :5 & + sleep 2 + GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 \ + dbus-run-session -- .venv/bin/python -m pytest -q -m "not sandbox" + build: + needs: tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -26,19 +55,12 @@ jobs: with: python-version: "3.13" - # Same reason as ci.yml: core/ imports Gio, so the unit tier needs the - # GLib bindings even though no window is ever opened here. - - name: Install GLib bindings + # The wheel is pure Python; only the launcher entry and the store listing + # need checking here, and neither needs a desktop. + - name: Install the packaging checkers run: | sudo apt-get update - sudo apt-get install -y python3-gi gir1.2-glib-2.0 libglib2.0-bin \ - desktop-file-utils appstream - - - name: Test before shipping - run: | - python -m venv --system-site-packages .venv - .venv/bin/python -m pip install -e '.[dev]' - .venv/bin/python -m pytest -q -m "not gtk and not sandbox" + sudo apt-get install -y desktop-file-utils appstream - name: Check the launcher entry and the store listing run: | @@ -47,6 +69,8 @@ jobs: - name: Build the wheel run: | + python -m venv .venv + .venv/bin/python -m pip install -e '.[dev]' .venv/bin/python -m pip install build .venv/bin/python -m build --wheel diff --git a/tests/unit/test_applyrunner.py b/tests/unit/test_applyrunner.py index 7c58e33..840a9cc 100644 --- a/tests/unit/test_applyrunner.py +++ b/tests/unit/test_applyrunner.py @@ -19,6 +19,11 @@ pytestmark = pytest.mark.gtk +# A marker deselects after collection, so ``-m "not gtk"`` cannot save a +# machine with no PyGObject from the module-scope import below: without this +# line the whole run aborts on a collection error instead of skipping. +pytest.importorskip("gi", reason="PyGObject is needed for these widgets") + from gtheme.ui.applyrunner import ApplyRunner # noqa: E402 diff --git a/tests/unit/test_window.py b/tests/unit/test_window.py index e1bd59d..56c1c24 100644 --- a/tests/unit/test_window.py +++ b/tests/unit/test_window.py @@ -30,6 +30,11 @@ pytestmark = pytest.mark.gtk +# A marker deselects after collection, so ``-m "not gtk"`` cannot save a +# machine with no PyGObject from the module-scope import below: without this +# line the whole run aborts on a collection error instead of skipping. +pytest.importorskip("gi", reason="PyGObject is needed for these widgets") + from gi.repository import Adw, Gtk # noqa: E402 from gtheme import window as window_module # noqa: E402