feat(vmgui): GUI launcher command, VMX optional

Add top-level `vmgui` to open the VMware Workstation GUI (renamed from the
earlier `vm open`). --vmx is optional: with it the GUI opens that VM, without
it the GUI starts bare. Power-on/fullscreen flags ignored (with a notice) when
no VMX is given. Needs an X display — sudo -u ci-runner strips $DISPLAY, so
--display / xhost; see runbook §4.7. 9 tests; suite green ≥90%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 00:15:22 +02:00
parent 461eb3f8de
commit 0e963f2194
4 changed files with 68 additions and 34 deletions
+28 -8
View File
@@ -499,7 +499,7 @@ def test_vm_cleanup_backend_unavailable(monkeypatch: pytest.MonkeyPatch, tmp_pat
assert "vmrun not available" in result.output
# ── vm open ───────────────────────────────────────────────────────────────────
# ── vmgui ───────────────────────────────────────────────────────────────────
def _capture_launch(monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]:
@@ -516,7 +516,7 @@ def _capture_launch(monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]:
def test_vm_open_missing_vmx_errors(tmp_path: Path) -> None:
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(tmp_path / "nope.vmx")])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(tmp_path / "nope.vmx")])
assert result.exit_code != 0
assert "VMX file not found" in result.output
@@ -526,7 +526,7 @@ def test_vm_open_happy_path(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) ->
vmx.write_text("config")
cap = _capture_launch(monkeypatch)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(vmx)])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
assert result.exit_code == 0, result.output
assert cap["argv"][-1] == str(vmx)
assert "-x" not in cap["argv"] and "-X" not in cap["argv"]
@@ -538,7 +538,7 @@ def test_vm_open_power_on_adds_x(monkeypatch: pytest.MonkeyPatch, tmp_path: Path
vmx.write_text("config")
cap = _capture_launch(monkeypatch)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(vmx), "--power-on"])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx), "--power-on"])
assert result.exit_code == 0, result.output
assert "-x" in cap["argv"]
@@ -549,7 +549,7 @@ def test_vm_open_fullscreen_adds_capital_x(monkeypatch: pytest.MonkeyPatch, tmp_
cap = _capture_launch(monkeypatch)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(
cli, ["vm", "open", "--vmx", str(vmx), "--fullscreen", "--new-window"]
cli, ["vmgui", "--vmx", str(vmx), "--fullscreen", "--new-window"]
)
assert result.exit_code == 0, result.output
assert "-X" in cap["argv"] and "-n" in cap["argv"]
@@ -560,7 +560,7 @@ def test_vm_open_display_option_overrides_env(monkeypatch: pytest.MonkeyPatch, t
vmx.write_text("config")
cap = _capture_launch(monkeypatch)
monkeypatch.delenv("DISPLAY", raising=False)
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(vmx), "--display", ":1"])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx), "--display", ":1"])
assert result.exit_code == 0, result.output
assert cap["env"]["DISPLAY"] == ":1"
assert "display=:1" in result.output
@@ -571,7 +571,7 @@ def test_vm_open_warns_without_display(monkeypatch: pytest.MonkeyPatch, tmp_path
vmx.write_text("config")
_capture_launch(monkeypatch)
monkeypatch.delenv("DISPLAY", raising=False)
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(vmx)])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
assert result.exit_code == 0, result.output
assert "no X display" in result.output
@@ -585,6 +585,26 @@ def test_vm_open_launch_failure_is_reported(monkeypatch: pytest.MonkeyPatch, tmp
monkeypatch.setattr(vm_module, "_launch_gui", _boom)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(cli, ["vm", "open", "--vmx", str(vmx)])
result = CliRunner().invoke(cli, ["vmgui", "--vmx", str(vmx)])
assert result.exit_code != 0
assert "failed to launch VMware GUI" in result.output
def test_vm_open_without_vmx_launches_bare_gui(monkeypatch: pytest.MonkeyPatch) -> None:
cap = _capture_launch(monkeypatch)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(cli, ["vmgui"])
assert result.exit_code == 0, result.output
# Only the binary (no vmx path, no power-on flags).
assert cap["argv"][1:] == [] or cap["argv"][1:] == ["-n"]
assert "-x" not in cap["argv"] and "-X" not in cap["argv"]
assert "pid 4242" in result.output
def test_vm_open_power_on_ignored_without_vmx(monkeypatch: pytest.MonkeyPatch) -> None:
cap = _capture_launch(monkeypatch)
monkeypatch.setenv("DISPLAY", ":0")
result = CliRunner().invoke(cli, ["vmgui", "--power-on"])
assert result.exit_code == 0, result.output
assert "-x" not in cap["argv"]
assert "ignored without --vmx" in result.output