Quellcode durchsuchen

metadata_manager: dedupe versions by number preferring stable over beta

Co-authored-by: Cursor <cursoragent@cursor.com>
Shiv Tyagi vor 1 Monat
Ursprung
Commit
1508c762b3

+ 20 - 6
metadata_manager/versions_manager/manager.py

@@ -15,7 +15,7 @@ REMOTES_SCHEMA_PATH = Path(__file__).resolve().parent.parent / "remotes.schema.j
 
 
 def _release_type_dedup_priority(release_type: str) -> int:
-    """Lower value wins when multiple releases share the same version_id."""
+    """Lower value wins when multiple releases collide on a dedup key."""
     match release_type:
         case "stable":
             return 0
@@ -29,6 +29,19 @@ def _release_type_dedup_priority(release_type: str) -> int:
             return 99
 
 
+def _version_dedup_key(version: VersionInfo) -> str:
+    """
+    Collapse releases that share a real version number (e.g. stable+beta 4.7.0).
+
+    Placeholder numbers like "NA" (latest/dev) keep identity by version_id so
+    unrelated entries are not merged.
+    """
+    number = (version.version_number or "").strip()
+    if number and number.upper() != "NA":
+        return f"num:{number}"
+    return f"id:{version.version_id}"
+
+
 class VersionsManager:
     """
     Version manager merges version metadata from different pluggable providers.
@@ -104,18 +117,19 @@ class VersionsManager:
         if vehicle is None:
             raise ValueError(f"Invalid vehicle ID '{vehicle_id}'.")
 
-        by_version_id: dict[str, VersionInfo] = {}
+        by_key: dict[str, VersionInfo] = {}
         for provider in self._providers:
             for version in provider.get_versions(vehicle_id):
-                existing = by_version_id.get(version.version_id)
+                key = _version_dedup_key(version)
+                existing = by_key.get(key)
                 if existing is None:
-                    by_version_id[version.version_id] = version
+                    by_key[key] = version
                     continue
                 if _release_type_dedup_priority(version.release_type) < (
                     _release_type_dedup_priority(existing.release_type)
                 ):
-                    by_version_id[version.version_id] = version
-        return list(by_version_id.values())
+                    by_key[key] = version
+        return list(by_key.values())
 
     def is_version_listed(self, vehicle_id: str, version_id: str) -> bool:
         if vehicle_id is None:

+ 51 - 0
tests/metadata_manager/test_versions_manager.py

@@ -107,6 +107,57 @@ class TestVersionsManagerDedup:
         assert len(versions) == 1
         assert versions[0].release_type == "stable"
 
+    def test_stable_wins_over_beta_with_same_number_different_commits(
+        self, versions_manager
+    ):
+        beta = self._make_version("beta", "4.7.0", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
+        stable = self._make_version(
+            "stable", "4.7.0", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        )
+
+        provider = Mock()
+        provider.get_versions.return_value = [beta, stable]
+        versions_manager._providers = [provider]
+
+        versions = versions_manager.get_versions_for_vehicle("sub")
+
+        assert len(versions) == 1
+        assert versions[0].release_type == "stable"
+        assert versions[0].version_number == "4.7.0"
+        assert versions[0].commit_ref == stable.commit_ref
+
+    def test_different_version_numbers_are_kept(self, versions_manager):
+        stable = self._make_version(
+            "stable", "4.6.0", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        )
+        beta = self._make_version(
+            "beta", "4.7.0", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+        )
+
+        provider = Mock()
+        provider.get_versions.return_value = [stable, beta]
+        versions_manager._providers = [provider]
+
+        versions = versions_manager.get_versions_for_vehicle("sub")
+
+        assert {v.version_number for v in versions} == {"4.6.0", "4.7.0"}
+
+    def test_na_version_numbers_are_not_collapsed(self, versions_manager):
+        latest_a = self._make_version(
+            "latest", "NA", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        )
+        latest_b = self._make_version(
+            "latest", "NA", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+        )
+
+        provider = Mock()
+        provider.get_versions.return_value = [latest_a, latest_b]
+        versions_manager._providers = [provider]
+
+        versions = versions_manager.get_versions_for_vehicle("sub")
+
+        assert len(versions) == 2
+
 
 class TestForkRemoteSpec:
     def test_default_rmackay9_uses_custom_repo_name(self):