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:
@@ -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/**
|
||||
|
||||
@@ -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,
|
||||
|
||||
50
script/hassfest/core_files.py
Normal file
50
script/hassfest/core_files.py
Normal 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",
|
||||
)
|
||||
98
tests/hassfest/test_core_files.py
Normal file
98
tests/hassfest/test_core_files.py
Normal 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"
|
||||
)
|
||||
Reference in New Issue
Block a user