diff --git a/README.md b/README.md index 363ab9c..023986f 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ pip install dbt-meshify # create a group of all models tagged with "finance" # leaf nodes and nodes with cross-group dependencies will be `public` # public nodes will also have contracts added to them -dbt-meshify group finance --owner name Monopoly Man -s +tag:finance +dbt-meshify group finance --owner-name "Monopoly Man" -s +tag:finance # optionally use the add-version operation to add a new version to a model dbt-meshify operation add-version -s fct_orders diff --git a/dbt_meshify/cli.py b/dbt_meshify/cli.py index a813810..cf0ca4d 100644 --- a/dbt_meshify/cli.py +++ b/dbt_meshify/cli.py @@ -1 +1,66 @@ -# TODO add the logic for each meshify command to independent tasks here to make cli thinner +import functools + +import click + +# define common parameters +project_path = click.option( + "--project-path", + type=click.Path(exists=True), + default=".", + help="The path to the dbt project to operate on. Defaults to the current directory.", +) + +exclude = click.option( + "--exclude", + "-e", + default=None, + help="The dbt selection syntax specifying the resources to exclude in the operation", +) + +group_yml_path = click.option( + "--group-yml-path", + type=click.Path(exists=False), + help="An optional path to store the new group YAML definition.", +) + +select = click.option( + "--select", + "-s", + default=None, + help="The dbt selection syntax specifying the resources to include in the operation", +) + +selector = click.option( + "--selector", + default=None, + help="The name of the YML selector specifying the resources to include in the operation", +) + +owner_name = click.option( + "--owner-name", + help="The group Owner's name.", +) + +owner_email = click.option( + "--owner-email", + help="The group Owner's email address.", +) + +owner_properties = click.option( + "--owner-properties", + help="Additional properties to assign to a group Owner.", +) + + +def owner(func): + """Add click options and argument validation for creating Owner objects.""" + + @functools.wraps(func) + def wrapper_decorator(*args, **kwargs): + if kwargs.get('owner_name') is None and kwargs.get('owner_email') is None: + raise click.UsageError( + "Groups require an Owner to be defined using --owner-name and/or --owner-email." + ) + return func(*args, **kwargs) + + return wrapper_decorator diff --git a/dbt_meshify/main.py b/dbt_meshify/main.py index 3ea3b5b..46fe647 100644 --- a/dbt_meshify/main.py +++ b/dbt_meshify/main.py @@ -1,55 +1,25 @@ import os from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Optional import click +import yaml from dbt.contracts.graph.unparsed import Owner +from .cli import ( + exclude, + group_yml_path, + owner, + owner_email, + owner_name, + owner_properties, + project_path, + select, + selector, +) from .dbt_projects import DbtProject, DbtProjectHolder, DbtSubProject from .storage.yaml_editors import DbtMeshModelConstructor -# define common parameters -project_path = click.option( - "--project-path", - type=click.Path(exists=True), - default=".", - help="The path to the dbt project to operate on. Defaults to the current directory.", -) - -exclude = click.option( - "--exclude", - "-e", - default=None, - help="The dbt selection syntax specifying the resources to exclude in the operation", -) - -group_yml_path = click.option( - "--group-yml-path", - type=click.Path(exists=False), - help="An optional path to store the new group YAML definition.", -) - -select = click.option( - "--select", - "-s", - default=None, - help="The dbt selection syntax specifying the resources to include in the operation", -) - -owner = click.option( - "--owner", - nargs=2, - multiple=True, - type=click.Tuple([str, str]), - help="A tuple of Owner information for the group. For example " "`--owner name example`", -) - -selector = click.option( - "--selector", - default=None, - help="The name of the YML selector specifying the resources to include in the operation", -) - # define cli group @click.group() @@ -187,14 +157,19 @@ def add_version(select, exclude, project_path, selector, prerelease, defined_in) @select @selector @click.argument("name") +@owner_name +@owner_email +@owner_properties @owner @group_yml_path def create_group( name, project_path: os.PathLike, - owner: List[Tuple[str, str]], group_yml_path: os.PathLike, select: str, + owner_name: Optional[str] = None, + owner_email: Optional[str] = None, + owner_properties: Optional[str] = None, exclude: Optional[str] = None, selector: Optional[str] = None, ): @@ -216,12 +191,14 @@ def create_group( "The provided group-yml-path is not contained within the provided dbt project." ) - owner: Owner = Owner(**{key: value for key, value in owner}) + group_owner: Owner = Owner( + name=owner_name, email=owner_email, _extra=yaml.safe_load(owner_properties or '{}') + ) grouper = ResourceGrouper(project) grouper.add_group( name=name, - owner=owner, + owner=group_owner, select=select, exclude=exclude, selector=selector, @@ -235,6 +212,9 @@ def create_group( @select @selector @click.argument("name") +@owner_name +@owner_email +@owner_properties @owner @group_yml_path @click.pass_context @@ -242,9 +222,11 @@ def group( ctx, name, project_path: os.PathLike, - owner: List[Tuple[str, str]], group_yml_path: os.PathLike, select: str, + owner_name: Optional[str] = None, + owner_email: Optional[str] = None, + owner_properties: Optional[str] = None, exclude: Optional[str] = None, selector: Optional[str] = None, ): diff --git a/docs/index.md b/docs/index.md index 82eccae..5c4192c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -30,7 +30,7 @@ Here's how that might look for the process of creating a separate `finance` subp # create a group of all models tagged with "finance" # leaf nodes and nodes with cross-group dependencies will be `public` # public nodes will also have contracts added to them -dbt-meshify group finance --owner name Monopoly Man -s +tag:finance +dbt-meshify group finance --owner-name "Monopoly Man" -s +tag:finance # optionally use the add-version operation to add a new version to a model dbt-meshify operation add-version -s fct_orders diff --git a/tests/integration/test_create_group_command.py b/tests/integration/test_create_group_command.py index 7c15573..e62a3e4 100644 --- a/tests/integration/test_create_group_command.py +++ b/tests/integration/test_create_group_command.py @@ -51,11 +51,9 @@ def test_create_group_command(model_yml, start_group_yml, end_group_yml): "shared_model", "--project-path", proj_path_string, - "--owner", - "name", + "--owner-name", "Shaina Fake", - "--owner", - "email", + "--owner-email", "fake@example.com", ], ) @@ -97,10 +95,10 @@ def test_group_group_owner_properties(name, email, end_group_yml): args = ["test_group", "--select", "shared_model", "--project-path", proj_path_string] if name: - args += ["--owner", "name", name] + args += ["--owner-name", name] if email: - args += ["--owner", "email", email] + args += ["--owner-email", email] runner = CliRunner() result = runner.invoke(create_group, args) diff --git a/tests/integration/test_group_command.py b/tests/integration/test_group_command.py index 1858719..565b323 100644 --- a/tests/integration/test_group_command.py +++ b/tests/integration/test_group_command.py @@ -36,8 +36,7 @@ def test_group_command(select, expected_public_contracted_models): group, [ "test_group", - "--owner", - "name", + "--owner-name", "Teenage Mutant Jinja Turtles", "--select", select,