feat(build): optional xvfb-run for Linux GUI builds
Add an --xvfb switch to 'build run' and 'job' that wraps the Linux build command in 'xvfb-run -a sh -c ...', giving GUI toolkits (GTK4/PyGObject) a headless $DISPLAY. Exported env vars precede xvfb-run so they propagate into the virtual-display session. No-op (with a notice) for Windows guests. The local-ci-build composite action exposes it as the 'xvfb' input (default false), forwarded as INPUT_XVFB -> --xvfb, mirroring the use-shared-cache/skip-artifact wiring. Docs: WORKFLOW-AUTHORING.md parameter table + Linux example note; LINUX-TEMPLATE-SETUP.md Step 4a (the template ships python3-gi gir1.2-gtk-4.0 xvfb). Adds build-run unit tests (wrap, plain, Windows no-op). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -212,6 +212,83 @@ def test_build_run_linux_clone_url_happy_path(
|
||||
assert any("/work/build" in c for c in cmds)
|
||||
|
||||
|
||||
def test_build_run_linux_xvfb_wraps_command(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
"""--xvfb wraps the Linux build in xvfb-run; env exports stay outside."""
|
||||
_patch(monkeypatch)
|
||||
result = CliRunner().invoke(
|
||||
cli,
|
||||
[
|
||||
"build", "run",
|
||||
"--ip-address", "10.0.0.5",
|
||||
"--guest-os", "linux",
|
||||
"--clone-url", "https://example/repo.git",
|
||||
"--build-command", "make all",
|
||||
"--guest-linux-work-dir", "/work",
|
||||
"--extra-env", "FOO=bar",
|
||||
"--xvfb",
|
||||
"--ssh-key-path", str(tmp_path / "key"),
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
cmds = [c[0] for c in _FakeTransport.instances[0].runs]
|
||||
# Build wrapped under xvfb-run via sh -c; env export precedes it.
|
||||
assert any(
|
||||
"xvfb-run -a sh -c 'cd /work && make all'" in c
|
||||
and "export FOO=bar" in c
|
||||
for c in cmds
|
||||
)
|
||||
|
||||
|
||||
def test_build_run_linux_no_xvfb_runs_plain(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
"""Without --xvfb the build runs directly (no xvfb-run wrapper)."""
|
||||
_patch(monkeypatch)
|
||||
result = CliRunner().invoke(
|
||||
cli,
|
||||
[
|
||||
"build", "run",
|
||||
"--ip-address", "10.0.0.5",
|
||||
"--guest-os", "linux",
|
||||
"--clone-url", "https://example/repo.git",
|
||||
"--build-command", "make all",
|
||||
"--guest-linux-work-dir", "/work",
|
||||
"--ssh-key-path", str(tmp_path / "key"),
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
cmds = [c[0] for c in _FakeTransport.instances[0].runs]
|
||||
assert any("cd /work && make all" in c for c in cmds)
|
||||
assert not any("xvfb-run" in c for c in cmds)
|
||||
|
||||
|
||||
def test_build_run_xvfb_ignored_on_windows(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
"""--xvfb is a no-op (with a notice) for Windows guests."""
|
||||
_patch(monkeypatch)
|
||||
src = tmp_path / "src"
|
||||
src.mkdir()
|
||||
(src / "f.txt").write_text("x")
|
||||
result = CliRunner().invoke(
|
||||
cli,
|
||||
[
|
||||
"build", "run",
|
||||
"--ip-address", "10.0.0.9",
|
||||
"--guest-os", "windows",
|
||||
"--host-source-dir", str(src),
|
||||
"--build-command", "echo hi",
|
||||
"--xvfb",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "--xvfb ignored for Windows guest" in result.output
|
||||
cmds = [c[0] for c in _FakeTransport.instances[0].runs]
|
||||
assert not any("xvfb-run" in c for c in cmds)
|
||||
|
||||
|
||||
def test_build_run_linux_host_source_dir(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user