refactor(installer): extract run_command helper to cut cognitive complexity

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-10-04 19:28:37 +02:00
parent 8f226dce99
commit aa92ed30b3
3 changed files with 48 additions and 11 deletions

View File

@ -10,6 +10,7 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
- **`npm run qa`**: central QA command (`scripts/qa.mjs`) with timed stages (lint, python/node unit tests, Playwright, security scans, bundle freshness) and an opt-in SonarQube stage (`--sonar`, token from the environment only). See `architecture/qa.md`.
### Changed
- `guided_installer.py`: command execution extracted into a testable `run_command` helper (lowers cognitive complexity, python:S3776); no behaviour change.
- **Voice list rows no longer show the "Source unknown" badge** (it crowded the play buttons). The badge stays in the voice inspector, next to the Source & consent panel.
### Fixed

View File

@ -46,6 +46,21 @@ MODEL_EXPLANATIONS = {
}
def run_command(cmd: list[str], log) -> bool:
"""Run one command, log its output; return False if it failed (non-zero exit or exception)."""
try:
proc = subprocess.run(cmd, cwd=ROOT, text=True, capture_output=True)
except Exception as exc:
log(f"Failed: {exc}")
return False
for out in (proc.stdout, proc.stderr):
if out:
log(out)
if proc.returncode:
log(f"Command exited with {proc.returncode}")
return not proc.returncode
class GuidedInstaller(tk.Tk):
def __init__(self) -> None:
super().__init__()
@ -192,17 +207,7 @@ class GuidedInstaller(tk.Tk):
self.log_line(f"\n== {title} ==")
for cmd in commands:
self.log_line("$ " + " ".join(cmd))
try:
proc = subprocess.run(cmd, cwd=ROOT, text=True, capture_output=True)
if proc.stdout:
self.log_line(proc.stdout)
if proc.stderr:
self.log_line(proc.stderr)
if proc.returncode:
self.log_line(f"Command exited with {proc.returncode}")
break
except Exception as exc:
self.log_line(f"Failed: {exc}")
if not run_command(cmd, self.log_line):
break
if cleanup_dir:
shutil.rmtree(cleanup_dir, ignore_errors=True)

View File

@ -0,0 +1,31 @@
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
try:
from guided_installer import run_command
except ImportError: # no tkinter on this host
run_command = None
@unittest.skipIf(run_command is None, "tkinter unavailable")
class RunCommandTest(unittest.TestCase):
def test_success_logs_output(self):
out = []
self.assertTrue(run_command([sys.executable, "-c", "print('hi')"], out.append))
self.assertIn("hi", "".join(out))
def test_nonzero_exit(self):
out = []
self.assertFalse(run_command([sys.executable, "-c", "raise SystemExit(3)"], out.append))
self.assertIn("exited with 3", out[-1])
def test_missing_binary(self):
out = []
self.assertFalse(run_command(["/nonexistent-binary-xyz"], out.append))
self.assertTrue(out[0].startswith("Failed:"))
if __name__ == "__main__":
unittest.main()