ci: Exempt Dependabot PRs from PR title validation #506
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Build ESPHome | |
| # yamllint disable-line rule:truthy | |
| on: | |
| pull_request: | |
| schedule: | |
| # Run daily at 10:00 AM UTC | |
| - cron: '0 10 * * *' | |
| workflow_dispatch: | |
| env: | |
| # Repository URL and ref for external_components resolution. | |
| # For fork PRs, points to the fork so the PR code is actually tested. | |
| REF_URL: >- | |
| https://github.com/${{ | |
| github.event.pull_request.head.repo.full_name | |
| || github.repository | |
| }} | |
| REF_NAME: ${{ github.head_ref || github.ref_name }} | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Detect whether any files relevant to this workflow have changed. | |
| # On schedule and workflow_dispatch, always proceed. | |
| # --------------------------------------------------------------------------- | |
| changes: | |
| name: Detect relevant changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| any_changed: ${{ steps.changed.outputs.any_changed || steps.fallback.outputs.any_changed }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Detect changed files | |
| id: changed | |
| if: github.event_name == 'pull_request' | |
| uses: step-security/changed-files@v47.0.5 | |
| with: | |
| files: | | |
| nspanel_esphome*.yaml | |
| esphome/nspanel_esphome*.yaml | |
| prebuilt/nspanel_esphome*.yaml | |
| prebuilt/wall_display*.yaml | |
| .github/workflows/esphome_build.yml | |
| .github/requirements.txt | |
| .rules/yamllint.yml | |
| .test/*.yaml | |
| **/*.h | |
| **/*.c | |
| **/*.cpp | |
| **/*.py | |
| # On schedule/workflow_dispatch the step above is skipped, so | |
| # any_changed is empty — treat that as "yes, proceed". | |
| - name: Set any_changed for non-PR triggers | |
| id: fallback | |
| if: github.event_name != 'pull_request' | |
| run: echo "any_changed=true" >> "$GITHUB_OUTPUT" | |
| # =========================================================================== | |
| # Code scan | |
| # =========================================================================== | |
| code_scan: | |
| name: Code scan (YAML) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Setup Python | |
| uses: actions/setup-python@v6.2.0 | |
| with: | |
| python-version: "3.11" | |
| - name: Install dependencies | |
| run: pip install -r .github/requirements.txt | |
| - name: Validate YAML files | |
| run: find . \( -name "*.yaml" -o -name "*.yml" \) -exec yamllint -c ./.rules/yamllint.yml {} + | |
| # =========================================================================== | |
| # ESPHome Latest | |
| # =========================================================================== | |
| build_latest: | |
| name: ${{ matrix.firmware.name }} (latest) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| firmware: | |
| - name: Basic (IDF) | |
| yaml-file: .test/esphome_idf_basic.yaml | |
| - name: Basic (Arduino) | |
| yaml-file: .test/esphome_ard_basic.yaml | |
| - name: BLE Tracker | |
| yaml-file: .test/esphome_idf_ble_tracker.yaml | |
| - name: Bluetooth Proxy | |
| yaml-file: .test/esphome_idf_bluetooth_proxy.yaml | |
| - name: Climate Cool | |
| yaml-file: .test/esphome_idf_climate_cool.yaml | |
| - name: Climate Heat | |
| yaml-file: .test/esphome_idf_climate_heat.yaml | |
| - name: Climate Dual | |
| yaml-file: .test/esphome_idf_climate_dual.yaml | |
| - name: Cover | |
| yaml-file: .test/esphome_idf_cover.yaml | |
| - name: Customizations | |
| yaml-file: .test/esphome_idf_climate_heat_customizations.yaml | |
| - name: Climate Cool + Bluetooth Proxy | |
| yaml-file: .test/esphome_idf_climate_cool_bluetooth_proxy.yaml | |
| - name: Display as a Light | |
| yaml-file: .test/esphome_idf_display_as_light.yaml | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Build firmware | |
| uses: edwardtfn/build-action@add-substitutions-support | |
| with: | |
| yaml-file: ${{ matrix.firmware.yaml-file }} | |
| substitutions: | | |
| ref_name=${{ env.REF_NAME }} | |
| ref_url=${{ env.REF_URL }} | |
| # =========================================================================== | |
| # ESPHome Dev | |
| # =========================================================================== | |
| build_dev: | |
| name: ${{ matrix.firmware.name }} (dev) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| firmware: | |
| - name: Basic (IDF) | |
| yaml-file: .test/esphome_idf_basic.yaml | |
| - name: Basic (Arduino) | |
| yaml-file: .test/esphome_ard_basic.yaml | |
| - name: BLE Tracker | |
| yaml-file: .test/esphome_idf_ble_tracker.yaml | |
| - name: Bluetooth Proxy | |
| yaml-file: .test/esphome_idf_bluetooth_proxy.yaml | |
| - name: Climate Cool | |
| yaml-file: .test/esphome_idf_climate_cool.yaml | |
| - name: Climate Heat | |
| yaml-file: .test/esphome_idf_climate_heat.yaml | |
| - name: Climate Dual | |
| yaml-file: .test/esphome_idf_climate_dual.yaml | |
| - name: Cover | |
| yaml-file: .test/esphome_idf_cover.yaml | |
| - name: Customizations | |
| yaml-file: .test/esphome_idf_climate_heat_customizations.yaml | |
| - name: Climate Cool + Bluetooth Proxy | |
| yaml-file: .test/esphome_idf_climate_cool_bluetooth_proxy.yaml | |
| - name: Display as a Light | |
| yaml-file: .test/esphome_idf_display_as_light.yaml | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Build firmware | |
| uses: edwardtfn/build-action@add-substitutions-support | |
| with: | |
| yaml-file: ${{ matrix.firmware.yaml-file }} | |
| version: dev | |
| substitutions: | | |
| ref_name=${{ env.REF_NAME }} | |
| ref_url=${{ env.REF_URL }} | |
| # =========================================================================== | |
| # Pre-built firmware - ESPHome Latest | |
| # =========================================================================== | |
| build_prebuilt_latest: | |
| name: ${{ matrix.firmware.name }} - Pre-built (latest) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| firmware: | |
| - name: NSPanel Easy | |
| yaml-file: prebuilt/nspanel_esphome_prebuilt.yaml | |
| - name: Wall Display | |
| yaml-file: prebuilt/wall_display.yaml | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Build firmware | |
| uses: edwardtfn/build-action@add-substitutions-support | |
| with: | |
| yaml-file: ${{ matrix.firmware.yaml-file }} | |
| substitutions: | | |
| ref_name=${{ env.REF_NAME }} | |
| ref_url=${{ env.REF_URL }} | |
| - name: Verify compiled output | |
| run: | | |
| # Locate the binary produced by the build action. | |
| # Using find avoids hardcoding the device name from the YAML. | |
| BIN=$(find prebuilt/.esphome/build -name "firmware.bin" | head -1) | |
| BIN_FACTORY=$(find prebuilt/.esphome/build -name "firmware-factory.bin" | head -1) | |
| ok=true | |
| if [ ! -s "$BIN" ]; then | |
| echo "ERROR: firmware.bin missing or empty" | |
| ok=false | |
| else | |
| echo "OK: firmware.bin ($(wc -c < "$BIN") bytes)" | |
| fi | |
| if [ -n "$BIN_FACTORY" ] && [ ! -s "$BIN_FACTORY" ]; then | |
| echo "ERROR: firmware-factory.bin found but empty" | |
| ok=false | |
| elif [ -n "$BIN_FACTORY" ]; then | |
| echo "OK: firmware-factory.bin ($(wc -c < "$BIN_FACTORY") bytes)" | |
| fi | |
| [ "$ok" = true ] || exit 1 | |
| # =========================================================================== | |
| # Pre-built firmware - ESPHome Dev | |
| # =========================================================================== | |
| build_prebuilt_dev: | |
| name: ${{ matrix.firmware.name }} - Pre-built (dev) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| firmware: | |
| - name: NSPanel Easy | |
| yaml-file: prebuilt/nspanel_esphome_prebuilt.yaml | |
| - name: Wall Display | |
| yaml-file: prebuilt/wall_display.yaml | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Build firmware | |
| uses: edwardtfn/build-action@add-substitutions-support | |
| with: | |
| yaml-file: ${{ matrix.firmware.yaml-file }} | |
| version: dev | |
| substitutions: | | |
| ref_name=${{ env.REF_NAME }} | |
| ref_url=${{ env.REF_URL }} | |
| - name: Verify compiled output | |
| run: | | |
| # Locate the binary produced by the build action. | |
| # Using find avoids hardcoding the device name from the YAML. | |
| BIN=$(find prebuilt/.esphome/build -name "firmware.bin" | head -1) | |
| BIN_FACTORY=$(find prebuilt/.esphome/build -name "firmware-factory.bin" | head -1) | |
| ok=true | |
| if [ ! -s "$BIN" ]; then | |
| echo "ERROR: firmware.bin missing or empty" | |
| ok=false | |
| else | |
| echo "OK: firmware.bin ($(wc -c < "$BIN") bytes)" | |
| fi | |
| if [ -n "$BIN_FACTORY" ] && [ ! -s "$BIN_FACTORY" ]; then | |
| echo "ERROR: firmware-factory.bin found but empty" | |
| ok=false | |
| elif [ -n "$BIN_FACTORY" ]; then | |
| echo "OK: firmware-factory.bin ($(wc -c < "$BIN_FACTORY") bytes)" | |
| fi | |
| [ "$ok" = true ] || exit 1 | |
| # =========================================================================== | |
| # Gate — required status check for branch protection | |
| # =========================================================================== | |
| all-checks-passed: | |
| name: Build ESPHome / All checks passed | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| needs: | |
| - changes | |
| - code_scan | |
| - build_latest | |
| - build_dev | |
| - build_prebuilt_latest | |
| - build_prebuilt_dev | |
| if: always() | |
| steps: | |
| - name: Check all jobs passed | |
| run: | | |
| results=( | |
| "changes=${{ needs.changes.result }}" | |
| "code_scan=${{ needs.code_scan.result }}" | |
| "build_latest=${{ needs.build_latest.result }}" | |
| "build_dev=${{ needs.build_dev.result }}" | |
| "build_prebuilt_latest=${{ needs.build_prebuilt_latest.result }}" | |
| "build_prebuilt_dev=${{ needs.build_prebuilt_dev.result }}" | |
| ) | |
| failed=false | |
| for entry in "${results[@]}"; do | |
| job="${entry%%=*}" | |
| result="${entry##*=}" | |
| echo "${job}: ${result}" | |
| case "${result}" in | |
| success|skipped) ;; | |
| *) failed=true ;; | |
| esac | |
| done | |
| if [ "${failed}" = "true" ]; then | |
| echo "One or more jobs failed or were cancelled." | |
| exit 1 | |
| fi | |
| echo "All jobs passed or were skipped." | |
| ... |