Skip to content

Commit 028a75f

Browse files
committed
adding --selected-rule
1 parent fde03ee commit 028a75f

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed

src/dbt_score/cli.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ def cli() -> None:
6666
default=None,
6767
multiple=True,
6868
)
69+
@click.option(
70+
"--selected-rule",
71+
help="Rule to select.",
72+
default=None,
73+
multiple=True,
74+
)
6975
@click.option(
7076
"--manifest",
7177
"-m",
@@ -121,6 +127,7 @@ def lint( # noqa: PLR0912, PLR0913, C901
121127
select: tuple[str],
122128
namespace: list[str],
123129
disabled_rule: list[str],
130+
selected_rule: list[str],
124131
manifest: Path,
125132
run_dbt_parse: bool,
126133
fail_project_under: float,
@@ -136,12 +143,19 @@ def lint( # noqa: PLR0912, PLR0913, C901
136143
if manifest_provided and run_dbt_parse:
137144
raise click.UsageError("--run-dbt-parse cannot be used with --manifest.")
138145

146+
if len(selected_rule) > 0 and len(disabled_rule) > 0:
147+
raise click.UsageError(
148+
"--disabled-rule and --selected-rule cannot be used together."
149+
)
150+
139151
config = Config()
140152
config.load()
141153
if namespace:
142154
config.overload({"rule_namespaces": namespace})
143155
if disabled_rule:
144156
config.overload({"disabled_rules": disabled_rule})
157+
if selected_rule:
158+
config.overload({"selected_rules": selected_rule})
145159
if fail_project_under:
146160
config.overload({"fail_project_under": fail_project_under})
147161
if fail_any_item_under:
@@ -194,6 +208,12 @@ def lint( # noqa: PLR0912, PLR0913, C901
194208
default=None,
195209
multiple=True,
196210
)
211+
@click.option(
212+
"--selected-rule",
213+
help="Rule to select.",
214+
default=None,
215+
multiple=True,
216+
)
197217
@click.option(
198218
"--title",
199219
help="Page title (Markdown only).",
@@ -207,14 +227,25 @@ def lint( # noqa: PLR0912, PLR0913, C901
207227
default="terminal",
208228
)
209229
def list_command(
210-
namespace: list[str], disabled_rule: list[str], title: str, format: str
230+
namespace: list[str],
231+
disabled_rule: list[str],
232+
selected_rule: list[str],
233+
title: str,
234+
format: str,
211235
) -> None:
212236
"""Display rules list."""
237+
if len(selected_rule) > 0 and len(disabled_rule) > 0:
238+
raise click.UsageError(
239+
"--disabled-rule and --selected-rule cannot be used together."
240+
)
241+
213242
config = Config()
214243
config.load()
215244
if namespace:
216245
config.overload({"rule_namespaces": namespace})
217246
if disabled_rule:
218247
config.overload({"disabled_rules": disabled_rule})
248+
if selected_rule:
249+
config.overload({"selected_rules": selected_rule})
219250

220251
display_catalog(config, title, format)

src/dbt_score/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class Config:
5454
_options: Final[list[str]] = [
5555
"rule_namespaces",
5656
"disabled_rules",
57+
"selected_rules",
5758
"inject_cwd_in_python_path",
5859
"fail_project_under",
5960
"fail_any_item_under",
@@ -67,6 +68,7 @@ def __init__(self) -> None:
6768
"""Initialize the Config object."""
6869
self.rule_namespaces: list[str] = ["dbt_score.rules", "dbt_score_rules"]
6970
self.disabled_rules: list[str] = []
71+
self.selected_rules: list[str] = []
7072
self.inject_cwd_in_python_path = True
7173
self.rules_config: dict[str, RuleConfig] = {}
7274
self.config_file: Path | None = None

src/dbt_score/rule_registry.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ def _add_rule(self, rule: Type[Rule]) -> None:
7979
rule_name = rule.source()
8080
if rule_name in self._rules:
8181
raise DuplicatedRuleException(rule_name)
82-
if rule_name not in self.config.disabled_rules:
82+
if (
83+
len(self.config.selected_rules) > 0
84+
and rule_name in self.config.selected_rules
85+
) or (
86+
len(self.config.selected_rules) == 0
87+
and rule_name not in self.config.disabled_rules
88+
):
8389
rule_config = self.config.rules_config.get(rule_name, RuleConfig())
8490
self._rules[rule_name] = rule(rule_config=rule_config)
8591

tests/test_cli.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ def test_invalid_options():
1818
assert result.exit_code == 2 # pylint: disable=PLR2004
1919

2020

21+
def test_selected_and_disabled_rule_options_mutually_exclusive():
22+
"""Test selected and disabled rule options are mutually exclusive."""
23+
runner = CliRunner()
24+
with patch("dbt_score.cli.Config._load_toml_file"):
25+
result = runner.invoke(
26+
lint,
27+
[
28+
"--manifest",
29+
"fake_manifest.json",
30+
"--selected-rule",
31+
"foo",
32+
"--disabled-rule",
33+
"bar",
34+
],
35+
)
36+
assert result.exit_code == 2 # pylint: disable=PLR2004
37+
38+
2139
def test_lint_existing_manifest(manifest_path):
2240
"""Test lint with an existing manifest."""
2341
runner = CliRunner()

tests/test_rule_registry.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,33 @@ def test_disabled_rule_registry_discovery():
3232
]
3333

3434

35+
def test_selected_rule_registry_discovery():
36+
"""Ensure only selected rules are discovered."""
37+
config = Config()
38+
config.selected_rules = ["tests.rules.nested.example.rule_test_nested_example"]
39+
r = RuleRegistry(config)
40+
r._load("tests.rules")
41+
assert sorted(r._rules.keys()) == [
42+
"tests.rules.nested.example.rule_test_nested_example"
43+
]
44+
45+
46+
def test_selected_and_disabled_rule_registry_discovery():
47+
"""Ensure selected rules are run even if otherwise disabled.
48+
49+
This is prevented by the CLI, but want to confirm selected rules
50+
are run even if disabled via pyproject.toml.
51+
"""
52+
config = Config()
53+
config.selected_rules = ["tests.rules.nested.example.rule_test_nested_example"]
54+
config.disabled_rules = ["tests.rules.nested.example.rule_test_nested_example"]
55+
r = RuleRegistry(config)
56+
r._load("tests.rules")
57+
assert sorted(r._rules.keys()) == [
58+
"tests.rules.nested.example.rule_test_nested_example"
59+
]
60+
61+
3562
def test_configured_rule_registry_discovery(valid_config_path):
3663
"""Ensure rules are discovered and configured correctly."""
3764
config = Config()

0 commit comments

Comments
 (0)