1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-21 19:23:45 +01:00
Files
esphome/script/ci_memory_impact_detector.py
2025-10-14 13:05:02 -10:00

135 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Detect if a PR changes exactly one component for memory impact analysis.
This script is used by the CI workflow to determine if a PR should trigger
memory impact analysis. The analysis only runs when:
1. Exactly one component has changed (not counting core changes)
2. The component has at least one test configuration
The script outputs GitHub Actions environment variables to control the workflow.
"""
from __future__ import annotations
from pathlib import Path
import sys
# Add esphome to path
sys.path.insert(0, str(Path(__file__).parent.parent))
# pylint: disable=wrong-import-position
from script.ci_helpers import write_github_output
from script.helpers import ESPHOME_COMPONENTS_PATH, changed_files
# Platform preference order for memory impact analysis
# Ordered by production relevance and memory constraint importance
PLATFORM_PREFERENCE = [
"esp32-idf", # Primary ESP32 IDF platform
"esp32-c3-idf", # ESP32-C3 IDF
"esp32-c6-idf", # ESP32-C6 IDF
"esp32-s2-idf", # ESP32-S2 IDF
"esp32-s3-idf", # ESP32-S3 IDF
"esp32-c2-idf", # ESP32-C2 IDF
"esp32-c5-idf", # ESP32-C5 IDF
"esp32-h2-idf", # ESP32-H2 IDF
"esp32-p4-idf", # ESP32-P4 IDF
"esp8266-ard", # ESP8266 Arduino (memory constrained)
"esp32-ard", # ESP32 Arduino
"esp32-c3-ard", # ESP32-C3 Arduino
"esp32-s2-ard", # ESP32-S2 Arduino
"esp32-s3-ard", # ESP32-S3 Arduino
"bk72xx-ard", # BK72xx Arduino
"rp2040-ard", # RP2040 Arduino
"nrf52-adafruit", # nRF52 Adafruit
"host", # Host platform (development/testing)
]
def find_test_for_component(component: str) -> tuple[str | None, str | None]:
"""Find a test configuration for the given component.
Prefers platforms based on PLATFORM_PREFERENCE order.
Args:
component: Component name
Returns:
Tuple of (test_file_name, platform) or (None, None) if no test found
"""
tests_dir = Path(__file__).parent.parent / "tests" / "components" / component
if not tests_dir.exists():
return None, None
# Look for test files
test_files = list(tests_dir.glob("test.*.yaml"))
if not test_files:
return None, None
# Try each preferred platform in order
for preferred_platform in PLATFORM_PREFERENCE:
for test_file in test_files:
parts = test_file.stem.split(".")
if len(parts) >= 2:
platform = parts[1]
if platform == preferred_platform:
return test_file.name, platform
# Fall back to first test file
test_file = test_files[0]
parts = test_file.stem.split(".")
platform = parts[1] if len(parts) >= 2 else "esp32-idf"
return test_file.name, platform
def detect_single_component_change() -> None:
"""Detect if exactly one component changed and output GitHub Actions variables."""
files = changed_files()
# Find all changed components (excluding core)
changed_components = set()
for file in files:
if file.startswith(ESPHOME_COMPONENTS_PATH):
parts = file.split("/")
if len(parts) >= 3:
component = parts[2]
# Skip base bus components as they're used across many builds
if component not in ["i2c", "spi", "uart", "modbus"]:
changed_components.add(component)
# Only proceed if exactly one component changed
if len(changed_components) != 1:
print(
f"Found {len(changed_components)} component(s) changed, skipping memory analysis"
)
write_github_output({"should_run": "false"})
return
component = list(changed_components)[0]
print(f"Detected single component change: {component}")
# Find a test configuration for this component
test_file, platform = find_test_for_component(component)
if not test_file:
print(f"No test configuration found for {component}, skipping memory analysis")
write_github_output({"should_run": "false"})
return
print(f"Found test: {test_file} for platform: {platform}")
print("Memory impact analysis will run")
write_github_output(
{
"should_run": "true",
"component": component,
"test_file": test_file,
"platform": platform,
}
)
if __name__ == "__main__":
detect_single_component_change()