mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-09 13:24:04 +02:00
148 lines
4.8 KiB
Python
Executable file
148 lines
4.8 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Update the pytest workflow matrix with latest HA Core versions.
|
|
|
|
This script fetches the latest Home Assistant Core release versions from GitHub
|
|
and updates the pytest workflow matrix to test against them.
|
|
|
|
Usage:
|
|
python scripts/update-test-matrix.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
# Keep the latest stable release month and the preceding 12 monthly release lines.
|
|
# Update this explicit floor when dropping another supported release month.
|
|
MIN_VERSION = (2025, 9)
|
|
|
|
|
|
def get_ha_core_versions() -> list[str]:
|
|
"""Fetch latest stable HA Core versions from GitHub API."""
|
|
all_tags = []
|
|
page = 1
|
|
|
|
# Paginate through all tags to ensure we get older versions too
|
|
while True:
|
|
url = f"https://api.github.com/repos/home-assistant/core/tags?per_page=100&page={page}"
|
|
with urllib.request.urlopen(url) as response:
|
|
tags = json.loads(response.read().decode())
|
|
|
|
if not tags:
|
|
break
|
|
|
|
all_tags.extend(tags)
|
|
|
|
# Check if we've gone far enough back
|
|
# Stop if we've found versions older than our minimum
|
|
oldest_in_page = None
|
|
for t in tags:
|
|
if re.match(r"^\d+\.\d+\.\d+$", t["name"]):
|
|
parts = t["name"].split(".")
|
|
year, month = int(parts[0]), int(parts[1])
|
|
if oldest_in_page is None or (year, month) < oldest_in_page:
|
|
oldest_in_page = (year, month)
|
|
|
|
if oldest_in_page and oldest_in_page < MIN_VERSION:
|
|
break
|
|
|
|
page += 1
|
|
if page > 10: # Safety limit
|
|
break
|
|
|
|
# Filter to stable releases only (no beta/rc)
|
|
stable_pattern = re.compile(r"^\d+\.\d+\.\d+$")
|
|
versions = [t["name"] for t in all_tags if stable_pattern.match(t["name"])]
|
|
|
|
# Group by minor version and get latest patch for each
|
|
latest: dict[str, str] = {}
|
|
for version in versions:
|
|
parts = version.split(".")
|
|
year, month = int(parts[0]), int(parts[1])
|
|
# Only include versions >= MIN_VERSION
|
|
if (year, month) >= MIN_VERSION:
|
|
minor_key = f"{parts[0]}.{parts[1]}"
|
|
# Keep the one with highest patch number
|
|
if minor_key not in latest:
|
|
latest[minor_key] = version
|
|
else:
|
|
current_patch = int(latest[minor_key].split(".")[2])
|
|
new_patch = int(parts[2])
|
|
if new_patch > current_patch:
|
|
latest[minor_key] = version
|
|
|
|
# Sort by version
|
|
return sorted(latest.values(), key=lambda v: [int(x) for x in v.split(".")])
|
|
|
|
|
|
def get_python_version(ha_version: str) -> str:
|
|
"""Determine Python version based on HA Core version."""
|
|
parts = ha_version.split(".")
|
|
year, month = int(parts[0]), int(parts[1])
|
|
# 2025.9 through 2026.2 use Python 3.13.
|
|
# 2026.3+ uses Python 3.14.
|
|
if year > 2026 or (year == 2026 and month >= 3):
|
|
return "3.14.2"
|
|
return "3.13"
|
|
|
|
|
|
def generate_matrix_yaml(versions: list[str]) -> str:
|
|
"""Generate the YAML matrix include block."""
|
|
lines = []
|
|
for version in versions:
|
|
python_ver = get_python_version(version)
|
|
lines.append(f' - core-version: "{version}"')
|
|
lines.append(f' python-version: "{python_ver}"')
|
|
# Add dev version
|
|
lines.append(' - core-version: "dev"')
|
|
lines.append(' python-version: "3.14.2"')
|
|
return "\n".join(lines)
|
|
|
|
|
|
def update_workflow_file(workflow_path: Path, new_matrix: str) -> bool:
|
|
"""Update the workflow file with new matrix. Returns True if changed."""
|
|
content = workflow_path.read_text()
|
|
|
|
# Pattern to match the matrix include block
|
|
# Matches from "include:" to just before " steps:"
|
|
pattern = re.compile(
|
|
r"( include:\n)(.*?)( steps:)",
|
|
re.DOTALL,
|
|
)
|
|
|
|
def replacer(match: re.Match) -> str:
|
|
return f"{match.group(1)}{new_matrix}\n{match.group(3)}"
|
|
|
|
new_content = pattern.sub(replacer, content)
|
|
|
|
if new_content == content:
|
|
return False
|
|
|
|
workflow_path.write_text(new_content)
|
|
return True
|
|
|
|
|
|
def main() -> None:
|
|
"""Main entry point."""
|
|
print("Fetching latest HA Core versions...") # noqa: T201
|
|
versions = get_ha_core_versions()
|
|
print(f"Found {len(versions)} versions: {', '.join(versions)}") # noqa: T201
|
|
|
|
print("\nGenerating matrix...") # noqa: T201
|
|
matrix = generate_matrix_yaml(versions)
|
|
print(matrix) # noqa: T201
|
|
|
|
workflow_path = Path(__file__).parent.parent / ".github/workflows/pytest.yaml"
|
|
print(f"\nUpdating {workflow_path}...") # noqa: T201
|
|
|
|
if update_workflow_file(workflow_path, matrix):
|
|
print("Workflow updated successfully!") # noqa: T201
|
|
else:
|
|
print("No changes needed.") # noqa: T201
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|