1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-14 23:28:42 +00:00

Validate core_files.yaml base_platforms completeness (#162826)

This commit is contained in:
Abílio Costa
2026-02-12 11:59:19 +00:00
committed by GitHub
parent f4440e992f
commit 0576dd91b7
4 changed files with 152 additions and 1 deletions

View File

@@ -22,6 +22,7 @@ base_platforms: &base_platforms
- homeassistant/components/calendar/**
- homeassistant/components/camera/**
- homeassistant/components/climate/**
- homeassistant/components/conversation/**
- homeassistant/components/cover/**
- homeassistant/components/date/**
- homeassistant/components/datetime/**
@@ -53,6 +54,7 @@ base_platforms: &base_platforms
- homeassistant/components/update/**
- homeassistant/components/vacuum/**
- homeassistant/components/valve/**
- homeassistant/components/wake_word/**
- homeassistant/components/water_heater/**
- homeassistant/components/weather/**
@@ -70,7 +72,6 @@ components: &components
- homeassistant/components/cloud/**
- homeassistant/components/config/**
- homeassistant/components/configurator/**
- homeassistant/components/conversation/**
- homeassistant/components/demo/**
- homeassistant/components/device_automation/**
- homeassistant/components/dhcp/**

View File

@@ -15,6 +15,7 @@ from . import (
conditions,
config_flow,
config_schema,
core_files,
dependencies,
dhcp,
docker,
@@ -62,6 +63,7 @@ INTEGRATION_PLUGINS = [
config_flow, # This needs to run last, after translations are processed
]
HASS_PLUGINS = [
core_files,
docker,
mypy_config,
metadata,

View File

@@ -0,0 +1,50 @@
"""Validate .core_files.yaml base_platforms alignment with entity platforms."""
import re
from homeassistant.util.yaml import load_yaml_dict
from .model import Config, Integration
# Non-entity-platform components that belong in base_platforms
EXTRA_BASE_PLATFORMS = {"diagnostics"}
_COMPONENT_RE = re.compile(r"homeassistant/components/([^/]+)/\*\*")
def validate(integrations: dict[str, Integration], config: Config) -> None:
"""Validate that base_platforms in .core_files.yaml matches entity platforms."""
if config.specific_integrations:
return
core_files_path = config.root / ".core_files.yaml"
core_files = load_yaml_dict(str(core_files_path))
base_platform_entries = {
match.group(1)
for entry in core_files["base_platforms"]
if (match := _COMPONENT_RE.match(entry))
}
entity_platforms = {
integration.domain
for integration in integrations.values()
if integration.manifest.get("integration_type") == "entity"
and integration.domain != "tag"
}
expected = entity_platforms | EXTRA_BASE_PLATFORMS
for domain in sorted(expected - base_platform_entries):
config.add_error(
"core_files",
f"Entity platform '{domain}' is missing from "
"base_platforms in .core_files.yaml",
)
for domain in sorted(base_platform_entries - expected):
config.add_error(
"core_files",
f"'{domain}' in base_platforms in .core_files.yaml "
"is not an entity platform or in EXTRA_BASE_PLATFORMS",
)

View File

@@ -0,0 +1,98 @@
"""Tests for hassfest core_files validation."""
from pathlib import Path
from unittest.mock import patch
from script.hassfest.core_files import EXTRA_BASE_PLATFORMS, validate
from script.hassfest.model import Config, Integration
def _create_integration(
config: Config, domain: str, integration_type: str = "hub"
) -> Integration:
"""Create a minimal Integration with the given type."""
integration = Integration(config.core_integrations_path / domain, _config=config)
integration._manifest = {
"domain": domain,
"name": domain,
"integration_type": integration_type,
}
return integration
def _create_core_files_yaml(base_platforms: list[str]) -> dict:
"""Build a minimal .core_files.yaml dict."""
return {
"base_platforms": [f"homeassistant/components/{p}/**" for p in base_platforms],
}
def test_skip_specific_integrations() -> None:
"""Test that validation is skipped for specific integrations."""
config = Config(
root=Path(".").absolute(),
specific_integrations=[Path("some/path")],
action="validate",
requirements=False,
)
# Should not raise or add errors — it just returns early
validate({}, config)
assert not config.errors
def test_valid_alignment(config: Config) -> None:
"""Test no errors when base_platforms matches entity platforms."""
integrations = {
"sensor": _create_integration(config, "sensor", "entity"),
"light": _create_integration(config, "light", "entity"),
"tag": _create_integration(config, "tag", "entity"), # excluded
"mqtt": _create_integration(config, "mqtt", "hub"),
}
core_files = _create_core_files_yaml(["sensor", "light", *EXTRA_BASE_PLATFORMS])
with patch("script.hassfest.core_files.load_yaml_dict", return_value=core_files):
validate(integrations, config)
assert not config.errors
def test_missing_entity_platform(config: Config) -> None:
"""Test error when an entity platform is missing from base_platforms."""
integrations = {
"sensor": _create_integration(config, "sensor", "entity"),
"light": _create_integration(config, "light", "entity"),
}
# light is missing from base_platforms
core_files = _create_core_files_yaml(["sensor", *EXTRA_BASE_PLATFORMS])
with patch("script.hassfest.core_files.load_yaml_dict", return_value=core_files):
validate(integrations, config)
assert len(config.errors) == 1
assert (
config.errors[0].error
== "Entity platform 'light' is missing from base_platforms in .core_files.yaml"
)
def test_unexpected_entry(config: Config) -> None:
"""Test error when base_platforms contains a non-entity-platform entry."""
integrations = {
"sensor": _create_integration(config, "sensor", "entity"),
}
core_files = _create_core_files_yaml(
["sensor", "unknown_thing", *EXTRA_BASE_PLATFORMS]
)
with patch("script.hassfest.core_files.load_yaml_dict", return_value=core_files):
validate(integrations, config)
assert len(config.errors) == 1
assert (
config.errors[0].error
== "'unknown_thing' in base_platforms in .core_files.yaml is not an entity platform or in EXTRA_BASE_PLATFORMS"
)