diff --git a/.coveragerc b/.coveragerc index c02a6fefe75..ceff3384202 100644 --- a/.coveragerc +++ b/.coveragerc @@ -6,11 +6,12 @@ source = homeassistant omit = homeassistant/__main__.py + homeassistant/helpers/backports/aiohttp_resolver.py homeassistant/helpers/signal.py homeassistant/scripts/__init__.py + homeassistant/scripts/benchmark/__init__.py homeassistant/scripts/check_config.py homeassistant/scripts/ensure_config.py - homeassistant/scripts/benchmark/__init__.py homeassistant/scripts/macos/__init__.py # omit pieces of code that rely on external devices being present diff --git a/script/hassfest/coverage.py b/script/hassfest/coverage.py index 264960a42e1..686a6697e49 100644 --- a/script/hassfest/coverage.py +++ b/script/hassfest/coverage.py @@ -20,24 +20,17 @@ DONT_IGNORE = ( "scene.py", ) -PREFIX = """# Sorted by hassfest. +CORE_PREFIX = """# Sorted by hassfest. # # To sort, run python3 -m script.hassfest -p coverage [run] source = homeassistant omit = - homeassistant/__main__.py - homeassistant/helpers/signal.py - homeassistant/scripts/__init__.py - homeassistant/scripts/check_config.py - homeassistant/scripts/ensure_config.py - homeassistant/scripts/benchmark/__init__.py - homeassistant/scripts/macos/__init__.py - - # omit pieces of code that rely on external devices being present """ - +COMPONENTS_PREFIX = ( + " # omit pieces of code that rely on external devices being present\n" +) SUFFIX = """[report] # Regexes for lines to exclude from consideration exclude_lines = @@ -62,6 +55,7 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: coverage_path = config.root / ".coveragerc" not_found: list[str] = [] + unsorted: list[str] = [] checking = False previous_line = "" @@ -69,6 +63,10 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: for line in fp: line = line.strip() + if line == COMPONENTS_PREFIX.strip(): + previous_line = "" + continue + if not line or line.startswith("#"): continue @@ -92,27 +90,21 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: not_found.append(line) continue + if line < previous_line: + unsorted.append(line) + previous_line = line + if not line.startswith("homeassistant/components/"): continue - integration_path = path.parent - while len(integration_path.parts) > 3: - integration_path = integration_path.parent - - integration = integrations[integration_path.name] - - # Ensure sorted - if line < previous_line: - integration.add_error( - "coverage", - f"{line} is unsorted in .coveragerc file", - ) - previous_line = line - - # Ignore sub-directories for further checks + # Ignore sub-directories if len(path.parts) > 4: continue + integration_path = path.parent + + integration = integrations[integration_path.name] + if ( path.parts[-1] == "*" and Path(f"tests/components/{integration.domain}/__init__.py").exists() @@ -132,6 +124,15 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: f"{check} must not be ignored by the .coveragerc file", ) + if unsorted: + config.add_error( + "coverage", + "Paths are unsorted in .coveragerc file. " + "Run python3 -m script.hassfest\n - " + f"{'\n - '.join(unsorted)}", + fixable=True, + ) + if not_found: raise RuntimeError( f".coveragerc references files that don't exist: {', '.join(not_found)}." @@ -141,23 +142,31 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: def generate(integrations: dict[str, Integration], config: Config) -> None: """Sort coverage.""" coverage_path = config.root / ".coveragerc" - lines = [] - start = False + core = [] + components = [] + section = "header" with coverage_path.open("rt") as fp: for line in fp: - if ( - not start - and line - == " # omit pieces of code that rely on external devices being present\n" - ): - start = True - elif line == "[report]\n": + if line == "[report]\n": break - elif start and line != "\n": - lines.append(line) - content = f"{PREFIX}{"".join(sorted(lines))}\n\n{SUFFIX}" + if section != "core" and line == "omit =\n": + section = "core" + elif section != "components" and line == COMPONENTS_PREFIX: + section = "components" + elif section == "core" and line != "\n": + core.append(line) + elif section == "components" and line != "\n": + components.append(line) + + assert core, "core should be a non-empty list" + assert components, "components should be a non-empty list" + content = ( + f"{CORE_PREFIX}{"".join(sorted(core))}\n" + f"{COMPONENTS_PREFIX}{"".join(sorted(components))}\n" + f"\n{SUFFIX}" + ) with coverage_path.open("w") as fp: fp.write(content)