name: ESP32 Build & Release on: push: branches: - main jobs: build: runs-on: ubuntu-latest container: image: espressif/idf:v5.5 steps: # ------------------------------------------------------------ # Checkout (Native Git - No Node.js required) # ------------------------------------------------------------ - name: Checkout shell: bash env: GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config --global --add safe.directory "$GITHUB_WORKSPACE" SERVER_HOST=$(echo "${{ github.server_url }}" | sed -e 's|^https://||' -e 's|^http://||') git init git remote add origin "https://${GITEA_TOKEN}@${SERVER_HOST}/${{ github.repository }}.git" || \ git remote set-url origin "https://${GITEA_TOKEN}@${SERVER_HOST}/${{ github.repository }}.git" git fetch --depth 1 origin "${{ github.sha }}" || git fetch --depth 1 origin main git checkout -f FETCH_HEAD # ------------------------------------------------------------ # Build firmware & merged binary # ------------------------------------------------------------ - name: Build firmware shell: bash run: | . /opt/esp/idf/export.sh idf.py --version idf.py set-target esp32 idf.py build idf.py merge-bin # ------------------------------------------------------------ # Prepare release artifacts & calculate hashes # ------------------------------------------------------------ - name: Prepare release shell: bash run: | mkdir -p release # Primary OTA application binary if [ -f build/mtg-rfid-companion.bin ]; then cp build/mtg-rfid-companion.bin release/mtg-rfid-companion.bin cp build/mtg-rfid-companion.bin release/firmware.bin else echo "ERROR: build/mtg-rfid-companion.bin not found!" exit 1 fi # Merged binary for USB factory flashing if [ -f build/merged-binary.bin ]; then cp build/merged-binary.bin release/merged-firmware.bin fi # ELF for debugging find build -maxdepth 1 -type f -name "*.elf" -exec cp {} release/ \; # Calculate hashes BIN_SHA256=$(sha256sum release/mtg-rfid-companion.bin | awk '{print $1}') IMG_SHA256=$(python3 -c "with open('release/mtg-rfid-companion.bin','rb') as f: f.seek(-32,2); print(f.read().hex())") echo "BIN_SHA256=${BIN_SHA256}" >> $GITHUB_ENV echo "IMG_SHA256=${IMG_SHA256}" >> $GITHUB_ENV echo "Firmware SHA256: ${BIN_SHA256}" > release/firmware.sha256 echo "Image SHA256: ${IMG_SHA256}" >> release/firmware.sha256 echo "Commit: ${{ github.sha }}" >> release/firmware.sha256 echo "OTA Release prepared:" echo " Binary: release/mtg-rfid-companion.bin" echo " File SHA-256: ${BIN_SHA256}" echo " Image SHA-256: ${IMG_SHA256}" ls -lh release/ # ------------------------------------------------------------ # Delete existing "latest" release & tag # ------------------------------------------------------------ - name: Delete existing latest release shell: bash env: GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | API="${{ github.server_url }}/api/v1" echo "Removing existing latest release..." curl -fsSL \ -X DELETE \ -H "Authorization: token ${GITEA_TOKEN}" \ "${API}/repos/${{ github.repository }}/releases/tags/latest" \ || true # Delete the tag as well curl -fsSL \ -X DELETE \ -H "Authorization: token ${GITEA_TOKEN}" \ "${API}/repos/${{ github.repository }}/tags/latest" \ || true # ------------------------------------------------------------ # Create latest release and upload assets (Native API & Curl) # ------------------------------------------------------------ - name: Create latest release shell: bash env: GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}" export RELEASE_BODY="Automatically built from the \`main\` branch. Commit: ${{ github.sha }} SHA256: ${{ env.IMG_SHA256 }} File-SHA256: ${{ env.BIN_SHA256 }} ESP-IDF: 5.5 Target: ESP32 This release is automatically replaced on every push to \`main\`." REL_ID=$(python3 -c "import urllib.request, json, os api = '${API}' token = os.environ['GITEA_TOKEN'] headers = {'Authorization': f'token {token}', 'Content-Type': 'application/json'} payload = { 'tag_name': 'latest', 'target_commitish': 'main', 'name': 'Latest ESP32 Firmware', 'body': os.environ.get('RELEASE_BODY', ''), 'draft': False, 'prerelease': False } req = urllib.request.Request(f'{api}/releases', data=json.dumps(payload).encode('utf-8'), headers=headers, method='POST') with urllib.request.urlopen(req) as resp: print(json.loads(resp.read().decode('utf-8'))['id']) ") echo "Created release ID: ${REL_ID}" for fpath in release/*; do [ -f "$fpath" ] || continue echo "Uploading $fpath..." curl -fsSL \ -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@${fpath}" \ "${API}/releases/${REL_ID}/assets" done echo "Release created and all assets uploaded successfully!"