This document explains how the Continuous Integration and Continuous Deployment (CI/CD) system works for the ESP32 Arduino Core project.
- Overview
- Centralized SoC Configuration
- Workflows
- Scripts
- Adding a New SoC
- Official Variants Filter
- Testing
The CI/CD system is designed to:
- Build and test Arduino sketches across multiple ESP32 SoC variants
- Test on physical hardware, Wokwi simulator, and QEMU emulator
- Build ESP-IDF component examples
- Validate board definitions
- Test external libraries
- Generate documentation
- Publish releases
All SoC definitions are centralized in .github/scripts/socs_config.sh to ensure consistency and ease of maintenance.
All supported SoC lists and definitions are maintained in a single file: .github/scripts/socs_config.sh
This eliminates duplication and ensures consistency across all workflows and scripts.
The configuration defines several target lists for different purposes:
HW_TEST_TARGETS- Physical devices available in GitLab for hardware testingWOKWI_TEST_TARGETS- SoCs supported by Wokwi simulatorQEMU_TEST_TARGETS- SoCs supported by QEMU emulator (currently disabled by default)BUILD_TEST_TARGETS- Automatically computed as the union of all test platform targets- This is the primary list used for builds and tests
Note: QEMU testing is disabled by default as Wokwi simulator can cover most of what QEMU does, with the added benefit of simulating more peripherals and providing a better testing experience.
IDF_V5_3_TARGETS- Supported by ESP-IDF v5.3IDF_V5_4_TARGETS- Supported by ESP-IDF v5.4IDF_V5_5_TARGETS- Supported by ESP-IDF v5.5IDF_COMPONENT_TARGETS- Default IDF targets (currently v5.5)
ALL_SOCS- Complete list of all supported SoCsSKIP_LIB_BUILD_SOCS- SoCs without pre-built libraries (e.g., esp32c2, esp32c61)
The configuration provides utility functions for common operations:
get_arch- Returns the architecture (xtensa or riscv32) for a given SoCis_qemu_supported- Checks if a SoC is supported by QEMU emulatorshould_skip_lib_build- Checks if a SoC should skip library builds (no pre-built libs)
array_to_csv- Converts bash array to comma-separated stringarray_to_json- Converts bash array to JSON array stringarray_to_quoted_csv- Converts bash array to quoted comma-separated string
get_targets_for_idf_version- Returns CSV list of targets supported by a specific IDF version
Scripts source the configuration file to access SoC lists and helper functions. The configuration provides arrays like BUILD_TEST_TARGETS that can be iterated over, and functions like is_qemu_supported() or get_arch() for runtime checks.
Workflows source the configuration in their setup steps and use the arrays to dynamically generate job matrices. This allows adding new SoCs without modifying workflow files - just update socs_config.sh and all workflows automatically include the new target.
Trigger:
- Push to
masterorrelease/*branches - Pull requests modifying:
cores/**libraries/**/*.{cpp,c,h,ino}libraries/**/ci.ymlpackage/**variants/**.github/workflows/push.yml.github/scripts/install-*,on-push.sh,sketch_utils.sh,get_affected.py,socs_config.sh
- Schedule: Every Sunday at 2:00 UTC (verbose logging)
- Manual workflow dispatch (with configurable log level)
Purpose: Build Arduino sketches across all SoC variants to catch compilation errors early
Jobs:
Runs on: Ubuntu-latest
Steps:
- Install universal-ctags for symbol parsing
- Checkout repository (fetch-depth: 2 for diff)
- Get changed files using
tj-actions/changed-files - Check Official Variants - Calls
check_official_variants.shwithBUILD_TEST_TARGETS - Set Chunks - Runs
get_affected.pyto:- Parse C/C++ dependencies using ctags
- Build forward/reverse dependency graphs
- Determine affected sketches from changed files
- Distribute sketches across chunks for parallel builds
- Upload affected sketches and debug artifacts
Outputs:
should_run- Whether workflow should proceed (based on variant check)should_build- Whether any sketches need buildingchunk_count- Number of parallel chunks neededchunks- JSON array of chunk indices
SoC Config Usage:
The script sources socs_config.sh and uses BUILD_TEST_TARGETS to determine which variants are considered official.
Runs on: Ubuntu-latest (matrix of chunks)
Conditions:
needs.gen-chunks.outputs.should_run == 'true'needs.gen-chunks.outputs.should_build == '1'
Matrix: Chunks from gen-chunks job (up to 15 parallel jobs)
Steps:
- Checkout repository
- Setup Python 3.x
- Get libs cache - Restores cached tools and libraries
- Key:
libs-{os}-{arch}-{hash(package_esp32_index.template.json, tools/get.py)} - Includes: esp32-arduino-libs, esptool, toolchains
- Key:
- Set log level (none/error/warn/info/debug/verbose)
- Download affected sketches list
- Build sketches - Runs
on-push.shwith chunk parameters - Upload compile results JSON
SoC Config Usage:
The build script sources socs_config.sh and iterates through all targets in BUILD_TEST_TARGETS, building sketches for each SoC variant.
Environment Variables:
MAX_CHUNKS=15- Maximum parallel build jobs
Key Features:
- Intelligent chunking: Only rebuilds affected sketches
- Parallel execution: Up to 15 simultaneous builds
- Dependency tracking: Uses ctags for accurate change detection
- Size reports: Generates JSON with sketch sizes for comparison
- Caching: Libraries and tools cached between runs
Runs on: Windows-latest, macOS-latest
Conditions:
needs.gen-chunks.outputs.should_run == 'true'needs.gen-chunks.outputs.recompile_preset == '1'
Purpose: Verify cross-platform compilation compatibility
Steps:
- Checkout repository
- Setup Python 3.x
- Install yq (Windows only - macOS/Linux have it by default)
- Build preset sketches - Runs
on-push.shwithout parameters- Builds hardcoded list of representative sketches
- Tests WiFiClientSecure, BLE Server, Camera, Insights examples
Why Preset Sketches:
- Windows/macOS builds are slower than Linux
- Full matrix would take too long
- Preset ensures cross-platform compatibility for critical examples
Runs on: Ubuntu-latest
Conditions:
- Only on push to
masterbranch - After
build-arduino-linuxcompletes
Purpose: Archive compile results for historical tracking
Steps:
- Checkout gh-pages branch
- Download all compile result artifacts
- Commit and push to gh-pages branch
- Enables size comparison with future PRs
Runs on: Ubuntu-latest
Conditions:
- Only on pull requests (not release branches)
Purpose: Store PR number for status reporting in later workflows
Concurrency:
- Group:
build-{pr_number or ref} - Cancel in progress: Yes (saves resources on force-pushes)
The runtime test system is a multi-stage pipeline that builds test sketches once and then executes them across multiple platforms (QEMU emulator, physical hardware, and Wokwi simulator). The system uses GitHub Actions for orchestration and building, while actual hardware tests run in GitLab CI for access to the internal test lab.
Trigger:
- Pull requests affecting test code, cores, libraries, or infrastructure
- Daily schedule for comprehensive testing
- Manual workflow dispatch
Purpose: Validate runtime behavior across all supported SoCs on three different platforms, catching issues that compilation testing cannot detect.
The system consists of four GitHub Actions workflows that execute in sequence, plus GitLab CI for hardware testing:
tests.yml (Orchestrator - GitHub Actions)
│
├─→ Calls: tests_build.yml
│ Compiles test binaries for all SoCs
│ Uploads artifacts to GitHub
│
└─→ Calls: tests_qemu.yml (disabled by default)
QEMU tests currently disabled
Wokwi covers most QEMU functionality with better peripheral support
↓ (workflow_run trigger on completion)
tests_hw_wokwi.yml (GitHub Actions)
│ Requires access to the repository secrets
│ Downloads test matrix and configuration
│
├─→ Triggers: GitLab CI Pipeline
│ Downloads test binaries from GitHub
│ Dynamically generates jobs per chip/type
│ Runs on physical hardware with runner tags
│ Hardware tests use internal test lab
│
└─→ Triggers: Wokwi Tests
Runs in GitHub Actions with Wokwi CLI
Simulates hardware behavior
↓ (workflow_run trigger on completion)
tests_results.yml (GitHub Actions)
Aggregates results from QEMU, hardware, and Wokwi
Identifies missed tests
Posts comprehensive report to PR
Why workflow_run?
tests_hw_wokwi.ymlneeds elevated permissions not available in PR contexttests_results.ymlmust wait for all platforms to complete- Separates permissions contexts for security
The main workflow coordinates the initial testing stages using GitHub Actions workflow_call feature.
Key Responsibilities:
-
Event Handling:
- Uploads event file artifact for downstream workflows
- Preserves PR context and commit information
-
Matrix Generation:
- Sources
socs_config.shto get platform-specific target lists - Creates matrices for builds (all
BUILD_TEST_TARGETS) - Determines test types to run based on PR labels and event type
- Generates
test_matrix.jsonwith complete configuration - Validation tests always run; performance tests require
perf_testlabel or scheduled run
- Sources
-
Workflow Orchestration via workflow_call:
- Calls
tests_build.yml: Matrix of chip × type combinations - Calls
tests_qemu.yml: QEMU tests (disabled by default - Wokwi provides better coverage) - Runs in parallel for faster feedback
- Both have access to PR context and can download artifacts
- Calls
-
Triggers Downstream:
- Completion triggers
tests_hw_wokwi.ymlvia workflow_run - Uploads artifacts that downstream workflows need
- Completion triggers
Test Type Logic:
- PRs: Only validation tests (fast feedback)
- Scheduled runs: Both validation and performance tests
- PR with
perf_testlabel: Both validation and performance tests
Concurrency: Cancels in-progress runs for same PR to save resources
Compiles test sketches once for reuse across all test platforms.
Build Strategy:
- Receives
chipandtypeinputs from orchestrator - Checks cache first - if binaries already exist from previous run, skip building
- Installs Arduino CLI and ESP32 core
- Compiles all test sketches for the specified chip and test type
- Stores binaries in standardized directory structure
Output Artifacts: Each build produces binaries organized by chip and test type, including:
- Compiled
.binfiles (flashable binaries) .elffiles (for debugging)- Merged binaries (bootloader + partition table + app)
sdkconfig(ESP-IDF configuration used)ci.yml(test requirements and configurations)
Caching Strategy: Build artifacts are cached with a key based on PR number and commit SHA. This allows:
- Fast rebuilds when retrying failed tests
- Skipping builds when only test code changes
- Reduced CI time and resource usage
Runs tests in QEMU emulator for quick feedback without hardware.
Why QEMU:
- Fast execution (seconds per test)
- No hardware bottlenecks
- Deterministic environment
- Good for basic functionality validation
Process:
- Downloads QEMU from espressif/qemu releases (cached)
- Fetches test binaries from build phase
- Downloads and installs pytest-embedded framework
- Uses
socs_config.shhelper functions to determine correct QEMU architecture - Runs pytest with QEMU-specific configurations
- Generates JUnit XML reports
- Caches results to avoid re-running on retry
Architecture Detection:
The test runner calls get_arch() to dynamically determine whether to use xtensa or riscv32 QEMU binary, making it easy to add new SoCs without modifying the test logic.
Trigger: workflow_run event when tests.yml completes (success or failure)
Why workflow_run?
- Requires elevated permissions (
actions: read,statuses: write) - PR workflows run with restricted permissions for security
- Cannot access organization secrets in PR context
- workflow_run provides isolated permission boundary
Architecture: Two separate testing paths
Why GitLab CI:
- Access to internal test lab with physical ESP32 hardware
- Secure credential management for test infrastructure
- Runner tags for specific hardware assignment
- Better resource scheduling for physical devices
Workflow Steps:
-
GitHub Actions Stage (
tests_hw_wokwi.yml):- Downloads test matrix from
tests.ymlartifacts - Extracts chip and type configurations
- Reports pending status to commit
- Triggers GitLab CI pipeline via webhook
- Downloads test matrix from
-
GitLab CI Stage (
.gitlab/workflows/hardware_tests_dynamic.yml):Job 1:
generate-hw-tests- Downloads test binaries from GitHub artifacts
- Runs
gen_hw_jobs.pyto dynamically create child pipeline - Groups tests by chip and required runner tags
- Generates
child-hw-jobs.ymlwith job definitions
Job 2:
trigger-hw-tests- Triggers child pipeline with generated jobs
- Each job runs on hardware with matching tags (e.g.,
esp32s3runner) - Uses template from
.gitlab/workflows/hw_test_template.yml
Job Template Execution (per chip/type):
- Runs on GitLab runner with physical hardware attached
- Downloads test binaries for specific chip
- Flashes binary to device via esptool
- Executes
tests_run.shwith hardware platform flag - Runs pytest with
--embedded-services esp,arduino - Provides WiFi credentials from runner environment
- Monitors serial output for test results
- Generates JUnit XML reports
Job 3:
collect-hw-results- Waits for all hardware jobs to complete
- Aggregates JUnit XML results
- Uploads consolidated artifacts
-
GitHub Actions Completion:
- Monitors GitLab pipeline status
- Reports final status to commit
- Uploads results as GitHub artifacts
Hardware Infrastructure:
- Physical devices for all
HW_TEST_TARGETSSoCs - Runner tags match chip names for job assignment
- 5-hour timeout for long-running tests
- WiFi network access for connectivity tests
Infrastructure:
- Runs in GitHub Actions with Wokwi CLI token
- SoCs in
WOKWI_TEST_TARGETSsupported - No physical hardware required
Process:
- Downloads test binaries from
tests.ymlartifacts - Installs Wokwi CLI with organization token
- Runs pytest with
--embedded-services arduino,wokwi - Uses sketch's
diagram.{chip}.jsonfor hardware simulation - Simulates peripherals, sensors, displays
- Generates JUnit XML reports
Advantages:
- More peripherals than QEMU (sensors, displays, buttons)
- No hardware availability bottlenecks
- Faster than physical hardware
- Deterministic behavior for debugging
Trigger: workflow_run event when tests_hw_wokwi.yml completes
Purpose: Aggregate results from all three test platforms (QEMU, hardware, Wokwi), identify any missed tests, and generate comprehensive report.
Why After tests_hw_wokwi.yml:
- Must wait for hardware tests to complete (longest running)
- Needs results from all platforms for complete picture
- Can access all artifacts once everything finishes
Process:
-
Artifact Collection:
- Downloads artifacts from originating
tests.ymlrun - Downloads artifacts from
tests_hw_wokwi.ymlrun - Extracts test matrix configuration to know what was expected
- Collects JUnit XML from:
- QEMU tests (if enabled - currently disabled by default)
- Hardware tests (from GitLab via tests_hw_wokwi.yml)
- Wokwi tests (from tests_hw_wokwi.yml)
- Downloads artifacts from originating
-
Analysis Phase:
- Parses all JUnit XML files
- Cross-references with expected test matrix
- Identifies missed tests: Tests that should have run but didn't
- Categorizes results by:
- Platform (QEMU/hardware/Wokwi)
- SoC variant
- Test type (validation/performance)
- Calculates pass/fail/skip/missing counts
- Identifies patterns in failures
-
Report Generation:
- Creates markdown summary table
- Shows results matrix: platforms × SoCs × test types
- Highlights missed tests with reasons (build failure, platform unavailable, etc.)
- Lists failed tests with error excerpts
- Includes links to:
- Full logs in GitHub Actions
- GitLab CI pipeline for hardware tests
- Artifact downloads
- Compares with previous runs (if available)
-
PR Communication:
- Posts comprehensive comment to pull request
- Updates commit status
- Provides actionable information for developers
Report Sections:
- Summary: Overall statistics across all platforms
- Per-Platform Results: Breakdown by hardware/Wokwi (and QEMU if enabled)
- Failed Tests: Detailed information with logs
- Missed Tests: What didn't run and why
- Performance Metrics: If performance tests ran
- Comparison: Changes from previous test run
Missing Test Detection: Critical feature that ensures no tests are silently skipped due to infrastructure issues. If hardware is unavailable or binaries fail to download, the report explicitly calls this out rather than showing false-positive "all passed."
Tests are organized in the repository under tests/ directory:
tests/validation/- Basic functionality tests (always run)tests/performance/- Performance benchmarks (conditional)
Each test directory contains:
{test_name}.ino- Arduino sketch with test codetest_{test_name}.py- pytest test fileci.yml- Test requirements and configurationdiagram.{chip}.json- Optional Wokwi hardware diagram
Test Configuration (ci.yml):
Defines test requirements and platform support:
targets: {chip: true/false}- Which SoCs support this testplatforms: {platform: true/false}- Which platforms can run itrequires: [CONFIG_X=y]- Required sdkconfig settingsrequires_or: [CONFIG_A=y, CONFIG_B=y]- Alternative requirementslibs: [Library1, Library2]- Required libraries
Example:
targets:
esp32: true
esp32c3: true
esp32c6: false
esp32h2: false
esp32p4: false
esp32s2: false
esp32s3: true
platforms:
qemu: false
wokwi: true
hardware: true
requires:
- CONFIG_SOC_WIFI_SUPPORTED=yTest Execution:
The test runner (tests_run.sh) automatically:
- Checks requirements against built sdkconfig
- Skips tests that don't meet requirements
- Installs required libraries
- Configures platform-specific parameters
- Retries failed tests once
- Generates JUnit XML reports
| Platform | Speed | Coverage | Hardware | Use Case |
|---|---|---|---|---|
| QEMU | Fastest | Basic | Emulated | Quick validation |
| Wokwi | Fast | Wide | Simulated | Peripheral testing |
| Hardware | Slower | Complete | Real | Final validation |
Combined Strategy: All three platforms complement each other:
- QEMU provides quick feedback for basic issues
- Wokwi tests peripheral interactions without hardware constraints
- Physical hardware validates real-world behavior
This multi-platform approach ensures comprehensive testing while maintaining reasonable CI execution times.
Trigger:
- Push to
masterorrelease/*branches - Pull requests modifying:
cores/**libraries/**/*.{cpp,c,h}idf_component_examples/**idf_component.yml,Kconfig.projbuild,CMakeLists.txtvariants/**.github/scripts/socs_config.sh- Workflow and script files
- Manual workflow dispatch with customizable IDF versions/targets
Purpose: Ensure Arduino core works correctly as an ESP-IDF component
Inputs (Manual Dispatch):
idf_ver: Comma-separated IDF branches (default: "release-v5.5")idf_targets: Comma-separated targets (default: empty = use version-specific defaults)
Jobs:
Runs on: Ubuntu-latest
Purpose: Validate CMakeLists.txt completeness
Steps:
- Checkout repository
- Run check script:
bash ./.github/scripts/check-cmakelists.sh
Check Process:
The script compares source files found in the repository against files listed in CMakeLists.txt. It uses cmake's trace feature to extract the source list, then diffs against actual files. Any mismatch causes the check to fail.
Why Important: ESP-IDF's CMake-based build system requires explicit source file listing. Missing files won't compile, extra files indicate stale CMakeLists.txt. This check prevents both issues.
Runs on: Ubuntu-latest
Purpose: Generate IDF version × target matrix
Steps:
- Install universal-ctags
- Checkout repository (fetch-depth: 2)
- Get changed files
- Check official variants - Calls
check_official_variants.shwithIDF_COMPONENT_TARGETS - Get affected examples - Runs
get_affected.py --component - Upload affected examples and debug artifacts
- Generate matrix combinations:
Matrix Generation Process:
The script sources socs_config.sh and creates combinations of IDF versions and targets. It uses the centralized get_targets_for_idf_version() function to get version-specific target lists unless manual inputs override them. This generates a JSON matrix with entries like {idf_ver: "release-v5.5", idf_target: "esp32c3"}.
Outputs:
should_run- Based on official variant checkmatrix- JSON with IDF version × target combinationsshould_build- Based on affected examples
The resulting matrix includes all combinations of supported IDF versions and their respective targets. For example, v5.3 might have 8 targets while v5.5 has 10 (including esp32c5 and esp32c61).
Runs on: Ubuntu-latest
Conditions:
needs.set-matrix.outputs.should_run == 'true'needs.set-matrix.outputs.should_build == '1'
Container: espressif/idf:${{ matrix.idf_ver }}
Matrix: From set-matrix output
Steps:
-
Checkout as component:
- Path:
components/arduino-esp32 - With submodules: recursive
- Path:
-
Setup jq and yq:
- jq: For JSON parsing
- yq: For YAML parsing (ci.yml files)
-
Download affected examples
-
Build examples:
export IDF_TARGET=${{ matrix.idf_target }} ./components/arduino-esp32/.github/scripts/on-push-idf.sh affected_examples.txt
Build Process:
For each affected example, the script checks if the current target is supported (via ci.yml), applies target-specific sdkconfig defaults if available, then uses ESP-IDF's standard build commands (idf.py set-target and idf.py build).
- Upload sdkconfig files (on failure):
- Artifact:
sdkconfig-{idf_ver}-{idf_target} - Helps debug configuration issues
- Artifact:
Why Multiple IDF Versions:
- Ensures compatibility across ESP-IDF releases
- Catches breaking changes early
- Supports users on different IDF versions
Concurrency:
- Group:
build-component-{pr_number or ref} - Cancel in progress: Yes
Trigger:
- Pull requests modifying:
boards.txtlibraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino.github/workflows/boards.yml
Purpose: Validate new or modified board definitions
Jobs:
Runs on: Ubuntu-latest
Purpose: Identify boards that changed in the PR
Steps:
- Checkout repository
- Get board name from PR changes:
bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{ github.base_ref }}
Detection Logic:
The script fetches boards.txt from both the base branch and PR branch, extracts board names from each, then compares to find additions and modifications. Only boards that are new or have changed definitions are flagged for testing.
Outputs:
fqbns- JSON array of board FQBNs to test
Runs on: Ubuntu-latest
Conditions: Only if find-boards.outputs.fqbns != ''
Matrix: FQBNs from find-boards job
Steps:
-
Checkout repository
-
Validate board definition using
validate_board.shscript
Validation Checks:
- Required properties exist:
{board}.name{board}.upload.tool{board}.upload.maximum_size{board}.build.mcu{board}.build.core{board}.build.variant{board}.build.board
- Build options are valid
- Upload configurations are correct
- Memory sizes are reasonable
- Variant directory exists
-
Get libs cache (same as other workflows)
-
Compile test sketch:
- Uses
P-R-O-C-H-Y/compile-sketchesaction - Sketch:
libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino - FQBN:
${{ matrix.fqbn }} - Warnings: all
- Uses
Test Sketch Features:
- Includes common libraries (WiFi, BLE, etc.)
- Tests board-specific features
- Validates pin definitions
- Checks variant configuration
Trigger:
- Pull requests with
lib_testlabel - Schedule: Weekly on Sunday at 4:00 AM UTC
Purpose: Test Arduino core compatibility with popular external libraries
Jobs:
Runs on: Ubuntu-latest
Purpose: Generate matrix of targets from centralized config
Steps:
- Checkout repository
- Generate matrix by sourcing
socs_config.shand creating JSON entries for each target inBUILD_TEST_TARGETS, pairing each SoC with its corresponding FQBN
Outputs:
matrix- JSON with target and FQBN for each SoC
Why All Targets: External libraries should work on all supported SoCs
Runs on: Ubuntu-latest
Matrix: From gen-matrix output (one job per SoC)
Steps:
-
Checkout repository
-
Compile external library sketches:
- Uses
P-R-O-C-H-Y/compile-sketchesaction - Target:
${{ matrix.target }} - FQBN:
${{ matrix.fqbn }} - Library list:
.github/workflows/lib.json - Enables delta reports (size comparison)
- Enables warnings report
- Uses
lib.json Contents: The file lists popular Arduino libraries with their names, which examples to test (regex pattern or specific list), and version constraints. This ensures compatibility testing with commonly-used external libraries.
- Upload artifacts:
- Name:
libraries-report-{target} - Contains: Compile results and size data
- Name:
Runs on: Ubuntu-latest
Conditions:
- Only on scheduled runs (not PRs)
- After compile-sketch completes
Purpose: Archive library test results to gh-pages
Steps:
- Checkout gh-pages branch
- Download all library report artifacts
- Generate report:
- Uses
P-R-O-C-H-Y/report-size-deltasaction - Input: All sketch reports
- Output:
LIBRARIES_TEST.md
- Uses
- Append GitHub Action link
- Commit and push to gh-pages
Report Contents:
- Library compatibility status
- Sketch sizes per SoC
- Size changes over time
- Compilation warnings/errors
Conditions: Only on PRs with lib_test label
Purpose: Store PR number for status updates
Concurrency:
- Group:
libs-{pr_number or ref} - Cancel in progress: Yes
Trigger: Repository dispatch event with type test-boards
Purpose: Test all board definitions (not just new ones)
Use Case: Manually triggered for comprehensive validation before release
Jobs:
Steps:
- Lists all boards from
boards.txt - Uses
find_all_boards.shscript - Skips boards in
SKIP_LIB_BUILD_SOCS
Purpose: Divide boards into chunks for parallel testing
- Maximum 15 chunks
- Distributes boards evenly
Matrix: Chunks from setup-chunks
- Validates each board
- Compiles test sketch
- Same process as
boards.yml
Trigger:
- Push to
masterorrelease/* - Pull requests modifying
docs/**
Purpose: Build and deploy Sphinx documentation to GitHub Pages
Jobs:
- Setup Python with Sphinx
- Install documentation dependencies
- Build HTML from RST files
- Check for warnings/errors
- Upload built docs
Conditions: Only on push to master
- Download built docs
- Deploy to gh-pages branch
- Available at
espressif.github.io/arduino-esp32
Trigger:
- Manual workflow dispatch with:
release_tag- Version to release (e.g., "3.0.0")git_ref- Branch/tag to release from
- Push of tags matching version pattern
Purpose: Create GitHub releases and publish packages
Jobs:
Steps:
- Check tag format
- Verify package.json version matches
- Ensure changelog is updated
Steps:
- Checkout at release tag
- Run
tools/get.pyto download all platform tools - Package libraries, cores, variants, tools
- Generate
package_esp32_index.json - Calculate checksums
Steps:
- Create GitHub release with tag
- Upload package artifacts
- Generate release notes from changelog
- Mark as pre-release if beta/rc version
Steps:
- Upload to ESP-IDF component registry
- Uses
upload-idf-component.ymlworkflow - Published at
components.espressif.com
Trigger: Completion of push.yml on PRs
Purpose: Post compile size comparison comment to PR
Jobs:
- Download compile results from master (gh-pages)
- Download compile results from PR
- Compare sizes
- Generate markdown table
- Post comment to PR showing:
- Size changes per sketch
- Percentage changes
- Memory usage trends
Trigger: Pull requests
Purpose: Run code quality checks
pre-commit.yml:
- Runs pre-commit hooks
- Checks code formatting
- Validates file structure
- Ensures style guidelines
pre-commit-status.yml:
- Reports pre-commit status to PR
- Can block merge if checks fail
Trigger:
- Schedule: Weekly
- Push to master
- Pull requests to master
Purpose: Security vulnerability scanning
Steps:
- Initialize CodeQL
- Autobuild C/C++ code
- Perform security analysis
- Upload results to Security tab
Purpose: Central configuration for all SoC definitions
Contains:
- All SoC target lists
- Helper functions for SoC operations
- IDF version mappings
- QEMU architecture mappings
Usage: Sourced by all other scripts and workflows
Purpose: Determine if workflow should run based on variant changes
Usage:
bash .github/scripts/check_official_variants.sh \
"${{ github.event_name }}" \
"BUILD_TEST_TARGETS" \
${{ steps.changed-files.outputs.all_changed_files }}Logic:
- Always run if not a PR
- Check if any official variant files changed
- Check if any non-variant files changed
- Skip only if PR changes non-official variants exclusively
Purpose: Build sketches for push workflow
Features:
- Builds all targets from
BUILD_TEST_TARGETS - Supports chunked parallel builds
- Generates compile size reports
- Uses
sketch_utils.shfor actual compilation
Purpose: Core Arduino sketch compilation utilities
Functions:
build_sketch- Build a single sketchchunk_build- Build sketches in chunkscount- Count sketches for chunkingcheck_requirements- Validate sketch requirementsinstall_libs- Install library dependencies
Purpose: Generate test matrices for workflows
Uses: Sources socs_config.sh to create JSON matrices of targets and types
Purpose: Build test sketches
Features:
- Sources
socs_config.shfor targets - Builds tests with Arduino CLI
- Supports multiple test types
Purpose: Run compiled tests on different platforms
Platforms:
- hardware - Physical devices
- wokwi - Wokwi simulator
- qemu - QEMU emulator
Features:
- Auto-detects QEMU architecture using
get_arch() - Supports retry on failure
- Generates JUnit XML reports
Purpose: List all board FQBNs for testing
Filter: Uses should_skip_lib_build() to exclude boards without pre-built libs
Purpose: Detect boards modified in PR
Purpose: Validate board definition completeness
Purpose: Intelligent affected files detection
Features:
- Analyzes dependencies between files
- Uses ctags for symbol mapping
- Determines which sketches need rebuilding
- Supports both Arduino and IDF component modes
Purpose: Install Arduino CLI, IDE, and core
When adding support for a new ESP32 SoC variant, follow these steps:
Edit .github/scripts/socs_config.sh:
# Add to ALL_SOCS (alphabetically)
ALL_SOCS=(
"esp32"
"esp32c3"
"esp32-new" # ← Add here
# ...
)
# Add to platform-specific arrays based on capabilities
HW_TEST_TARGETS=(
# ...
"esp32-new" # If physical hardware available
)
WOKWI_TEST_TARGETS=(
# ...
"esp32-new" # If supported by Wokwi
)
QEMU_TEST_TARGETS=(
# ...
"esp32-new" # If supported by QEMU
)
# BUILD_TEST_TARGETS is auto-computed from above# Add to appropriate IDF version arrays
IDF_V5_5_TARGETS=(
# ...
"esp32-new"
)
# Update default if this is the latest
IDF_COMPONENT_TARGETS=("${IDF_V5_5_TARGETS[@]}")# If no pre-built libraries available
SKIP_LIB_BUILD_SOCS=(
"esp32c2"
"esp32c61"
"esp32-new" # ← Add if needed
)All workflows and scripts will automatically:
- Include the new SoC in builds
- Test on appropriate platforms
- Generate correct matrices
- Use correct QEMU architecture
No need to modify:
- Any workflow files
- Any other scripts
- Any test configurations
Prevent unnecessary CI runs when community members contribute custom board variants that aren't officially tested.
The script .github/scripts/check_official_variants.sh is called by workflows to determine if builds should run:
- name: Check if official variants changed
id: check-variants
run: |
bash .github/scripts/check_official_variants.sh \
"${{ github.event_name }}" \
"BUILD_TEST_TARGETS" \
${{ steps.changed-files.outputs.all_changed_files }}- Always run if not a PR (push, schedule, manual)
- Check variants if PR:
- Extract variant name from path (e.g.,
variants/esp32/...→esp32) - Check if variant is in official targets list
- If official variant found → run
- Extract variant name from path (e.g.,
- Check non-variant files:
- If any non-variant file changed → run
- Skip if only non-official variants changed
| Changes | Result | Reason |
|---|---|---|
variants/esp32/pins.h |
✅ Run | esp32 is official |
variants/custom_board/pins.h |
❌ Skip | custom_board not official |
cores/esp32/Arduino.h |
✅ Run | Non-variant file |
variants/esp32/... + variants/custom/... |
✅ Run | Official variant included |
| Push to master | ✅ Run | Not a PR |
push.yml- UsesBUILD_TEST_TARGETSbuild_component.yml- UsesIDF_COMPONENT_TARGETS
After modifying socs_config.sh:
- Source the config file and verify arrays are populated correctly
- Test helper functions return expected values
- Check that functions like
get_archandis_qemu_supportedwork for all SoCs
Test the official variant filter script with different scenarios:
- Official variant changes should return
true - Non-official variant changes should return
false - Push events should always return
trueregardless of changes
Individual scripts can be tested locally:
- Build scripts can run with Arduino CLI installed
- Test scripts require appropriate runtime environment (QEMU/hardware/Wokwi)
- Matrix generation scripts can be run to verify JSON output
Note: GitHub Actions workflows cannot run locally, but the bash scripts they call can be.
- Adding SoCs: Only edit
socs_config.sh- all workflows update automatically - Test Requirements: Use
ci.ymlin test directories to specify requirements - Library Dependencies: List in
ci.ymlfor automatic installation
- Keep config centralized: Resist adding SoC lists elsewhere
- Document changes: Update this README when adding workflows
- Test locally: Verify scripts work before pushing
- Monitor CI costs: Use official variant filter to reduce unnecessary runs
Problem: Workflow doesn't trigger
- Check
pathsin workflow file - Verify
socs_config.shis in sparse-checkout if used
Problem: Build fails for new SoC
- Ensure SoC is in appropriate target lists
- Check if pre-built libs exist (add to
SKIP_LIB_BUILD_SOCSif not) - Verify IDF version support
Problem: QEMU tests fail
- Check
get_arch()returns correct architecture - Verify SoC is in
QEMU_TEST_TARGETS - Ensure QEMU version supports the SoC
Problem: Variant filter not working
- Verify variant name matches exactly (case-sensitive)
- Check changed files are being passed correctly
- Test script locally with actual file paths
- Issues: Check existing GitHub issues
- Discussions: Use GitHub Discussions for questions
- CI Logs: Check workflow run logs for detailed errors
- Scripts: Most scripts have
--helpor-hflags
- Update IDF versions: Add new IDF releases to
socs_config.sh - Review external libs: Update
lib.jsonwith popular libraries - Monitor CI costs: Review workflow usage and optimize
- Update dependencies: Keep actions versions current
- Add new version arrays to
socs_config.sh - Update
get_targets_for_idf_version()function - Test builds with new version
- Update default
IDF_COMPONENT_TARGETSif needed
- Follow Adding a New SoC guide
- Create board definitions in
variants/ - Add to appropriate test matrices
- Verify all workflows pass
The ESP32 Arduino Core CI/CD system is designed for:
- Consistency: Centralized configuration ensures all parts use the same SoC lists
- Efficiency: Official variant filter reduces unnecessary runs
- Scalability: Easy to add new SoCs without touching workflows
- Maintainability: Single source of truth for all SoC definitions
- Comprehensiveness: Tests on multiple platforms (hardware, QEMU, Wokwi)
All SoC management flows through .github/scripts/socs_config.sh - when in doubt, start there!