name: 'Build dev release' on: workflow_dispatch: push: paths: - 'src/emsesp_version.h' branches: - 'dev' permissions: contents: write # Parallel graph (wall-clock is ~max of the firmware jobs, not the sum): # webui ──────┐ # ├─► firmware (s_4M / s_16M / s_16M_P / s3_16M_P) ─┐ # modbus ─────┤ ├─► release # └─► standalone ───────────────────────────────────┘ # # Extra -j on a single runner does not help: PlatformIO already compiles each # environment with all CPUs. The win is separate GitHub runners. jobs: webui: name: Build webUI if: github.event_name == 'workflow_dispatch' || github.repository == 'emsesp/EMS-ESP32' runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v6 with: package_json_file: interface/package.json - name: Install Node.js 26 uses: actions/setup-node@v7 with: node-version: 26 - name: Cache pnpm store uses: actions/cache@v6 with: path: ~/.local/share/pnpm/store key: ${{ runner.os }}-pnpm-${{ hashFiles('interface/package.json') }} restore-keys: | ${{ runner.os }}-pnpm- - name: Build webUI env: CI: true working-directory: interface run: | pnpm install pnpm build-webUI - name: Upload WWWData.h uses: actions/upload-artifact@v7 with: name: wwwdata path: src/ESP32React/WWWData.h if-no-files-found: error modbus: name: Build modbus if: github.event_name == 'workflow_dispatch' || github.repository == 'emsesp/EMS-ESP32' runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v7 - name: Install python 3.13 uses: actions/setup-python@v7 with: python-version: '3.13' - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "latest" enable-cache: false - name: Install pioarduino run: uv pip install --system pioarduino==6.2.0 - name: Build modbus run: platformio run -e build_modbus - name: Upload modbus header uses: actions/upload-artifact@v7 with: name: modbus-header path: src/core/modbus_entity_parameters.hpp if-no-files-found: error standalone: name: Build standalone needs: modbus runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v7 - name: Install python 3.13 uses: actions/setup-python@v7 with: python-version: '3.13' - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "latest" enable-cache: false - name: Install pioarduino run: uv pip install --system pioarduino==6.2.0 - name: Restore generated modbus header uses: actions/download-artifact@v8 with: name: modbus-header path: src/core - name: Build standalone run: platformio run -e build_standalone - name: Upload generated docs uses: actions/upload-artifact@v7 with: name: generated-docs path: | docs/dump_entities.csv docs/dump_telegrams.csv docs/Modbus-Entity-Registers.md if-no-files-found: error firmware: name: Firmware ${{ matrix.env }} needs: [webui, modbus] runs-on: ubuntu-latest strategy: fail-fast: true matrix: # Keep in sync with platformio.ini default_envs env: [s_4M, s_16M, s_16M_P, s3_16M_P] steps: - name: Checkout repository uses: actions/checkout@v7 - name: Install python 3.13 uses: actions/setup-python@v7 with: python-version: '3.13' - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "latest" enable-cache: false - name: Cache PlatformIO packages uses: actions/cache@v6 with: path: | ~/.platformio/.cache ~/.platformio/packages ~/.platformio/platforms key: ${{ runner.os }}-pio-${{ matrix.env }}-${{ hashFiles('platformio.ini') }} restore-keys: | ${{ runner.os }}-pio-${{ matrix.env }}- ${{ runner.os }}-pio- - name: Install pioarduino run: uv pip install --system pioarduino==6.2.0 - name: Restore WWWData.h uses: actions/download-artifact@v8 with: name: wwwdata path: src/ESP32React - name: Restore generated modbus header uses: actions/download-artifact@v8 with: name: modbus-header path: src/core - name: Setup ccache uses: hendrikmuhs/ccache-action@v1.2.24 with: key: firmware-${{ matrix.env }} restore-keys: firmware-${{ matrix.env }}- max-size: 1G - name: Build ${{ matrix.env }} env: CCACHE_COMPILERCHECK: content run: platformio run -e ${{ matrix.env }} - name: Upload firmware uses: actions/upload-artifact@v7 with: name: firmware-${{ matrix.env }} path: build/firmware if-no-files-found: error release: name: Create GitHub Release needs: [firmware, standalone] runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v7 with: fetch-depth: 0 - name: Get the EMS-ESP version id: build_info run: | version=`grep -E '^#define EMSESP_APP_VERSION' ./src/emsesp_version.h | awk -F'"' '{print $2}'` echo "VERSION=$version" >> $GITHUB_OUTPUT # must run before the release moves the 'latest' tag to this build - name: Find the previous dev release id: previous run: | prev=`git rev-parse -q --verify 'refs/tags/latest^{commit}' || git describe --tags --abbrev=0 --match 'v*'` echo "REF=$prev" >> $GITHUB_OUTPUT - name: Restore generated modbus header uses: actions/download-artifact@v8 with: name: modbus-header path: src/core - name: Restore generated docs uses: actions/download-artifact@v8 with: name: generated-docs path: . - name: Restore firmware binaries uses: actions/download-artifact@v8 with: pattern: firmware-* merge-multiple: true path: build/firmware - name: List firmware files run: ls -la build/firmware # the recovery build needs PlatformIO, and pnpm + Node.js to build its own WebUI (recovery/WWWData.h) - name: Install python 3.13 uses: actions/setup-python@v7 with: python-version: '3.13' - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "latest" enable-cache: false # falls back to the firmware jobs' caches, which hold the same toolchains - name: Cache PlatformIO packages uses: actions/cache@v6 with: path: | ~/.platformio/.cache ~/.platformio/packages ~/.platformio/platforms key: ${{ runner.os }}-pio-recovery-${{ hashFiles('platformio.ini') }} restore-keys: | ${{ runner.os }}-pio-recovery- ${{ runner.os }}-pio- - name: Install pioarduino run: uv pip install --system pioarduino==6.2.0 - name: Install pnpm uses: pnpm/action-setup@v6 with: package_json_file: interface/package.json - name: Install Node.js 26 uses: actions/setup-node@v7 with: node-version: 26 - name: Cache pnpm store uses: actions/cache@v6 with: path: ~/.local/share/pnpm/store key: ${{ runner.os }}-pnpm-${{ hashFiles('interface/package.json') }} restore-keys: | ${{ runner.os }}-pnpm- - name: Build the recovery firmware for the 16MB boards run: | platformio run -e recovery_s_16M -e recovery_s_16M_P -e recovery_s3_16M_P - name: Commit the generated files uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "chore: update generated files for v${{steps.build_info.outputs.VERSION}}" # an empty body falls back to the commit list generated by the release action - name: Build the release notes id: notes env: PREV_REF: ${{ steps.previous.outputs.REF }} VERSION: ${{ steps.build_info.outputs.VERSION }} run: | ./scripts/release_notes.sh "$PREV_REF" "$VERSION" > release_notes.md || : cat release_notes.md { echo 'BODY<<__RELEASE_NOTES_EOF__' cat release_notes.md echo '__RELEASE_NOTES_EOF__' } >> $GITHUB_OUTPUT - name: Create GitHub Release id: 'automatic_releases' uses: emsesp/action-automatic-releases@v1.0.1 with: repo_token: '${{ secrets.GITHUB_TOKEN }}' title: Development Build v${{steps.build_info.outputs.VERSION}} body: ${{ steps.notes.outputs.BODY }} generate_notes: false automatic_release_tag: 'latest' prerelease: true files: | CHANGELOG_LATEST.md ./build/firmware/*.* - name: Update version in Cloudflare KV store if: github.repository == 'emsesp/EMS-ESP32' env: CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} CF_NAMESPACE_ID: ${{ secrets.CF_NAMESPACE_ID }} CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} VERSION: ${{ steps.build_info.outputs.VERSION }} run: | JSON_DATA=$(jq -n \ --arg version "$VERSION" \ --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ '{version: $version, date: $date}') echo "JSON_DATA: $JSON_DATA" curl -sS --fail-with-body \ -X PUT "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/storage/kv/namespaces/${CF_NAMESPACE_ID}/values/dev" \ -H "Authorization: Bearer ${CF_API_TOKEN}" \ -H "Content-Type: application/json" \ -d "$JSON_DATA" echo