Skip to content

Commit a207b94

Browse files
refactor: [SNOW-1890085] reimplement dbt execute as pass-through command group
1 parent cf2ead1 commit a207b94

File tree

3 files changed

+97
-34
lines changed

3 files changed

+97
-34
lines changed

src/snowflake/cli/_plugins/dbt/commands.py

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
from __future__ import annotations
1616

1717
import logging
18+
from typing import Annotated
1819

1920
import typer
21+
from snowflake.cli._plugins.dbt.constants import DBT_COMMANDS
2022
from snowflake.cli._plugins.dbt.manager import DBTManager
23+
from snowflake.cli.api.commands.decorators import global_options_with_connection
2124
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
2225
from snowflake.cli.api.output.types import CommandResult, QueryResult
2326

@@ -37,31 +40,47 @@ def list_dbts(
3740
**options,
3841
) -> CommandResult:
3942
"""
40-
List all dbt projects on Snowflake.
43+
List all dbt on Snowflake projects.
4144
"""
4245
return QueryResult(DBTManager().list())
4346

4447

45-
@app.command(
46-
"execute",
47-
requires_connection=True,
48-
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
48+
# `execute` is a pass through command group, meaning that all params after command should be passed over as they are,
49+
# suppressing usual CLI behaviour for displaying help or formatting options.
50+
dbt_execute_app = SnowTyperFactory(
51+
name="execute",
52+
help="Execute a dbt command",
4953
)
50-
def execute(
51-
ctx: typer.Context,
52-
dbt_command: str = typer.Argument(
53-
help="dbt command to execute, i. e. run, compile, seed...",
54-
),
55-
name: str = typer.Option(
56-
default=...,
57-
help="Name of the dbt object to execute command on.",
58-
),
54+
app.add_typer(dbt_execute_app)
55+
56+
57+
@dbt_execute_app.callback()
58+
@global_options_with_connection
59+
def before_callback(
60+
name: Annotated[
61+
str, typer.Argument(help="Name of the dbt object to execute command on.")
62+
],
5963
**options,
60-
) -> CommandResult:
61-
"""
62-
Execute command on dbt in Snowflake project.
63-
"""
64-
# ctx.args are parameters that were not captured as known cli params (those are in **options).
65-
# as a consequence, we don't support passing params known to snowflake cli further to dbt
66-
dbt_cli_args = ctx.args
67-
return QueryResult(DBTManager().execute(dbt_command, name, *dbt_cli_args))
64+
):
65+
"""Handles global options passed before the command and takes pipeline name to be accessed through child context later"""
66+
pass
67+
68+
69+
for cmd in DBT_COMMANDS:
70+
71+
@dbt_execute_app.command(
72+
name=cmd,
73+
requires_connection=False,
74+
requires_global_options=False,
75+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
76+
help=f"Execute {cmd} command on dbt on Snowflake project.",
77+
add_help_option=False,
78+
)
79+
def _dbt_execute(
80+
ctx: typer.Context,
81+
) -> CommandResult:
82+
# TODO: figure out how to present logs to users
83+
dbt_cli_args = ctx.args
84+
dbt_command = ctx.command.name
85+
name = ctx.parent.params["name"]
86+
return QueryResult(DBTManager().execute(dbt_command, name, *dbt_cli_args))
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
DBT_COMMANDS = [
2+
"build",
3+
"clean",
4+
"clone",
5+
"compile",
6+
"debug",
7+
"deps",
8+
"docs",
9+
"init",
10+
"list",
11+
"parse",
12+
"retry",
13+
"run",
14+
"run",
15+
"seed",
16+
"show",
17+
"snapshot",
18+
"source",
19+
"test",
20+
]

tests/dbt/test_dbt_commands.py

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,59 @@ def test_dbt_list(mock_connect, runner):
3737
@pytest.mark.parametrize(
3838
"args,expected_query",
3939
[
40-
(
41-
["dbt", "execute", "compile", "--name=pipeline_name"],
42-
"EXECUTE DBT pipeline_name compile",
40+
pytest.param(
41+
[
42+
"dbt",
43+
"execute",
44+
"pipeline_name",
45+
"test",
46+
],
47+
"EXECUTE DBT pipeline_name test",
48+
id="simple-command",
4349
),
44-
(
50+
pytest.param(
4551
[
4652
"dbt",
4753
"execute",
48-
"compile",
49-
"--name=pipeline_name",
54+
"pipeline_name",
55+
"run",
5056
"-f",
5157
"--select @source:snowplow,tag:nightly models/export",
5258
],
53-
"EXECUTE DBT pipeline_name compile -f --select @source:snowplow,tag:nightly models/export",
59+
"EXECUTE DBT pipeline_name run -f --select @source:snowplow,tag:nightly models/export",
60+
id="with-dbt-options",
5461
),
55-
(
56-
["dbt", "execute", "compile", "--name=pipeline_name", "--vars '{foo:bar}'"],
62+
pytest.param(
63+
["dbt", "execute", "pipeline_name", "compile", "--vars '{foo:bar}'"],
5764
"EXECUTE DBT pipeline_name compile --vars '{foo:bar}'",
65+
id="with-dbt-vars",
5866
),
59-
(
67+
pytest.param(
6068
[
6169
"dbt",
6270
"execute",
71+
"pipeline_name",
6372
"compile",
64-
"--name=pipeline_name",
65-
"--format=JSON",
73+
"--format=TXT", # collision with CLI's option; unsupported option
74+
"-v", # collision with CLI's option
75+
"-h",
6676
"--debug",
77+
"--info",
78+
"--config-file=/",
79+
],
80+
"EXECUTE DBT pipeline_name compile --format=TXT -v -h --debug --info --config-file=/",
81+
id="with-dbt-conflicting-options",
82+
),
83+
pytest.param(
84+
[
85+
"dbt",
86+
"execute",
87+
"--format=JSON",
88+
"pipeline_name",
89+
"compile",
6790
],
6891
"EXECUTE DBT pipeline_name compile",
92+
id="with-cli-flag",
6993
),
7094
],
7195
)

0 commit comments

Comments
 (0)