mirror of
https://github.com/esphome/esphome.git
synced 2025-10-21 11:13:46 +01:00
[ci] Automatic Flash/RAM impact analysis
This commit is contained in:
117
.github/workflows/ci.yml
vendored
117
.github/workflows/ci.yml
vendored
@@ -179,6 +179,7 @@ jobs:
|
|||||||
changed-components: ${{ steps.determine.outputs.changed-components }}
|
changed-components: ${{ steps.determine.outputs.changed-components }}
|
||||||
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
|
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
|
||||||
component-test-count: ${{ steps.determine.outputs.component-test-count }}
|
component-test-count: ${{ steps.determine.outputs.component-test-count }}
|
||||||
|
memory_impact: ${{ steps.determine.outputs.memory-impact }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
@@ -207,6 +208,7 @@ jobs:
|
|||||||
echo "changed-components=$(echo "$output" | jq -c '.changed_components')" >> $GITHUB_OUTPUT
|
echo "changed-components=$(echo "$output" | jq -c '.changed_components')" >> $GITHUB_OUTPUT
|
||||||
echo "changed-components-with-tests=$(echo "$output" | jq -c '.changed_components_with_tests')" >> $GITHUB_OUTPUT
|
echo "changed-components-with-tests=$(echo "$output" | jq -c '.changed_components_with_tests')" >> $GITHUB_OUTPUT
|
||||||
echo "component-test-count=$(echo "$output" | jq -r '.component_test_count')" >> $GITHUB_OUTPUT
|
echo "component-test-count=$(echo "$output" | jq -r '.component_test_count')" >> $GITHUB_OUTPUT
|
||||||
|
echo "memory-impact=$(echo "$output" | jq -c '.memory_impact')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
integration-tests:
|
integration-tests:
|
||||||
name: Run integration tests
|
name: Run integration tests
|
||||||
@@ -510,6 +512,118 @@ jobs:
|
|||||||
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
|
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
|
memory-impact-target-branch:
|
||||||
|
name: Build target branch for memory impact
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs:
|
||||||
|
- common
|
||||||
|
- determine-jobs
|
||||||
|
if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true'
|
||||||
|
outputs:
|
||||||
|
ram_usage: ${{ steps.extract.outputs.ram_usage }}
|
||||||
|
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
||||||
|
steps:
|
||||||
|
- name: Check out target branch
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
ref: ${{ github.base_ref }}
|
||||||
|
- name: Restore Python
|
||||||
|
uses: ./.github/actions/restore-python
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
- name: Cache platformio
|
||||||
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||||
|
with:
|
||||||
|
path: ~/.platformio
|
||||||
|
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
|
||||||
|
- name: Compile test configuration and extract memory usage
|
||||||
|
id: extract
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
component="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).component }}"
|
||||||
|
platform="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}"
|
||||||
|
test_file="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).test_file }}"
|
||||||
|
|
||||||
|
echo "Compiling $component for $platform using $test_file"
|
||||||
|
python script/test_build_components.py -e compile -c "$component" -t "$platform" --no-grouping 2>&1 | \
|
||||||
|
python script/ci_memory_impact_extract.py --output-env
|
||||||
|
|
||||||
|
memory-impact-pr-branch:
|
||||||
|
name: Build PR branch for memory impact
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs:
|
||||||
|
- common
|
||||||
|
- determine-jobs
|
||||||
|
if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true'
|
||||||
|
outputs:
|
||||||
|
ram_usage: ${{ steps.extract.outputs.ram_usage }}
|
||||||
|
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
||||||
|
steps:
|
||||||
|
- name: Check out PR branch
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
- name: Restore Python
|
||||||
|
uses: ./.github/actions/restore-python
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
- name: Cache platformio
|
||||||
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||||
|
with:
|
||||||
|
path: ~/.platformio
|
||||||
|
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
|
||||||
|
- name: Compile test configuration and extract memory usage
|
||||||
|
id: extract
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
component="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).component }}"
|
||||||
|
platform="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}"
|
||||||
|
test_file="${{ fromJSON(needs.determine-jobs.outputs.memory_impact).test_file }}"
|
||||||
|
|
||||||
|
echo "Compiling $component for $platform using $test_file"
|
||||||
|
python script/test_build_components.py -e compile -c "$component" -t "$platform" --no-grouping 2>&1 | \
|
||||||
|
python script/ci_memory_impact_extract.py --output-env
|
||||||
|
|
||||||
|
memory-impact-comment:
|
||||||
|
name: Comment memory impact
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs:
|
||||||
|
- common
|
||||||
|
- determine-jobs
|
||||||
|
- memory-impact-target-branch
|
||||||
|
- memory-impact-pr-branch
|
||||||
|
if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
- name: Restore Python
|
||||||
|
uses: ./.github/actions/restore-python
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
- name: Post or update PR comment
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
COMPONENT: ${{ fromJSON(needs.determine-jobs.outputs.memory_impact).component }}
|
||||||
|
PLATFORM: ${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}
|
||||||
|
TARGET_RAM: ${{ needs.memory-impact-target-branch.outputs.ram_usage }}
|
||||||
|
TARGET_FLASH: ${{ needs.memory-impact-target-branch.outputs.flash_usage }}
|
||||||
|
PR_RAM: ${{ needs.memory-impact-pr-branch.outputs.ram_usage }}
|
||||||
|
PR_FLASH: ${{ needs.memory-impact-pr-branch.outputs.flash_usage }}
|
||||||
|
run: |
|
||||||
|
. venv/bin/activate
|
||||||
|
python script/ci_memory_impact_comment.py \
|
||||||
|
--pr-number "${{ github.event.pull_request.number }}" \
|
||||||
|
--component "$COMPONENT" \
|
||||||
|
--platform "$PLATFORM" \
|
||||||
|
--target-ram "$TARGET_RAM" \
|
||||||
|
--target-flash "$TARGET_FLASH" \
|
||||||
|
--pr-ram "$PR_RAM" \
|
||||||
|
--pr-flash "$PR_FLASH"
|
||||||
|
|
||||||
ci-status:
|
ci-status:
|
||||||
name: CI Status
|
name: CI Status
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -525,6 +639,9 @@ jobs:
|
|||||||
- test-build-components-splitter
|
- test-build-components-splitter
|
||||||
- test-build-components-split
|
- test-build-components-split
|
||||||
- pre-commit-ci-lite
|
- pre-commit-ci-lite
|
||||||
|
- memory-impact-target-branch
|
||||||
|
- memory-impact-pr-branch
|
||||||
|
- memory-impact-comment
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- name: Success
|
- name: Success
|
||||||
|
150
.github/workflows/memory-impact.yml
vendored
150
.github/workflows/memory-impact.yml
vendored
@@ -1,150 +0,0 @@
|
|||||||
---
|
|
||||||
name: Memory Impact Analysis
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "esphome/components/**"
|
|
||||||
- "esphome/core/**"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
DEFAULT_PYTHON: "3.11"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
detect-single-component:
|
|
||||||
name: Detect single component change
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
outputs:
|
|
||||||
should_run: ${{ steps.detect.outputs.should_run }}
|
|
||||||
component: ${{ steps.detect.outputs.component }}
|
|
||||||
test_file: ${{ steps.detect.outputs.test_file }}
|
|
||||||
platform: ${{ steps.detect.outputs.platform }}
|
|
||||||
steps:
|
|
||||||
- name: Check out code from GitHub
|
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install PyYAML
|
|
||||||
- name: Detect single component change
|
|
||||||
id: detect
|
|
||||||
run: |
|
|
||||||
python script/ci_memory_impact_detector.py
|
|
||||||
|
|
||||||
build-target-branch:
|
|
||||||
name: Build target branch
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
needs: detect-single-component
|
|
||||||
if: needs.detect-single-component.outputs.should_run == 'true'
|
|
||||||
outputs:
|
|
||||||
ram_usage: ${{ steps.extract.outputs.ram_usage }}
|
|
||||||
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
|
||||||
steps:
|
|
||||||
- name: Check out target branch
|
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
ref: ${{ github.base_ref }}
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
||||||
- name: Install ESPHome
|
|
||||||
run: |
|
|
||||||
pip install -e .
|
|
||||||
- name: Cache platformio
|
|
||||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
||||||
with:
|
|
||||||
path: ~/.platformio
|
|
||||||
key: platformio-memory-${{ needs.detect-single-component.outputs.platform }}-${{ hashFiles('platformio.ini') }}
|
|
||||||
- name: Compile test configuration and extract memory usage
|
|
||||||
id: extract
|
|
||||||
run: |
|
|
||||||
component="${{ needs.detect-single-component.outputs.component }}"
|
|
||||||
platform="${{ needs.detect-single-component.outputs.platform }}"
|
|
||||||
test_file="${{ needs.detect-single-component.outputs.test_file }}"
|
|
||||||
|
|
||||||
echo "Compiling $component for $platform using $test_file"
|
|
||||||
python script/test_build_components.py -e compile -c "$component" -t "$platform" --no-grouping 2>&1 | \
|
|
||||||
python script/ci_memory_impact_extract.py --output-env
|
|
||||||
|
|
||||||
build-pr-branch:
|
|
||||||
name: Build PR branch
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
needs: detect-single-component
|
|
||||||
if: needs.detect-single-component.outputs.should_run == 'true'
|
|
||||||
outputs:
|
|
||||||
ram_usage: ${{ steps.extract.outputs.ram_usage }}
|
|
||||||
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
|
||||||
steps:
|
|
||||||
- name: Check out PR branch
|
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
||||||
- name: Install ESPHome
|
|
||||||
run: |
|
|
||||||
pip install -e .
|
|
||||||
- name: Cache platformio
|
|
||||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
||||||
with:
|
|
||||||
path: ~/.platformio
|
|
||||||
key: platformio-memory-${{ needs.detect-single-component.outputs.platform }}-${{ hashFiles('platformio.ini') }}
|
|
||||||
- name: Compile test configuration and extract memory usage
|
|
||||||
id: extract
|
|
||||||
run: |
|
|
||||||
component="${{ needs.detect-single-component.outputs.component }}"
|
|
||||||
platform="${{ needs.detect-single-component.outputs.platform }}"
|
|
||||||
test_file="${{ needs.detect-single-component.outputs.test_file }}"
|
|
||||||
|
|
||||||
echo "Compiling $component for $platform using $test_file"
|
|
||||||
python script/test_build_components.py -e compile -c "$component" -t "$platform" --no-grouping 2>&1 | \
|
|
||||||
python script/ci_memory_impact_extract.py --output-env
|
|
||||||
|
|
||||||
comment-results:
|
|
||||||
name: Comment memory impact
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
needs:
|
|
||||||
- detect-single-component
|
|
||||||
- build-target-branch
|
|
||||||
- build-pr-branch
|
|
||||||
if: needs.detect-single-component.outputs.should_run == 'true'
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
||||||
- name: Post or update PR comment
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
COMPONENT: ${{ needs.detect-single-component.outputs.component }}
|
|
||||||
PLATFORM: ${{ needs.detect-single-component.outputs.platform }}
|
|
||||||
TARGET_RAM: ${{ needs.build-target-branch.outputs.ram_usage }}
|
|
||||||
TARGET_FLASH: ${{ needs.build-target-branch.outputs.flash_usage }}
|
|
||||||
PR_RAM: ${{ needs.build-pr-branch.outputs.ram_usage }}
|
|
||||||
PR_FLASH: ${{ needs.build-pr-branch.outputs.flash_usage }}
|
|
||||||
run: |
|
|
||||||
python script/ci_memory_impact_comment.py \
|
|
||||||
--pr-number "${{ github.event.pull_request.number }}" \
|
|
||||||
--component "$COMPONENT" \
|
|
||||||
--platform "$PLATFORM" \
|
|
||||||
--target-ram "$TARGET_RAM" \
|
|
||||||
--target-flash "$TARGET_FLASH" \
|
|
||||||
--pr-ram "$PR_RAM" \
|
|
||||||
--pr-flash "$PR_FLASH"
|
|
@@ -1,134 +0,0 @@
|
|||||||
#!/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()
|
|
@@ -10,7 +10,13 @@ what files have changed. It outputs JSON with the following structure:
|
|||||||
"clang_format": true/false,
|
"clang_format": true/false,
|
||||||
"python_linters": true/false,
|
"python_linters": true/false,
|
||||||
"changed_components": ["component1", "component2", ...],
|
"changed_components": ["component1", "component2", ...],
|
||||||
"component_test_count": 5
|
"component_test_count": 5,
|
||||||
|
"memory_impact": {
|
||||||
|
"should_run": "true/false",
|
||||||
|
"component": "component_name",
|
||||||
|
"test_file": "test.esp32-idf.yaml",
|
||||||
|
"platform": "esp32-idf"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The CI workflow uses this information to:
|
The CI workflow uses this information to:
|
||||||
@@ -20,6 +26,7 @@ The CI workflow uses this information to:
|
|||||||
- Skip or run Python linters (ruff, flake8, pylint, pyupgrade)
|
- Skip or run Python linters (ruff, flake8, pylint, pyupgrade)
|
||||||
- Determine which components to test individually
|
- Determine which components to test individually
|
||||||
- Decide how to split component tests (if there are many)
|
- Decide how to split component tests (if there are many)
|
||||||
|
- Run memory impact analysis when exactly one component changes
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python script/determine-jobs.py [-b BRANCH]
|
python script/determine-jobs.py [-b BRANCH]
|
||||||
@@ -212,6 +219,92 @@ def _any_changed_file_endswith(branch: str | None, extensions: tuple[str, ...])
|
|||||||
return any(file.endswith(extensions) for file in changed_files(branch))
|
return any(file.endswith(extensions) for file in changed_files(branch))
|
||||||
|
|
||||||
|
|
||||||
|
def detect_single_component_for_memory_impact(
|
||||||
|
changed_components: list[str],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Detect if exactly one component changed for memory impact analysis.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
changed_components: List of changed component names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with memory impact analysis parameters:
|
||||||
|
- should_run: "true" or "false"
|
||||||
|
- component: component name (if should_run is true)
|
||||||
|
- test_file: test file name (if should_run is true)
|
||||||
|
- platform: platform name (if should_run is true)
|
||||||
|
"""
|
||||||
|
# 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)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Skip base bus components as they're used across many builds
|
||||||
|
filtered_components = [
|
||||||
|
c for c in changed_components if c not in ["i2c", "spi", "uart", "modbus"]
|
||||||
|
]
|
||||||
|
|
||||||
|
# Only proceed if exactly one component changed
|
||||||
|
if len(filtered_components) != 1:
|
||||||
|
return {"should_run": "false"}
|
||||||
|
|
||||||
|
component = filtered_components[0]
|
||||||
|
|
||||||
|
# Find a test configuration for this component
|
||||||
|
tests_dir = Path(root_path) / "tests" / "components" / component
|
||||||
|
|
||||||
|
if not tests_dir.exists():
|
||||||
|
return {"should_run": "false"}
|
||||||
|
|
||||||
|
# Look for test files
|
||||||
|
test_files = list(tests_dir.glob("test.*.yaml"))
|
||||||
|
if not test_files:
|
||||||
|
return {"should_run": "false"}
|
||||||
|
|
||||||
|
# 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 {
|
||||||
|
"should_run": "true",
|
||||||
|
"component": component,
|
||||||
|
"test_file": test_file.name,
|
||||||
|
"platform": 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 {
|
||||||
|
"should_run": "true",
|
||||||
|
"component": component,
|
||||||
|
"test_file": test_file.name,
|
||||||
|
"platform": platform,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Main function that determines which CI jobs to run."""
|
"""Main function that determines which CI jobs to run."""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@@ -247,6 +340,9 @@ def main() -> None:
|
|||||||
and any(component_test_dir.glob("test.*.yaml"))
|
and any(component_test_dir.glob("test.*.yaml"))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Detect single component change for memory impact analysis
|
||||||
|
memory_impact = detect_single_component_for_memory_impact(changed_components)
|
||||||
|
|
||||||
# Build output
|
# Build output
|
||||||
output: dict[str, Any] = {
|
output: dict[str, Any] = {
|
||||||
"integration_tests": run_integration,
|
"integration_tests": run_integration,
|
||||||
@@ -256,6 +352,7 @@ def main() -> None:
|
|||||||
"changed_components": changed_components,
|
"changed_components": changed_components,
|
||||||
"changed_components_with_tests": changed_components_with_tests,
|
"changed_components_with_tests": changed_components_with_tests,
|
||||||
"component_test_count": len(changed_components_with_tests),
|
"component_test_count": len(changed_components_with_tests),
|
||||||
|
"memory_impact": memory_impact,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Output as JSON
|
# Output as JSON
|
||||||
|
Reference in New Issue
Block a user