Skip to content

Commit 3a0ef0d

Browse files
jmjavacursoragent
andauthored
Fail closed when default validate reports FAIL. (#153)
Plain `docgen validate` printed FAIL then exited 0, so callers could treat a broken bundle as success. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent d78a755 commit 3a0ef0d

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

‎src/docgen/cli.py‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,14 @@ def validate(ctx: click.Context, max_drift: float | None, pre_push: bool) -> Non
535535
v = Validator(cfg)
536536
if pre_push:
537537
v.run_pre_push()
538-
else:
539-
report = v.run_all(max_drift_override=max_drift)
540-
v.print_report(report)
538+
return
539+
report = v.run_all(max_drift_override=max_drift)
540+
v.print_report(report)
541+
if any(
542+
isinstance(r, dict) and not r.get("passed", True)
543+
for r in report
544+
):
545+
raise SystemExit(1)
541546

542547

543548
@main.command()

‎tests/test_cli_env.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,42 @@ def test_cli_validate_pre_push_missing_recording_is_soft(tmp_path: Path) -> None
288288
assert "Traceback" not in combined
289289

290290

291+
def test_cli_validate_default_fail_exits_1(tmp_path: Path) -> None:
292+
"""Click-invoke default validate (no --pre-push) must exit 1 on FAIL."""
293+
from click.testing import CliRunner
294+
295+
from docgen.cli import main
296+
297+
raw = {
298+
"dirs": {
299+
"narration": "narration",
300+
"audio": "audio",
301+
"animations": "animations",
302+
"recordings": "recordings",
303+
},
304+
"segments": {"default": ["01"], "all": ["01"]},
305+
"segment_names": {"01": "01-intro"},
306+
"visual_map": {"01": {"type": "still", "source": "01.mp4"}},
307+
}
308+
yaml_path = tmp_path / "docgen.yaml"
309+
yaml_path.write_text(yaml.dump(raw), encoding="utf-8")
310+
(tmp_path / "narration").mkdir()
311+
(tmp_path / "narration" / "01-intro.md").write_text(
312+
"This segment is a short still-image intro.\n",
313+
encoding="utf-8",
314+
)
315+
for name in ("audio", "animations", "recordings"):
316+
(tmp_path / name).mkdir()
317+
318+
result = CliRunner().invoke(main, ["--config", str(yaml_path), "validate"])
319+
combined = result.output + result.stderr
320+
assert result.exit_code == 1, combined
321+
assert "FAIL" in combined
322+
assert "recording_exists" in combined
323+
assert "AttributeError" not in combined
324+
assert "Traceback" not in combined
325+
326+
291327
def test_cli_lint_empty_segments_is_click_error(tmp_path: Path) -> None:
292328
from click.testing import CliRunner
293329

0 commit comments

Comments
 (0)