Skip to content

FIX: 修复 CI 测试失败 #158

FIX: 修复 CI 测试失败

FIX: 修复 CI 测试失败 #158

Workflow file for this run

name: CI
on:
push:
branches: [main, master]
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main, master]
paths-ignore:
- '**.md'
- 'docs/**'
env:
FLUTTER_VERSION: '3.41.5'
jobs:
analyze:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
cache-key: flutter-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
- name: Get dependencies
run: flutter pub get
- name: Run analyze
run: flutter analyze --no-fatal-warnings --no-fatal-infos
test:
runs-on: ubuntu-latest
needs: analyze
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
cache-key: flutter-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
- name: Get dependencies
run: flutter pub get
- name: Run tests
# Ubuntu runner 上全量测试收尾时,偶发「全部用例通过但 flutter test 以 1
# 退出」的 Flutter 测试运行器收尾工具链 flakiness(发生在所有用例已完成、
# reporter 已写出结果之后,与 app 代码无关)。诊断证实 --concurrency=1 防不住
# 它(失败样本本就是串行),故不再牺牲速度串行。改用 JSON reporter 的
# done.success 作为权威判定:忽略被收尾污染的进程退出码,仅当存在失败用例
# (或运行未正常结束、无 done 事件)时才判失败。
run: |
flutter test \
--file-reporter=json:test-results.json || true
python3 - <<'PY'
import json, sys
done = None
try:
with open('test-results.json', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
try:
event = json.loads(line)
except json.JSONDecodeError:
continue
if event.get('type') == 'done':
done = event
except FileNotFoundError:
print('::error::test-results.json 缺失 —— 测试未产出结果')
sys.exit(1)
if done is None:
print('::error::未找到 done 事件,测试运行未正常结束')
sys.exit(1)
if not done.get('success'):
print('::error::flutter test 报告存在失败用例')
sys.exit(1)
print('全部用例通过(依据 JSON reporter done.success),忽略进程退出码')
PY
build:
needs: [analyze, test]
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
platform: [ios, android]
include:
- platform: ios
runner: macos-latest
- platform: android
runner: ubuntu-latest
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
cache-key: flutter-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
- name: Get dependencies
run: flutter pub get
# Pods 缓存键必须同时绑定 pubspec.lock:ffmpeg_kit_flutter_new_min 的
# FFmpegKit xcframework 由 podspec prepare_command 下载到 pub-cache 包目录,
# 该命令只在 pod 首次安装时执行。若 pub-cache 因 pubspec.lock 变更被重建(Frameworks 丢失),
# 而 Pods 缓存仅按 Podfile.lock 命中,pod install 会跳过 prepare_command,
# 导致 framework 头文件缺失、iOS 构建失败。不用 restore-keys(部分命中会带回旧
# Manifest.lock,同样跳过 prepare_command)。
- name: Cache CocoaPods
if: matrix.platform == 'ios'
uses: actions/cache@v4
with:
path: ios/Pods
key: pods-${{ runner.os }}-${{ hashFiles('ios/Podfile.lock', 'pubspec.lock') }}
- name: Install CocoaPods
if: matrix.platform == 'ios'
run: cd ios && pod install
- name: Build iOS (no codesign)
if: matrix.platform == 'ios'
run: |
flutter build ios --release --no-codesign --flavor=prod \
--dart-define=API_BASE_URL=${{ vars.API_BASE_URL }} \
--dart-define=POSTHOG_HOST=${{ vars.POSTHOG_HOST }} \
--dart-define=SUPABASE_URL=${{ vars.SUPABASE_URL }} \
--dart-define=SUPABASE_PUBLISHABLE_KEY=${{ vars.SUPABASE_PUBLISHABLE_KEY }} \
--dart-define=GOOGLE_WEB_CLIENT_ID=${{ vars.GOOGLE_WEB_CLIENT_ID }}
- name: Setup Java
if: matrix.platform == 'android'
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Restore Android signing config
if: matrix.platform == 'android'
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
run: |
echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/app/upload-keystore.jks
cat > android/key.properties <<EOF
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyPassword=$ANDROID_KEY_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
storeFile=../app/upload-keystore.jks
EOF
- name: Build Android APK
if: matrix.platform == 'android'
run: |
flutter clean
flutter build apk --release --flavor=prod \
--target-platform android-arm64 \
--dart-define=API_BASE_URL=${{ vars.API_BASE_URL }} \
--dart-define=POSTHOG_HOST=${{ vars.POSTHOG_HOST }} \
--dart-define=SUPABASE_URL=${{ vars.SUPABASE_URL }} \
--dart-define=SUPABASE_PUBLISHABLE_KEY=${{ vars.SUPABASE_PUBLISHABLE_KEY }} \
--dart-define=GOOGLE_WEB_CLIENT_ID=${{ vars.GOOGLE_WEB_CLIENT_ID }}