feat: wire service subcommand group into CLI (install, uninstall, start, stop, restart, status, logs)

This commit is contained in:
Brian Krabach
2026-03-31 16:58:08 -07:00
parent 8637b740c0
commit ff2abb5f77
2 changed files with 133 additions and 0 deletions
+40
View File
@@ -707,6 +707,18 @@ def main() -> None:
"--system", action="store_true", help="System-wide (requires sudo)" "--system", action="store_true", help="System-wide (requires sudo)"
) )
service_parser = sub.add_parser(
"service", help="Manage the muxplex background service"
)
service_sub = service_parser.add_subparsers(dest="service_command")
service_sub.add_parser("install", help="Install + enable + start the service")
service_sub.add_parser("uninstall", help="Stop + disable + remove the service")
service_sub.add_parser("start", help="Start the service")
service_sub.add_parser("stop", help="Stop the service")
service_sub.add_parser("restart", help="Stop + start the service")
service_sub.add_parser("status", help="Show service status")
service_sub.add_parser("logs", help="Tail service logs")
sub.add_parser("show-password", help="Show the current muxplex password") sub.add_parser("show-password", help="Show the current muxplex password")
sub.add_parser( sub.add_parser(
@@ -743,6 +755,34 @@ def main() -> None:
doctor() doctor()
elif args.command in ("upgrade", "update"): elif args.command in ("upgrade", "update"):
upgrade(force=getattr(args, "force", False)) upgrade(force=getattr(args, "force", False))
elif args.command == "service":
from muxplex.service import ( # noqa: PLC0415
service_install,
service_logs,
service_restart,
service_start,
service_status,
service_stop,
service_uninstall,
)
cmd = getattr(args, "service_command", None)
if cmd == "install":
service_install()
elif cmd == "uninstall":
service_uninstall()
elif cmd == "start":
service_start()
elif cmd == "stop":
service_stop()
elif cmd == "restart":
service_restart()
elif cmd == "status":
service_status()
elif cmd == "logs":
service_logs()
else:
service_parser.print_help()
else: else:
_check_dependencies() _check_dependencies()
serve( serve(
+93
View File
@@ -1025,3 +1025,96 @@ def test_doctor_shows_serve_config(tmp_path, monkeypatch, capsys):
assert "0.0.0.0" in out assert "0.0.0.0" in out
assert "9999" in out assert "9999" in out
assert "password" in out assert "password" in out
# ---------------------------------------------------------------------------
# service subcommand dispatch tests
# ---------------------------------------------------------------------------
def test_service_install_dispatches():
"""muxplex service install must call service_install()."""
from muxplex.cli import main
with patch("muxplex.service.service_install") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "install"]):
main()
mock_fn.assert_called_once()
def test_service_uninstall_dispatches():
"""muxplex service uninstall must call service_uninstall()."""
from muxplex.cli import main
with patch("muxplex.service.service_uninstall") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "uninstall"]):
main()
mock_fn.assert_called_once()
def test_service_start_dispatches():
"""muxplex service start must call service_start()."""
from muxplex.cli import main
with patch("muxplex.service.service_start") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "start"]):
main()
mock_fn.assert_called_once()
def test_service_stop_dispatches():
"""muxplex service stop must call service_stop()."""
from muxplex.cli import main
with patch("muxplex.service.service_stop") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "stop"]):
main()
mock_fn.assert_called_once()
def test_service_restart_dispatches():
"""muxplex service restart must call service_restart()."""
from muxplex.cli import main
with patch("muxplex.service.service_restart") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "restart"]):
main()
mock_fn.assert_called_once()
def test_service_status_dispatches():
"""muxplex service status must call service_status()."""
from muxplex.cli import main
with patch("muxplex.service.service_status") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "status"]):
main()
mock_fn.assert_called_once()
def test_service_logs_dispatches():
"""muxplex service logs must call service_logs()."""
from muxplex.cli import main
with patch("muxplex.service.service_logs") as mock_fn:
with patch("sys.argv", ["muxplex", "service", "logs"]):
main()
mock_fn.assert_called_once()
def test_service_subcommand_in_help():
"""'service' must appear in muxplex --help output."""
import io
from muxplex.cli import main
buf = io.StringIO()
with patch("sys.argv", ["muxplex", "--help"]):
try:
with patch("sys.stdout", buf):
main()
except SystemExit:
pass
help_text = buf.getvalue().lower()
assert "service" in help_text