1.0.0 #26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build firmware | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: "Optional tag name to cut a release (example 'v1.2.3'). Leave empty for build-only." | |
| required: false | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'main/**' | |
| - 'web/**' | |
| - 'sdkconfig*' | |
| - 'partitions_*.csv' | |
| - 'CMakeLists.txt' | |
| - 'tools/build_all.py' | |
| - 'tools/gen_web_flasher.py' | |
| - '.github/workflows/build.yml' | |
| tags: | |
| - 'v*' | |
| # A new push to the same ref supersedes in-flight builds. | |
| concurrency: | |
| group: build-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Single source of truth: derive the board matrix from tools/build_all.py so | |
| # adding a board there automatically adds it to CI. | |
| # --------------------------------------------------------------------------- | |
| prepare: | |
| name: Prepare matrix | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| matrix: ${{ steps.set.outputs.matrix }} | |
| wc_version: ${{ steps.version.outputs.wc_version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build board matrix | |
| id: set | |
| run: echo "matrix=$(python3 tools/build_all.py --print-matrix)" >> "$GITHUB_OUTPUT" | |
| - name: Read firmware version | |
| id: version | |
| run: | | |
| ver=$(grep -oP '(?<=JANOS_WC_VERSION ")[^"]+' main/main.c) | |
| echo "wc_version=$ver" >> "$GITHUB_OUTPUT" | |
| # --------------------------------------------------------------------------- | |
| # Build every board in parallel. fail-fast:false => one broken board does not | |
| # cancel the others, so you see every failure in a single run. | |
| # --------------------------------------------------------------------------- | |
| build: | |
| name: ${{ matrix.board }} | |
| needs: prepare | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-24.04 | |
| container: | |
| image: espressif/idf:release-v6.0 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: ${{ fromJSON(needs.prepare.outputs.matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Cache ESP-IDF artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: /root/.espressif | |
| key: espidf-release-v6.0-${{ matrix.board }}-${{ hashFiles('sdkconfig.defaults', 'dependencies.lock') }} | |
| restore-keys: | | |
| espidf-release-v6.0-${{ matrix.board }}- | |
| espidf-release-v6.0- | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: web/package-lock.json | |
| - name: Install web dependencies | |
| run: npm ci | |
| working-directory: web | |
| - name: Build web UI | |
| run: npm run build | |
| working-directory: web | |
| # build_all.py runs the firmware build, generates the per-board | |
| # flash_board.py, and verifies the generated sdkconfig matches the | |
| # board's defaults (catches config leakage). --no-docker because we are | |
| # already inside the esp-idf container. --retry 2 re-attempts the board | |
| # up to 2 extra times so a flaky failure (e.g. transient component-manager | |
| # network error) does not fail the job and block the release gate. | |
| - name: Build firmware (${{ matrix.board }}) | |
| run: | | |
| python3 tools/build_all.py \ | |
| --no-docker \ | |
| --no-web \ | |
| --retry 2 \ | |
| --targets ${{ matrix.board }} \ | |
| --output-dir artifacts | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: firmware-${{ matrix.board }} | |
| path: artifacts/${{ matrix.board }}/ | |
| if-no-files-found: error | |
| retention-days: 30 | |
| # --------------------------------------------------------------------------- | |
| # Release gate: needs ALL build jobs => runs only after every board is green. | |
| # Fires on a pushed v* tag, a published release, or a manual run with a tag. | |
| # --------------------------------------------------------------------------- | |
| release: | |
| name: Release | |
| needs: [prepare, build] | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: write | |
| outputs: | |
| tag: ${{ steps.meta.outputs.tag }} | |
| if: >- | |
| startsWith(github.ref, 'refs/tags/v') || | |
| (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release_artifacts/ | |
| - name: Resolve release tag | |
| id: meta | |
| env: | |
| INPUT_TAG: ${{ inputs.release_tag }} | |
| WC_VERSION: ${{ needs.prepare.outputs.wc_version }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| if [ "$TAG" = "$GITHUB_REF" ]; then TAG="${INPUT_TAG:-}"; fi | |
| if [ -z "$TAG" ]; then TAG="v${WC_VERSION}"; fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "Using tag: $TAG" | |
| # Bundle each board into its own zip (bins + flash_board.py). Release | |
| # assets share a flat namespace, so the per-board flash_board.py files | |
| # would otherwise collide — one zip per board keeps them separate and | |
| # gives users a single self-contained download. | |
| - name: Package per-board zips | |
| run: | | |
| set -euo pipefail | |
| mkdir -p release_zips | |
| for d in release_artifacts/firmware-*; do | |
| [ -d "$d" ] || continue | |
| board="${d#release_artifacts/firmware-}" | |
| (cd "$d" && zip -r -q "${GITHUB_WORKSPACE}/release_zips/mate-${board}.zip" .) | |
| done | |
| - name: Build release notes | |
| run: | | |
| { | |
| printf 'Auto-build from commit %s\n\nBoards:\n' "${GITHUB_SHA}" | |
| for z in release_zips/mate-*.zip; do | |
| board="$(basename "$z" .zip)" | |
| printf -- '- %s.zip\n' "$board" | |
| done | |
| } > release_notes.md | |
| - name: Create or update GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| TAG: ${{ steps.meta.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| gh release delete "$TAG" -R "$GITHUB_REPOSITORY" --yes 2>/dev/null || true | |
| gh release create "$TAG" -R "$GITHUB_REPOSITORY" \ | |
| --target "$GITHUB_SHA" \ | |
| --title "Mate $TAG" \ | |
| --notes-file release_notes.md \ | |
| release_zips/*.zip | |
| # --------------------------------------------------------------------------- | |
| # Web flasher: deploy the browser-based esptool-js flasher (docs/) to GitHub | |
| # Pages, arranging every board's bins under docs/firmware/<board>/ and | |
| # generating a per-board manifest + boards.json (the dropdown). needs release | |
| # => only publishes once every board is green AND a release was cut, so the | |
| # flasher never points at a half-built matrix. | |
| # --------------------------------------------------------------------------- | |
| pages: | |
| name: Web Flasher (Pages) | |
| needs: [prepare, build, release] | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deploy.outputs.page_url }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download all firmware artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: _artifacts | |
| pattern: firmware-* | |
| # Each artifact "firmware-<board>" holds that board's bins at its root. | |
| # Fan them out into docs/firmware/<board>/ so the manifests (and Pages) | |
| # can serve firmware/<board>/<file>.bin by relative URL. | |
| - name: Arrange firmware under docs/firmware/ | |
| run: | | |
| set -euo pipefail | |
| rm -rf docs/firmware | |
| mkdir -p docs/firmware | |
| for d in _artifacts/firmware-*; do | |
| [ -d "$d" ] || continue | |
| board="${d#_artifacts/firmware-}" | |
| mkdir -p "docs/firmware/${board}" | |
| cp "$d"/*.bin "docs/firmware/${board}/" | |
| done | |
| ls -R docs/firmware | |
| - name: Generate manifests + boards.json | |
| run: | | |
| python3 tools/gen_web_flasher.py \ | |
| --firmware-dir docs/firmware \ | |
| --out-dir docs \ | |
| --version "${{ needs.prepare.outputs.wc_version }}" \ | |
| --build "${{ needs.release.outputs.tag }}" | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v4 | |
| with: | |
| enablement: true | |
| - name: Upload Pages artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: docs | |
| - name: Deploy to GitHub Pages | |
| id: deploy | |
| uses: actions/deploy-pages@v4 |