From 3c2eb6cd557f0c3ec5d11c987a96e3f200dfce15 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 16 Sep 2026 11:32:35 -0700 Subject: [PATCH] ci: build the Espressif examples weekly A weekly scheduled job builds both ESP-IDF example projects, so a break in the Espressif port surfaces on its own instead of waiting for a user to report it. - compileAllExamples.sh builds every project under examples/, pointing the local components at WOLFSSH_ROOT and WOLFSSL_ROOT - the workflow covers ESP-IDF release-v5.5 and release-v5.1, built against wolfSSL v5.9.1-stable - a scheduled failure opens or comments on an issue labelled espressif-build-failure --- .github/workflows/espressif.yml | 97 +++++++++++++++++++++ ide/Espressif/ESP-IDF/compileAllExamples.sh | 89 +++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 .github/workflows/espressif.yml create mode 100755 ide/Espressif/ESP-IDF/compileAllExamples.sh diff --git a/.github/workflows/espressif.yml b/.github/workflows/espressif.yml new file mode 100644 index 00000000..72ef6958 --- /dev/null +++ b/.github/workflows/espressif.yml @@ -0,0 +1,97 @@ +name: wolfSSH Espressif Build Test + +on: + schedule: + # Weekly: Mondays at 07:00 UTC + - cron: '0 7 * * 1' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + WOLFSSL_REF: v5.9.1-stable + +jobs: + build_examples: + name: ESP-IDF ${{ matrix.idf-ref }} + strategy: + fail-fast: false + matrix: + # release-v5.5 is the current stable line; release-v5.1 is the version + # the example READMEs and VisualGDB projects document. + idf-ref: [ release-v5.5, release-v5.1 ] + runs-on: ubuntu-latest + container: + image: espressif/idf:${{ matrix.idf-ref }} + timeout-minutes: 30 + steps: + - name: Checkout wolfSSH + uses: actions/checkout@v6 + with: + path: wolfssh + + - name: Checkout wolfSSL + uses: actions/checkout@v6 + with: + repository: wolfssl/wolfssl + ref: ${{ env.WOLFSSL_REF }} + path: wolfssl + + - name: Build the Espressif examples + env: + WOLFSSH_ROOT: ${{ github.workspace }}/wolfssh + WOLFSSL_ROOT: ${{ github.workspace }}/wolfssl + run: | + # The image sets IDF_PATH, but the ESP-IDF tool paths come from + # export.sh, which a job step does not get from the entrypoint. + . "${IDF_PATH}/export.sh" + "${WOLFSSH_ROOT}/ide/Espressif/ESP-IDF/compileAllExamples.sh" + + notify_failure: + name: Open issue on scheduled failure + needs: [build_examples] + if: failure() && github.event_name == 'schedule' + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + issues: write + steps: + - uses: actions/github-script@v7 + with: + script: | + const label = 'espressif-build-failure'; + const runUrl = `${context.serverUrl}/${context.repo.owner}/` + + `${context.repo.repo}/actions/runs/${context.runId}`; + const body = [ + 'The weekly Espressif example build failed.', + '', + `Run: ${runUrl}`, + `Commit: ${context.sha}`, + ].join('\n'); + const existing = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + labels: label, + }); + if (existing.data.length > 0) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: existing.data[0].number, + body: body, + }); + } else { + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'Weekly Espressif example build failed', + body: body, + labels: [label], + }); + } diff --git a/ide/Espressif/ESP-IDF/compileAllExamples.sh b/ide/Espressif/ESP-IDF/compileAllExamples.sh new file mode 100755 index 00000000..f79079df --- /dev/null +++ b/ide/Espressif/ESP-IDF/compileAllExamples.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash + +# Build every wolfSSH ESP-IDF example project under ./examples/ +# +# The examples carry local wolfssh and wolfssl components that compile the +# library sources in place, so both source trees have to be on disk. Their +# CMakeLists find them through the WOLFSSH_ROOT and WOLFSSL_ROOT environment +# variables, which this script fills in when they are not already set. +# +# Run from an ESP-IDF environment: +# +# . /opt/esp/idf/export.sh +# WOLFSSL_ROOT=/path/to/wolfssl ide/Espressif/ESP-IDF/compileAllExamples.sh +# +# WOLFSSH_ROOT defaults to the tree holding this script, WOLFSSL_ROOT to a +# wolfssl checkout beside it. IDF_TARGET selects the chip; default esp32. + +if [ -z "${IDF_PATH}" ]; then + echo "ERROR: IDF_PATH is not set. Source the ESP-IDF export.sh first." + exit 1 +fi + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) + +if [ -z "${WOLFSSH_ROOT}" ]; then + WOLFSSH_ROOT=$(cd "${SCRIPT_DIR}/../../.." && pwd) +fi + +if [ -z "${WOLFSSL_ROOT}" ]; then + WOLFSSL_ROOT="$(dirname "${WOLFSSH_ROOT}")/wolfssl" +fi + +export WOLFSSH_ROOT +export WOLFSSL_ROOT +export IDF_TARGET="${IDF_TARGET:-esp32}" + +if [ ! -f "${WOLFSSH_ROOT}/wolfssh/ssh.h" ]; then + echo "ERROR: no wolfSSH source in WOLFSSH_ROOT=${WOLFSSH_ROOT}" + exit 1 +fi + +if [ ! -f "${WOLFSSL_ROOT}/wolfssl/ssl.h" ]; then + echo "ERROR: no wolfSSL source in WOLFSSL_ROOT=${WOLFSSL_ROOT}" + echo "Clone wolfssl beside wolfssh or set WOLFSSL_ROOT." + exit 1 +fi + +echo "IDF_PATH = ${IDF_PATH}" +echo "IDF_TARGET = ${IDF_TARGET}" +echo "WOLFSSH_ROOT = ${WOLFSSH_ROOT}" +echo "WOLFSSL_ROOT = ${WOLFSSL_ROOT}" + +BUILT="" +FAILED="" + +for PROJECT in "${SCRIPT_DIR}"/examples/*/; do + # A project directory is one with a top level CMakeLists.txt. + if [ ! -f "${PROJECT}/CMakeLists.txt" ]; then + continue + fi + + NAME=$(basename "${PROJECT}") + + echo + echo "--------------------------------------------------------------" + echo "Building ${NAME} for ${IDF_TARGET}" + echo "--------------------------------------------------------------" + + if (cd "${PROJECT}" && idf.py fullclean && idf.py build); then + BUILT="${BUILT} ${NAME}" + else + FAILED="${FAILED} ${NAME}" + fi +done + +if [ -z "${BUILT}" ] && [ -z "${FAILED}" ]; then + echo "ERROR: no example projects found in ${SCRIPT_DIR}/examples/" + exit 1 +fi + +echo +echo "Built: ${BUILT:- none}" + +if [ -n "${FAILED}" ]; then + echo "Failed:${FAILED}" + exit 1 +fi + +echo "All wolfSSH Espressif examples built."