From 3c332614576d600eb0b4f2c193327efecb9168dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20de=20Saint=20Martin?= Date: Tue, 20 Oct 2026 07:48:31 +0200 Subject: [PATCH] fix: check only the major version against the Helm Chart A minor or patch release of the package keeps the Helm Chart contract. The check compared major.minor, so a chart upgrade forced a backend upgrade, and a package upgrade forced a chart upgrade. Chartreuse 7.1.0 refuses to start with the Helm Chart appVersion 7.0.0. --- CHANGELOG.md | 10 ++++---- README.md | 2 +- VERSION | 2 +- src/chartreuse/chartreuse_upgrade.py | 12 +++++----- .../unit_tests/test_chartreuse_restore.py | 4 ++-- .../unit_tests/test_chartreuse_upgrade.py | 7 +++--- .../test_chartreuse_upgrade_extended.py | 24 +++++++++---------- 7 files changed, 30 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8602beb..8e0a140 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,6 @@ # Changelog -## v7.1.0 (unreleased) - -v7.1.0 replaces v8.0.0. Chartreuse keeps major 7, because the -[Chartreuse Helm Chart](https://github.com/wiremind/wiremind-helm-charts/tree/main/charts/chartreuse) -requires the same major version as the Python package. Do not use v8.0.0. +## v7.1.1 (2026-10-20) ### Upgrade Chartreuse no longer installs a database driver. Pick the extra that matches your SQLAlchemy version: @@ -21,6 +17,10 @@ Chartreuse no longer installs a database driver. Pick the extra that matches you - The minimum supported Python version is 3.14. Wiremind decommissions Python 3.13. ### Fix +- The compatibility check compares only the major version of the package and of the Helm Chart + `appVersion`, not `major.minor`. A minor release keeps the Helm Chart contract. A chart upgrade within + the same major no longer forces a backend upgrade, and a package upgrade no longer forces a chart + upgrade. - Chartreuse no longer depends on `psycopg2`. The project image provides the database driver. SQLAlchemy selects the driver from the dialect: `postgresql` means psycopg2 with SQLAlchemy 2.0 and psycopg (3) with SQLAlchemy 2.1. See [Upgrade](#upgrade). diff --git a/README.md b/README.md index 2bafe71..67664ae 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ helm repo add wiremind https://wiremind.github.io/wiremind-helm-charts helm install wiremind-crds wiremind/wiremind-crds --version 0.1.0 ``` -- Please make sure Chartreuse Python **Package version** and Chartreuse **Helm Chart version**, you use, share `major.minor` otherwise Chartreuse won't start. +- Please make sure Chartreuse Python **Package version** and Chartreuse **Helm Chart version**, you use, share the same major otherwise Chartreuse won't start. ## Configuration diff --git a/VERSION b/VERSION index a3fcc71..21c8c7b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.1.0 +7.1.1 diff --git a/src/chartreuse/chartreuse_upgrade.py b/src/chartreuse/chartreuse_upgrade.py index 81f5716..f90bde4 100755 --- a/src/chartreuse/chartreuse_upgrade.py +++ b/src/chartreuse/chartreuse_upgrade.py @@ -13,11 +13,11 @@ def ensure_safe_run() -> None: """ The compatibility between the Chartreuse package and Chartreuse Helm Chart is only ensured for - versions with the same "major.minor". + versions with the same major. A minor or patch release of the package keeps the Helm Chart contract. """ package_v: str = get_version() - # Get "1.2" from "1.2.3" - package_v_major_minor: list[str] = package_v.split(".", 2)[:2] + # Get "1" from "1.2.3" + package_v_major: str = package_v.split(".", 1)[0] helm_chart_v: str = os.getenv("HELM_CHART_APP_VERSION", "") if not helm_chart_v: @@ -25,11 +25,11 @@ def ensure_safe_run() -> None: "Couldn't get the Chartreuse's Helm Chart appVersion from the env var HELM_CHART_APP_VERSION," " couldn't make sure that the package is of a compatible version, ABORTING!" ) - helm_chart_v_major_minor: list[str] = helm_chart_v.split(".", 2)[:2] - if helm_chart_v_major_minor != package_v_major_minor: + helm_chart_v_major: str = helm_chart_v.split(".", 1)[0] + if helm_chart_v_major != package_v_major: raise ValueError( f"Chartreuse's Helm Chart version '{helm_chart_v}' and the package's version '{package_v}' " - f"don't have the same 'major.minor' ({helm_chart_v_major_minor} != {package_v_major_minor})," + f"don't have the same major ({helm_chart_v_major!r} != {package_v_major!r})," " they may be incompatible. Make sure they're semver, align them and retry, ABORTING!" ) diff --git a/src/chartreuse/tests/unit_tests/test_chartreuse_restore.py b/src/chartreuse/tests/unit_tests/test_chartreuse_restore.py index 085b920..423d25d 100644 --- a/src/chartreuse/tests/unit_tests/test_chartreuse_restore.py +++ b/src/chartreuse/tests/unit_tests/test_chartreuse_restore.py @@ -32,10 +32,10 @@ def test_chartreuse_restore_restores_stopped_pods(mocker: MockerFixture) -> None def test_chartreuse_restore_incompatible_helm_chart_version(mocker: MockerFixture) -> None: """ Test that chartreuse_restore aborts before touching anything when the package and the - Helm Chart don't have the same major.minor. + Helm Chart don't have the same major. """ mocked_kdm = _configure_deployment_manager_mock(mocker) - mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="5.1.0") + mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="6.0.0") configure_os_environ_mock(mocker=mocker, additional_environment={"HELM_CHART_APP_VERSION": "5.0.0"}) with pytest.raises(ValueError): diff --git a/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade.py b/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade.py index d3df7d7..47dd034 100644 --- a/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade.py +++ b/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade.py @@ -70,13 +70,14 @@ def test_chartreuse_upgrade_no_migration_disabled_stop_pods( ("1.32.1", "1.32.21-dev.12", False), ("12.32.1", "12.32.33.dev.yes.we.can", False), ("2.0.0", "", True), - ("2.0.0", "2.2.3", True), + ("2.0.0", "2.2.3", False), ("2.2.0", "1.8.5", True), ("2.0", "2.0.3.344", False), ("2.0.", "2.0.3.344", False), ("2.0.", "2.0", False), - ("2", "2.0", True), - ("2", "2.0.0", True), + ("2", "2.0", False), + ("2", "2.0.0", False), + ("3.0.0", "2.9.9", True), ], ) def test_chartreuse_upgrade_compatibility_check( diff --git a/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade_extended.py b/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade_extended.py index 3ced5c5..e021f40 100644 --- a/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade_extended.py +++ b/src/chartreuse/tests/unit_tests/test_chartreuse_upgrade_extended.py @@ -12,24 +12,20 @@ class TestEnsureSafeRun: """Test cases for ensure_safe_run function.""" def test_ensure_safe_run_matching_versions(self, mocker: MockerFixture) -> None: - """Test ensure_safe_run with matching major.minor versions.""" + """Test ensure_safe_run with matching major versions.""" mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="5.2.1") mocker.patch.dict(os.environ, {"HELM_CHART_APP_VERSION": "5.2.0"}) # Should not raise any exception ensure_safe_run() - def test_ensure_safe_run_mismatched_versions(self, mocker: MockerFixture) -> None: - """Test ensure_safe_run with mismatched major.minor versions.""" - mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="5.1.3") - mocker.patch.dict(os.environ, {"HELM_CHART_APP_VERSION": "5.2.0"}) - - with pytest.raises(ValueError) as exc_info: - ensure_safe_run() + def test_ensure_safe_run_different_minor_versions(self, mocker: MockerFixture) -> None: + """Test ensure_safe_run accepts a different minor version.""" + mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="7.1.0") + mocker.patch.dict(os.environ, {"HELM_CHART_APP_VERSION": "7.0.0"}) - assert "don't have the same 'major.minor'" in str(exc_info.value) - assert "5.1.3" in str(exc_info.value) - assert "5.2.0" in str(exc_info.value) + # Should not raise any exception + ensure_safe_run() def test_ensure_safe_run_missing_helm_version(self, mocker: MockerFixture) -> None: """Test ensure_safe_run with missing HELM_CHART_APP_VERSION environment variable.""" @@ -59,14 +55,16 @@ def test_ensure_safe_run_different_major_versions(self, mocker: MockerFixture) - with pytest.raises(ValueError) as exc_info: ensure_safe_run() - assert "(['5', '2'] != ['4', '2'])" in str(exc_info.value) + assert "don't have the same major ('5' != '4')" in str(exc_info.value) + assert "4.2.1" in str(exc_info.value) + assert "5.2.0" in str(exc_info.value) def test_ensure_safe_run_complex_version_formats(self, mocker: MockerFixture) -> None: """Test ensure_safe_run with complex version formats.""" mocker.patch("chartreuse.chartreuse_upgrade.get_version", return_value="5.2.1-alpha.1") mocker.patch.dict(os.environ, {"HELM_CHART_APP_VERSION": "5.2.0-beta.2"}) - # Should not raise any exception as major.minor match + # Should not raise any exception as the majors match ensure_safe_run()