All network calls are monkeypatched (urllib.request.urlopen) — no live
network in tests. Covers older/newer/equal comparisons, v-prefix,
differing-length tuples, malformed input on both sides, and
fetch_latest_release success/timeout/network-failure/malformed-response
paths.
- Add a real QMenuBar (Help -> About...).
- AboutDialog: app icon, name, version (core.__version__), and links to the
repo/issues/license opened via QDesktopServices.openUrl (system browser,
never in-app navigation). macOS unsigned-app note.
- "Check for updates" button + UpdateCheckWorker (QThread) runs
core.fetch_latest_release() off the UI thread; shows "up to date" or
"vX.Y.Z available" with a button to open the releases page. No binary
download, ever.
- Optional quiet startup auto-check, throttled to once/day via a QSettings
timestamp, off-thread, silent on failure, toggle lives in the About dialog.
- Add `__version__ = "1.1.0"` as the single source of truth (matches pyproject.toml).
- Add parse_version()/is_newer_version() for numeric (never lexical) version
comparison, handling v-prefix, pre-release suffixes, and malformed input.
- Add fetch_latest_release(): reads the public Gitea releases API
(anonymous, no token) and returns {version, url} or None on any failure.
Never downloads or touches a binary — metadata only.
The crashed/exited/stderr spawn tests used 0.3-0.5s timeouts. On a slow CI
runner, interpreter startup can exceed that, so the process is still starting
when the timeout fires, gets killed, and is misclassified "ok" (still running)
instead of "crashed"/"exited". Bump those three to 2.0s. The two "ok" paths
(sleep-60, stdin-block) stay at 0.3s since timing out there means success.