Skip to content

Commit

Permalink
fix: DBTP-1375 - platform helper version get-platform-helper-for-proj…
Browse files Browse the repository at this point in the history
…ect no longer validates config (#575)
  • Loading branch information
ksugden authored Sep 27, 2024
1 parent abfc5d7 commit f62c25d
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 99 deletions.
4 changes: 2 additions & 2 deletions dbt_platform_helper/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1002,8 +1002,8 @@ platform-helper database copy <source_db> <target_db>

[↩ Parent](#platform-helper)

Contains subcommands for getting version information about the current
project.
Contains subcommands for getting version information about the
current project.

## Usage

Expand Down
58 changes: 29 additions & 29 deletions dbt_platform_helper/commands/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,37 @@

from dbt_platform_helper.utils.click import ClickDocOptGroup
from dbt_platform_helper.utils.platform_config import get_environment_pipeline_names
from dbt_platform_helper.utils.versioning import (
check_platform_helper_version_needs_update,
)
from dbt_platform_helper.utils.versioning import get_required_platform_helper_version


@click.group(chain=True, cls=ClickDocOptGroup)
def version():
"""Contains subcommands for getting version information about the current
project."""
check_platform_helper_version_needs_update()
class VersionCommand:
def __init__(self):
self.command_group = self.version
self.command = self.get_platform_helper_for_project

@click.group(chain=True, cls=ClickDocOptGroup)
def version():
"""Contains subcommands for getting version information about the
current project."""

@version.command(help="Print the version of platform-tools required by the current project")
@click.option(
"--pipeline",
required=False,
type=click.Choice(get_environment_pipeline_names()),
help="Take into account platform-tools version overrides in the specified pipeline",
)
def get_platform_helper_for_project(pipeline):
"""
Version precedence is in this order:
- if the --pipeline option is supplied, the version in 'platform-config.yml' in:
environment_pipelines:
<pipeline>:
...
versions:
platform-helper
- The version from default_versions/platform-helper in 'platform-config.yml'
- Fall back on the version in the deprecated '.platform-helper-version' file
"""
required_version = get_required_platform_helper_version(pipeline)
click.secho(required_version)
@version.command(help="Print the version of platform-tools required by the current project")
@click.option(
"--pipeline",
required=False,
type=click.Choice(get_environment_pipeline_names()),
help="Take into account platform-tools version overrides in the specified pipeline",
)
def get_platform_helper_for_project(pipeline):
"""
Version precedence is in this order:
- if the --pipeline option is supplied, the version in 'platform-config.yml' in:
environment_pipelines:
<pipeline>:
...
versions:
platform-helper
- The version from default_versions/platform-helper in 'platform-config.yml'
- Fall back on the version in the deprecated '.platform-helper-version' file
"""
required_version = get_required_platform_helper_version(pipeline)
click.secho(required_version)
27 changes: 20 additions & 7 deletions dbt_platform_helper/utils/platform_config.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
from pathlib import Path

import yaml

from pathlib import Path

from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
from dbt_platform_helper.utils.validation import load_and_validate_platform_config


def get_environment_pipeline_names():
if not Path(PLATFORM_CONFIG_FILE).exists():
def _read_config_file_contents():
if Path(PLATFORM_CONFIG_FILE).exists():
return Path(PLATFORM_CONFIG_FILE).read_text()


def load_unvalidated_config_file():
file_contents = _read_config_file_contents()
if not file_contents:
return {}
try:
return yaml.safe_load(file_contents)
except yaml.parser.ParserError:
return {}

config = load_and_validate_platform_config(disable_aws_validation=True, disable_file_check=True)
return config.get("environment_pipelines", {}).keys()

def get_environment_pipeline_names():
pipelines_config = load_unvalidated_config_file().get("environment_pipelines")
if pipelines_config:
return pipelines_config.keys()
return {}


def is_terraform_project() -> bool:
Expand Down
46 changes: 28 additions & 18 deletions dbt_platform_helper/utils/versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from dbt_platform_helper.exceptions import IncompatibleMajorVersion
from dbt_platform_helper.exceptions import IncompatibleMinorVersion
from dbt_platform_helper.exceptions import ValidationException
from dbt_platform_helper.utils.validation import load_and_validate_platform_config
from dbt_platform_helper.utils.platform_config import load_unvalidated_config_file

VersionTuple = Optional[Tuple[int, int, int]]

Expand Down Expand Up @@ -104,22 +104,40 @@ def get_github_released_version(repository: str, tags: bool = False) -> Tuple[in
return parse_version(package_info["tag_name"])


def _get_latest_release():
package_info = requests.get("https://pypi.org/pypi/dbt-platform-helper/json").json()
released_versions = package_info["releases"].keys()
parsed_released_versions = [parse_version(v) for v in released_versions]
parsed_released_versions.sort(reverse=True)
return parsed_released_versions[0]


def get_platform_helper_versions(include_project_versions=True) -> PlatformHelperVersions:
try:
locally_installed_version = parse_version(version("dbt-platform-helper"))
except PackageNotFoundError:
locally_installed_version = None

package_info = requests.get("https://pypi.org/pypi/dbt-platform-helper/json").json()
released_versions = package_info["releases"].keys()
parsed_released_versions = [parse_version(v) for v in released_versions]
parsed_released_versions.sort(reverse=True)
latest_release = parsed_released_versions[0]
latest_release = _get_latest_release()

if not include_project_versions:
return PlatformHelperVersions(
local_version=locally_installed_version,
latest_release=latest_release,
)

deprecated_version_file = Path(PLATFORM_HELPER_VERSION_FILE)
version_from_file = (
parse_version(deprecated_version_file.read_text())
if deprecated_version_file.exists()
else None
)

platform_config_default, pipeline_overrides = None, {}

platform_config_default, pipeline_overrides, version_from_file = None, {}, None
platform_config = load_unvalidated_config_file()

if include_project_versions:
platform_config = load_and_validate_platform_config(disable_aws_validation=True)
if platform_config:
platform_config_default = parse_version(
platform_config.get("default_versions", {}).get("platform-helper")
)
Expand All @@ -130,13 +148,6 @@ def get_platform_helper_versions(include_project_versions=True) -> PlatformHelpe
if pipeline.get("versions", {}).get("platform-helper")
}

deprecated_version_file = Path(PLATFORM_HELPER_VERSION_FILE)
version_from_file = (
parse_version(deprecated_version_file.read_text())
if deprecated_version_file.exists()
else None
)

out = PlatformHelperVersions(
local_version=locally_installed_version,
latest_release=latest_release,
Expand All @@ -145,8 +156,7 @@ def get_platform_helper_versions(include_project_versions=True) -> PlatformHelpe
pipeline_overrides=pipeline_overrides,
)

if include_project_versions:
_process_version_file_warnings(out)
_process_version_file_warnings(out)

return out

Expand Down
4 changes: 2 additions & 2 deletions platform_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from dbt_platform_helper.commands.notify import notify as notify_commands
from dbt_platform_helper.commands.pipeline import pipeline as pipeline_commands
from dbt_platform_helper.commands.secrets import secrets as secrets_commands
from dbt_platform_helper.commands.version import version as version_commands
from dbt_platform_helper.commands.version import VersionCommand
from dbt_platform_helper.utils.click import ClickDocOptGroup


Expand All @@ -47,7 +47,7 @@ def platform_helper():
platform_helper.add_command(secrets_commands)
platform_helper.add_command(notify_commands)
platform_helper.add_command(database_commands)
platform_helper.add_command(version_commands)
platform_helper.add_command(VersionCommand().command_group)

if __name__ == "__main__":
platform_helper()
47 changes: 47 additions & 0 deletions tests/platform_helper/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,50 @@ def s3_extensions_fixture(fakefs):
}
),
)


INVALID_PLATFORM_CONFIG_WITH_PLATFORM_VERSION_OVERRIDES = """
application: invalid-config-app
legacy_project: false
default_versions:
platform-helper: 1.2.3
terraform-platform-modules: 9.9.9
environments:
dev:
test:
staging:
prod:
vpc: prod-vpc
extensions:
test-app-s3-bucket:
type: s3
this_field_is_incompatible_with_current_version: foo
environment_pipelines:
prod-main:
account: prod-acc
branch: main
slack_channel: "/codebuild/slack_oauth_channel"
trigger_on_push: false
versions:
platform-helper: 9.0.9
environments:
prod:
requires_approval: true
"""


@pytest.fixture
def create_valid_platform_config_file(fakefs, valid_platform_config):
fakefs.create_file(Path(PLATFORM_CONFIG_FILE), contents=yaml.dump(valid_platform_config))


@pytest.fixture
def create_invalid_platform_config_file(fakefs):
fakefs.create_file(
Path(PLATFORM_CONFIG_FILE),
contents=INVALID_PLATFORM_CONFIG_WITH_PLATFORM_VERSION_OVERRIDES,
)
100 changes: 60 additions & 40 deletions tests/platform_helper/test_command_version.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,76 @@
import pytest
import re
from pathlib import Path
from unittest.mock import patch

import yaml
from unittest.mock import patch
from click.testing import CliRunner

from dbt_platform_helper.commands.version import get_platform_helper_for_project
from dbt_platform_helper.constants import PLATFORM_CONFIG_FILE
from dbt_platform_helper.commands.version import VersionCommand


@pytest.mark.usefixtures("create_valid_platform_config_file")
class TestVersionCommandWithValidConfig:
@patch("dbt_platform_helper.commands.version.get_required_platform_helper_version")
def test_calls_versioning_function_and_prints_returned_version(
self,
mock_get_required_platform_helper_version,
):
mock_get_required_platform_helper_version.return_value = "1.2.3"

command = VersionCommand().command
result = CliRunner().invoke(command, [])

assert len(mock_get_required_platform_helper_version.mock_calls) == 1
assert mock_get_required_platform_helper_version.mock_calls[0].args == (None,)
assert result.exit_code == 0
assert re.match(r"\s*1\.2\.3\s*", result.output)

@patch("dbt_platform_helper.commands.version.get_required_platform_helper_version")
def test_calls_versioning_function_and_prints_returned_version_with_pipeline_override(
self,
mock_get_required_platform_helper_version,
):
mock_get_required_platform_helper_version.return_value = "1.2.3"

@patch("dbt_platform_helper.commands.version.get_required_platform_helper_version")
def test_calls_versioning_function_and_prints_returned_version(
mock_get_required_platform_helper_version,
fakefs,
valid_platform_config,
):
fakefs.create_file(Path(PLATFORM_CONFIG_FILE), contents=yaml.dump(valid_platform_config))
mock_get_required_platform_helper_version.return_value = "1.2.3"
command = VersionCommand().command
result = CliRunner().invoke(command, ["--pipeline", "main"])

result = CliRunner().invoke(get_platform_helper_for_project, [])
assert len(mock_get_required_platform_helper_version.mock_calls) == 1
assert mock_get_required_platform_helper_version.mock_calls[0].args == ("main",)
assert result.exit_code == 0
assert re.match(r"\s*1\.2\.3\s*", result.output)

assert len(mock_get_required_platform_helper_version.mock_calls) == 1
assert mock_get_required_platform_helper_version.mock_calls[0].args == (None,)
assert result.exit_code == 0
assert re.match(r"\s*1\.2\.3\s*", result.output)
def test_fail_if_pipeline_option_is_not_a_pipeline(self):
command = VersionCommand().command
result = CliRunner().invoke(command, ["--pipeline", "bogus"])

assert result.exit_code != 0
assert "'bogus' is not one of" in result.output
assert "'main'" in result.output

@patch("dbt_platform_helper.commands.version.get_required_platform_helper_version")
def test_calls_versioning_function_and_prints_returned_version_with_pipeline_override(
mock_get_required_platform_helper_version,
fakefs,
valid_platform_config,
):
fakefs.create_file(Path(PLATFORM_CONFIG_FILE), contents=yaml.dump(valid_platform_config))
mock_get_required_platform_helper_version.return_value = "1.2.3"

result = CliRunner().invoke(get_platform_helper_for_project, ["--pipeline", "main"])
@pytest.mark.usefixtures("create_invalid_platform_config_file")
@patch("dbt_platform_helper.utils.versioning._get_latest_release", return_value="10.9.9")
class TestVersionCommandWithInvalidConfig:
def test_works_given_invalid_config(self, mock_latest_release):
command = VersionCommand().command
result = CliRunner().invoke(command, [])

assert len(mock_get_required_platform_helper_version.mock_calls) == 1
assert mock_get_required_platform_helper_version.mock_calls[0].args == ("main",)
assert result.exit_code == 0
assert re.match(r"\s*1\.2\.3\s*", result.output)
assert result.exit_code == 0
assert result.output == "1.2.3\n"

def test_pipeline_override_given_invalid_config(self, mock_latest_release):
command = VersionCommand().command
result = CliRunner().invoke(command, ["--pipeline", "prod-main"])

def test_fail_if_pipeline_option_is_not_a_pipeline(
fakefs,
valid_platform_config,
):
fakefs.create_file(Path(PLATFORM_CONFIG_FILE), contents=yaml.dump(valid_platform_config))
assert result.exit_code == 0
assert result.output == "9.0.9\n"

result = CliRunner().invoke(get_platform_helper_for_project, ["--pipeline", "bogus"])
def test_fails_if_pipeline_option_is_not_a_pipeline_given_invalid_config(
self, mock_latest_release
):
command = VersionCommand().command
result = CliRunner().invoke(command, ["--pipeline", "bogus"])

assert result.exit_code != 0
assert "'bogus' is not one of" in result.output
assert "'main'" in result.output
assert result.exit_code != 0
assert "'bogus' is not " in result.output
assert "'prod-main'" in result.output
Loading

0 comments on commit f62c25d

Please sign in to comment.