Skip to content

Refactor radio configuration and enhance SX1262/SX1276 handling #60

Refactor radio configuration and enhance SX1262/SX1276 handling

Refactor radio configuration and enhance SX1262/SX1276 handling #60

Workflow file for this run

# ╔══════════════════════════════════════════════════════════════════════════╗
# ║ Rivr – Firmware Release Pipeline ║
# ║ ║
# ║ Triggered by: git tag push matching v* (e.g. v1.2.0) ║
# ║ ║
# ║ Pipeline overview: ║
# ║ 1. Build all firmware variants in parallel (matrix) ║
# ║ 2. Each job caches pip and PlatformIO layers ║
# ║ 3. Rust rivr_core is cross-compiled for the matching Xtensa target ║
# ║ 4. scripts/package_firmware.py assembles a user-ready ZIP per variant ║
# ║ containing: binaries, exact flash-layout JSON, merged image, ║
# ║ flash scripts, README ║
# ║ 5. A follow-up job collects all ZIPs and publishes the GitHub Release ║
# ╚══════════════════════════════════════════════════════════════════════════╝
name: Release
on:
push:
tags:
- "v*"
# All jobs need write permission to create the GitHub Release and attach assets.
permissions:
contents: write
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true
# ─────────────────────────────────────────────────────────────────────────────
# Build matrix – loaded from versioned repo metadata
# ─────────────────────────────────────────────────────────────────────────────
jobs:
firmware-matrix:
name: Firmware matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: matrix
name: Load firmware matrix
run: |
MATRIX=$(python3 -c "import json,pathlib; print(json.dumps(json.loads(pathlib.Path('.github/firmware-matrix.json').read_text())))")
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
build:
name: Build ${{ matrix.artifact }}
runs-on: ubuntu-latest
needs: firmware-matrix
strategy:
fail-fast: false # keep other variants building if one fails
matrix: ${{ fromJSON(needs.firmware-matrix.outputs.matrix) }}
steps:
# ── 1. Checkout ──────────────────────────────────────────────────────
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
# ── 2. Python (required by PlatformIO, ESP-IDF, esptool) ─────────────
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
# ── 3. Install PlatformIO + esptool ───────────────────────────────────
#
# esptool is installed here so it is available to both:
# - The ESP-IDF build system (called internally by PlatformIO)
# - scripts/package_firmware.py (for merge_bin)
- name: Install PlatformIO and esptool
run: |
pip install --upgrade pip
pip install platformio esptool adafruit-nrfutil
# ── 4. Install Espressif Rust toolchain (Xtensa) or ARM target ──────
- name: Install Espressif Rust toolchain via espup
if: ${{ matrix.rust_target != 'thumbv7em-none-eabihf' }}
run: |
cargo install espup --locked
espup install
source "$HOME/export-esp.sh"
[ -n "$LIBCLANG_PATH" ] && echo "LIBCLANG_PATH=$LIBCLANG_PATH" >> "$GITHUB_ENV"
[ -n "$CLANG_PATH" ] && echo "CLANG_PATH=$CLANG_PATH" >> "$GITHUB_ENV"
# Discover toolchain name (e.g. "esp" or "esp-1.84.0.0") from rustup
ESP_TOOLCHAIN=$(rustup toolchain list | grep -E '^esp' | awk '{print $1}' | head -n1)
echo "Activating Xtensa toolchain: $ESP_TOOLCHAIN"
echo "RUSTUP_TOOLCHAIN=$ESP_TOOLCHAIN" >> "$GITHUB_ENV"
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
shell: bash
- name: Install ARM Rust target for nRF52
if: ${{ matrix.rust_target == 'thumbv7em-none-eabihf' }}
run: rustup target add thumbv7em-none-eabihf
# ── 5. Restore build cache ────────────────────────────────────────────
#
# Key includes the PIO env name so cache from one variant is not
# accidentally reused by a different variant (different toolchain flags).
- name: Restore build cache
uses: actions/cache@v5
with:
path: |
~/.cache/pip
~/.platformio
key: firmware-${{ matrix.pio_env }}-${{ runner.os }}-${{ hashFiles('.github/firmware-matrix.json', 'platformio.ini', 'variants/**/*.ini', 'Cargo.lock', 'firmware_core/CMakeLists.txt', 'sdkconfig/**', 'sdkconfig*') }}
restore-keys: |
firmware-${{ matrix.pio_env }}-${{ runner.os }}-
firmware-${{ runner.os }}-
# ── 6. Build Rust rivr_core for the matching target ──────────────────
- name: Build Rust rivr_core (${{ matrix.rust_target }})
run: |
if [[ "${{ matrix.rust_target }}" == "thumbv7em-none-eabihf" ]]; then
cargo +stable build -p rivr_core \
--target ${{ matrix.rust_target }} \
--no-default-features \
--features ffi \
--release
else
source "$HOME/export-esp.sh"
cargo build -p rivr_core \
--target ${{ matrix.rust_target }} \
--no-default-features \
--features ffi \
--release \
-Zbuild-std=core,alloc,panic_abort
fi
shell: bash
# ── 7. Build firmware with PlatformIO ────────────────────────────────
- name: Build firmware (${{ matrix.pio_env }})
run: pio run -e ${{ matrix.pio_env }}
# ── 8. Package firmware ZIP ───────────────────────────────────────────
#
# scripts/package_firmware.py:
# - Copies bootloader.bin, partitions.bin, firmware.bin (→ rivr_<variant>.bin)
# - Writes rivr_<variant>.json with exact flash settings + offsets
# - Generates rivr_<variant>_full.bin via esptool merge_bin
# - Writes flash.sh (Linux/macOS) and flash.bat (Windows)
# - Writes README.txt with flashing instructions
# - Creates rivr_<variant>.zip containing the above
- name: Package firmware ZIP (${{ matrix.artifact }})
run: |
python scripts/package_firmware.py \
${{ matrix.pio_env }} \
${{ matrix.artifact }}
# ── 9. Upload per-variant ZIP artifact ───────────────────────────────
#
# Each matrix job uploads its own ZIP; the release job below downloads
# all of them and attaches them to the GitHub Release.
- name: Upload firmware ZIP artifact
uses: actions/upload-artifact@v4
with:
name: rivr_${{ matrix.artifact }}
path: rivr_${{ matrix.artifact }}.zip
if-no-files-found: error
retention-days: 7
# ───────────────────────────────────────────────────────────────────────────
# Release job – runs after all build matrix jobs succeed
# ───────────────────────────────────────────────────────────────────────────
release:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs: build # wait for all matrix builds to finish
steps:
# ── 10. Checkout (needed for bundle script + bundles JSON) ────────────
- name: Checkout repository
uses: actions/checkout@v4
# ── 11. Download all firmware ZIPs ────────────────────────────────────
#
# pattern: "rivr_*" matches every artifact uploaded by the build matrix.
# merge-multiple: true flattens them into the zips/ directory.
- name: Download all firmware ZIPs
uses: actions/download-artifact@v4
with:
pattern: rivr_*
path: zips
merge-multiple: true
- name: List collected ZIPs
run: ls -lh zips/
# ── 12. Assemble per-board bundle ZIPs ────────────────────────────────
#
# scripts/bundle_firmware.py reads .github/firmware-bundles.json and
# combines client / client_ble / repeater per-variant ZIPs into a single
# board-level bundle ZIP (rivr_<board>_bundle.zip).
# These are the files linked from the download page.
- name: Create board bundle ZIPs
run: |
python3 scripts/bundle_firmware.py \
zips \
.github/firmware-bundles.json \
zips
- name: List all ZIPs (variants + bundles)
run: ls -lh zips/
# ── 13. Create GitHub Release and attach ZIPs ─────────────────────────
#
# softprops/action-gh-release creates the release from the pushed tag and
# attaches every .zip file found in zips/ — both per-variant and bundles.
# Release notes are auto-generated from git log between tags.
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: "Rivr ${{ github.ref_name }}"
draft: false
prerelease: ${{ contains(github.ref_name, '-rc') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-alpha') }}
generate_release_notes: true
files: zips/*.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}