mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-02-24 09:56:20 +00:00
fix: Adapt versioning scheme to Home Assistant and switch to uv (#896)
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
Home Assistant expects versioning always increases numbers. Add a date component to the development version to comply with this expectation. The scheme is now 0.0.0.dev<date><hash>. Use uv for creating and managing the virtual environment for developement. This enourmously speeds up dependency updates. For this change dependency requirements are now solely handled in pyproject.toml. requirements.tx and requirements-dev.txt are deleted. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
42
scripts/cz_check_branch.py
Normal file → Executable file
42
scripts/cz_check_branch.py
Normal file → Executable file
@@ -11,16 +11,40 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def find_cz() -> str:
|
||||
venv = os.getenv("VIRTUAL_ENV")
|
||||
paths = [Path(venv)] if venv else []
|
||||
paths.append(Path.cwd() / ".venv")
|
||||
def find_cz() -> list[str]:
|
||||
"""Return command to invoke Commitizen via virtualenv or globally."""
|
||||
candidates = []
|
||||
|
||||
for base in paths:
|
||||
cz = base / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz.exists():
|
||||
return str(cz)
|
||||
return "cz"
|
||||
# 1️⃣ Currently active virtualenv
|
||||
venv = os.getenv("VIRTUAL_ENV")
|
||||
if venv:
|
||||
candidates.append(Path(venv))
|
||||
|
||||
# 2️⃣ uv-managed virtualenv
|
||||
uv_venv = Path(".uv") / "venv"
|
||||
if uv_venv.exists():
|
||||
candidates.append(uv_venv)
|
||||
|
||||
# 3️⃣ traditional .venv
|
||||
dot_venv = Path(".venv")
|
||||
if dot_venv.exists():
|
||||
candidates.append(dot_venv)
|
||||
|
||||
# Check each candidate for Commitizen binary
|
||||
for base in candidates:
|
||||
cz_path = base / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz_path.exists():
|
||||
return [str(cz_path)]
|
||||
|
||||
# 4️⃣ fallback to uv run cz
|
||||
try:
|
||||
subprocess.run(["uv", "run", "cz", "--version"], check=True, stdout=subprocess.DEVNULL)
|
||||
return ["uv", "run", "cz"]
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
# 5️⃣ fallback to system cz
|
||||
return ["cz"]
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
53
scripts/cz_check_commit_message.py
Normal file → Executable file
53
scripts/cz_check_commit_message.py
Normal file → Executable file
@@ -2,6 +2,12 @@
|
||||
"""Commitizen commit message checker that is .venv aware.
|
||||
|
||||
Works for commits with -m or commit message file.
|
||||
|
||||
Cross-platform + uv/.venv aware:
|
||||
- Prefers activated virtual environment (VIRTUAL_ENV)
|
||||
- Falls back to uv-managed .uv/venv
|
||||
- Falls back to .venv
|
||||
- Falls back to global cz
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -10,19 +16,40 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def find_cz() -> str:
|
||||
"""Find Commitizen executable, preferring virtualenv."""
|
||||
venv = os.getenv("VIRTUAL_ENV")
|
||||
paths = []
|
||||
if venv:
|
||||
paths.append(Path(venv))
|
||||
paths.append(Path.cwd() / ".venv")
|
||||
def find_cz() -> list[str]:
|
||||
"""Return command to invoke Commitizen via virtualenv or globally."""
|
||||
candidates = []
|
||||
|
||||
for base in paths:
|
||||
cz = base / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz.exists():
|
||||
return str(cz)
|
||||
return "cz"
|
||||
# 1️⃣ Currently active virtualenv
|
||||
venv = os.getenv("VIRTUAL_ENV")
|
||||
if venv:
|
||||
candidates.append(Path(venv))
|
||||
|
||||
# 2️⃣ uv-managed virtualenv
|
||||
uv_venv = Path(".uv") / "venv"
|
||||
if uv_venv.exists():
|
||||
candidates.append(uv_venv)
|
||||
|
||||
# 3️⃣ traditional .venv
|
||||
dot_venv = Path(".venv")
|
||||
if dot_venv.exists():
|
||||
candidates.append(dot_venv)
|
||||
|
||||
# Check each candidate for Commitizen binary
|
||||
for base in candidates:
|
||||
cz_path = base / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz_path.exists():
|
||||
return [str(cz_path)]
|
||||
|
||||
# 4️⃣ fallback to uv run cz
|
||||
try:
|
||||
subprocess.run(["uv", "run", "cz", "--version"], check=True, stdout=subprocess.DEVNULL)
|
||||
return ["uv", "run", "cz"]
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
# 5️⃣ fallback to system cz
|
||||
return ["cz"]
|
||||
|
||||
|
||||
def main():
|
||||
@@ -47,7 +74,7 @@ def main():
|
||||
print(f"🔍 Checking commit message using {cz}...")
|
||||
|
||||
try:
|
||||
subprocess.check_call([cz, "check", "--commit-msg-file", commit_msg_file])
|
||||
subprocess.check_call(cz + ["check", "--commit-msg-file", commit_msg_file])
|
||||
print("✅ Commit message follows Commitizen convention.")
|
||||
return 0
|
||||
except subprocess.CalledProcessError:
|
||||
|
||||
58
scripts/cz_check_new_commits.py
Normal file → Executable file
58
scripts/cz_check_new_commits.py
Normal file → Executable file
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pre-push hook: Commitizen check for *new commits only*.
|
||||
|
||||
Cross-platform + virtualenv-aware:
|
||||
Cross-platform + uv/.venv aware:
|
||||
- Prefers activated virtual environment (VIRTUAL_ENV)
|
||||
- Falls back to ./.venv if found
|
||||
- Falls back to global cz otherwise
|
||||
- Falls back to uv-managed .uv/venv
|
||||
- Falls back to .venv
|
||||
- Falls back to global cz
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -13,23 +14,40 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def find_cz_executable() -> str:
|
||||
"""Return path to Commitizen executable, preferring virtual environments."""
|
||||
# 1️⃣ Active virtual environment (if running inside one)
|
||||
venv_env = os.getenv("VIRTUAL_ENV")
|
||||
if venv_env:
|
||||
cz_path = Path(venv_env) / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
def find_cz() -> list[str]:
|
||||
"""Return command to invoke Commitizen via virtualenv or globally."""
|
||||
candidates = []
|
||||
|
||||
# 1️⃣ Currently active virtualenv
|
||||
venv = os.getenv("VIRTUAL_ENV")
|
||||
if venv:
|
||||
candidates.append(Path(venv))
|
||||
|
||||
# 2️⃣ uv-managed virtualenv
|
||||
uv_venv = Path(".uv") / "venv"
|
||||
if uv_venv.exists():
|
||||
candidates.append(uv_venv)
|
||||
|
||||
# 3️⃣ traditional .venv
|
||||
dot_venv = Path(".venv")
|
||||
if dot_venv.exists():
|
||||
candidates.append(dot_venv)
|
||||
|
||||
# Check each candidate for Commitizen binary
|
||||
for base in candidates:
|
||||
cz_path = base / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz_path.exists():
|
||||
return str(cz_path)
|
||||
return [str(cz_path)]
|
||||
|
||||
# 2️⃣ Local .venv in repo root
|
||||
repo_venv = Path.cwd() / ".venv"
|
||||
cz_path = repo_venv / ("Scripts" if os.name == "nt" else "bin") / ("cz.exe" if os.name == "nt" else "cz")
|
||||
if cz_path.exists():
|
||||
return str(cz_path)
|
||||
# 4️⃣ fallback to uv run cz
|
||||
try:
|
||||
subprocess.run(["uv", "run", "cz", "--version"], check=True, stdout=subprocess.DEVNULL)
|
||||
return ["uv", "run", "cz"]
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
# 3️⃣ Global fallback
|
||||
return "cz"
|
||||
# 5️⃣ fallback to system cz
|
||||
return ["cz"]
|
||||
|
||||
|
||||
def get_merge_base() -> str | None:
|
||||
@@ -48,17 +66,17 @@ def get_merge_base() -> str | None:
|
||||
|
||||
|
||||
def main() -> int:
|
||||
cz = find_cz_executable()
|
||||
cz = find_cz()
|
||||
base = get_merge_base()
|
||||
|
||||
if not base:
|
||||
print("⚠️ No upstream found; skipping Commitizen check for new commits.")
|
||||
print("⚠️ No upstream found; skipping Commitizen check {cz} for new commits.")
|
||||
return 0
|
||||
|
||||
print(f"🔍 Using {cz} to check new commits from {base}..HEAD ...")
|
||||
|
||||
try:
|
||||
subprocess.check_call([cz, "check", "--rev-range", f"{base}..HEAD"])
|
||||
subprocess.check_call(cz + ["check", "--rev-range", f"{base}..HEAD"])
|
||||
print("✅ All new commits follow Commitizen conventions.")
|
||||
return 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
|
||||
@@ -14,6 +14,11 @@ from loguru import logger
|
||||
from pydantic.fields import ComputedFieldInfo, FieldInfo
|
||||
from pydantic_core import PydanticUndefined
|
||||
|
||||
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
SRC_DIR = PROJECT_ROOT / "src"
|
||||
sys.path.insert(0, str(SRC_DIR))
|
||||
|
||||
from akkudoktoreos.config.config import ConfigEOS, default_data_folder_path
|
||||
from akkudoktoreos.core.coreabc import get_config, singletons_init
|
||||
from akkudoktoreos.core.pydantic import PydanticBaseModel
|
||||
|
||||
@@ -18,6 +18,12 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
SRC_DIR = PROJECT_ROOT / "src"
|
||||
sys.path.insert(0, str(SRC_DIR))
|
||||
|
||||
from akkudoktoreos.core.coreabc import get_config
|
||||
from akkudoktoreos.server.eos import app
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
#!.venv/bin/python
|
||||
"""Get version of EOS"""
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 11):
|
||||
print(
|
||||
f"ERROR: Python >=3.11 is required. Found {sys.version_info.major}.{sys.version_info.minor}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Add the src directory to sys.path so Sphinx can import akkudoktoreos
|
||||
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
SRC_DIR = PROJECT_ROOT / "src"
|
||||
sys.path.insert(0, str(SRC_DIR))
|
||||
|
||||
from akkudoktoreos.core.version import __version__
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(__version__)
|
||||
# Import here to prevent mypy to execute the functions that evaluate __version__
|
||||
try:
|
||||
from akkudoktoreos.core.version import __version__
|
||||
version = __version__
|
||||
except Exception:
|
||||
# This may be a first time install
|
||||
raise RuntimeError("Can not find out version!")
|
||||
version = "0.0.0"
|
||||
|
||||
print(version)
|
||||
|
||||
@@ -11,6 +11,12 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
# Add the src directory to sys.path so import akkudoktoreos works in all cases
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
SRC_DIR = PROJECT_ROOT / "src"
|
||||
sys.path.insert(0, str(SRC_DIR))
|
||||
|
||||
|
||||
# --- Patterns to match version strings ---
|
||||
VERSION_PATTERNS = [
|
||||
# Python: __version__ = "1.2.3"
|
||||
@@ -88,6 +94,21 @@ def update_version_in_file(file_path: Path, new_version: str) -> bool:
|
||||
return file_would_be_updated
|
||||
|
||||
|
||||
def update_version_date_file() -> str:
|
||||
"""Write current version date to __version_date__.py"""
|
||||
from akkudoktoreos.core.version import VERSION_DATE_FILE, _version_date_hash
|
||||
|
||||
version_date, _ = _version_date_hash()
|
||||
version_date_str = version_date.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
content = f'VERSION_DATE = "{version_date_str}"\n'
|
||||
|
||||
VERSION_DATE_FILE.write_text(content)
|
||||
|
||||
print(f"Updated {VERSION_DATE_FILE} with UTC date {version_date_str}")
|
||||
|
||||
return str(VERSION_DATE_FILE)
|
||||
|
||||
|
||||
def main(version: str, files: List[str]):
|
||||
if not version:
|
||||
raise ValueError("No version provided")
|
||||
@@ -103,6 +124,8 @@ def main(version: str, files: List[str]):
|
||||
if update_version_in_file(path, version):
|
||||
updated_files.append(str(path))
|
||||
|
||||
updated_files.append(update_version_date_file())
|
||||
|
||||
if updated_files:
|
||||
print(f"Updated files: {', '.join(updated_files)}")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user