--- name: Validate ESPHome permissions: contents: read pull-requests: read on: # yamllint disable-line rule:truthy push: paths: - "**/*.yml" - "**/*.yaml" - "**/*.h" - "**/*.cpp" - "**/*.c" - "**/*.py" pull_request: paths: - "**/*.yml" - "**/*.yaml" - "**/*.h" - "**/*.cpp" - "**/*.c" - "**/*.py" workflow_dispatch: inputs: skip_dev: description: 'Skip dev testing (test only on latest)' required: false default: false type: boolean concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: code_scan: name: Code scan (YAML) runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@main - name: Setup Python uses: actions/setup-python@main with: python-version: '3.11' - name: Install Yamllint run: pip install yamllint - name: Validate YAML files run: find . -name "*.yaml" -exec yamllint -c ./.rules/yamllint.yml {} + # Arduino Framework - Foundation (latest) build_ard_core: name: "🏗️ Arduino Core (latest)" needs: code_scan runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino Core - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_core.yaml" version: latest build_ard_basic: name: "📦 Arduino Basic (latest)" needs: build_ard_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino Basic - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_basic.yaml" version: latest build_ard_hw_relays: name: "🔌 Arduino HW Relays (latest)" needs: [build_ard_core, build_ard_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino HW Relays - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_hw_relays.yaml" version: latest build_ard_hw_speaker: name: "🔌 Arduino HW Speaker (latest)" needs: [build_ard_core, build_ard_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino HW Speaker - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_hw_speaker.yaml" version: latest build_ard_hw_vibration: name: "🔌 Arduino HW Vibration (latest)" needs: [build_ard_core, build_ard_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino HW Vibration - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_hw_vibration.yaml" version: latest build_ard_ble_proxy_latest: name: "⚡ Arduino BLE Proxy (latest)" needs: [build_ard_core, build_ard_basic, build_ard_hw_relays, build_ard_hw_speaker, build_ard_hw_vibration] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino BLE Proxy - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_ble_proxy.yaml" version: latest build_ard_ble_proxy_dev: name: "⚡ Arduino BLE Proxy (dev)" needs: [build_ard_core, build_ard_basic, build_ard_hw_relays, build_ard_hw_speaker, build_ard_hw_vibration] if: success() && !inputs.skip_dev runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino BLE Proxy - dev uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_ble_proxy.yaml" version: dev build_ard_media_player_latest: name: "⚡ Arduino Media Player (latest)" needs: [build_ard_core, build_ard_basic, build_ard_hw_relays, build_ard_hw_speaker, build_ard_hw_vibration] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino Media Player - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_media_player.yaml" version: latest build_ard_media_player_dev: name: "⚡ Arduino Media Player (dev)" needs: [build_ard_core, build_ard_basic, build_ard_hw_relays, build_ard_hw_speaker, build_ard_hw_vibration] if: success() && !inputs.skip_dev runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build Arduino Media Player - dev uses: esphome/build-action@main with: yaml-file: ".test/esphome_ard_media_player.yaml" version: dev # IDF Framework - Foundation (latest) build_idf_core: name: "🏗️ IDF Core (latest)" needs: code_scan runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF Core - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_core.yaml" version: latest build_idf_basic: name: "📦 IDF Basic (latest)" needs: build_idf_core runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF Basic - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_basic.yaml" version: latest build_idf_hw_relays: name: "🔌 IDF HW Relays (latest)" needs: [build_idf_core, build_idf_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF HW Relays - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_hw_relays.yaml" version: latest build_idf_hw_speaker: name: "🔌 IDF HW Speaker (latest)" needs: [build_idf_core, build_idf_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF HW Speaker - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_hw_speaker.yaml" version: latest build_idf_hw_vibration: name: "🔌 IDF HW Vibration (latest)" needs: [build_idf_core, build_idf_basic] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF HW Vibration - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_hw_vibration.yaml" version: latest build_idf_ble_proxy_latest: name: "⚡ IDF BLE Proxy (latest)" needs: [build_idf_core, build_idf_basic, build_idf_hw_relays, build_idf_hw_speaker, build_idf_hw_vibration] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF BLE Proxy - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_ble_proxy.yaml" version: latest build_idf_ble_proxy_dev: name: "⚡ IDF BLE Proxy (dev)" needs: [build_idf_core, build_idf_basic, build_idf_hw_relays, build_idf_hw_speaker, build_idf_hw_vibration] if: success() && !inputs.skip_dev runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF BLE Proxy - dev uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_ble_proxy.yaml" version: dev build_idf_media_player_latest: name: "⚡ IDF Media Player (latest)" needs: [build_idf_core, build_idf_basic, build_idf_hw_relays, build_idf_hw_speaker, build_idf_hw_vibration] runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF Media Player - latest uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_media_player.yaml" version: latest build_idf_media_player_dev: name: "⚡ IDF Media Player (dev)" needs: [build_idf_core, build_idf_basic, build_idf_hw_relays, build_idf_hw_speaker, build_idf_hw_vibration] if: success() && !inputs.skip_dev runs-on: ubuntu-latest steps: - uses: actions/checkout@main - name: Build IDF Media Player - dev uses: esphome/build-action@main with: yaml-file: ".test/esphome_idf_media_player.yaml" version: dev # Results summary build_summary: name: "📊 Build Summary" needs: - build_ard_core - build_ard_basic - build_ard_hw_relays - build_ard_hw_speaker - build_ard_hw_vibration - build_ard_ble_proxy_latest - build_ard_ble_proxy_dev - build_ard_media_player_latest - build_ard_media_player_dev - build_idf_core - build_idf_basic - build_idf_hw_relays - build_idf_hw_speaker - build_idf_hw_vibration - build_idf_ble_proxy_latest - build_idf_ble_proxy_dev - build_idf_media_player_latest - build_idf_media_player_dev if: always() runs-on: ubuntu-latest steps: - name: Generate Results Summary run: | echo "## 📋 ESPHome Build Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Build Matrix Summary echo "### 🏗️ Foundation Components (Latest Only)" >> $GITHUB_STEP_SUMMARY echo "| Component | 🤖 Arduino | 🔧 ESP-IDF |" >> $GITHUB_STEP_SUMMARY echo "|-----------|-------------|------------|" >> $GITHUB_STEP_SUMMARY echo "| 🏗️ Core | ${{ needs.build_ard_core.result }} | ${{ needs.build_idf_core.result }} |" >> $GITHUB_STEP_SUMMARY echo "| 📦 Basic | ${{ needs.build_ard_basic.result }} | ${{ needs.build_idf_basic.result }} |" >> $GITHUB_STEP_SUMMARY echo "| 🔌 HW Relays | ${{ needs.build_ard_hw_relays.result }} | ${{ needs.build_idf_hw_relays.result }} |" >> $GITHUB_STEP_SUMMARY echo "| 🔌 HW Speaker | ${{ needs.build_ard_hw_speaker.result }} | ${{ needs.build_idf_hw_speaker.result }} |" >> $GITHUB_STEP_SUMMARY echo "| 🔌 HW Vibration | ${{ needs.build_ard_hw_vibration.result }} | ${{ needs.build_idf_hw_vibration.result }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### ⚡ Advanced Features (Multi-Version)" >> $GITHUB_STEP_SUMMARY echo "| Component | 🤖 Arduino Latest | 🤖 Arduino Dev | 🔧 IDF Latest | 🔧 IDF Dev |" >> $GITHUB_STEP_SUMMARY echo "|-----------|-------------------|----------------|---------------|------------|" >> $GITHUB_STEP_SUMMARY echo "| ⚡ BLE Proxy | ${{ needs.build_ard_ble_proxy_latest.result }} | \ ${{ needs.build_ard_ble_proxy_dev.result }} | \ ${{ needs.build_idf_ble_proxy_latest.result }} | \ ${{ needs.build_idf_ble_proxy_dev.result }} |" >> $GITHUB_STEP_SUMMARY echo "| ⚡ Media Player | ${{ needs.build_ard_media_player_latest.result }} | \ ${{ needs.build_ard_media_player_dev.result }} | \ ${{ needs.build_idf_media_player_latest.result }} | \ ${{ needs.build_idf_media_player_dev.result }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Environment Summary echo "### 🌍 Environment Summary" >> $GITHUB_STEP_SUMMARY # Count successes per environment ARD_LATEST_SUCCESS=0 ARD_DEV_SUCCESS=0 IDF_LATEST_SUCCESS=0 IDF_DEV_SUCCESS=0 # Arduino Latest (7 builds) [ "${{ needs.build_ard_core.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_basic.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_hw_relays.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_hw_speaker.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_hw_vibration.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_ble_proxy_latest.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) [ "${{ needs.build_ard_media_player_latest.result }}" == "success" ] && ARD_LATEST_SUCCESS=$((ARD_LATEST_SUCCESS + 1)) # Arduino Dev (2 builds if not skipped) if [ "${{ inputs.skip_dev }}" != "true" ]; then [ "${{ needs.build_ard_ble_proxy_dev.result }}" == "success" ] && ARD_DEV_SUCCESS=$((ARD_DEV_SUCCESS + 1)) [ "${{ needs.build_ard_media_player_dev.result }}" == "success" ] && ARD_DEV_SUCCESS=$((ARD_DEV_SUCCESS + 1)) fi # IDF Latest (7 builds) [ "${{ needs.build_idf_core.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_basic.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_hw_relays.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_hw_speaker.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_hw_vibration.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_ble_proxy_latest.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) [ "${{ needs.build_idf_media_player_latest.result }}" == "success" ] && IDF_LATEST_SUCCESS=$((IDF_LATEST_SUCCESS + 1)) # IDF Dev (2 builds if not skipped) if [ "${{ inputs.skip_dev }}" != "true" ]; then [ "${{ needs.build_idf_ble_proxy_dev.result }}" == "success" ] && IDF_DEV_SUCCESS=$((IDF_DEV_SUCCESS + 1)) [ "${{ needs.build_idf_media_player_dev.result }}" == "success" ] && IDF_DEV_SUCCESS=$((IDF_DEV_SUCCESS + 1)) fi echo "| Framework | Latest ESPHome | Dev ESPHome |" >> $GITHUB_STEP_SUMMARY echo "|-----------|----------------|-------------|" >> $GITHUB_STEP_SUMMARY echo "| 🤖 **Arduino** | ✅ $ARD_LATEST_SUCCESS/7 | ✅ $ARD_DEV_SUCCESS/2 |" >> $GITHUB_STEP_SUMMARY echo "| 🔧 **ESP-IDF** | ✅ $IDF_LATEST_SUCCESS/7 | ✅ $IDF_DEV_SUCCESS/2 |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Framework Summary echo "### 🎯 Framework Summary" >> $GITHUB_STEP_SUMMARY ARD_TOTAL=$((ARD_LATEST_SUCCESS + ARD_DEV_SUCCESS)) IDF_TOTAL=$((IDF_LATEST_SUCCESS + IDF_DEV_SUCCESS)) if [ "${{ inputs.skip_dev }}" == "true" ]; then ARD_MAX=7 IDF_MAX=7 TOTAL_MAX=14 else ARD_MAX=9 IDF_MAX=9 TOTAL_MAX=18 fi GRAND_TOTAL=$((ARD_TOTAL + IDF_TOTAL)) echo "- 🤖 **Arduino**: $ARD_TOTAL/$ARD_MAX builds passed" >> $GITHUB_STEP_SUMMARY echo "- 🔧 **ESP-IDF**: $IDF_TOTAL/$IDF_MAX builds passed" >> $GITHUB_STEP_SUMMARY echo "- 🎯 **Overall**: $GRAND_TOTAL/$TOTAL_MAX builds passed" >> $GITHUB_STEP_SUMMARY # Final status emoji if [ "$GRAND_TOTAL" -eq "$TOTAL_MAX" ]; then echo "- 🎉 **Status**: All builds successful!" >> $GITHUB_STEP_SUMMARY elif [ "$GRAND_TOTAL" -gt "$((TOTAL_MAX * 3 / 4))" ]; then echo "- ⚠️ **Status**: Most builds successful, some issues detected" >> $GITHUB_STEP_SUMMARY else echo "- ❌ **Status**: Multiple build failures detected" >> $GITHUB_STEP_SUMMARY fi ...