From 3447b681363f6aae7aeed9f7a1570b7028b5dc7c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 10 Oct 2026 08:00:40 -1000 Subject: [PATCH] [ci] Compile an ESP8266 config with the native toolchain on Windows (#20467) --- .github/workflows/ci.yml | 86 +++++++++++++++++++++++++++++++++ script/test_build_components.py | 5 +- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 586263c651..285d6869e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1335,6 +1335,91 @@ jobs: # config first, so a separate config pass is redundant. python3 script/test_build_components.py -e compile -t esp8266-ard -c "$TEST_COMPONENTS" -f --toolchain arduino --fail-on-no-tests + test-esp8266-native-windows: + name: Compile esp8266 with the native toolchain on Windows (ccache ${{ matrix.ccache }}) + runs-on: windows-latest + needs: + - common + - determine-jobs + if: github.event_name == 'pull_request' && needs.determine-jobs.outputs.esp8266-native == 'true' + # A hung compiler must fail the job, not hold the runner for six hours. + timeout-minutes: 40 + strategy: + fail-fast: false + matrix: + # Both ways the build runs on Windows: ESPHome Desktop bundles + # ccache and puts it on PATH, a pip install has none. + ccache: ["1", "0"] + env: + ESPHOME_CCACHE_ENABLE: ${{ matrix.ccache }} + # The test script prints characters the cp1252 console cannot encode + PYTHONUTF8: "1" + # The exact static build ESPHome Desktop ships + CCACHE_URL: https://github.com/ccache/ccache/releases/download/v4.14/ccache-4.14-windows-x86_64.zip + CCACHE_SHA256: 2568347a697e103ca1b073981c704ad76fb2507d066c38dba038dd73399d968f + steps: + - name: Check out code from GitHub + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Restore Python + uses: ./.github/actions/restore-python + with: + python-version: ${{ env.DEFAULT_PYTHON }} + cache-key: ${{ needs.common.outputs.cache-key }} + + - name: Install ccache + if: matrix.ccache == '1' + shell: pwsh + run: | + $dir = Join-Path $env:RUNNER_TEMP "ccache" + New-Item -ItemType Directory -Force $dir | Out-Null + $zip = Join-Path $dir "ccache.zip" + Invoke-WebRequest -Uri $env:CCACHE_URL -OutFile $zip + $hash = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower() + if ($hash -ne $env:CCACHE_SHA256) { + Write-Host "::error::ccache archive sha256 $hash does not match $env:CCACHE_SHA256" + exit 1 + } + Expand-Archive -Path $zip -DestinationPath $dir + $bin = Get-ChildItem -Path $dir -Recurse -Filter ccache.exe | Select-Object -First 1 + Add-Content -Path $env:GITHUB_PATH -Value $bin.DirectoryName + & $bin.FullName --version + + - name: Compile + shell: pwsh + # One component test: web_server brings wifi, api and the async web + # server libraries, the shape of a typical ESP8266 device + run: | + . .\venv\Scripts\Activate.ps1 + $arguments = "script/test_build_components.py", "-e", "compile", "-t", "esp8266-ard", "-c", "web_server", "--base-only", "--toolchain", "arduino", "--fail-on-no-tests" + $p = Start-Process -FilePath python -ArgumentList $arguments -NoNewWindow -PassThru + # Reading the handle keeps ExitCode available after the process exits + $null = $p.Handle + if (-not $p.WaitForExit(25 * 60 * 1000)) { + Write-Host "::error::The compile did not finish in 25 minutes; processes still running:" + Get-CimInstance Win32_Process | + Where-Object { $_.CommandLine -match 'xtensa|ccache|ninja|esphome' } | + Select-Object ProcessId, ParentProcessId, CreationDate, CommandLine | + Format-List | Out-String -Width 4096 | Write-Host + Get-Process | + Where-Object { $_.Name -match 'cc1|ccache|ninja|xtensa|python' } | + Select-Object Id, Name, CPU, WorkingSet64 | + Format-Table | Out-String | Write-Host + taskkill /PID $p.Id /T /F + exit 1 + } + exit $p.ExitCode + + - name: Show ccache statistics + # Also after a failed or killed compile: the counters say whether + # ccache was ever reached + if: always() && matrix.ccache == '1' + shell: pwsh + # The build keeps its store under the esphome tools cache + run: | + $env:CCACHE_DIR = Join-Path $env:LOCALAPPDATA "esphome\Cache\arduino8266\ccache" + ccache -s + device-builder: name: Test downstream esphome/device-builder runs-on: ubuntu-24.04 @@ -1705,6 +1790,7 @@ jobs: - test-build-components-split - test-esp32-platformio - test-esp8266-native + - test-esp8266-native-windows - device-builder - memory-impact-target-branch - memory-impact-pr-branch diff --git a/script/test_build_components.py b/script/test_build_components.py index c955391a61..85e4df38f1 100755 --- a/script/test_build_components.py +++ b/script/test_build_components.py @@ -21,6 +21,7 @@ from dataclasses import dataclass import hashlib import os from pathlib import Path +import shutil import subprocess import sys import time @@ -83,7 +84,9 @@ def show_disk_space_if_ci(esphome_command: str) -> None: print("=" * 80) # Use sys.stdout.flush() to ensure output appears immediately sys.stdout.flush() - subprocess.run(["df", "-h"], check=False, stdout=sys.stdout, stderr=sys.stderr) + # Windows has no df + if df := shutil.which("df"): + subprocess.run([df, "-h"], check=False, stdout=sys.stdout, stderr=sys.stderr) print("=" * 80 + "\n") sys.stdout.flush()