name: CI - Sanity Checks on: push: branches: - main # Keep untrusted code on the read-only pull_request event. Never use pull_request_target here. pull_request: branches: - main workflow_dispatch: jobs: analyze: name: Code Analysis runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false - name: Setup Flutter uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: channel: "stable" flutter-version: "3.44.0" cache: true pub-cache: false - name: Cache Pub dependencies uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | ~/.pub-cache key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }} - name: Install dependencies run: | flutter pub get - name: Verify generated files committed run: scripts/codegen.sh --check - name: Verify translation hygiene run: python3 scripts/clean_translations.py --check --strict - name: Verify workflow and script guards run: | python3 scripts/check_build_workflow.py python3 scripts/check_apple_spm_locks.py python3 scripts/test_check_apple_spm_locks.py python3 scripts/check_workflow_security.py python3 scripts/test_check_workflow_security.py python3 scripts/check_workflow_action_pins.py python3 scripts/test_check_workflow_action_pins.py python3 scripts/test_check_codegen.py python3 scripts/test_format_native.py python3 scripts/test_run_maestro.py python3 scripts/check_update_packages_workflow.py python3 scripts/test_pubspec_version.py python3 scripts/test_clean_translations.py python3 scripts/test_check_icon_consistency.py - name: Verify formatting run: | paths=(lib) [ ! -d test ] || paths+=(test) find "${paths[@]}" -name "*.dart" ! -name "*.g.dart" ! -name "*.freezed.dart" -type f -print0 | xargs -0 -r dart format --output=none --set-exit-if-changed - name: Verify icon consistency run: dart run scripts/check_icon_consistency.dart - name: Analyze code run: dart run scripts/check_analyzer.dart - name: Check for unused code run: | echo "🔍 Checking for unused code..." dart run dart_code_linter:metrics check-unused-code lib 2>&1 | tee unused_code.txt if grep -qi "no unused code found" unused_code.txt; then echo "✅ No unused code found" else echo "❌ Found unused code:" cat unused_code.txt exit 1 fi - name: Check for unused files run: | echo "🔍 Checking for unused files..." dart run dart_code_linter:metrics check-unused-files lib 2>&1 | tee unused_files.txt if grep -qi "no unused files found" unused_files.txt; then echo "✅ No unused files found" else echo "❌ Found unused files:" cat unused_files.txt exit 1 fi test: name: Unit Tests runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false - name: Setup Flutter uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: channel: "stable" flutter-version: "3.44.0" cache: true pub-cache: false - name: Cache Pub dependencies uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | ~/.pub-cache key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }} - name: Install dependencies run: | flutter clean flutter pub get - name: Run tests run: | if [ -d "test" ] && [ "$(find test -name '*_test.dart' | wc -l)" -gt 0 ]; then flutter test else echo "No tests found, skipping test execution" fi android-test: name: Android JVM Unit Tests runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false - name: Setup Java uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5 with: distribution: "temurin" java-version: "17" - name: Setup Flutter uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: channel: "stable" flutter-version: "3.44.0" cache: true pub-cache: false - name: Cache Pub dependencies uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | ~/.pub-cache key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }} - name: Cache Gradle uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle- - name: Install dependencies run: flutter pub get - name: Configure Android local properties run: printf 'flutter.sdk=%s\nsdk.dir=%s\n' "$FLUTTER_ROOT" "$ANDROID_HOME" > android/local.properties - name: Run Android JVM unit tests working-directory: android run: ./gradlew :app:testDebugUnitTest :saf_util:testDebugUnitTest :libass:testDebugUnitTest -x :app:compileFlutterBuildDebug --continue - name: Check Android API compatibility working-directory: android run: ./gradlew :app:lintDebug native-format: name: Native Formatting runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false - name: Setup Java uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5 with: distribution: "temurin" java-version: "17" - name: Verify native formatting run: scripts/format_native.sh --check dependency-check: name: Dependency Validation runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false - name: Setup Flutter uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: channel: "stable" flutter-version: "3.44.0" cache: true pub-cache: false - name: Cache Pub dependencies uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | ~/.pub-cache key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }} - name: Verify dependencies run: | flutter clean flutter pub get flutter pub outdated