diff --git a/dbt-metricflow/dbt_metricflow/cli/cli_link.py b/dbt-metricflow/dbt_metricflow/cli/cli_link.py new file mode 100644 index 000000000..81f61d0d2 --- /dev/null +++ b/dbt-metricflow/dbt_metricflow/cli/cli_link.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import Optional + +import click +from packaging.version import Version + + +class CliLink: + """Groups methods for links / URLs that displayed through the CLI.""" + + @staticmethod + def _blue_text(url: str) -> str: + return click.style(url, fg="blue", bold=True) + + @staticmethod + def get_time_spine_docs_link(dbt_core_version: Optional[Version]) -> str: # noqa: D102 + time_spine_docs_url = "https://docs.getdbt.com/docs/build/metricflow-time-spine" + if dbt_core_version is not None: + time_spine_docs_url = time_spine_docs_url + f"?version={dbt_core_version.major}.{dbt_core_version.minor}" + return CliLink._blue_text(time_spine_docs_url) + + @staticmethod + def get_report_issue_link() -> str: # noqa: D102 + return CliLink._blue_text("https://github.com/dbt-labs/metricflow/issues") + + @staticmethod + def get_github_repository_link() -> str: # noqa: D102 + return CliLink._blue_text("https://github.com/dbt-labs/metricflow") diff --git a/dbt-metricflow/dbt_metricflow/cli/tutorial.py b/dbt-metricflow/dbt_metricflow/cli/tutorial.py index 78197e116..ed20fd669 100644 --- a/dbt-metricflow/dbt_metricflow/cli/tutorial.py +++ b/dbt-metricflow/dbt_metricflow/cli/tutorial.py @@ -16,6 +16,7 @@ from typing_extensions import Optional from dbt_metricflow.cli.cli_configuration import CLIConfiguration +from dbt_metricflow.cli.cli_link import CliLink logger = logging.getLogger(__name__) @@ -127,11 +128,12 @@ def _generate_help_message_text(dbt_core_version: Optional[Version], tutorial_di {click.style(complex_query, bold=True)} 12. When you're done with the tutorial, run mf tutorial --clean to delete sample models and seeds. * If a sample project was created, it wil remain. - 13. Before integrating metrics into your project, read up on adding a time spine (try +Left Click on the link): - {click.style(time_spine_docs_link, fg="blue", bold=True)} + 13. Before integrating metrics into your project, read up on adding a time spine. + (+ may work in your terminal to follow the link) + {CliLink.get_time_spine_docs_link(dbt_core_version)} If you found MetricFlow to be helpful, consider adding a Github star to promote the project: - {click.style('https://github.com/dbt-labs/metricflow', fg="blue", bold=True)} + {CliLink.get_github_repository_link()} """ ) diff --git a/dbt-metricflow/dbt_metricflow/cli/utils.py b/dbt-metricflow/dbt_metricflow/cli/utils.py index ddba75eab..f67ffe233 100644 --- a/dbt-metricflow/dbt_metricflow/cli/utils.py +++ b/dbt-metricflow/dbt_metricflow/cli/utils.py @@ -3,6 +3,7 @@ import datetime as dt import logging import pathlib +import textwrap import traceback from functools import update_wrapper, wraps from typing import Any, Callable, List, Optional @@ -13,6 +14,7 @@ import dbt_metricflow.cli.custom_click_types as click_custom from dbt_metricflow.cli.cli_configuration import CLIConfiguration +from dbt_metricflow.cli.cli_link import CliLink logger = logging.getLogger(__name__) @@ -114,8 +116,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: # type: ignore[misc] func(*args, **kwargs) except Exception as e: # This will log to the file handlers registered in the root. - logging.exception("Got an exception in the exception handler.") - # Checks if CLIContext has verbose flag set + logging.exception("Logging exception") if isinstance(args[0], CLIConfiguration): cli_context: CLIConfiguration = args[0] @@ -129,6 +130,18 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: # type: ignore[misc] ) ) click.echo(f"\nERROR: {str(e)}") + + click.echo( + "\n" + + textwrap.dedent( + f"""\ + If you think you found a bug, please report it here: + {CliLink.get_report_issue_link()} + """ + ) + ) + + # Checks if CLIContext has verbose flag set if args and hasattr(args[0], "verbose") and args[0].verbose is True: click.echo(traceback.format_exc())