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 all changes against base branch (not just latest commit) # Using three-dot syntax (...) shows all files changed in the PR branch BASE_REF="${{ github.event.pull_request.base.ref }}" CHANGED_FILES=$(git diff --name-only origin/$BASE_REF...HEAD 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.38.x' channel: 'stable' cache: true - name: ๐Ÿ”ง Install Firebase CLI run: | npm install -g firebase-tools - name: ๐Ÿ“ฆ Get Flutter dependencies run: | make mobile-install - name: ๐Ÿ”จ Run compilation check run: | set -o pipefail echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." if ! make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt; then echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "โŒ CLIENT APP BUILD FAILED" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" exit 1 fi echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ—๏ธ Building staff app for Android (dev mode)..." if ! make mobile-staff-build PLATFORM=apk MODE=debug 2>&1 | tee staff_build.txt; then echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "โŒ STAFF APP BUILD FAILED" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" exit 1 fi echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "โœ… Build check PASSED - Both apps built successfully" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" 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.38.x' channel: 'stable' cache: true - name: ๐Ÿ”ง Install Firebase CLI run: | npm install -g firebase-tools - name: ๐Ÿ“ฆ Get Flutter dependencies run: | make mobile-install - name: ๐Ÿ” Lint changed Dart files run: | set -o pipefail # 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 && -f "$file" ]]; then echo "๐Ÿ“ Analyzing: $file" if ! dart analyze "$file" 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