This commit is contained in:
95
src/depcheck/analyzers/version.py
Normal file
95
src/depcheck/analyzers/version.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""Version analysis utilities."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from depcheck.models import Severity
|
||||
|
||||
|
||||
class VersionAnalyzer:
|
||||
"""Analyze dependency versions for update recommendations."""
|
||||
|
||||
def __init__(self):
|
||||
self._bump_recommendations = {
|
||||
"major": "major",
|
||||
"minor": "minor",
|
||||
"patch": "patch",
|
||||
}
|
||||
|
||||
def get_update_type(self, current: str, latest: str) -> Optional[str]:
|
||||
"""Determine the type of version bump needed."""
|
||||
if not current or not latest:
|
||||
return None
|
||||
|
||||
current_parts = self._parse_version(current)
|
||||
latest_parts = self._parse_version(latest)
|
||||
|
||||
if not current_parts or not latest_parts:
|
||||
return None
|
||||
|
||||
if latest_parts[0] > current_parts[0]:
|
||||
return "major"
|
||||
if len(latest_parts) > 1 and len(current_parts) > 1:
|
||||
if latest_parts[1] > current_parts[1]:
|
||||
return "minor"
|
||||
if len(latest_parts) > 2 and len(current_parts) > 2:
|
||||
if latest_parts[2] > current_parts[2]:
|
||||
return "patch"
|
||||
|
||||
return None
|
||||
|
||||
def _parse_version(self, version: str) -> tuple:
|
||||
"""Parse version string into tuple of integers."""
|
||||
version = version.strip().lstrip("vV")
|
||||
parts = []
|
||||
for part in version.split("."):
|
||||
cleaned = "".join(c for c in part if c.isdigit())
|
||||
if cleaned:
|
||||
parts.append(int(cleaned))
|
||||
else:
|
||||
parts.append(0)
|
||||
return tuple(parts)
|
||||
|
||||
def get_severity_for_update(self, update_type: Optional[str]) -> Severity:
|
||||
"""Map update type to severity level."""
|
||||
mapping = {
|
||||
"major": Severity.HIGH,
|
||||
"minor": Severity.MEDIUM,
|
||||
"patch": Severity.LOW,
|
||||
}
|
||||
if update_type is None:
|
||||
return Severity.INFO
|
||||
return mapping.get(update_type, Severity.INFO)
|
||||
|
||||
def suggest_safe_upgrade(self, current: str, update_type: str) -> str:
|
||||
"""Suggest a safe upgrade version based on current version and update type."""
|
||||
parts = self._parse_version(current)
|
||||
if not parts:
|
||||
return current
|
||||
|
||||
while len(parts) < 3:
|
||||
parts = parts + (0,)
|
||||
|
||||
if update_type == "major":
|
||||
return f"{parts[0] + 1}.0.0"
|
||||
elif update_type == "minor":
|
||||
return f"{parts[0]}.{parts[1] + 1}.0"
|
||||
elif update_type == "patch":
|
||||
return f"{parts[0]}.{parts[1]}.{parts[2] + 1}"
|
||||
|
||||
return current
|
||||
|
||||
def compare_versions(self, v1: str, v2: str) -> int:
|
||||
"""Compare two version strings."""
|
||||
parts1 = self._parse_version(v1)
|
||||
parts2 = self._parse_version(v2)
|
||||
|
||||
for i in range(max(len(parts1), len(parts2))):
|
||||
p1 = parts1[i] if i < len(parts1) else 0
|
||||
p2 = parts2[i] if i < len(parts2) else 0
|
||||
|
||||
if p1 > p2:
|
||||
return 1
|
||||
elif p1 < p2:
|
||||
return -1
|
||||
|
||||
return 0
|
||||
Reference in New Issue
Block a user