From 3d673ac55e571624620b72fb4a3b9e934ea7670b Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 17 Dec 2025 16:13:18 -0500 Subject: [PATCH] [ci] Check changed headers in clang-tidy when using --changed (#12540) Co-authored-by: Claude --- script/clang-tidy | 26 +++++++++++++++++++------- script/helpers.py | 29 ++++++++++++++++------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/script/clang-tidy b/script/clang-tidy index 142b616119..17bcafacc7 100755 --- a/script/clang-tidy +++ b/script/clang-tidy @@ -253,19 +253,31 @@ def main(): print(f"Split {args.split_at}/{args.split_num}: checking {len(files)} files") # Print file count before adding header file - print(f"\nTotal files to check: {len(files)}") + print(f"\nTotal cpp files to check: {len(files)}") + + # Add header file for checking (before early exit check) + if args.all_headers and args.split_at in (None, 1): + # When --changed is used, only include changed headers instead of all headers + if args.changed: + all_headers = [ + os.path.relpath(p, cwd) for p in git_ls_files(["esphome/**/*.h"]) + ] + changed_headers = filter_changed(all_headers) + if changed_headers: + build_all_include(changed_headers) + files.insert(0, temp_header_file) + else: + print("No changed headers to check") + else: + build_all_include() + files.insert(0, temp_header_file) + print(f"Added all-include header file, new total: {len(files)}") # Early exit if no files to check if not files: print("No files to check - exiting early") return 0 - # Only build header file if we have actual files to check - if args.all_headers and args.split_at in (None, 1): - build_all_include() - files.insert(0, temp_header_file) - print(f"Added all-include header file, new total: {len(files)}") - # Print final file list before loading idedata print_file_list(files, "Final files to process:") diff --git a/script/helpers.py b/script/helpers.py index 06a50a3092..202ac9b5fc 100644 --- a/script/helpers.py +++ b/script/helpers.py @@ -156,22 +156,25 @@ def print_error_for_file(file: str | Path, body: str | None) -> None: print() -def build_all_include() -> None: - # Build a cpp file that includes all header files in this repo. - # Otherwise header-only integrations would not be tested by clang-tidy +def build_all_include(header_files: list[str] | None = None) -> None: + # Build a cpp file that includes header files for clang-tidy to check. + # If header_files is provided, only include those headers. + # Otherwise, include all header files in the esphome directory. - # Use git ls-files to find all .h files in the esphome directory - # This is much faster than walking the filesystem - cmd = ["git", "ls-files", "esphome/**/*.h"] - proc = subprocess.run(cmd, capture_output=True, text=True, check=True) + if header_files is None: + # Use git ls-files to find all .h files in the esphome directory + # This is much faster than walking the filesystem + cmd = ["git", "ls-files", "esphome/**/*.h"] + proc = subprocess.run(cmd, capture_output=True, text=True, check=True) - # Process git output - git already returns paths relative to repo root - headers = [ - f'#include "{include_p}"' - for line in proc.stdout.strip().split("\n") - if (include_p := line.replace(os.path.sep, "/")) - ] + # Process git output - git already returns paths relative to repo root + header_files = [ + line.replace(os.path.sep, "/") + for line in proc.stdout.strip().split("\n") + if line + ] + headers = [f'#include "{h}"' for h in header_files] headers.sort() headers.append("") content = "\n".join(headers)