diff --git a/dbt-metricflow/Makefile b/dbt-metricflow/Makefile new file mode 100644 index 0000000000..732dfb897f --- /dev/null +++ b/dbt-metricflow/Makefile @@ -0,0 +1,6 @@ +# Controls the number of parallel workers running tests. Try "make -e PARALLELISM=4 test". +PARALLELISM = auto +# Testing and linting +.PHONY: test +test: + hatch -v run dev-env:pytest -vv -n $(PARALLELISM) tests_dbt_metricflow diff --git a/scripts/mf_release_tool.py b/scripts/mf_release_tool.py new file mode 100644 index 0000000000..4801292728 --- /dev/null +++ b/scripts/mf_release_tool.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +import logging +from pathlib import Path + +from metricflow_semantics.toolkit.mf_logging.lazy_formattable import LazyFormat +from scripts.mf_script_helper import MetricFlowScriptHelper + +logger = logging.getLogger(__name__) + + +class MetricFlowReleaseTool: + def __init__(self, mf_repo_root: Path, release_version: str) -> None: + self._release_version = release_version + self._mf_repo_root = mf_repo_root + self._dbt_mf_root = self._mf_repo_root.joinpath("dbt-metricflow") + self._hatch_command = "/opt/homebrew/bin/hatch" + + def assert_clean_git_repo(self) -> None: + result = MetricFlowScriptHelper.run_command( + ["git", "status", "--porcelain"], working_directory=self._mf_repo_root, capture_output=True + ) + stdout_lines = result.stdout.decode("utf-8").rstrip().split("\n") + if tuple(stdout_lines) != ("",): + raise RuntimeError(LazyFormat("Git state is not clean", mf_repo_root=self._mf_repo_root, stdout_lines=stdout_lines)) + + def setup_main_branch(self) -> None: + MetricFlowScriptHelper.run_command(["git", "switch", "main"], working_directory=self._mf_repo_root) + MetricFlowScriptHelper.run_command(["git", "pull"], working_directory=self._mf_repo_root) + + def check_dbt_metricflow(self) -> None: + requirements_file_path = self._dbt_mf_root.joinpath("requirements-files", "requirements-metricflow.txt") + + with open(requirements_file_path, "w") as f: + f.write("metricflow @ {root:parent:uri}\n") + + MetricFlowScriptHelper.run_command([self._hatch_command, "env", "prune"], working_directory=self._dbt_mf_root, env={}) + MetricFlowScriptHelper.run_command( + [self._hatch_command, "-v", "run", "dev-env:pytest", "-vv", "-n", "auto", "tests_dbt_metricflow"], + working_directory=self._dbt_mf_root, + env={}, + ) + MetricFlowScriptHelper.run_command(["git", "checkout", str(requirements_file_path)], working_directory=self._mf_repo_root) + + +if __name__ == "__main__": + MetricFlowScriptHelper.setup_logging() + mf_repo_root = Path("/Users/paul_work/repos/metricflow-release") + release_tool = MetricFlowReleaseTool(mf_repo_root=mf_repo_root) + logger.info(LazyFormat("Checking that the repo is clean", mf_repo_root=mf_repo_root)) + release_tool.assert_clean_git_repo() + + logger.info("Updating the `main` branch") + release_tool.setup_main_branch() + + logger.info("Checking `dbt-metricflow` tests work using the current version of `metricflow`") + release_tool.check_dbt_metricflow() diff --git a/scripts/mf_script_helper.py b/scripts/mf_script_helper.py index 6d554f6f00..a23c1f035c 100644 --- a/scripts/mf_script_helper.py +++ b/scripts/mf_script_helper.py @@ -2,6 +2,7 @@ import logging import subprocess +from collections.abc import Mapping from pathlib import Path from subprocess import CompletedProcess from typing import Optional, Sequence @@ -27,6 +28,7 @@ def run_command( working_directory: Optional[Path] = None, raise_exception_on_error: bool = True, capture_output: bool = False, + env: Optional[Mapping[str, str]] = None, ) -> CompletedProcess: """Thin wrapper around `subprocess.run` with more string types and log statements. @@ -35,6 +37,8 @@ def run_command( working_directory: The working directory where the command should be run. raise_exception_on_error: If the command fails, raise an exception. capture_output: Same as the argument for `subprocess.run`. + env: The environment variables to use in the subprocess. If not specified, the ones from the parent are + used. Returns: The `CompletedProcess` similar to `subprocess.run` """ @@ -43,7 +47,11 @@ def run_command( else: logger.info(f"In {str(working_directory)!r}: Running {command=}") return subprocess.run( - command, cwd=working_directory, check=raise_exception_on_error, capture_output=capture_output + command, + cwd=working_directory, + check=raise_exception_on_error, + capture_output=capture_output, + env=env, ) @staticmethod