Skip to content

Weekly Auto Build FAP for Release and Dev Channels #2

Weekly Auto Build FAP for Release and Dev Channels

Weekly Auto Build FAP for Release and Dev Channels #2

Workflow file for this run

name: Auto Build FAP for All Firmwares and Channels
on:
schedule:
# Check for new firmware releases daily at 12:00 UTC
- cron: '0 12 * * *'
workflow_dispatch:
inputs:
force_build:
description: 'Force build even if no new firmware detected'
required: false
default: false
type: boolean
jobs:
check-firmware-updates:
runs-on: ubuntu-latest
outputs:
official-release-latest: ${{ steps.check-official-release.outputs.latest }}
official-dev-latest: ${{ steps.check-official-dev.outputs.latest }}
momentum-release-latest: ${{ steps.check-momentum-release.outputs.latest }}
momentum-dev-latest: ${{ steps.check-momentum-dev.outputs.latest }}
unleashed-release-latest: ${{ steps.check-unleashed-release.outputs.latest }}
unleashed-dev-latest: ${{ steps.check-unleashed-dev.outputs.latest }}
official-release-changed: ${{ steps.check-official-release.outputs.changed }}
official-dev-changed: ${{ steps.check-official-dev.outputs.changed }}
momentum-release-changed: ${{ steps.check-momentum-release.outputs.changed }}
momentum-dev-changed: ${{ steps.check-momentum-dev.outputs.changed }}
unleashed-release-changed: ${{ steps.check-unleashed-release.outputs.changed }}
unleashed-dev-changed: ${{ steps.check-unleashed-dev.outputs.changed }}
should-build: ${{ steps.determine-build.outputs.should-build }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install ufbt
run: |
python -m pip install --upgrade pip
pip install ufbt
- name: Check Official Release Channel
id: check-official-release
run: |
ufbt update --channel=release
LATEST=$(ufbt status | grep -E "Firmware origin:|Target:" | head -1 | sed 's/.*: *//' | cut -d' ' -f1 || echo "unknown")
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "official-release-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check Official Dev Channel
id: check-official-dev
run: |
ufbt update --channel=dev
LATEST=$(ufbt status | grep -E "Firmware origin:|Target:" | head -1 | sed 's/.*: *//' | cut -d' ' -f1 || echo "unknown")
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "official-dev-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check Momentum Release Channel
id: check-momentum-release
run: |
LATEST=$(curl -s https://api.github.com/repos/Next-Flip/Momentum-Firmware/releases | jq -r '[.[] | select(.prerelease == false)][0].tag_name // "unknown"')
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ "$LATEST" == "null" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "momentum-release-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check Momentum Dev Channel
id: check-momentum-dev
run: |
LATEST=$(curl -s https://api.github.com/repos/Next-Flip/Momentum-Firmware/releases | jq -r '[.[] | select(.prerelease == true)][0].tag_name // "unknown"')
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ "$LATEST" == "null" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "momentum-dev-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check Unleashed Release Channel
id: check-unleashed-release
run: |
LATEST=$(curl -s https://api.github.com/repos/DarkFlippers/unleashed-firmware/releases | jq -r '[.[] | select(.prerelease == false)][0].tag_name // "unknown"')
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ "$LATEST" == "null" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "unleashed-release-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check Unleashed Dev Channel
id: check-unleashed-dev
run: |
LATEST=$(curl -s https://api.github.com/repos/DarkFlippers/unleashed-firmware/releases | jq -r '[.[] | select(.prerelease == true)][0].tag_name // "unknown"')
echo "latest=$LATEST" >> $GITHUB_OUTPUT
if [[ "$LATEST" == "unknown" ]] || [[ "$LATEST" == "null" ]] || [[ -z "$LATEST" ]]; then
echo "changed=false" >> $GITHUB_OUTPUT
elif curl -s https://api.github.com/repos/${{ github.repository }}/releases | jq -r '.[].tag_name' | grep -q "unleashed-dev-$LATEST"; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Determine if build is needed
id: determine-build
run: |
if [[ "${{ github.event.inputs.force_build }}" == "true" ]] || \
[[ "${{ steps.check-official-release.outputs.changed }}" == "true" ]] || \
[[ "${{ steps.check-official-dev.outputs.changed }}" == "true" ]] || \
[[ "${{ steps.check-momentum-release.outputs.changed }}" == "true" ]] || \
[[ "${{ steps.check-momentum-dev.outputs.changed }}" == "true" ]] || \
[[ "${{ steps.check-unleashed-release.outputs.changed }}" == "true" ]] || \
[[ "${{ steps.check-unleashed-dev.outputs.changed }}" == "true" ]]; then
echo "should-build=true" >> $GITHUB_OUTPUT
else
echo "should-build=false" >> $GITHUB_OUTPUT
fi
build:
needs: check-firmware-updates
if: needs.check-firmware-updates.outputs.should-build == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
include:
# Official Firmware
- firmware: official
channel: release
ufbt_channel: release
version: ${{ needs.check-firmware-updates.outputs.official-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.official-release-changed }}
- firmware: official
channel: dev
ufbt_channel: dev
version: ${{ needs.check-firmware-updates.outputs.official-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.official-dev-changed }}
# Momentum Firmware
- firmware: momentum
channel: release
ufbt_channel: release
version: ${{ needs.check-firmware-updates.outputs.momentum-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.momentum-release-changed }}
- firmware: momentum
channel: dev
ufbt_channel: dev
version: ${{ needs.check-firmware-updates.outputs.momentum-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.momentum-dev-changed }}
# Unleashed Firmware
- firmware: unleashed
channel: release
ufbt_channel: release
version: ${{ needs.check-firmware-updates.outputs.unleashed-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.unleashed-release-changed }}
- firmware: unleashed
channel: dev
ufbt_channel: dev
version: ${{ needs.check-firmware-updates.outputs.unleashed-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.unleashed-dev-changed }}
steps:
- name: Check if build is needed
id: check-build
run: |
if [[ "${{ matrix.changed }}" == "false" ]] && [[ "${{ github.event.inputs.force_build }}" != "true" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
elif [[ "${{ matrix.version }}" == "null" ]] || [[ "${{ matrix.version }}" == "unknown" ]] || [[ -z "${{ matrix.version }}" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Skip if no changes or invalid version
if: steps.check-build.outputs.skip == 'true'
run: |
echo "Skipping ${{ matrix.firmware }} ${{ matrix.channel }} - no new version or invalid version"
exit 0
- name: Checkout code
if: steps.check-build.outputs.skip != 'true'
uses: actions/checkout@v4
- name: Set up Python
if: steps.check-build.outputs.skip != 'true'
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install ufbt
if: steps.check-build.outputs.skip != 'true'
run: |
python -m pip install --upgrade pip
pip install ufbt
- name: Setup ufbt for Official firmware
if: matrix.firmware == 'official' && steps.check-build.outputs.skip != 'true'
run: |
ufbt update --channel=${{ matrix.ufbt_channel }}
- name: Setup ufbt for Momentum firmware
if: matrix.firmware == 'momentum' && steps.check-build.outputs.skip != 'true'
run: |
# Use Momentum's custom index
ufbt update --channel=${{ matrix.ufbt_channel }} --index-url=https://up.momentum-fw.dev/directory.json
- name: Setup ufbt for Unleashed firmware
if: matrix.firmware == 'unleashed' && steps.check-build.outputs.skip != 'true'
run: |
# Use Unleashed's custom index
ufbt update --channel=${{ matrix.ufbt_channel }} --index-url=https://up.unleashedflip.com/directory.json
- name: Get app name from source
if: steps.check-build.outputs.skip != 'true'
id: app-info
run: |
# Try to extract app name from common patterns
if [ -f "application.fam" ]; then
APP_NAME=$(grep -E "name\s*=" application.fam | sed 's/.*name\s*=\s*"\([^"]*\)".*/\1/' | head -1)
elif [ -f "*.c" ]; then
# Look for app name in C files
APP_NAME=$(grep -r "\.name.*=" *.c | sed 's/.*\.name.*=.*"\([^"]*\)".*/\1/' | head -1)
fi
# Fallback to directory name
if [ -z "$APP_NAME" ]; then
APP_NAME=$(basename $(pwd))
fi
# Clean up name for filename
APP_NAME_CLEAN=$(echo "$APP_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/_/g')
echo "name=$APP_NAME" >> $GITHUB_OUTPUT
echo "clean_name=$APP_NAME_CLEAN" >> $GITHUB_OUTPUT
- name: Build FAP
if: steps.check-build.outputs.skip != 'true'
run: |
ufbt build
- name: Find and rename FAP
if: steps.check-build.outputs.skip != 'true'
id: fap-info
run: |
FAP_FILE=$(find . -name "*.fap" -path "*/dist/*" | head -1)
if [ -z "$FAP_FILE" ]; then
echo "No FAP file found!"
exit 1
fi
NEW_NAME="${{ steps.app-info.outputs.clean_name }}-${{ matrix.firmware }}-${{ matrix.channel }}-${{ matrix.version }}.fap"
cp "$FAP_FILE" "$NEW_NAME"
echo "filename=$NEW_NAME" >> $GITHUB_OUTPUT
- name: Upload artifact
if: steps.check-build.outputs.skip != 'true'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.firmware }}-${{ matrix.channel }}-${{ matrix.version }}
path: ${{ steps.fap-info.outputs.filename }}
create-releases:
needs: [check-firmware-updates, build]
if: needs.check-firmware-updates.outputs.should-build == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
include:
# Official Firmware
- firmware: official
channel: release
version: ${{ needs.check-firmware-updates.outputs.official-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.official-release-changed }}
- firmware: official
channel: dev
version: ${{ needs.check-firmware-updates.outputs.official-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.official-dev-changed }}
# Momentum Firmware
- firmware: momentum
channel: release
version: ${{ needs.check-firmware-updates.outputs.momentum-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.momentum-release-changed }}
- firmware: momentum
channel: dev
version: ${{ needs.check-firmware-updates.outputs.momentum-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.momentum-dev-changed }}
# Unleashed Firmware
- firmware: unleashed
channel: release
version: ${{ needs.check-firmware-updates.outputs.unleashed-release-latest }}
changed: ${{ needs.check-firmware-updates.outputs.unleashed-release-changed }}
- firmware: unleashed
channel: dev
version: ${{ needs.check-firmware-updates.outputs.unleashed-dev-latest }}
changed: ${{ needs.check-firmware-updates.outputs.unleashed-dev-changed }}
steps:
- name: Check if release is needed
id: check-release
run: |
if [[ "${{ matrix.changed }}" == "false" ]] && [[ "${{ github.event.inputs.force_build }}" != "true" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
elif [[ "${{ matrix.version }}" == "null" ]] || [[ "${{ matrix.version }}" == "unknown" ]] || [[ -z "${{ matrix.version }}" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Skip if no changes or invalid version
if: steps.check-release.outputs.skip == 'true'
run: |
echo "Skipping release for ${{ matrix.firmware }} ${{ matrix.channel }} - no new version or invalid version"
exit 0
- name: Checkout code
if: steps.check-release.outputs.skip != 'true'
uses: actions/checkout@v4
- name: Download artifact
if: steps.check-release.outputs.skip != 'true'
uses: actions/download-artifact@v4
with:
name: ${{ matrix.firmware }}-${{ matrix.channel }}-${{ matrix.version }}
path: ./release-files
- name: Get app info
if: steps.check-release.outputs.skip != 'true'
id: app-info
run: |
if [ -f "application.fam" ]; then
APP_NAME=$(grep -E "name\s*=" application.fam | sed 's/.*name\s*=\s*"\([^"]*\)".*/\1/' | head -1)
else
APP_NAME=$(basename $(pwd))
fi
echo "name=$APP_NAME" >> $GITHUB_OUTPUT
- name: Create Release
if: steps.check-release.outputs.skip != 'true'
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ matrix.firmware }}-${{ matrix.channel }}-${{ matrix.version }}
name: ${{ steps.app-info.outputs.name }} for ${{ matrix.firmware }} ${{ matrix.channel }} ${{ matrix.version }}
files: ./release-files/*.fap
body: |
## ${{ steps.app-info.outputs.name }}
**Built for:** ${{ matrix.firmware }} firmware ${{ matrix.channel }} channel ${{ matrix.version }}
This FAP was automatically built when ${{ matrix.firmware }} firmware ${{ matrix.channel }} ${{ matrix.version }} was released.
**Installation:**
1. Download the .fap file
2. Copy to your Flipper Zero's `apps` folder
3. The app will appear in your applications menu
**Firmware Compatibility:**
- ✅ ${{ matrix.firmware }} ${{ matrix.channel }} ${{ matrix.version }}
- ❌ Other firmware versions/channels (use the appropriate release)
**Channel Info:**
- **Release**: Stable, tested firmware
- **Dev**: Latest features, may be unstable
draft: false
prerelease: ${{ matrix.channel == 'dev' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
cleanup-old-releases:
needs: [check-firmware-updates, create-releases]
if: needs.check-firmware-updates.outputs.should-build == 'true'
runs-on: ubuntu-latest
steps:
- name: Cleanup old releases
run: |
# Keep only the latest 2 releases per firmware/channel combo to avoid clutter
for firmware in official momentum unleashed; do
for channel in release dev; do
RELEASES=$(curl -s https://api.github.com/repos/${{ github.repository }}/releases | \
jq -r --arg fw "$firmware" --arg ch "$channel" \
'.[] | select(.tag_name | startswith($fw + "-" + $ch)) | .id' | tail -n +3)
for release_id in $RELEASES; do
echo "Deleting old release: $release_id"
curl -X DELETE -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/$release_id"
done
done
done