build system #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release FAP | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release-fap | |
| cancel-in-progress: false | |
| jobs: | |
| metadata: | |
| name: Read app metadata | |
| runs-on: ubuntu-latest | |
| outputs: | |
| appid: ${{ steps.meta.outputs.appid }} | |
| app_name: ${{ steps.meta.outputs.app_name }} | |
| category: ${{ steps.meta.outputs.category }} | |
| version: ${{ steps.meta.outputs.version }} | |
| tag_name: ${{ steps.meta.outputs.tag_name }} | |
| release_exists: ${{ steps.tag.outputs.release_exists }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Parse application.fam | |
| id: meta | |
| shell: bash | |
| run: | | |
| python <<'PY' | |
| import os | |
| import pathlib | |
| import re | |
| import sys | |
| text = pathlib.Path("application.fam").read_text(encoding="utf-8") | |
| def read_field(name: str) -> str: | |
| match = re.search(rf'{name}\s*=\s*"([^"]+)"', text) | |
| if not match: | |
| print(f"Missing field: {name}", file=sys.stderr) | |
| sys.exit(1) | |
| return match.group(1) | |
| appid = read_field("appid") | |
| app_name = read_field("name") | |
| category = read_field("fap_category") | |
| version = read_field("fap_version") | |
| tag_name = f"v{version}" | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: | |
| fh.write(f"appid={appid}\n") | |
| fh.write(f"app_name={app_name}\n") | |
| fh.write(f"category={category}\n") | |
| fh.write(f"version={version}\n") | |
| fh.write(f"tag_name={tag_name}\n") | |
| PY | |
| - name: Check existing tag | |
| id: tag | |
| shell: bash | |
| run: | | |
| git fetch --tags --force | |
| if git rev-parse "${{ steps.meta.outputs.tag_name }}" >/dev/null 2>&1; then | |
| echo "release_exists=true" >> "$GITHUB_OUTPUT" | |
| echo "Release tag already exists: ${{ steps.meta.outputs.tag_name }}" | |
| else | |
| echo "release_exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| build: | |
| name: Build release assets (${{ matrix.track_name }}) | |
| runs-on: ubuntu-latest | |
| needs: metadata | |
| if: needs.metadata.outputs.release_exists != 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - track_id: momentum_dev | |
| track_name: Momentum Dev | |
| sdk_id: mntm-dev-22408e4c | |
| sdk_url: https://up.momentum-fw.dev/builds/firmware/dev/flipper-z-f7-sdk-mntm-dev-22408e4c.zip | |
| - track_id: unleashed | |
| track_name: Unleashed | |
| sdk_id: unlshd-086 | |
| sdk_url: https://github.com/DarkFlippers/unleashed-firmware/releases/download/unlshd-086/flipper-z-f7-sdk-unlshd-086.zip | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Build with ufbt | |
| id: build-app | |
| uses: flipperdevices/flipperzero-ufbt-action@v0.1.3 | |
| with: | |
| app-dir: . | |
| sdk-url: ${{ matrix.sdk_url }} | |
| sdk-hw-target: f7 | |
| - name: Stage release asset | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p release | |
| fap_path="$(find "${{ steps.build-app.outputs.fap-dir }}" -maxdepth 1 -type f -name '*.fap' | head -n 1)" | |
| if [ -z "$fap_path" ]; then | |
| echo "No .fap produced by build" >&2 | |
| exit 1 | |
| fi | |
| asset_name="${{ needs.metadata.outputs.appid }}_v${{ needs.metadata.outputs.version }}_${{ matrix.track_id }}.fap" | |
| cp "$fap_path" "release/$asset_name" | |
| echo "Created release/$asset_name" | |
| - name: Upload staged asset | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-${{ matrix.track_id }} | |
| path: release/*.fap | |
| if-no-files-found: error | |
| release: | |
| name: Publish GitHub release | |
| runs-on: ubuntu-latest | |
| needs: | |
| - metadata | |
| - build | |
| if: needs.metadata.outputs.release_exists != 'true' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download staged assets | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release-assets | |
| pattern: release-* | |
| merge-multiple: true | |
| - name: Create release notes | |
| shell: bash | |
| run: | | |
| cat > RELEASE_NOTES.md <<'EOF' | |
| Automated release generated from `application.fam`. | |
| - App: ${{ needs.metadata.outputs.app_name }} | |
| - App ID: `${{ needs.metadata.outputs.appid }}` | |
| - Category: `${{ needs.metadata.outputs.category }}` | |
| - Version: `${{ needs.metadata.outputs.version }}` | |
| - Assets: | |
| - `${{ needs.metadata.outputs.appid }}_v${{ needs.metadata.outputs.version }}_momentum_dev.fap` | |
| - `${{ needs.metadata.outputs.appid }}_v${{ needs.metadata.outputs.version }}_unleashed.fap` | |
| EOF | |
| - name: Create GitHub release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.metadata.outputs.tag_name }} | |
| name: ${{ needs.metadata.outputs.tag_name }} | |
| body_path: RELEASE_NOTES.md | |
| target_commitish: ${{ github.sha }} | |
| files: release-assets/*.fap | |
| generate_release_notes: true | |
| release-exists: | |
| name: Release already exists | |
| runs-on: ubuntu-latest | |
| needs: metadata | |
| if: needs.metadata.outputs.release_exists == 'true' | |
| steps: | |
| - name: Skip duplicate release | |
| run: echo "Release ${{ needs.metadata.outputs.tag_name }} already exists. Skipping." |