release.yml 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. name: Release
  2. on:
  3. push:
  4. branches:
  5. - main
  6. tags:
  7. - '[0-9]*.[0-9]*.[0-9]*'
  8. release:
  9. types:
  10. - published
  11. permissions:
  12. contents: write
  13. jobs:
  14. bump-version-tag:
  15. if: github.event_name == 'push' && github.ref == 'refs/heads/main'
  16. runs-on: ubuntu-latest
  17. steps:
  18. - name: Check out repository
  19. uses: actions/checkout@v4
  20. with:
  21. fetch-depth: 0
  22. - name: Tag next patch version
  23. run: |
  24. set -eu
  25. git fetch --force --tags origin
  26. SEMVER_RE='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
  27. if git tag --points-at "$GITHUB_SHA" | grep -Eq "$SEMVER_RE"; then
  28. echo "semver tag already exists on this commit; skipping bump"
  29. echo "Tag already present on ${GITHUB_SHA}; release build runs from the tag event." >> "$GITHUB_STEP_SUMMARY"
  30. exit 0
  31. fi
  32. LAST="$(
  33. git tag --list \
  34. | grep -E "$SEMVER_RE" \
  35. | sort -V \
  36. | tail -n1 || true
  37. )"
  38. if [ -z "$LAST" ]; then
  39. # Seed semver history at the requested public baseline.
  40. NEXT="0.9.1"
  41. else
  42. MAJOR="${LAST%%.*}"
  43. REST="${LAST#*.}"
  44. MINOR="${REST%%.*}"
  45. PATCH="${LAST##*.}"
  46. NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))"
  47. fi
  48. git tag "$NEXT" "$GITHUB_SHA"
  49. git push origin "$NEXT"
  50. build-release:
  51. if: github.event_name == 'release' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
  52. runs-on: ubuntu-latest
  53. steps:
  54. - name: Check out repository
  55. uses: actions/checkout@v4
  56. with:
  57. fetch-depth: 0
  58. - name: Resolve release version
  59. id: release_version
  60. run: |
  61. if [ "${{ github.event_name }}" = "release" ]; then
  62. VERSION="${{ github.event.release.tag_name }}"
  63. else
  64. VERSION="${GITHUB_REF_NAME}"
  65. fi
  66. echo "version=$VERSION" >> "$GITHUB_OUTPUT"
  67. - name: Set up Arduino CLI
  68. uses: arduino/setup-arduino-cli@v2
  69. - name: Set up Python
  70. uses: actions/setup-python@v5
  71. with:
  72. python-version: '3.x'
  73. - name: Install adafruit-nrfutil
  74. run: pip install adafruit-nrfutil
  75. - name: Install Adafruit nRF52 core
  76. run: |
  77. arduino-cli config init --overwrite
  78. arduino-cli config set board_manager.additional_urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
  79. arduino-cli core update-index
  80. arduino-cli core install adafruit:nrf52
  81. - name: Generate version header
  82. env:
  83. OPK_BUILD_VERSION: ${{ steps.release_version.outputs.version }}
  84. run: ./gen_version.sh
  85. - name: Compile OpenPuck
  86. run: |
  87. mkdir -p build/openpuck build/cache/openpuck
  88. arduino-cli compile \
  89. -b adafruit:nrf52:feather52840 \
  90. --clean \
  91. --build-path build/cache/openpuck \
  92. --output-dir build/openpuck \
  93. --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" \
  94. OpenPuck
  95. - name: Generate UF2 (standard)
  96. run: ./gen_uf2.sh build/openpuck/OpenPuck.ino.hex build/openpuck/OpenPuck.ino.uf2
  97. - name: Compile ReversePuckFirmware
  98. run: |
  99. mkdir -p build/reversepuck build/cache/reversepuck
  100. arduino-cli compile \
  101. -b adafruit:nrf52:feather52840 \
  102. --clean \
  103. --build-path build/cache/reversepuck \
  104. --output-dir build/reversepuck \
  105. --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb}" \
  106. ReversePuckFirmware
  107. - name: Generate UF2 (ReversePuckFirmware)
  108. run: ./gen_uf2.sh build/reversepuck/ReversePuckFirmware.ino.hex build/reversepuck/ReversePuckFirmware.ino.uf2
  109. - name: Compile recovery build
  110. run: |
  111. mkdir -p build/openpuck-recovery build/cache/openpuck-recovery
  112. arduino-cli compile \
  113. -b adafruit:nrf52:feather52840 \
  114. --clean \
  115. --build-path build/cache/openpuck-recovery \
  116. --output-dir build/openpuck-recovery \
  117. --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" \
  118. OpenPuck
  119. - name: Generate UF2 (recovery)
  120. run: ./gen_uf2.sh build/openpuck-recovery/OpenPuck.ino.hex build/openpuck-recovery/OpenPuck.ino.uf2
  121. - name: Collect artifacts
  122. env:
  123. VERSION: ${{ steps.release_version.outputs.version }}
  124. run: |
  125. mkdir -p release_assets
  126. find build/openpuck build/openpuck-recovery \
  127. -maxdepth 1 -type f \
  128. \( -name '*.uf2' -o -name '*.zip' \) \
  129. -print | while read -r f; do
  130. # Keep only the extension; the arduino base name (OpenPuck.ino.*)
  131. # is redundant once we prefix with OpenPuck-<version>-<flavor>.
  132. ext="${f##*.}"
  133. dir="$(basename "$(dirname "$f")")"
  134. if [ "$dir" = "openpuck-recovery" ]; then
  135. flavor="factory-reset"
  136. else
  137. flavor="standard"
  138. fi
  139. cp "$f" "release_assets/OpenPuck-${VERSION}-${flavor}.${ext}"
  140. done
  141. find build/reversepuck \
  142. -maxdepth 1 -type f \
  143. \( -name '*.uf2' -o -name '*.zip' \) \
  144. -print | while read -r f; do
  145. ext="${f##*.}"
  146. cp "$f" "release_assets/ReversePuckFirmware-${VERSION}.${ext}"
  147. done
  148. test -n "$(find release_assets -maxdepth 1 -type f -print -quit)"
  149. ls -la release_assets
  150. - name: Create GitHub Release
  151. uses: softprops/action-gh-release@v2
  152. with:
  153. tag_name: ${{ steps.release_version.outputs.version }}
  154. name: ${{ format('OpenPuck {0}', steps.release_version.outputs.version) }}
  155. prerelease: false
  156. files: release_assets/*
  157. body: |
  158. OpenPuck Firmware Release
  159. Version: ${{ steps.release_version.outputs.version }}
  160. Commit: ${{ github.sha }}
  161. ### Files included:
  162. - `OpenPuck-*-standard.*` — puck firmware (standard)
  163. - `OpenPuck-*-factory-reset.*` — puck firmware (factory reset)
  164. - `ReversePuckFirmware-*.*` — reverse-puck firmware (controller emulator)
  165. - `.zip` files for Adafruit DFU tool
  166. - `.uf2` files for drag-and-drop flashing (BOOT/UF2 drive)
  167. env:
  168. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}