mirror of
https://github.com/esphome/esphome.git
synced 2026-09-25 22:10:21 +00:00
[ci] Run downstream device-builder tests against PR Python code
Add a CI job that checks out esphome/device-builder@main, installs it, overlays the PR's esphome via `pip install -e ./esphome`, and runs its pytest suite. Gated by determine-jobs.py: only runs when Python files under esphome/ change or runtime deps (requirements.txt, pyproject.toml) change -- the surface device-builder consumes when it imports esphome. This catches downstream breakage at PR time instead of after release, mirroring the yarl -> aiohttp pattern.
This commit is contained in:
@@ -10,6 +10,7 @@ what files have changed. It outputs JSON with the following structure:
|
||||
"clang_tidy": true/false,
|
||||
"clang_format": true/false,
|
||||
"python_linters": true/false,
|
||||
"device_builder": true/false,
|
||||
"changed_components": ["component1", "component2", ...],
|
||||
"component_test_count": 5,
|
||||
"memory_impact": {
|
||||
@@ -25,6 +26,7 @@ The CI workflow uses this information to:
|
||||
- Skip or run clang-tidy (and whether to do a full scan)
|
||||
- Skip or run clang-format
|
||||
- Skip or run Python linters (ruff, flake8, pylint, pyupgrade)
|
||||
- Skip or run downstream esphome/device-builder tests against the PR's Python code
|
||||
- Determine which components to test individually
|
||||
- Decide how to split component tests (if there are many)
|
||||
- Run memory impact analysis whenever there are changed components (merged config), and also for core-only changes
|
||||
@@ -440,6 +442,39 @@ def should_run_import_time(branch: str | None = None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
# Files outside esphome/**/*.py whose changes can affect the downstream
|
||||
# device-builder build. requirements.txt / pyproject.toml change the runtime
|
||||
# dependency graph that device-builder picks up when it installs esphome.
|
||||
DEVICE_BUILDER_TRIGGER_FILES = frozenset(
|
||||
{
|
||||
"requirements.txt",
|
||||
"pyproject.toml",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def should_run_device_builder(branch: str | None = None) -> bool:
|
||||
"""Determine if downstream esphome/device-builder tests should run.
|
||||
|
||||
device-builder imports esphome as a library, so whenever the importable
|
||||
Python surface or the runtime dependencies change we re-run its test
|
||||
suite against the PR's code to catch breakage we'd otherwise only see
|
||||
after a release.
|
||||
|
||||
Args:
|
||||
branch: Branch to compare against. If None, uses default.
|
||||
|
||||
Returns:
|
||||
True if the device-builder downstream tests should run, False otherwise.
|
||||
"""
|
||||
for file in changed_files(branch):
|
||||
if file.startswith("esphome/") and file.endswith(PYTHON_FILE_EXTENSIONS):
|
||||
return True
|
||||
if file in DEVICE_BUILDER_TRIGGER_FILES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def determine_cpp_unit_tests(
|
||||
branch: str | None = None,
|
||||
) -> tuple[bool, list[str]]:
|
||||
@@ -874,6 +909,7 @@ def main() -> None:
|
||||
run_clang_format = should_run_clang_format(args.branch)
|
||||
run_python_linters = should_run_python_linters(args.branch)
|
||||
run_import_time = should_run_import_time(args.branch)
|
||||
run_device_builder = should_run_device_builder(args.branch)
|
||||
changed_cpp_file_count = count_changed_cpp_files(args.branch)
|
||||
|
||||
# Get changed components
|
||||
@@ -1007,6 +1043,7 @@ def main() -> None:
|
||||
"clang_format": run_clang_format,
|
||||
"python_linters": run_python_linters,
|
||||
"import_time": run_import_time,
|
||||
"device_builder": run_device_builder,
|
||||
"changed_components": changed_components,
|
||||
"changed_components_with_tests": changed_components_with_tests,
|
||||
"directly_changed_components_with_tests": list(directly_changed_with_tests),
|
||||
|
||||
Reference in New Issue
Block a user