name: Release on: push: branches: - main tags: - '[0-9]*.[0-9]*.[0-9]*' release: types: - published permissions: contents: write jobs: bump-version-tag: if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Tag next patch version run: | set -eu git fetch --force --tags origin SEMVER_RE='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$' if git tag --points-at "$GITHUB_SHA" | grep -Eq "$SEMVER_RE"; then echo "semver tag already exists on this commit; skipping bump" echo "Tag already present on ${GITHUB_SHA}; release build runs from the tag event." >> "$GITHUB_STEP_SUMMARY" exit 0 fi LAST="$( git tag --list \ | grep -E "$SEMVER_RE" \ | sort -V \ | tail -n1 || true )" if [ -z "$LAST" ]; then # Seed semver history at the requested public baseline. NEXT="0.9.1" else MAJOR="${LAST%%.*}" REST="${LAST#*.}" MINOR="${REST%%.*}" PATCH="${LAST##*.}" NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))" fi git tag "$NEXT" "$GITHUB_SHA" git push origin "$NEXT" build-release: if: github.event_name == 'release' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) runs-on: ubuntu-latest env: SEMVER_RE: '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$' steps: - name: Check out repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Validate pushed tag is semver if: github.event_name == 'push' run: | echo "${GITHUB_REF_NAME}" | grep -Eq "${SEMVER_RE}" - name: Resolve release version id: release_version run: | if [ "${{ github.event_name }}" = "release" ]; then VERSION="${{ github.event.release.tag_name }}" else VERSION="${GITHUB_REF_NAME}" fi echo "version=$VERSION" >> "$GITHUB_OUTPUT" - name: Set up Arduino CLI uses: arduino/setup-arduino-cli@v2 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install adafruit-nrfutil run: pip install adafruit-nrfutil - name: Install Adafruit nRF52 core run: | arduino-cli config init --overwrite arduino-cli config set board_manager.additional_urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json arduino-cli core update-index arduino-cli core install adafruit:nrf52 - name: Generate version header env: OPK_BUILD_VERSION: ${{ steps.release_version.outputs.version }} run: ./gen_version.sh - name: Compile OpenPuck run: | mkdir -p build/openpuck build/cache/openpuck arduino-cli compile \ -b adafruit:nrf52:feather52840 \ --clean \ --build-path build/cache/openpuck \ --output-dir build/openpuck \ --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb} -DCFG_TUD_HID=4 -DCFG_TUD_TASK_QUEUE_SZ=64 -DCFG_TUD_VENDOR_TX_BUFSIZE=256" \ OpenPuck - name: Generate UF2 (standard) run: ./gen_uf2.sh build/openpuck/OpenPuck.ino.hex build/openpuck/OpenPuck.ino.uf2 - name: Compile ReversePuckFirmware run: | mkdir -p build/reversepuck build/cache/reversepuck arduino-cli compile \ -b adafruit:nrf52:feather52840 \ --clean \ --build-path build/cache/reversepuck \ --output-dir build/reversepuck \ --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb}" \ ReversePuckFirmware - name: Generate UF2 (ReversePuckFirmware) run: ./gen_uf2.sh build/reversepuck/ReversePuckFirmware.ino.hex build/reversepuck/ReversePuckFirmware.ino.uf2 - name: Compile recovery build run: | mkdir -p build/openpuck-recovery build/cache/openpuck-recovery arduino-cli compile \ -b adafruit:nrf52:feather52840 \ --clean \ --build-path build/cache/openpuck-recovery \ --output-dir build/openpuck-recovery \ --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb} -DCFG_TUD_HID=4 -DCFG_TUD_TASK_QUEUE_SZ=64 -DCFG_TUD_VENDOR_TX_BUFSIZE=256 -DOPK_FACTORY_RESET=1" \ OpenPuck - name: Generate UF2 (recovery) run: ./gen_uf2.sh build/openpuck-recovery/OpenPuck.ino.hex build/openpuck-recovery/OpenPuck.ino.uf2 - name: Collect artifacts env: VERSION: ${{ steps.release_version.outputs.version }} run: | mkdir -p release_assets find build/openpuck build/openpuck-recovery \ -maxdepth 1 -type f \ \( -name '*.uf2' -o -name '*.hex' \) \ -print | while read -r f; do # Keep only the extension; the arduino base name (OpenPuck.ino.*) # is redundant once we prefix with OpenPuck--. ext="${f##*.}" dir="$(basename "$(dirname "$f")")" if [ "$dir" = "openpuck-recovery" ]; then flavor="factory-reset" else flavor="standard" fi cp "$f" "release_assets/OpenPuck-${VERSION}-${flavor}.${ext}" done find build/reversepuck \ -maxdepth 1 -type f \ \( -name '*.uf2' -o -name '*.hex' \) \ -print | while read -r f; do ext="${f##*.}" cp "$f" "release_assets/ReversePuckFirmware-${VERSION}.${ext}" done test -n "$(find release_assets -maxdepth 1 -type f -print -quit)" ls -la release_assets - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.release_version.outputs.version }} name: ${{ format('OpenPuck {0}', steps.release_version.outputs.version) }} prerelease: false files: release_assets/* body: | OpenPuck Firmware Release Version: ${{ steps.release_version.outputs.version }} Commit: ${{ github.sha }} ### Files included: - `OpenPuck-*-standard.*` — puck firmware (standard) - `OpenPuck-*-factory-reset.*` — puck firmware (factory reset) - `ReversePuckFirmware-*.*` — reverse-puck firmware (controller emulator) - `.uf2` files for drag-and-drop flashing (BOOT/UF2 drive) - `.hex` files for direct flashing workflows env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}