uv, npm ci, icon generation and the desktop build printed hundreds of lines on every interactive install, update and `hermes desktop`. pm/progress.py holds one policy. CI (CI / GITHUB_ACTIONS) or HERMES_VERBOSE=1 streams child output unchanged. Otherwise each child is one "→ label…" line, rewritten in place with its latest output on a terminal, or just the start and finish lines when piped. A failure always prints the last 80 lines. HERMES_VERBOSE=0 forces containment. Applied to PM's uv runs (no uv --verbose outside CI; quick steps stay silent unless they fail), the source build scripts (node-deps, TUI, icons, web; npm warn lines stay out of the live line), the desktop build and package steps, and the Windows ARM64 vcpkg/OpenSSL provider. The policy reads the parent's environment, so the CI=1 the builders force on their node children does not switch it to verbose.
34 lines
1.3 KiB
Python
34 lines
1.3 KiB
Python
"""Contained child output: CI keeps every line, interactive runs never hide a failure."""
|
|
|
|
import io
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from pm.progress import run_contained, verbose_output
|
|
|
|
|
|
def test_ci_streams_and_an_explicit_choice_overrides_it():
|
|
assert verbose_output({"CI": "true"}) and verbose_output({"GITHUB_ACTIONS": "true"})
|
|
assert not verbose_output({}) and not verbose_output({"CI": "0"})
|
|
assert not verbose_output({"CI": "1", "HERMES_VERBOSE": "0"})
|
|
assert verbose_output({"HERMES_VERBOSE": "1"})
|
|
|
|
|
|
@pytest.mark.parametrize("fails", [False, True])
|
|
def test_contained_run_shows_output_only_when_the_child_fails(monkeypatch, fails):
|
|
monkeypatch.setenv("HERMES_VERBOSE", "0")
|
|
stream = io.StringIO()
|
|
script = "import sys\nfor i in range(200): print('noise', i)\nprint('the real error')\nsys.exit(%d)" % fails
|
|
command = [sys.executable, "-c", script]
|
|
if fails:
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
run_contained(command, "Installing things", stream=stream)
|
|
else:
|
|
run_contained(command, "Installing things", stream=stream)
|
|
text = stream.getvalue()
|
|
assert "→ Installing things" in text
|
|
assert ("the real error" in text) is fails
|
|
assert "noise 0" not in text, "the failure tail stays bounded"
|