name: Custom Firmware Build on: workflow_dispatch: inputs: target: description: 'Target board (e.g. rak4631)' required: true type: string flags: description: 'Build flags (e.g. -DMESHTASTIC_EXCLUDE_MQTT)' required: false type: string version: description: 'Firmware Version (Tag/Branch)' required: true build_id: description: 'Convex Build ID' required: true type: string build_hash: description: 'Build hash for artifact naming' required: true type: string convex_url: description: 'Convex Site URL' required: true type: string jobs: build: runs-on: ubuntu-latest env: CONVEX_URL: ${{ inputs.convex_url }} BUILD_ID: ${{ inputs.build_id }} steps: - name: Setup status update helper shell: bash run: | cat > /tmp/update_status.sh << 'EOF' update_status() { curl -sSf -X POST "$CONVEX_URL/github-webhook" \ -H "Content-Type: application/json" \ -d "{\"action\": \"status_update\", \"build_id\": \"$BUILD_ID\", \"status\": \"$1\"}" || true } EOF chmod +x /tmp/update_status.sh - name: Update Status - Fetching Web Flasher shell: bash run: | source /tmp/update_status.sh update_status checking_out_web_flasher - name: Checkout Web Flasher (this repo) uses: actions/checkout@v4 with: repository: meshtastic/web-flasher ref: main path: web-flasher submodules: recursive fetch-depth: 1 - name: Update Status - Fetching Firmware shell: bash run: | source /tmp/update_status.sh update_status checking_out_firmware - name: Checkout Firmware uses: actions/checkout@v4 with: repository: meshtastic/firmware ref: ${{ inputs.version }} path: firmware submodules: recursive fetch-depth: 1 - name: Update Status - Downloading PlatformIO Cache shell: bash run: | source /tmp/update_status.sh update_status downloading_platformio_cache - name: Cache PlatformIO uses: actions/cache@v4 with: path: | ~/.platformio firmware/.pio/libdeps key: ${{ runner.os }}-pio-${{ hashFiles('firmware/platformio.ini') }} restore-keys: | ${{ runner.os }}-pio- - name: Update Status - Setting Up Python shell: bash run: | source /tmp/update_status.sh update_status setting_up_python - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.x' - name: Update Status - Installing PlatformIO shell: bash run: | source /tmp/update_status.sh update_status installing_platformio - name: Install PlatformIO run: | python -m pip install --upgrade pip pip install platformio - name: Update Status - Building Firmware shell: bash run: | source /tmp/update_status.sh update_status building_firmware - name: Build Firmware working-directory: firmware run: | echo "Building for target: ${{ inputs.target }}" echo "Flags: ${{ inputs.flags }}" # Inject flags into platformio.ini or environment export PLATFORMIO_BUILD_FLAGS="${{ inputs.flags }}" echo "PLATFORMIO_BUILD_FLAGS set to: $PLATFORMIO_BUILD_FLAGS" pio run -e ${{ inputs.target }} - name: Update Status - Preparing Upload if: success() shell: bash run: | source /tmp/update_status.sh update_status preparing_upload - name: Update Status - Installing Wrangler if: success() shell: bash run: | source /tmp/update_status.sh update_status installing_wrangler - name: Install Wrangler (for R2) if: success() shell: bash run: | npm install -g wrangler - name: Update Status - Uploading uf2 to R2 if: success() shell: bash run: | source /tmp/update_status.sh update_status uploading_uf2_to_r2 - name: Upload to R2 if: success() env: CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} R2_BUCKET_NAME: ${{ secrets.R2_BUCKET_NAME }} shell: bash run: | source /tmp/update_status.sh update_status locating_build_file # Determine file extension based on target (most are .bin, some might be .uf2) BUILD_FILE="firmware/.pio/build/${{ inputs.target }}/firmware.bin" FILE_EXT=".bin" if [ ! -f "$BUILD_FILE" ]; then BUILD_FILE="firmware/.pio/build/${{ inputs.target }}/firmware.uf2" FILE_EXT=".uf2" fi # Determine artifact path with correct extension (with leading slash for storage) ARTIFACT_PATH="/${{ inputs.build_hash }}${FILE_EXT}" # Object path for wrangler is bucket/key without leading slash OBJECT_PATH="${R2_BUCKET_NAME}/${{ inputs.build_hash }}${FILE_EXT}" update_status uploading # Upload to R2 with hash and correct extension wrangler r2 object put "$OBJECT_PATH" \ --file "$BUILD_FILE" --remote # Update build with artifact path (with leading slash) curl -sSf -X POST "$CONVEX_URL/github-webhook" \ -H "Content-Type: application/json" \ -d "{\"action\": \"status_update\", \"build_id\": \"$BUILD_ID\", \"status\": \"uploaded\", \"artifactPath\": \"$ARTIFACT_PATH\"}" || true echo "✅ Uploaded to R2: $ARTIFACT_PATH" - name: Update Build Status - Final if: always() run: | STATUS="${{ job.status }}" if [ "$STATUS" = "success" ]; then STATUS_MSG="success" else STATUS_MSG="failure" fi curl -X POST "${{ inputs.convex_url }}/github-webhook" \ -H "Content-Type: application/json" \ -d "{\"action\": \"completed\", \"build_id\": \"${{ inputs.build_id }}\", \"status\": \"$STATUS_MSG\"}"