Skip to content

Commit

Permalink
Add helm repo update <repo-name> for Helm >3.7 (#239)
Browse files Browse the repository at this point in the history
fixes #18
  • Loading branch information
raminqaf authored Jun 12, 2023
1 parent 6eb6c56 commit 15ce42c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 13 deletions.
21 changes: 20 additions & 1 deletion kpops/component_handlers/helm_wrapper/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
HelmTemplateFlags,
HelmUpgradeInstallFlags,
RepoAuthFlags,
Version,
YamlReader,
)

Expand All @@ -26,6 +27,11 @@ class Helm:
def __init__(self, helm_config: HelmConfig) -> None:
self._context = helm_config.context
self._debug = helm_config.debug
self._version = self.get_version()
if self._version.major != 3:
raise RuntimeError(
f"The supported Helm version is 3.x.x. The current Helm version is {self._version.major}.{self._version.minor}.{self._version.patch}"
)

def add_repo(
self,
Expand Down Expand Up @@ -68,7 +74,10 @@ def add_repo(
else:
raise e

self.__execute(["helm", "repo", "update"])
if self._version.minor > 7:
self.__execute(["helm", "repo", "update", repository_name])
else:
self.__execute(["helm", "repo", "update"])

def upgrade_install(
self,
Expand Down Expand Up @@ -186,6 +195,16 @@ def get_manifest(self, release_name: str, namespace: str) -> Iterable[HelmTempla
except ReleaseNotFoundException:
return ()

def get_version(self) -> Version:
command = ["helm", "version", "--short"]
short_version = self.__execute(command)
version_match = re.search(r"v(\d+\.\d+\.\d+)", short_version)
if version_match is None:
raise RuntimeError("Could not parse the Helm version.")

major, minor, patch = map(int, version_match.group(1).split("."))
return Version(major, minor, patch)

@staticmethod
def load_manifest(yaml_contents: str) -> Iterator[HelmTemplate]:
is_beginning: bool = False
Expand Down
7 changes: 7 additions & 0 deletions kpops/component_handlers/helm_wrapper/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,10 @@ def __iter__(self) -> Iterator[str]:
self.content = self.content[start:end]
yield from self.content.splitlines()
yield "---" # add final divider to make parsing easier


@dataclass
class Version:
major: int
minor: int
patch: int
86 changes: 74 additions & 12 deletions tests/component_handlers/helm_wrapper/test_helm_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
HelmTemplateFlags,
HelmUpgradeInstallFlags,
RepoAuthFlags,
Version,
)
from kpops.components.streams_bootstrap.app_type import AppType

Expand All @@ -33,8 +34,14 @@ def run_command(self, mocker: MockerFixture) -> MagicMock:
def log_warning_mock(self, mocker: MockerFixture) -> MagicMock:
return mocker.patch("kpops.component_handlers.helm_wrapper.helm.log.warning")

@pytest.fixture
def mock_get_version(self, mocker: MockerFixture) -> MagicMock:
mock_get_version = mocker.patch.object(Helm, "get_version")
mock_get_version.return_value = Version(major=3, minor=12, patch=0)
return mock_get_version

def test_should_call_run_command_method_when_helm_install_with_defaults(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())

Expand Down Expand Up @@ -62,10 +69,13 @@ def test_should_call_run_command_method_when_helm_install_with_defaults(
],
)

def test_should_include_configured_tls_parameters_on_add(
self, run_command: MagicMock
def test_should_include_configured_tls_parameters_on_add_when_version_is_old(
self, run_command: MagicMock, mocker: MockerFixture
):
mock_get_version = mocker.patch.object(Helm, "get_version")
mock_get_version.return_value = Version(major=3, minor=6, patch=0)
helm = Helm(HelmConfig())

helm.add_repo(
"test-repository",
"fake",
Expand All @@ -89,8 +99,36 @@ def test_should_include_configured_tls_parameters_on_add(
),
]

def test_should_include_configured_tls_parameters_on_add_when_version_is_new(
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm = Helm(HelmConfig())

helm.add_repo(
"test-repository",
"fake",
RepoAuthFlags(ca_file=Path("a_file.ca"), insecure_skip_tls_verify=True),
)
assert run_command.mock_calls == [
mock.call(
[
"helm",
"repo",
"add",
"test-repository",
"fake",
"--ca-file",
"a_file.ca",
"--insecure-skip-tls-verify",
],
),
mock.call(
["helm", "repo", "update", "test-repository"],
),
]

def test_should_include_configured_tls_parameters_on_update(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())
helm_wrapper.upgrade_install(
Expand Down Expand Up @@ -126,8 +164,7 @@ def test_should_include_configured_tls_parameters_on_update(
)

def test_should_call_run_command_method_when_helm_install_with_non_defaults(
self,
run_command: MagicMock,
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())
helm_wrapper.upgrade_install(
Expand Down Expand Up @@ -168,7 +205,7 @@ def test_should_call_run_command_method_when_helm_install_with_non_defaults(
)

def test_should_call_run_command_method_when_uninstalling_streams_app(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())
helm_wrapper.uninstall(
Expand All @@ -181,7 +218,10 @@ def test_should_call_run_command_method_when_uninstalling_streams_app(
)

def test_should_log_warning_when_release_not_found(
self, run_command: MagicMock, log_warning_mock: MagicMock
self,
run_command: MagicMock,
log_warning_mock: MagicMock,
mock_get_version: MagicMock,
):
helm_wrapper = Helm(helm_config=HelmConfig())
run_command.side_effect = ReleaseNotFoundException()
Expand All @@ -196,7 +236,7 @@ def test_should_log_warning_when_release_not_found(
)

def test_should_call_run_command_method_when_installing_streams_app__with_dry_run(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())

Expand Down Expand Up @@ -326,7 +366,7 @@ def test_load_manifest(self):
assert helm_templates[1].filepath == "chart/templates/test3b.yaml"
assert helm_templates[1].template == {"foo": "bar"}

def test_get_manifest(self, run_command: MagicMock):
def test_get_manifest(self, run_command: MagicMock, mock_get_version: MagicMock):
helm_wrapper = Helm(helm_config=HelmConfig())
run_command.return_value = """Release "test-release" has been upgraded. Happy Helming!
NAME: test-release
Expand Down Expand Up @@ -357,7 +397,7 @@ def test_get_manifest(self, run_command: MagicMock):
assert helm_wrapper.get_manifest("test-release", "test-namespace") == ()

def test_should_call_run_command_method_when_helm_template_with_optional_args(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())

Expand Down Expand Up @@ -392,7 +432,7 @@ def test_should_call_run_command_method_when_helm_template_with_optional_args(
)

def test_should_call_run_command_method_when_helm_template_without_optional_args(
self, run_command: MagicMock
self, run_command: MagicMock, mock_get_version: MagicMock
):
helm_wrapper = Helm(helm_config=HelmConfig())

Expand All @@ -415,3 +455,25 @@ def test_should_call_run_command_method_when_helm_template_without_optional_args
"values.yaml",
],
)

def test_should_call_helm_version(self, run_command: MagicMock):
run_command.return_value = "v3.12.0+gc9f554d"
Helm(helm_config=HelmConfig())

run_command.assert_called_once_with(
[
"helm",
"version",
"--short",
],
)

def test_should_raise_exception_if_helm_version_is_old(
self, run_command: MagicMock
):
run_command.return_value = "v2.9.0+gc9f554d"
with pytest.raises(RuntimeError) as runtime_error:
Helm(helm_config=HelmConfig())
assert str(runtime_error.value) == (
"The supported Helm version is 3.x.x. The current Helm version is 2.9.0"
)
4 changes: 4 additions & 0 deletions tests/pipeline/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def run_command(self, mocker: MockerFixture) -> MagicMock:
return mocker.patch.object(Helm, "_Helm__execute")

def test_default_template_config(self, run_command: MagicMock):
run_command.return_value = "v3.12.0+gc9f554d"

result = runner.invoke(
app,
[
Expand Down Expand Up @@ -52,6 +54,8 @@ def test_default_template_config(self, run_command: MagicMock):
assert result.exit_code == 0

def test_template_config_with_flags(self, run_command: MagicMock):
run_command.return_value = "v3.12.0+gc9f554d"

result = runner.invoke(
app,
[
Expand Down

0 comments on commit 15ce42c

Please sign in to comment.