@cli.command()
@click.option(
"--format",
"-f",
help="Output format. Plain is suitable for terminals, manifest for rich "
"documentation, json for machine-readable output.",
type=click.Choice(["plain", "manifest", "ascii", "json"]),
default="plain",
)
@click.option(
"--select",
"-s",
help="Specify the nodes to include.",
multiple=True,
)
@click.option(
"--namespace",
"-n",
help="Namespace to look for rules.",
default=None,
multiple=True,
)
@click.option(
"--disabled-rule",
help="Rule to disable.",
default=None,
multiple=True,
)
@click.option(
"--manifest",
"-m",
help="Manifest filepath.",
type=click.Path(path_type=Path),
default=get_default_manifest_path(),
)
@click.option(
"--run-dbt-parse",
"-p",
help="Run dbt parse.",
is_flag=True,
default=False,
)
@click.option(
"--fail-project-under",
help="Fail if the project score is under this value.",
type=float,
is_flag=False,
default=None,
)
@click.option(
"--fail-any-item-under",
help="Fail if any evaluable item is under this value.",
type=float,
is_flag=False,
default=None,
)
@click.option(
"--show",
help="Type of output which should be shown "
"when using `plain` as `--format`. "
"`all` shows all items and all rules. "
"`failing-items` shows failing rules of failing items. "
"`failing-rules` shows failing rules of all items. "
"Default is --failing-rules.",
type=click.Choice(["all", "failing-items", "failing-rules"]),
is_flag=False,
default="failing-rules",
)
@click.pass_context
def lint( # noqa: PLR0913, C901
ctx: click.Context,
format: Literal["plain", "manifest", "ascii"],
select: tuple[str],
namespace: list[str],
disabled_rule: list[str],
manifest: Path,
run_dbt_parse: bool,
fail_project_under: float,
fail_any_item_under: float,
show: Literal["all", "failing-items", "failing-rules"],
) -> None:
"""Lint dbt metadata."""
manifest_provided = (
click.get_current_context().get_parameter_source("manifest")
!= ParameterSource.DEFAULT
)
if manifest_provided and run_dbt_parse:
raise click.UsageError("--run-dbt-parse cannot be used with --manifest.")
config = Config()
config.load()
if namespace:
config.overload({"rule_namespaces": namespace})
if disabled_rule:
config.overload({"disabled_rules": disabled_rule})
if fail_project_under:
config.overload({"fail_project_under": fail_project_under})
if fail_any_item_under:
config.overload({"fail_any_item_under": fail_any_item_under})
if show:
config.overload({"show": show})
try:
if run_dbt_parse:
dbt_parse()
evaluation = lint_dbt_project(
manifest_path=manifest, config=config, format=format, select=select
)
except FileNotFoundError:
logger.error(
"dbt's manifest.json could not be found. If you're in a dbt project, be "
"sure to run 'dbt parse' first, or use the option '--run-dbt-parse'."
)
ctx.exit(2)
except DbtParseException:
logger.error("dbt failed to parse project. Run `dbt parse` to investigate.")
ctx.exit(2)
except Exception:
logger.error(traceback.format_exc())
ctx.exit(2)
if (
any(x.value < config.fail_any_item_under for x in evaluation.scores.values())
or evaluation.project_score.value < config.fail_project_under
):
ctx.exit(1)