Track 3 submission: rework of notch floating bar into a chat-first dynamic island #2861
Workflow file for this run
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: Mobile App Checks | |
| on: | |
| push: | |
| branches: main | |
| pull_request: | |
| branches: main | |
| concurrency: | |
| group: mobile-app-checks-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| has_app_codegen: ${{ steps.changes.outputs.has_app_codegen }} | |
| has_app_compile_smoke: ${{ steps.changes.outputs.has_app_compile_smoke }} | |
| has_app_dart: ${{ steps.changes.outputs.has_app_dart }} | |
| has_app_l10n: ${{ steps.changes.outputs.has_app_l10n }} | |
| has_flutter_generated: ${{ steps.changes.outputs.has_flutter_generated }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect changed paths | |
| id: changes | |
| uses: ./.github/actions/detect-changes | |
| generated-files: | |
| name: Generated Files | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.has_flutter_generated == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Resolve Flutter dependencies | |
| working-directory: app | |
| run: flutter pub get | |
| - name: Check Flutter generated code | |
| if: needs.changes.outputs.has_app_codegen == 'true' | |
| working-directory: app | |
| run: | | |
| dart run build_runner build --delete-conflicting-outputs | |
| git diff --exit-code -- lib || { | |
| echo "Generated Dart files are stale. Run: cd app && dart run build_runner build --delete-conflicting-outputs" | |
| exit 1 | |
| } | |
| if [ -n "$(git ls-files --others --exclude-standard -- lib)" ]; then | |
| echo "Generated Dart files are stale; untracked generated files were produced:" | |
| git ls-files --others --exclude-standard -- lib | |
| exit 1 | |
| fi | |
| - name: Check Flutter l10n | |
| if: needs.changes.outputs.has_app_l10n == 'true' | |
| working-directory: app | |
| run: | | |
| flutter gen-l10n | |
| git diff --exit-code -- lib/l10n || { | |
| echo "Generated localization files are stale. Run: cd app && flutter gen-l10n" | |
| exit 1 | |
| } | |
| if [ -n "$(git ls-files --others --exclude-standard -- lib/l10n)" ]; then | |
| echo "Generated localization files are stale; untracked generated files were produced:" | |
| git ls-files --others --exclude-standard -- lib/l10n | |
| exit 1 | |
| fi | |
| analyze: | |
| name: Dart Analyze (ratchet) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.has_app_dart == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Resolve Flutter dependencies | |
| working-directory: app | |
| run: flutter pub get | |
| - name: Prepare Flutter dev compile inputs | |
| working-directory: app | |
| run: | | |
| cp setup/prebuilt/firebase_options.dart lib/firebase_options_dev.dart | |
| cp setup/prebuilt/firebase_options.dart lib/firebase_options_prod.dart | |
| { | |
| echo "API_BASE_URL=" | |
| echo "USE_WEB_AUTH=true" | |
| echo "USE_AUTH_CUSTOM_TOKEN=true" | |
| echo "STAGING_API_URL=" | |
| } > .dev.env | |
| : > .env | |
| - name: Generate Flutter code | |
| working-directory: app | |
| run: dart run build_runner build --delete-conflicting-outputs | |
| - name: Run analyzer ratchet | |
| working-directory: app | |
| run: bash scripts/analyze_ratchet.sh | |
| flutter-test: | |
| name: Flutter Tests | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.has_app_dart == 'true' | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Run Flutter tests | |
| id: flutter_tests | |
| working-directory: app | |
| run: | | |
| set -o pipefail | |
| bash test.sh \ | |
| --reporter expanded \ | |
| --file-reporter "json:$GITHUB_WORKSPACE/flutter-test-results.json" \ | |
| 2>&1 | tee "$GITHUB_WORKSPACE/flutter-test-output.log" | |
| - name: Summarize failed Flutter tests | |
| if: ${{ failure() && steps.flutter_tests.outcome == 'failure' }} | |
| env: | |
| FLUTTER_TEST_RESULTS: ${{ github.workspace }}/flutter-test-results.json | |
| run: | | |
| python3 - <<'PY' | |
| import json | |
| import os | |
| from collections import defaultdict | |
| from pathlib import Path | |
| report = Path(os.environ['FLUTTER_TEST_RESULTS']) | |
| summary = Path(os.environ['GITHUB_STEP_SUMMARY']) | |
| tests = {} | |
| errors = defaultdict(list) | |
| failures = [] | |
| if report.exists(): | |
| for raw_line in report.read_text().splitlines(): | |
| try: | |
| event = json.loads(raw_line) | |
| except json.JSONDecodeError: | |
| continue | |
| event_type = event.get('type') | |
| if event_type == 'testStart': | |
| test = event.get('test', {}) | |
| tests[str(test.get('id'))] = test | |
| elif event_type == 'error': | |
| details = str(event.get('error', 'Unknown error')) | |
| if event.get('stackTrace'): | |
| details = f"{details}\n{event['stackTrace']}" | |
| errors[str(event.get('testID'))].append(details) | |
| elif event_type == 'testDone' and event.get('result') in {'failure', 'error'}: | |
| failures.append(event) | |
| with summary.open('a') as output: | |
| output.write('## Flutter test diagnostics\n\n') | |
| if not failures: | |
| output.write( | |
| 'Flutter exited unsuccessfully but emitted no failed-test event. ' | |
| 'Download the `flutter-test-diagnostics` artifact for the complete JSON stream and console log.\n' | |
| ) | |
| for failure in failures: | |
| test_id = str(failure.get('testID')) | |
| test = tests.get(test_id, {}) | |
| name = test.get('name', f'Unknown test (id {test_id})') | |
| output.write(f'### {name}\n\n') | |
| details = '\n'.join(errors[test_id]).strip() | |
| if details: | |
| output.write('```text\n') | |
| output.write(details[-6000:].replace('```', '``\\`')) | |
| output.write('\n```\n\n') | |
| PY | |
| - name: Upload Flutter test diagnostics | |
| if: ${{ failure() && steps.flutter_tests.outcome == 'failure' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: flutter-test-diagnostics | |
| path: | | |
| flutter-test-results.json | |
| flutter-test-output.log | |
| if-no-files-found: warn | |
| android-compile-smoke: | |
| name: Android Compile Smoke | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.has_app_compile_smoke == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| - name: Free runner disk space | |
| # ubuntu-latest ships with ~14GB free; the Gradle build runs out of | |
| # space during stripDebugSymbols. Remove unused preinstalled toolchains | |
| # (keep /usr/local/lib/android — the build needs the Android SDK). | |
| run: | | |
| sudo rm -rf /usr/share/dotnet /usr/local/.ghcup /opt/hostedtoolcache/CodeQL \ | |
| /usr/local/share/boost /usr/local/share/chromium /usr/local/lib/node_modules | |
| sudo docker image prune --all --force | |
| df -h / | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Resolve Flutter dependencies | |
| working-directory: app | |
| run: flutter pub get | |
| - name: Prepare Flutter dev compile inputs | |
| working-directory: app | |
| run: | | |
| mkdir -p android/app/src/dev/ android/app/src/prod/ | |
| cp setup/prebuilt/firebase_options.dart lib/firebase_options_dev.dart | |
| cp setup/prebuilt/firebase_options.dart lib/firebase_options_prod.dart | |
| cp setup/prebuilt/google-services.json android/app/src/dev/ | |
| cp setup/prebuilt/google-services.json android/app/src/prod/ | |
| cp setup/prebuilt/key.properties android/key.properties | |
| { | |
| echo "API_BASE_URL=" | |
| echo "USE_WEB_AUTH=true" | |
| echo "USE_AUTH_CUSTOM_TOKEN=true" | |
| echo "STAGING_API_URL=" | |
| } > .dev.env | |
| : > .env | |
| - name: Generate Flutter code for compile smoke | |
| working-directory: app | |
| run: dart run build_runner build --delete-conflicting-outputs | |
| - name: Setup Gradle for Flutter compile smoke | |
| uses: gradle/actions/setup-gradle@v6 | |
| - name: Build Flutter Android dev debug APK | |
| working-directory: app | |
| env: | |
| # GitHub Actions sets CI=true; android/app/build.gradle reads Codemagic | |
| # keystore env vars in that case even for debug APK builds. | |
| CM_KEYSTORE_PATH: ${{ github.workspace }}/app/setup/prebuilt/debug.keystore | |
| CM_KEYSTORE_PASSWORD: android | |
| CM_KEY_ALIAS: androiddebugkey | |
| CM_KEY_PASSWORD: android | |
| # Single ABI: a compile smoke doesn't need arm + arm64 + x86_64 native | |
| # libs, and the extra ABIs double disk usage during stripDebugSymbols. | |
| run: flutter build apk --debug --flavor dev --target-platform android-arm64 |