Skip to content

Productize coach plan and restore Apple sign-in capability #82

Productize coach plan and restore Apple sign-in capability

Productize coach plan and restore Apple sign-in capability #82

Workflow file for this run

# 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