fix(context): count errors in the validate warning summary (#2781)

This commit is contained in:
Mohammad Hijjawi
2026-10-08 10:01:25 +08:00
committed by GitHub
parent eab640c67c
commit fedf182b4b
3 changed files with 49 additions and 4 deletions
+6 -4
View File
@@ -543,7 +543,9 @@ def validate(
typer.echo(f" \u2717 {msg}", err=True)
all_warnings: list[str] = [str(w) for w in struct_warnings] + list(sem_warnings)
_print_warnings(all_warnings, verbose=verbose)
_print_warnings(
all_warnings, verbose=verbose, errors=len(struct_hard) + len(sem_errors)
)
# ── Exit logic ──────────────────────────────────────────────────────────────────
has_hard_error = bool(struct_hard or sem_errors)
@@ -576,7 +578,7 @@ def validate(
)
def _print_warnings(warnings: list[str], *, verbose: bool) -> None:
def _print_warnings(warnings: list[str], *, verbose: bool, errors: int = 0) -> None:
"""Render warnings: every line below the threshold, grouped summary above.
Agents and humans both read the first "Warnings:" line as a signal
@@ -593,7 +595,7 @@ def _print_warnings(warnings: list[str], *, verbose: bool) -> None:
typer.echo("\nWarnings:")
for msg in warnings:
typer.echo(f" \u26a0 {msg}")
typer.echo(f"\n{total} warning(s), 0 errors.")
typer.echo(f"\n{total} warning(s), {errors} error(s).")
return
# Bucket by warning *category* — the text after the last colon
@@ -1165,7 +1167,7 @@ def _validate_from_osi(
for e in hard:
typer.echo(f" ✗ {e}", err=True)
_print_warnings(warns, verbose=verbose)
_print_warnings(warns, verbose=verbose, errors=len(hard))
if hard or (strict and warns):
raise typer.Exit(1)
+13
View File
@@ -506,6 +506,19 @@ def test_validate_strict_warns(tmp_path):
assert result.exit_code == 1
def test_validate_summary_counts_errors(tmp_path):
_make_valid_project(tmp_path)
project_file = tmp_path / "wren_project.yml"
project_file.write_text(project_file.read_text().replace("name: test_proj\n", ""))
model_meta = tmp_path / "models" / "orders" / "metadata.yml"
model_meta.write_text(model_meta.read_text() + "dialect: postgres\n")
result = runner.invoke(app, ["context", "validate", "--path", str(tmp_path)])
assert result.exit_code == 1
assert "missing required field 'name'" in result.output
assert "1 warning(s), 1 error(s)." in result.output
def _write_null_models_relationship(tmp_path: Path) -> None:
# A relationship whose `models:` is an explicit YAML null. `.get("models", [])`
# returns None (not the default) for a present-but-null key, so iterating /
+30
View File
@@ -713,6 +713,36 @@ def test_cli_validate_from_osi_surfaces_warnings():
assert "column_types" in result.output # snippet emitted
def test_cli_validate_from_osi_summary_counts_errors(tmp_path: Path):
osi_file = tmp_path / "osi.yaml"
osi_file.write_text(
'version: "0.2.0"\n'
"semantic_model:\n"
" - name: shop\n"
" datasets:\n"
" - name: orders\n"
" source: shop.public.orders\n"
" fields:\n"
" - name: order_id\n"
" expression: order_id\n"
" - source: shop.public.customers\n"
)
result = runner.invoke(
app,
[
"context",
"validate",
"--from-osi",
str(osi_file),
"--data-source",
"postgres",
],
)
assert result.exit_code == 1
assert "dataset missing 'name'" in result.output
assert "1 warning(s), 1 error(s)." in result.output
def test_cli_validate_from_osi_strict_fails_on_warning():
result = runner.invoke(
app,