[ci] Carry native-toolchain needs on component test batches (#17359)

This commit is contained in:
Jonathan Swoboda
2026-07-03 13:47:08 -04:00
committed by GitHub
parent fd16eec416
commit 187cd51867
3 changed files with 33 additions and 19 deletions
+8 -6
View File
@@ -795,7 +795,7 @@ jobs:
if: always()
test-build-components-split:
name: Test components batch (${{ matrix.components }})
name: Test components batch (${{ matrix.batch.components }})
runs-on: ubuntu-24.04
needs:
- common
@@ -809,7 +809,7 @@ jobs:
fail-fast: false
max-parallel: ${{ (startsWith(github.base_ref, 'beta') || startsWith(github.base_ref, 'release')) && 8 || 4 }}
matrix:
components: ${{ fromJson(needs.determine-jobs.outputs.component-test-batches) }}
batch: ${{ fromJson(needs.determine-jobs.outputs.component-test-batches) }}
steps:
- name: Show disk space
run: |
@@ -817,7 +817,7 @@ jobs:
df -h
- name: List components
run: echo ${{ matrix.components }}
run: echo ${{ matrix.batch.components }}
- name: Cache apt packages
uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 # v1.6.3
@@ -833,8 +833,10 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache ESP-IDF install (restore-only)
# A batch may contain no esp32 build, so never save -- just reuse the
# shared install the dev tidy jobs already cached when present.
# Only batches whose test platforms include esp32 need the native
# ESP-IDF install; never save -- just reuse the shared install the
# dev tidy jobs already cached when present.
if: matrix.batch.needs_idf
uses: ./.github/actions/cache-esp-idf
with:
restore-only: true
@@ -868,7 +870,7 @@ jobs:
fi
# Convert space-separated components to comma-separated for Python script
components_csv=$(echo "${{ matrix.components }}" | tr ' ' ',')
components_csv=$(echo "${{ matrix.batch.components }}" | tr ' ' ',')
# Only isolate directly changed components when targeting dev branch
# For beta/release branches, group everything for faster CI
+15 -5
View File
@@ -1338,7 +1338,7 @@ def main() -> None:
# Split components into batches for CI testing
# This intelligently groups components with similar bus configurations
component_test_batches: list[str]
component_test_batches: list[dict[str, Any]] = []
if changed_components_with_tests:
tests_dir = Path(root_path) / ESPHOME_TESTS_COMPONENTS_PATH
@@ -1363,10 +1363,20 @@ def main() -> None:
batch_size=COMPONENT_TEST_BATCH_SIZE,
directly_changed=batch_directly_changed,
)
# Convert batches to space-separated strings for CI matrix
component_test_batches = [" ".join(batch) for batch in batches]
else:
component_test_batches = []
# Convert batches to CI matrix entries: the component list plus which
# native toolchain installs the batch's test platforms need, so the
# workflow only restores the matching multi-GB toolchain caches.
for batch in batches:
platforms: set[str] = set()
for component in batch:
platforms.update(get_component_test_platforms(component))
component_test_batches.append(
{
"components": " ".join(batch),
"needs_idf": any(p.startswith("esp32") for p in platforms),
"needs_nrf": any(p.startswith("nrf52") for p in platforms),
}
)
output: dict[str, Any] = {
"core_ci": run_core_ci,
+10 -8
View File
@@ -231,14 +231,16 @@ def test_main_all_tests_should_run(
assert output["memory_impact"]["should_run"] == "false"
assert output["cpp_unit_tests_run_all"] is False
assert output["cpp_unit_tests_components"] == ["wifi", "api", "sensor"]
# component_test_batches should be present and be a list of space-separated strings
# component_test_batches should be a list of matrix entries carrying the
# space-separated component list and the toolchain-need flags
assert "component_test_batches" in output
assert isinstance(output["component_test_batches"], list)
# Each batch should be a space-separated string of component names
for batch in output["component_test_batches"]:
assert isinstance(batch, str)
assert isinstance(batch, dict)
# Should contain at least one component (no empty batches)
assert len(batch) > 0
assert len(batch["components"]) > 0
assert isinstance(batch["needs_idf"], bool)
assert isinstance(batch["needs_nrf"], bool)
def test_main_no_tests_should_run(
@@ -2417,16 +2419,16 @@ def test_component_batching_beta_branch_40_per_batch(
assert len(batches) == 3, f"Expected 3 batches, got {len(batches)}"
# Each batch should have approximately 40 components (all weight=1, groupable)
for i, batch_str in enumerate(batches):
batch_components = batch_str.split()
for i, batch in enumerate(batches):
batch_components = batch["components"].split()
assert len(batch_components) == 40, (
f"Batch {i} should have 40 components, got {len(batch_components)}"
)
# Verify all 120 components are in batches
all_components = []
for batch_str in batches:
all_components.extend(batch_str.split())
for batch in batches:
all_components.extend(batch["components"].split())
assert len(all_components) == 120
assert set(all_components) == set(component_names)