ci(flutter): Forgejo workflow — sync, analyze, test, build APK

Triggers on push to dev/main, tag pushes, PR to main, and manual
dispatch — all path-filtered to flutter_client/** and the three
shared web inputs the sync_shared.sh script reads.

Steps:
- Sync tokens/error-copy/svg from web/ via tool/sync_shared.sh
- Re-run dart run tool/gen_tokens.dart and fail if lib/theme/tokens.dart
  drifts from shared/fabledsword.tokens.json (catches forgotten regen
  on the JSON edit path)
- flutter pub get / analyze --fatal-infos / test
- Debug APK on every push (uploaded as a workflow artifact)
- Release APK on tag, attached to the corresponding Forgejo release
  via RELEASE_TOKEN (release.yml creates the release entry; this
  workflow just attaches the APK as minstrel-<tag>.apk)

Uses subosito/flutter-action@v2 on ubuntu-latest for portability —
no dependence on a Flutter-pre-installed runner.
This commit is contained in:
2026-05-02 17:42:38 -04:00
parent ec0c10f312
commit 7c0f9750d8
+105
View File
@@ -0,0 +1,105 @@
name: flutter
# Analyze + test + build the Flutter mobile client. Only runs when the
# diff touches flutter_client/ or one of the shared web inputs the
# sync_shared.sh script copies. Other pushes skip — this workflow is
# independent from the Go/web test.yml and release.yml.
on:
push:
branches: [dev, main]
tags: ['v*']
paths:
- 'flutter_client/**'
- 'web/src/lib/styles/tokens.json'
- 'web/src/lib/styles/error-copy.json'
- 'web/static/placeholders/album-fallback.svg'
- '.forgejo/workflows/flutter.yml'
pull_request:
branches: [main]
paths:
- 'flutter_client/**'
- 'web/src/lib/styles/tokens.json'
- 'web/src/lib/styles/error-copy.json'
- 'web/static/placeholders/album-fallback.svg'
- '.forgejo/workflows/flutter.yml'
workflow_dispatch:
jobs:
analyze-test-build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: flutter_client
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.5'
channel: stable
cache: true
- name: Sync shared assets from web/
run: ./tool/sync_shared.sh
- name: Verify generated tokens.dart matches JSON
shell: bash
run: |
dart run tool/gen_tokens.dart
if ! git diff --exit-code lib/theme/tokens.dart; then
echo "::error::lib/theme/tokens.dart is out of sync with shared/fabledsword.tokens.json"
echo "Run: cd flutter_client && dart run tool/gen_tokens.dart"
exit 1
fi
- name: Pub get
run: flutter pub get
- name: Analyze
run: flutter analyze --fatal-infos
- name: Test
run: flutter test --reporter compact
- name: Build debug APK
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')
run: flutter build apk --debug
- name: Build release APK
if: startsWith(github.ref, 'refs/tags/v')
run: flutter build apk --release
- name: Upload debug APK artifact
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')
uses: forgejo/upload-artifact@v3
with:
name: minstrel-debug-${{ github.sha }}
path: flutter_client/build/app/outputs/flutter-apk/app-debug.apk
- name: Attach release APK to release
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
TAG="${GITHUB_REF#refs/tags/}"
REPO="${GITHUB_REPOSITORY}"
# Look up the release ID for this tag (release must exist already;
# release.yml creates it as part of the server-side release flow).
RELEASE_ID=$(curl -fsSL \
-H "Authorization: token ${RELEASE_TOKEN}" \
"https://git.fabledsword.com/api/v1/repos/${REPO}/releases/tags/${TAG}" \
| grep -oP '"id":\s*\K[0-9]+' | head -1)
if [ -z "${RELEASE_ID}" ]; then
echo "::error::release for tag ${TAG} not found"
exit 1
fi
curl -fsSL \
-H "Authorization: token ${RELEASE_TOKEN}" \
-F "attachment=@build/app/outputs/flutter-apk/app-release.apk" \
"https://git.fabledsword.com/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=minstrel-${TAG}.apk"