From e650af87c062f8df563709396b9635052a0ec299 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 16:28:06 -0500 Subject: [PATCH] feat: Add mobile CI workflow for change detection, compilation, and linting --- .github/workflows/mobile-ci.yml | 237 ++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 .github/workflows/mobile-ci.yml diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml new file mode 100644 index 00000000..5f18d948 --- /dev/null +++ b/.github/workflows/mobile-ci.yml @@ -0,0 +1,237 @@ +name: Mobile CI + +on: + pull_request: + paths: + - 'apps/mobile/**' + - '.github/workflows/mobile-ci.yml' + push: + branches: + - main + paths: + - 'apps/mobile/**' + - '.github/workflows/mobile-ci.yml' + +jobs: + detect-changes: + name: ๐Ÿ” Detect Mobile Changes + runs-on: ubuntu-latest + outputs: + mobile-changed: ${{ steps.detect.outputs.mobile-changed }} + changed-files: ${{ steps.detect.outputs.changed-files }} + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐Ÿ”Ž Detect changes in apps/mobile + id: detect + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + # For PR, compare with base branch + BASE_REF="${{ github.event.pull_request.base.ref }}" + HEAD_REF="${{ github.event.pull_request.head.ref }}" + CHANGED_FILES=$(git diff --name-only origin/$BASE_REF..origin/$HEAD_REF 2>/dev/null || echo "") + else + # For push, compare with previous commit + if [[ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]]; then + # Initial commit, check all files + CHANGED_FILES=$(git ls-tree -r --name-only HEAD) + else + CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }}) + fi + fi + + # Filter for files in apps/mobile + MOBILE_CHANGED=$(echo "$CHANGED_FILES" | grep -c "^apps/mobile/" || echo "0") + + if [[ $MOBILE_CHANGED -gt 0 ]]; then + echo "mobile-changed=true" >> $GITHUB_OUTPUT + # Get list of changed Dart files in apps/mobile + MOBILE_FILES=$(echo "$CHANGED_FILES" | grep "^apps/mobile/" | grep "\.dart$" || echo "") + echo "changed-files<> $GITHUB_OUTPUT + echo "$MOBILE_FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "โœ… Changes detected in apps/mobile/" + echo "๐Ÿ“ Changed files:" + echo "$MOBILE_FILES" + else + echo "mobile-changed=false" >> $GITHUB_OUTPUT + echo "changed-files=" >> $GITHUB_OUTPUT + echo "โญ๏ธ No changes detected in apps/mobile/ - skipping checks" + fi + + compile: + name: ๐Ÿ—๏ธ Compile Mobile App + runs-on: macos-latest + needs: detect-changes + if: needs.detect-changes.outputs.mobile-changed == 'true' + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + + - name: ๐Ÿฆ‹ Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.19.x' + channel: 'stable' + cache: true + + - name: ๐Ÿ“ฆ Get Flutter dependencies + run: | + cd apps/mobile + flutter pub get + + - name: ๐Ÿ”จ Run compilation check + run: | + cd apps/mobile + echo "โš™๏ธ Running build_runner..." + flutter pub run build_runner build --delete-conflicting-outputs 2>&1 || true + + echo "" + echo "๐Ÿ”ฌ Running flutter analyze on all files..." + flutter analyze lib/ --no-fatal-infos 2>&1 | tee analyze_output.txt || true + + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + # Check for actual errors (not just warnings) + if grep -E "^\s*(error|SEVERE):" analyze_output.txt > /dev/null; then + echo "โŒ COMPILATION ERRORS FOUND:" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + grep -B 2 -A 1 -E "^\s*(error|SEVERE):" analyze_output.txt | sed 's/^/ /' + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + exit 1 + else + echo "โœ… Compilation check PASSED - No errors found" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + fi + + lint: + name: ๐Ÿงน Lint Changed Files + runs-on: macos-latest + needs: detect-changes + if: needs.detect-changes.outputs.mobile-changed == 'true' && needs.detect-changes.outputs.changed-files != '' + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + + - name: ๐Ÿฆ‹ Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.19.x' + channel: 'stable' + cache: true + + - name: ๐Ÿ“ฆ Get Flutter dependencies + run: | + cd apps/mobile + flutter pub get + + - name: ๐Ÿ” Lint changed Dart files + run: | + cd apps/mobile + + # Get the list of changed files + CHANGED_FILES="${{ needs.detect-changes.outputs.changed-files }}" + + if [[ -z "$CHANGED_FILES" ]]; then + echo "โญ๏ธ No Dart files changed, skipping lint" + exit 0 + fi + + echo "๐ŸŽฏ Running lint on changed files:" + echo "$CHANGED_FILES" + echo "" + + # Run dart analyze on each changed file + HAS_ERRORS=false + FAILED_FILES=() + + while IFS= read -r file; do + if [[ -n "$file" && "$file" == *.dart ]]; then + echo "๐Ÿ“ Analyzing: $file" + + if ! flutter analyze "$file" --no-fatal-infos 2>&1 | tee -a lint_output.txt; then + HAS_ERRORS=true + FAILED_FILES+=("$file") + fi + echo "" + fi + done <<< "$CHANGED_FILES" + + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + # Check if there were any errors + if [[ "$HAS_ERRORS" == "true" ]]; then + echo "โŒ LINT ERRORS FOUND IN ${#FAILED_FILES[@]} FILE(S):" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + for file in "${FAILED_FILES[@]}"; do + echo " โŒ $file" + done + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "" + echo "See details above for each file" + exit 1 + else + echo "โœ… Lint check PASSED for all changed files" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + fi + + status-check: + name: ๐Ÿ“Š CI Status Check + runs-on: ubuntu-latest + needs: [detect-changes, compile, lint] + if: always() + steps: + - name: ๐Ÿ” Check mobile changes detected + run: | + if [[ "${{ needs.detect-changes.outputs.mobile-changed }}" == "true" ]]; then + echo "โœ… Mobile changes detected - running full checks" + else + echo "โญ๏ธ No mobile changes detected - skipping checks" + fi + + - name: ๐Ÿ—๏ธ Report compilation status + if: needs.detect-changes.outputs.mobile-changed == 'true' + run: | + if [[ "${{ needs.compile.result }}" == "success" ]]; then + echo "โœ… Compilation check: PASSED" + else + echo "โŒ Compilation check: FAILED" + exit 1 + fi + + - name: ๐Ÿงน Report lint status + if: needs.detect-changes.outputs.mobile-changed == 'true' && needs.detect-changes.outputs.changed-files != '' + run: | + if [[ "${{ needs.lint.result }}" == "success" ]]; then + echo "โœ… Lint check: PASSED" + else + echo "โŒ Lint check: FAILED" + exit 1 + fi + + - name: ๐ŸŽ‰ Final status + if: always() + run: | + echo "" + echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" + echo "โ•‘ ๐Ÿ“Š Mobile CI Pipeline Summary โ•‘" + echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + echo "" + echo "๐Ÿ” Change Detection: ${{ needs.detect-changes.result }}" + echo "๐Ÿ—๏ธ Compilation: ${{ needs.compile.result }}" + echo "๐Ÿงน Lint Check: ${{ needs.lint.result }}" + echo "" + + if [[ "${{ needs.detect-changes.result }}" != "success" || \ + ("${{ needs.detect-changes.outputs.mobile-changed }}" == "true" && \ + ("${{ needs.compile.result }}" != "success" || "${{ needs.lint.result }}" != "success")) ]]; then + echo "โŒ Pipeline FAILED" + exit 1 + else + echo "โœ… Pipeline PASSED" + fi +