Skip to content

ci: Exempt Dependabot PRs from PR title validation #506

ci: Exempt Dependabot PRs from PR title validation

ci: Exempt Dependabot PRs from PR title validation #506

Workflow file for this run

---
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."
...