Skip to content

Commit d69ba5c

Browse files
Fix(dbt_cli): Add global error handling group for dbt subcommands
1 parent a7feeb7 commit d69ba5c

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

sqlmesh_dbt/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33
import click
44
from sqlmesh_dbt.operations import DbtOperations, create
5-
from sqlmesh_dbt.error import cli_global_error_handler
5+
from sqlmesh_dbt.error import cli_global_error_handler, ErrorHandlingGroup
66
from pathlib import Path
77
from sqlmesh_dbt.options import YamlParamType
88
import functools
@@ -43,7 +43,7 @@ def _cleanup() -> None:
4343
exclude_option = click.option("--exclude", multiple=True, help="Specify the nodes to exclude.")
4444

4545

46-
@click.group(invoke_without_command=True)
46+
@click.group(cls=ErrorHandlingGroup, invoke_without_command=True)
4747
@click.option("--profile", help="Which existing profile to load. Overrides output.profile")
4848
@click.option("-t", "--target", help="Which target to load for the given profile")
4949
@click.option(

sqlmesh_dbt/error.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,10 @@ def wrapper(*args: t.List[t.Any], **kwargs: t.Any) -> t.Any:
2727
raise
2828

2929
return wrapper
30+
31+
32+
class ErrorHandlingGroup(click.Group):
33+
def add_command(self, cmd: click.Command, name: str | None = None) -> None:
34+
if cmd.callback:
35+
cmd.callback = cli_global_error_handler(cmd.callback)
36+
super().add_command(cmd, name=name)

tests/dbt/cli/test_global_flags.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from pathlib import Path
33
import pytest
44
from click.testing import Result
5+
from unittest.mock import patch
6+
from sqlmesh.utils.errors import SQLMeshError
7+
from sqlglot.errors import SqlglotError
58

69
pytestmark = pytest.mark.slow
710

@@ -28,3 +31,61 @@ def test_profile_and_target(jaffle_shop_duckdb: Path, invoke_cli: t.Callable[...
2831
result = invoke_cli(["--profile", "jaffle_shop", "--target", "dev"])
2932
assert result.exit_code == 0
3033
assert "No command specified" in result.output
34+
35+
36+
def test_run_error_handler(jaffle_shop_duckdb: Path, invoke_cli: t.Callable[..., Result]):
37+
with patch("sqlmesh_dbt.operations.DbtOperations.run") as mock_run:
38+
mock_run.side_effect = SQLMeshError("Test error message")
39+
40+
result = invoke_cli(["run"])
41+
42+
# tesg that SQLMeshError are handled gracefully in run command
43+
assert result.exit_code == 1
44+
assert "Traceback" not in result.output
45+
46+
with patch("sqlmesh_dbt.operations.DbtOperations.run") as mock_run:
47+
mock_run.side_effect = SqlglotError("Invalid SQL syntax")
48+
49+
result = invoke_cli(["run"])
50+
51+
assert result.exit_code == 1
52+
assert "Error: Invalid SQL syntax" in result.output
53+
assert "Traceback" not in result.output
54+
55+
with patch("sqlmesh_dbt.operations.DbtOperations.run") as mock_run:
56+
mock_run.side_effect = ValueError("Invalid configuration value")
57+
58+
result = invoke_cli(["run"])
59+
60+
assert result.exit_code == 1
61+
assert "Error: Invalid configuration value" in result.output
62+
assert "Traceback" not in result.output
63+
64+
with patch("sqlmesh_dbt.operations.DbtOperations.list_") as mock_list:
65+
mock_list.side_effect = SQLMeshError("List command error")
66+
67+
result = invoke_cli(["list"])
68+
69+
assert result.exit_code == 1
70+
assert "Error: List command error" in result.output
71+
assert "Traceback" not in result.output
72+
73+
with patch("sqlmesh_dbt.cli.create") as mock_create:
74+
mock_create.side_effect = SQLMeshError("Failed to load project")
75+
76+
# use without subcommand
77+
result = invoke_cli(["--profile", "jaffle_shop"])
78+
79+
assert result.exit_code == 1
80+
assert "Error: Failed to load project" in result.output
81+
assert "Traceback" not in result.output
82+
83+
with patch("sqlmesh_dbt.operations.DbtOperations.run") as mock_run:
84+
mock_run.side_effect = SQLMeshError("Error with selector")
85+
86+
# with select option
87+
result = invoke_cli(["run", "--select", "model1"])
88+
89+
assert result.exit_code == 1
90+
assert "Error: Error with selector" in result.output
91+
assert "Traceback" not in result.output

0 commit comments

Comments
 (0)