Merge pull request 'feat(m9): .deb package + CI build/publish — 0.35.0' (#29) from feat/deb-packaging into main
Reviewed-on: #29
This commit was merged in pull request #29.
This commit is contained in:
@@ -43,6 +43,9 @@ jobs:
|
|||||||
- name: Build self-extracting installer (.run)
|
- name: Build self-extracting installer (.run)
|
||||||
run: python packaging/make_run.py
|
run: python packaging/make_run.py
|
||||||
|
|
||||||
|
- name: Build .deb
|
||||||
|
run: python packaging/make_deb.py
|
||||||
|
|
||||||
- name: Read version
|
- name: Read version
|
||||||
id: ver
|
id: ver
|
||||||
run: |
|
run: |
|
||||||
@@ -103,3 +106,20 @@ jobs:
|
|||||||
"${API}/releases/${rid}/assets?name=$(basename "$f")" >/dev/null
|
"${API}/releases/${rid}/assets?name=$(basename "$f")" >/dev/null
|
||||||
done
|
done
|
||||||
echo "Published ${TAG}."
|
echo "Published ${TAG}."
|
||||||
|
|
||||||
|
- name: Publish .deb to the Gitea apt registry (optional — needs REGISTRY_TOKEN)
|
||||||
|
env:
|
||||||
|
PKG_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [ -z "${PKG_TOKEN:-}" ]; then
|
||||||
|
echo "PACKAGES_TOKEN not set — skipping apt publish (the .deb is still a release asset)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
OWNER="${{ github.repository_owner }}"
|
||||||
|
URL="${{ github.server_url }}/api/packages/${OWNER}/debian/pool/stable/main/upload"
|
||||||
|
for f in dist/*.deb; do
|
||||||
|
echo "Uploading $(basename "$f") to the apt registry…"
|
||||||
|
curl -sS --fail --user "${OWNER}:${PKG_TOKEN}" --upload-file "$f" "$URL"
|
||||||
|
done
|
||||||
|
echo "apt source: deb ${{ github.server_url }}/api/packages/${OWNER}/debian stable main"
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ All notable changes to RigDoctor are recorded here. Format follows
|
|||||||
(`MAJOR.MINOR.PATCH`, pre-1.0). `__version__` and `pyproject.toml` must match the git
|
(`MAJOR.MINOR.PATCH`, pre-1.0). `__version__` and `pyproject.toml` must match the git
|
||||||
release tag (so the auto-updater, D18, can compare versions).
|
release tag (so the auto-updater, D18, can compare versions).
|
||||||
|
|
||||||
|
## [0.35.0] - 2026-05-22
|
||||||
|
### Added
|
||||||
|
- **`.deb` package (M9 / D8)** — `packaging/make_deb.py` builds a `rigdoctor_<version>_all.deb`
|
||||||
|
(pure-Python, `Architecture: all`) via `dpkg-deb`: `Depends: python3`, with the GUI deps
|
||||||
|
(`python3-pyside6`, `python3-pyte`) as **Recommends** so `sudo apt install ./rigdoctor_*.deb`
|
||||||
|
gives the full app and `--no-install-recommends` gives CLI-only. Installs the package, both
|
||||||
|
launchers, the desktop entry, and the icon. CI (`release.yml`) builds it as a **release asset**
|
||||||
|
every release, and optionally publishes it to the Gitea **apt registry** (set a `REGISTRY_TOKEN`
|
||||||
|
secret) for `sudo apt install rigdoctor`. **M9 is now complete.**
|
||||||
|
|
||||||
## [0.34.0] - 2026-05-22
|
## [0.34.0] - 2026-05-22
|
||||||
### Added
|
### Added
|
||||||
- **Event-based alerts (M8).** Beyond temperature + GPU-lost, RigDoctor now notifies on
|
- **Event-based alerts (M8).** Beyond temperature + GPU-lost, RigDoctor now notifies on
|
||||||
|
|||||||
@@ -78,6 +78,26 @@ also ships a one-file **`.run`** installer (download, `chmod +x`, run). Updates
|
|||||||
accounts on the Git server (a Personal Access Token); save one via the GUI **Setup → Update
|
accounts on the Git server (a Personal Access Token); save one via the GUI **Setup → Update
|
||||||
access** panel or `rigdoctor login`, then `rigdoctor update` (or the sidebar button).
|
access** panel or `rigdoctor login`, then `rigdoctor update` (or the sidebar button).
|
||||||
|
|
||||||
|
## Install (`.deb`, system-wide)
|
||||||
|
|
||||||
|
Each release also ships a **`.deb`** (`Architecture: all`, M9/D8). Download it from the release
|
||||||
|
and install with apt (pulls the GUI deps — PySide6/pyte — via Recommends):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install ./rigdoctor_<version>_all.deb # CLI-only: add --no-install-recommends
|
||||||
|
```
|
||||||
|
|
||||||
|
When the apt registry is enabled on the server, you can instead add it as a source and
|
||||||
|
`sudo apt update && sudo apt install rigdoctor` (with `apt upgrade` for updates):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://git.jesseyvanofferen.com/api/packages/jessey/debian/repository.key \
|
||||||
|
| sudo tee /etc/apt/keyrings/gitea-rigdoctor.asc > /dev/null
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-rigdoctor.asc] \
|
||||||
|
https://git.jesseyvanofferen.com/api/packages/jessey/debian stable main" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/rigdoctor.list
|
||||||
|
```
|
||||||
|
|
||||||
## Run it (dev)
|
## Run it (dev)
|
||||||
|
|
||||||
Stdlib-only, no install needed (target is Python ≥ 3.11; tested on 3.14):
|
Stdlib-only, no install needed (target is Python ≥ 3.11; tested on 3.14):
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ Status: ⬜ not started · 🟦 designing · 🟨 in progress · ✅ done
|
|||||||
| M6 | Gaming env checks | Diagnostics | none | all | P2 | 🟨 |
|
| M6 | Gaming env checks | Diagnostics | none | all | P2 | 🟨 |
|
||||||
| M10 | Desktop GUI | Desktop UI | **python3-pyside6** | all | P2 | ✅ |
|
| M10 | Desktop GUI | Desktop UI | **python3-pyside6** | all | P2 | ✅ |
|
||||||
| M11 | Tray / menu-bar applet | Desktop UI | **python3-pyside6** (+ AppIndicator on GNOME) | all | P2 | ✅ |
|
| M11 | Tray / menu-bar applet | Desktop UI | **python3-pyside6** (+ AppIndicator on GNOME) | all | P2 | ✅ |
|
||||||
| M9 | Installer | (meta) | none | all | P1 | 🟨 |
|
| M9 | Installer (+ `.deb`) | (meta) | none | all | P1 | ✅ |
|
||||||
| M12 | Session sharing (shared terminal) | Sharing | none (relay) | all | P3 | ✅ |
|
| M12 | Session sharing (shared terminal) | Sharing | none (relay) | all | P3 | ✅ |
|
||||||
| M13 | Auto-update | (core) | none (stdlib; user-local file swap) | all | P3 | ✅ |
|
| M13 | Auto-update | (core) | none (stdlib; user-local file swap) | all | P3 | ✅ |
|
||||||
| M14 | AI assistant (explain diagnostics) | (optional) | none (stdlib urllib; Ollama or Claude) | all | P3 | ✅ |
|
| M14 | AI assistant (explain diagnostics) | (optional) | none (stdlib urllib; Ollama or Claude) | all | P3 | ✅ |
|
||||||
|
|||||||
+6
-3
@@ -67,9 +67,12 @@ Ubuntu + NVIDIA first; `.deb` distribution (see `DECISIONS.md`).
|
|||||||
Settings "Recording trigger") incl. the zero-config **game-launch watcher**
|
Settings "Recording trigger") incl. the zero-config **game-launch watcher**
|
||||||
(`core/watcher.py`, `rigdoctor watch`); and a **graphical first-run setup wizard**
|
(`core/watcher.py`, `rigdoctor watch`); and a **graphical first-run setup wizard**
|
||||||
(`gui/setup_wizard.py`): environment → dependency-bundle selection → install → recording
|
(`gui/setup_wizard.py`): environment → dependency-bundle selection → install → recording
|
||||||
trigger → readiness, auto-launched by install.sh and re-runnable from Settings.
|
trigger → readiness, auto-launched by install.sh and re-runnable from Settings; and a
|
||||||
*Pending:* `.deb` packaging (next bullet).
|
**`.deb`** (`packaging/make_deb.py`, `Architecture: all`, `Depends: python3`,
|
||||||
- [ ] `.deb` packaging (D8) declaring per-bundle deps incl. python3-pyside6 for Desktop UI
|
`Recommends: python3-pyside6/pyte`) built + published in CI (release asset + optional
|
||||||
|
Gitea apt registry). **M9 complete.**
|
||||||
|
- [x] `.deb` packaging (D8) — built via `dpkg-deb` (no debhelper); GUI deps as Recommends so
|
||||||
|
`apt install rigdoctor` includes the Desktop UI, `--no-install-recommends` = CLI only.
|
||||||
|
|
||||||
## Phase 5 — Breadth (later)
|
## Phase 5 — Breadth (later)
|
||||||
- [ ] AMD GPU support in M1 (Steam Deck / Radeon)
|
- [ ] AMD GPU support in M1 (Steam Deck / Radeon)
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
"""Build a `.deb` for RigDoctor (M9 / D8) — dependency-light, no debhelper.
|
||||||
|
|
||||||
|
Pure-Python app, so it's `Architecture: all`: we stage the package into dist-packages, drop the
|
||||||
|
two launchers in /usr/bin, install the desktop entry + icon, write a DEBIAN/control, and call
|
||||||
|
`dpkg-deb`. The core is stdlib (`Depends: python3`); the GUI/tray deps are **Recommends**
|
||||||
|
(`python3-pyside6`, `python3-pyte`) so `apt install rigdoctor` gives the full app by default,
|
||||||
|
while `--no-install-recommends` yields a CLI-only install.
|
||||||
|
|
||||||
|
Run: `python packaging/make_deb.py` → `dist/rigdoctor_<version>_all.deb`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
DIST = ROOT / "dist"
|
||||||
|
MAINTAINER = "Jessey van Offeren <jjvanofferen@gmail.com>"
|
||||||
|
HOMEPAGE = "https://git.jesseyvanofferen.com/jessey/rigdoctor"
|
||||||
|
|
||||||
|
|
||||||
|
def _version() -> str:
|
||||||
|
text = (ROOT / "src" / "rigdoctor" / "__init__.py").read_text(encoding="utf-8")
|
||||||
|
for line in text.splitlines():
|
||||||
|
if line.startswith("__version__"):
|
||||||
|
return line.split('"')[1]
|
||||||
|
raise SystemExit("could not read __version__")
|
||||||
|
|
||||||
|
|
||||||
|
_LAUNCHER = """\
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import sys
|
||||||
|
from {module} import main
|
||||||
|
sys.exit(main())
|
||||||
|
"""
|
||||||
|
|
||||||
|
_DESKTOP = """\
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=RigDoctor
|
||||||
|
Comment=Hardware monitoring & crash diagnostics for Linux gamers
|
||||||
|
Exec=rigdoctor-gui
|
||||||
|
Icon=rigdoctor
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;Monitor;Utility;
|
||||||
|
StartupWMClass=rigdoctor
|
||||||
|
"""
|
||||||
|
|
||||||
|
_CONTROL = """\
|
||||||
|
Package: rigdoctor
|
||||||
|
Version: {version}
|
||||||
|
Architecture: all
|
||||||
|
Maintainer: {maintainer}
|
||||||
|
Section: utils
|
||||||
|
Priority: optional
|
||||||
|
Depends: python3 (>= 3.11)
|
||||||
|
Recommends: python3-pyside6, python3-pyte
|
||||||
|
Homepage: {homepage}
|
||||||
|
Description: Hardware monitoring & crash diagnostics for Linux gamers
|
||||||
|
RigDoctor monitors GPU/CPU temperatures, load, and sensors, captures crash
|
||||||
|
diagnostics while gaming, scans logs (Xid/SMART/kernel) for problems, and can
|
||||||
|
explain them in plain language. The CLI and background daemon are pure Python
|
||||||
|
(stdlib only); the optional desktop GUI and system-tray applet use PySide6,
|
||||||
|
pulled in via Recommends. Install with --no-install-recommends for CLI only.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _write(path: Path, text: str, mode: int = 0o644) -> None:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(text, encoding="utf-8")
|
||||||
|
path.chmod(mode)
|
||||||
|
|
||||||
|
|
||||||
|
def build() -> Path:
|
||||||
|
version = _version()
|
||||||
|
DIST.mkdir(exist_ok=True)
|
||||||
|
stage = DIST / f"rigdoctor_{version}_all"
|
||||||
|
if stage.exists():
|
||||||
|
shutil.rmtree(stage)
|
||||||
|
|
||||||
|
# Python package → dist-packages (importable system-wide), minus bytecode.
|
||||||
|
pkg_dst = stage / "usr/lib/python3/dist-packages/rigdoctor"
|
||||||
|
shutil.copytree(ROOT / "src" / "rigdoctor", pkg_dst,
|
||||||
|
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
||||||
|
|
||||||
|
# Launchers.
|
||||||
|
_write(stage / "usr/bin/rigdoctor", _LAUNCHER.format(module="rigdoctor.cli"), 0o755)
|
||||||
|
_write(stage / "usr/bin/rigdoctor-gui", _LAUNCHER.format(module="rigdoctor.gui.app"), 0o755)
|
||||||
|
|
||||||
|
# Desktop entry + icon.
|
||||||
|
_write(stage / "usr/share/applications/rigdoctor.desktop", _DESKTOP)
|
||||||
|
icon = ROOT / "src" / "rigdoctor" / "gui" / "assets" / "rigdoctor.svg"
|
||||||
|
_write(stage / "usr/share/icons/hicolor/scalable/apps/rigdoctor.svg",
|
||||||
|
icon.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
# Refresh the desktop database on install/remove (best-effort).
|
||||||
|
_write(stage / "DEBIAN/postinst",
|
||||||
|
"#!/bin/sh\nset -e\nupdate-desktop-database -q 2>/dev/null || true\n", 0o755)
|
||||||
|
_write(stage / "DEBIAN/postrm",
|
||||||
|
"#!/bin/sh\nset -e\nupdate-desktop-database -q 2>/dev/null || true\n", 0o755)
|
||||||
|
_write(stage / "DEBIAN/control",
|
||||||
|
_CONTROL.format(version=version, maintainer=MAINTAINER, homepage=HOMEPAGE))
|
||||||
|
|
||||||
|
out = DIST / f"rigdoctor_{version}_all.deb"
|
||||||
|
subprocess.run(["dpkg-deb", "--root-owner-group", "--build", str(stage), str(out)], check=True)
|
||||||
|
shutil.rmtree(stage)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
path = build()
|
||||||
|
print(f"built {path}")
|
||||||
|
sys.exit(0)
|
||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "rigdoctor"
|
name = "rigdoctor"
|
||||||
version = "0.34.0"
|
version = "0.35.0"
|
||||||
description = "Modular hardware monitoring & crash diagnostics for Linux gamers."
|
description = "Modular hardware monitoring & crash diagnostics for Linux gamers."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""RigDoctor — modular hardware monitoring & crash diagnostics for Linux gamers."""
|
"""RigDoctor — modular hardware monitoring & crash diagnostics for Linux gamers."""
|
||||||
|
|
||||||
__version__ = "0.34.0"
|
__version__ = "0.35.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user