Productize coach plan and restore Apple sign-in capability #82
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
| # CI Pipeline for Thump (HeartCoach) | |
| # Builds iOS and watchOS targets, runs ALL unit tests, and validates | |
| # that every test function in source is actually executed. | |
| # | |
| # Runs on: push to main, ALL pull requests (any branch). | |
| # Branch protection requires this workflow to pass before merge. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| # Minimum number of test functions that must execute. | |
| # Update this when adding new tests. Current count: 833 | |
| MIN_TEST_COUNT: 1050 | |
| IOS_SIMULATOR: "platform=iOS Simulator,name=iPhone 16 Pro" | |
| WATCH_SIMULATOR: "platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)" | |
| jobs: | |
| build-and-test: | |
| name: Build & Test | |
| runs-on: macos-15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # -- Cache SPM packages -- | |
| - name: Cache SPM packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Developer/Xcode/DerivedData/**/SourcePackages | |
| ~/.build | |
| key: spm-${{ runner.os }}-${{ hashFiles('apps/HeartCoach/Package.swift') }} | |
| restore-keys: | | |
| spm-${{ runner.os }}- | |
| # -- Install tools -- | |
| - name: Install XcodeGen | |
| run: brew install xcodegen | |
| - name: Show Xcode version | |
| run: xcodebuild -version | |
| - name: List available simulators | |
| run: xcrun simctl list devices available | grep -E "iPhone|Apple Watch" | head -10 | |
| - name: Generate Xcode Project | |
| run: | | |
| cd apps/HeartCoach | |
| xcodegen generate | |
| # -- Validate all test files are in project -- | |
| - name: Validate test file inclusion | |
| run: | | |
| cd apps/HeartCoach | |
| MISSING=0 | |
| for f in $(find Tests -name "*Tests.swift" -exec basename {} \;); do | |
| if ! grep -q "$f" Thump.xcodeproj/project.pbxproj 2>/dev/null; then | |
| echo "::error::Test file $f exists on disk but is NOT in ThumpCoreTests target" | |
| MISSING=$((MISSING + 1)) | |
| fi | |
| done | |
| if [ "$MISSING" -gt 0 ]; then | |
| echo "::error::$MISSING test file(s) missing from Xcode project. Add them to project.yml." | |
| exit 1 | |
| fi | |
| echo "All test files are in the project" | |
| # -- Build iOS -- | |
| - name: Build iOS | |
| env: | |
| SIMULATOR: ${{ env.IOS_SIMULATOR }} | |
| run: | | |
| set -o pipefail | |
| cd apps/HeartCoach | |
| xcodebuild build \ | |
| -project Thump.xcodeproj \ | |
| -scheme Thump \ | |
| -destination "platform=iOS Simulator,name=iPhone 16 Pro" \ | |
| -configuration Debug \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| 2>&1 | tee /tmp/xcodebuild-ios.log | xcpretty | |
| - name: Show Build Errors (if failed) | |
| if: failure() | |
| run: grep -A2 "error:" /tmp/xcodebuild-ios.log || echo "No error lines found" | |
| # -- Build watchOS -- | |
| - name: Build watchOS | |
| run: | | |
| set -o pipefail | |
| cd apps/HeartCoach | |
| xcodebuild build \ | |
| -project Thump.xcodeproj \ | |
| -scheme ThumpWatch \ | |
| -destination "platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)" \ | |
| -configuration Debug \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| 2>&1 | tee /tmp/xcodebuild-watchos.log | xcpretty | |
| - name: Show watchOS Build Errors (if failed) | |
| if: failure() | |
| run: grep -A2 "error:" /tmp/xcodebuild-watchos.log 2>/dev/null || echo "No watchOS error log" | |
| # -- Run ALL unit tests -- | |
| - name: Run Tests | |
| run: | | |
| set -o pipefail | |
| cd apps/HeartCoach | |
| xcodebuild test \ | |
| -project Thump.xcodeproj \ | |
| -scheme Thump \ | |
| -destination "platform=iOS Simulator,name=iPhone 16 Pro" \ | |
| -enableCodeCoverage YES \ | |
| -resultBundlePath TestResults.xcresult \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| 2>&1 | tee /tmp/xcodebuild-test.log | xcpretty | |
| - name: Show Test Errors (if failed) | |
| if: failure() | |
| run: | | |
| echo "### Test Failures" >> "$GITHUB_STEP_SUMMARY" | |
| grep -E "error:|FAIL|failed" /tmp/xcodebuild-test.log | head -30 >> "$GITHUB_STEP_SUMMARY" | |
| grep -A2 "error:" /tmp/xcodebuild-test.log 2>/dev/null || echo "No test error log" | |
| # -- Validate test count to catch orphaned tests -- | |
| - name: Validate test count | |
| if: success() | |
| env: | |
| MIN_TESTS: ${{ env.MIN_TEST_COUNT }} | |
| run: | | |
| cd apps/HeartCoach | |
| # Count executed tests from xcodebuild output | |
| EXECUTED=$(grep "Test Case.*started" /tmp/xcodebuild-test.log | wc -l | tr -d ' ') | |
| # Count defined test functions in source | |
| DEFINED=$(grep -rn "func test" Tests --include="*.swift" | wc -l | tr -d ' ') | |
| echo "### Test Pipeline Report" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| Metric | Count |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "|--------|-------|" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| Defined in source | **${DEFINED}** |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| Executed by Xcode | **${EXECUTED}** |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| Minimum required | **${MIN_TESTS}** |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| # Fail if executed count drops below minimum | |
| if [ "$EXECUTED" -lt "$MIN_TESTS" ]; then | |
| echo "::error::Only ${EXECUTED} tests executed, minimum is ${MIN_TESTS}. Tests may have been excluded or orphaned." | |
| echo "FAILED: ${EXECUTED} tests executed < ${MIN_TESTS} minimum" >> "$GITHUB_STEP_SUMMARY" | |
| exit 1 | |
| fi | |
| # Warn if defined > executed (some tests not running) | |
| DIFF=$((DEFINED - EXECUTED)) | |
| if [ "$DIFF" -gt 10 ]; then | |
| echo "::warning::${DIFF} test functions defined but not executed. Check for excluded files in project.yml." | |
| echo "WARNING: ${DIFF} tests defined but not executed" >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| echo "All ${EXECUTED} tests executed (minimum: ${MIN_TESTS})" | |
| echo "PASSED: ${EXECUTED} tests executed" >> "$GITHUB_STEP_SUMMARY" | |
| # -- Coverage report -- | |
| - name: Extract Code Coverage | |
| if: success() | |
| run: | | |
| cd apps/HeartCoach | |
| echo "### Code Coverage" >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| xcrun xccov view --report TestResults.xcresult | head -30 >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload Test Results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: apps/HeartCoach/TestResults.xcresult | |
| retention-days: 7 |