fix(ci): fresh checkout of the event ref every run; robust tkinter skip #34

Merged
ykp merged 3 commits from fix/ci-fresh-checkout into main 2026-09-29 11:40:13 +02:00
Owner

Fixes the persistent CI failures on the 3.12/3.14 legs (failing since run 119, even on docs-only commits, while local runs were green). Two compounding root causes:

1. Stale workspace pinning CI to old code (workflow issue)

The workflow cloned only when pyproject.toml was missing. The self-hosted runner reuses a persistent workspace directory, so once a leg holds a leftover (stale/partial) checkout it is silently reused forever: pyproject.toml exists -> no clone -> git not even installed -> never heals. Evidence: failures on docs-only commits, the first attempt at fixing the skip still failing (run 130 - its workspace never received the new code), and contaminated workspaces containing unrelated junk (src/main/.../zte_dummy_legacy/, demo.txt).

Fix: wipe the workspace and clone the event ref fresh on every run - GITHUB_HEAD_REF for pull_request events, GITHUB_REF_NAME for push, refs/pull/N/head fetch fallback, hardcoded FORGE_URL/REPO_SLUG fallbacks for runners that do not export the GITHUB_* context.

2. pytest.importorskip("tkinter") broke under pytest 9.1 (code/test issue)

Since pytest 9.1, importorskip only catches ModuleNotFoundError by default and re-raises plain ImportErrors at collection time. The python-slim CI images ship the tkinter/ package but not libtk8.6.so, so import tkinter raises ImportError (not ModuleNotFoundError) -> collection error libtk8.6.so: cannot open shared object file interrupting the whole run. (The 3.9 image lacks the package entirely -> ModuleNotFoundError -> skipped -> explains its green leg; CI pip install pulled pytest 9.x between runs 118 and 119, which is when the failures started.)

Fix: guard the tkinter import with try/except ImportError and skip via a gui_skip marker helper (tkinter is None or not HAS_DISPLAY). No behavior change when tkinter works.

Also

  • README: drop the hardcoded test count (drifts every increment).

Verification

  • pytest: 198 passed, 4 skipped (headless); ruff clean.
  • The workflow change can only be fully validated by CI itself; this PR's own run exercises the fresh checkout on all three legs.
Fixes the persistent CI failures on the 3.12/3.14 legs (failing since run 119, even on docs-only commits, while local runs were green). Two compounding root causes: ## 1. Stale workspace pinning CI to old code (workflow issue) The workflow cloned only when `pyproject.toml` was missing. The self-hosted runner reuses a persistent workspace directory, so once a leg holds a leftover (stale/partial) checkout it is silently reused **forever**: `pyproject.toml` exists -> no clone -> git not even installed -> never heals. Evidence: failures on docs-only commits, the first attempt at fixing the skip still failing (run 130 - its workspace never received the new code), and contaminated workspaces containing unrelated junk (`src/main/.../zte_dummy_legacy/`, `demo.txt`). **Fix:** wipe the workspace and clone the event ref fresh on every run - `GITHUB_HEAD_REF` for pull_request events, `GITHUB_REF_NAME` for push, `refs/pull/N/head` fetch fallback, hardcoded `FORGE_URL`/`REPO_SLUG` fallbacks for runners that do not export the `GITHUB_*` context. ## 2. `pytest.importorskip("tkinter")` broke under pytest 9.1 (code/test issue) Since pytest 9.1, `importorskip` only catches `ModuleNotFoundError` by default and **re-raises plain ImportErrors at collection time**. The python-slim CI images ship the `tkinter/` package but not `libtk8.6.so`, so `import tkinter` raises `ImportError` (not `ModuleNotFoundError`) -> collection error `libtk8.6.so: cannot open shared object file` interrupting the whole run. (The 3.9 image lacks the package entirely -> `ModuleNotFoundError` -> skipped -> explains its green leg; CI `pip install` pulled pytest 9.x between runs 118 and 119, which is when the failures started.) **Fix:** guard the tkinter import with `try/except ImportError` and skip via a `gui_skip` marker helper (`tkinter is None or not HAS_DISPLAY`). No behavior change when tkinter works. ## Also - README: drop the hardcoded test count (drifts every increment). ## Verification - `pytest`: **198 passed, 4 skipped** (headless); `ruff` clean. - The workflow change can only be fully validated by CI itself; this PR's own run exercises the fresh checkout on all three legs.
fix(ci): fresh checkout of the event ref every run; robust tkinter skip
Some checks failed
ci / test (3.14) (push) Successful in 1m35s
ci / test (3.12) (push) Successful in 1m40s
ci / test (3.9) (push) Failing after 2m22s
ci / test (3.12) (pull_request) Failing after 2m15s
ci / test (3.14) (pull_request) Successful in 1m47s
ci / test (3.9) (pull_request) Successful in 1m53s
ea6b487b26
Two compounding CI problems (3.12/3.14 legs failing since run 119 on
docs-only commits while local runs were green):

1. Stale workspace pinning CI to old code. The workflow cloned only when
   pyproject.toml was missing, so a leftover workspace on the
   self-hosted runner was silently reused forever (pyproject.toml
   present -> no clone -> no git needed -> never heals). This workspace
   was even contaminated with unrelated junk (src/main/..., demo.txt).
   Fix: wipe the workspace and clone the event ref fresh on every run
   (GITHUB_HEAD_REF for pull_request, GITHUB_REF_NAME for push, with
   hardcoded fallbacks for runners that do not export the context).

2. pytest 9.1 changed importorskip: by default it only catches
   ModuleNotFoundError and re-raises plain ImportErrors at collection
   time. On images where the tkinter package exists but _tkinter cannot
   load (python slim images ship tkinter/ but not libtk8.6.so),
   pytest.importorskip("tkinter") failed collection with
   ImportError: libtk8.6.so instead of skipping. Fix: guard the import
   with try/except ImportError and skip via a gui_skip marker helper.

README: drop the hardcoded test count (drifts every increment).

pytest: 198 passed, 4 skipped (headless); ruff clean.
ci: retrigger (transient leg failures — same commit green on the mirrored event)
Some checks failed
ci / test (3.12) (push) Successful in 1m55s
ci / test (3.14) (push) Successful in 2m4s
ci / test (3.12) (pull_request) Successful in 4m14s
ci / test (3.9) (push) Successful in 4m31s
ci / test (3.14) (pull_request) Failing after 1m55s
ci / test (3.9) (pull_request) Successful in 2m52s
7b3aad96ea
ci(checkout): stdlib tarball download with retries — drop git/apt
All checks were successful
ci / test (3.14) (push) Successful in 1m13s
ci / test (3.12) (push) Successful in 1m17s
ci / test (3.9) (push) Successful in 2m19s
ci / test (3.12) (pull_request) Successful in 2m20s
ci / test (3.14) (pull_request) Successful in 2m56s
ci / test (3.9) (pull_request) Successful in 2m57s
cc44d53518
The git+apt checkout added two fragile network steps to every job
(apt-get update/install + git clone over the flaky DNS here). Replace
with a single urllib download of the forge tarball API (event sha, ref
fallback, 4 attempts each) extracted with tarfile — pure stdlib, works
in the bare slim images. pip install gains --retries/--timeout for the
same reason. Checkout logic verified end-to-end against the live forge
(archive fetched, extracted flat, pyproject.toml asserted present).
ykp merged commit b9d1507319 into main 2026-09-29 11:40:13 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ykp/gengnss!34
No description provided.