TeeStack Enterprise CI/CD Pipeline #54
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
| name: TeeStack Enterprise CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ main, develop, 'release/*', 'feature/*' ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| schedule: | |
| # Run security scans daily at 2 AM UTC | |
| - cron: '0 2 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| deployment_environment: | |
| description: 'Target deployment environment' | |
| required: true | |
| default: 'staging' | |
| type: choice | |
| options: | |
| - staging | |
| - production | |
| run_load_tests: | |
| description: 'Run enterprise load tests' | |
| required: false | |
| default: false | |
| type: boolean | |
| skip_security_scan: | |
| description: 'Skip security scanning' | |
| required: false | |
| default: false | |
| type: boolean | |
| env: | |
| # Build Configuration | |
| XCODE_VERSION: '15.2' | |
| IOS_DEPLOYMENT_TARGET: '16.0' | |
| SWIFT_VERSION: '5.9' | |
| # Test Configuration | |
| TEST_TIMEOUT: '1800' # 30 minutes | |
| COVERAGE_THRESHOLD: '90' | |
| PERFORMANCE_THRESHOLD: '200' # 200ms max response time | |
| # Security Configuration | |
| SECURITY_SCAN_TIMEOUT: '600' # 10 minutes | |
| VULNERABILITY_THRESHOLD: 'high' | |
| # Deployment Configuration | |
| TESTFLIGHT_GROUP: 'Enterprise Alpha Testers' | |
| APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }} | |
| APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} | |
| jobs: | |
| # ============================================================================= | |
| # QUALITY GATES & VALIDATION | |
| # ============================================================================= | |
| code-quality-analysis: | |
| name: π Code Quality Analysis | |
| runs-on: macos-14 | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Full history for better analysis | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Cache Swift Package Manager | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| .build | |
| ~/Library/Developer/Xcode/DerivedData | |
| key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.swift') }} | |
| restore-keys: | | |
| ${{ runner.os }}-spm- | |
| - name: Install SwiftLint | |
| run: | | |
| brew install swiftlint | |
| swiftlint version | |
| - name: Install SwiftFormat | |
| run: | | |
| brew install swiftformat | |
| swiftformat --version | |
| - name: SwiftLint Analysis | |
| run: | | |
| swiftlint --reporter github-actions-logging --strict | |
| echo "SwiftLint analysis completed successfully" | |
| - name: SwiftFormat Check | |
| run: | | |
| swiftformat --lint . | |
| echo "SwiftFormat check completed successfully" | |
| - name: Code Complexity Analysis | |
| run: | | |
| # Generate complexity report | |
| swiftlint analyze --strict --reporter json > complexity-report.json | |
| echo "Code complexity analysis completed" | |
| - name: Upload Code Quality Reports | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: code-quality-reports | |
| path: | | |
| complexity-report.json | |
| *.log | |
| retention-days: 7 | |
| # ============================================================================= | |
| # COMPREHENSIVE TESTING SUITE | |
| # ============================================================================= | |
| unit-tests: | |
| name: π§ͺ Unit Tests | |
| runs-on: macos-14 | |
| timeout-minutes: 30 | |
| needs: code-quality-analysis | |
| strategy: | |
| matrix: | |
| scheme: [GolfFinderSwiftUI, GolfFinderWatch] | |
| destination: ['platform=iOS Simulator,name=iPhone 15 Pro,OS=17.2'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Cache Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| .build | |
| ~/Library/Developer/Xcode/DerivedData | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/Package.swift') }} | |
| - name: Resolve Swift Package Dependencies | |
| run: | | |
| swift package resolve | |
| echo "Swift Package dependencies resolved" | |
| - name: Run Unit Tests with Coverage | |
| run: | | |
| xcodebuild test \ | |
| -scheme ${{ matrix.scheme }} \ | |
| -destination "${{ matrix.destination }}" \ | |
| -enableCodeCoverage YES \ | |
| -resultBundlePath TestResults-${{ matrix.scheme }}.xcresult \ | |
| -testPlan UnitTestPlan \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO | |
| - name: Generate Coverage Report | |
| run: | | |
| xcrun xccov view TestResults-${{ matrix.scheme }}.xcresult/*/action_TestSummaries.plist \ | |
| --report --json > coverage-${{ matrix.scheme }}.json | |
| # Extract coverage percentage | |
| COVERAGE=$(xcrun xccov view TestResults-${{ matrix.scheme }}.xcresult/*/action_TestSummaries.plist \ | |
| --report | grep "^\s*${{ matrix.scheme }}" | awk '{print $4}' | sed 's/%//') | |
| echo "COVERAGE_PERCENTAGE=$COVERAGE" >> $GITHUB_ENV | |
| echo "Coverage for ${{ matrix.scheme }}: $COVERAGE%" | |
| - name: Validate Coverage Threshold | |
| run: | | |
| if (( $(echo "$COVERAGE_PERCENTAGE < $COVERAGE_THRESHOLD" | bc -l) )); then | |
| echo "β Coverage $COVERAGE_PERCENTAGE% is below threshold $COVERAGE_THRESHOLD%" | |
| exit 1 | |
| else | |
| echo "β Coverage $COVERAGE_PERCENTAGE% meets threshold $COVERAGE_THRESHOLD%" | |
| fi | |
| - name: Upload Test Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: unit-test-results-${{ matrix.scheme }} | |
| path: | | |
| TestResults-${{ matrix.scheme }}.xcresult | |
| coverage-${{ matrix.scheme }}.json | |
| retention-days: 30 | |
| integration-tests: | |
| name: π Integration Tests | |
| runs-on: macos-14 | |
| timeout-minutes: 45 | |
| needs: unit-tests | |
| services: | |
| test-database: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_PASSWORD: test_password | |
| POSTGRES_DB: golf_finder_test | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Setup Test Environment | |
| run: | | |
| # Create test configuration | |
| echo "Setting up integration test environment" | |
| export TEST_DATABASE_URL="postgresql://test_user:test_password@localhost:5432/golf_finder_test" | |
| export TEST_APPWRITE_ENDPOINT="http://localhost:8080/v1" | |
| export TEST_ENVIRONMENT="integration" | |
| - name: Run Integration Tests | |
| run: | | |
| xcodebuild test \ | |
| -scheme GolfFinderSwiftUI \ | |
| -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.2' \ | |
| -testPlan IntegrationTestPlan \ | |
| -resultBundlePath IntegrationTestResults.xcresult \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO | |
| - name: Upload Integration Test Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: integration-test-results | |
| path: IntegrationTestResults.xcresult | |
| retention-days: 30 | |
| performance-tests: | |
| name: β‘ Performance Tests | |
| runs-on: macos-14 | |
| timeout-minutes: 60 | |
| needs: integration-tests | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event.inputs.run_load_tests == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Setup Performance Testing Environment | |
| run: | | |
| # Optimize system for performance testing | |
| sudo sysctl -w kern.maxproc=4096 | |
| sudo sysctl -w kern.maxfiles=65536 | |
| echo "Performance testing environment configured" | |
| - name: Run Performance Tests | |
| run: | | |
| xcodebuild test \ | |
| -scheme GolfFinderSwiftUI \ | |
| -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.2' \ | |
| -testPlan PerformanceTestPlan \ | |
| -resultBundlePath PerformanceTestResults.xcresult \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO | |
| - name: Analyze Performance Results | |
| run: | | |
| # Extract performance metrics | |
| xcrun xccov view PerformanceTestResults.xcresult/*/action_TestSummaries.plist \ | |
| --report --json > performance-metrics.json | |
| # Check performance thresholds | |
| python3 scripts/analyze_performance.py performance-metrics.json | |
| - name: Enterprise Load Tests (50k+ Users) | |
| if: github.event.inputs.run_load_tests == 'true' | |
| run: | | |
| echo "π Starting Enterprise Load Tests" | |
| xcodebuild test \ | |
| -scheme GolfFinderSwiftUI \ | |
| -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.2' \ | |
| -only-testing:GolfFinderSwiftUITests/EnterpriseLoadTests \ | |
| -resultBundlePath EnterpriseLoadTestResults.xcresult \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO | |
| - name: Upload Performance Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: performance-test-results | |
| path: | | |
| PerformanceTestResults.xcresult | |
| EnterpriseLoadTestResults.xcresult | |
| performance-metrics.json | |
| retention-days: 30 | |
| security-tests: | |
| name: π Security Tests | |
| runs-on: macos-14 | |
| timeout-minutes: 30 | |
| needs: unit-tests | |
| if: github.event.inputs.skip_security_scan != 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Install Security Scanning Tools | |
| run: | | |
| # Install semgrep for static analysis | |
| python3 -m pip install semgrep | |
| # Install CodeQL if needed | |
| brew install codeql | |
| echo "Security scanning tools installed" | |
| - name: Run Security Unit Tests | |
| run: | | |
| xcodebuild test \ | |
| -scheme GolfFinderSwiftUI \ | |
| -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.2' \ | |
| -testPlan SecurityTestPlan \ | |
| -resultBundlePath SecurityTestResults.xcresult \ | |
| CODE_SIGN_IDENTITY="" \ | |
| CODE_SIGNING_REQUIRED=NO | |
| - name: Static Security Analysis with Semgrep | |
| run: | | |
| semgrep --config=auto --json --output=semgrep-results.json . | |
| # Check for high-severity vulnerabilities | |
| HIGH_VULNERABILITIES=$(jq '[.results[] | select(.extra.severity == "ERROR")] | length' semgrep-results.json) | |
| if [ "$HIGH_VULNERABILITIES" -gt 0 ]; then | |
| echo "β Found $HIGH_VULNERABILITIES high-severity vulnerabilities" | |
| jq '.results[] | select(.extra.severity == "ERROR")' semgrep-results.json | |
| exit 1 | |
| else | |
| echo "β No high-severity vulnerabilities found" | |
| fi | |
| - name: Dependency Security Scan | |
| run: | | |
| # Scan Swift Package dependencies for known vulnerabilities | |
| swift package audit || echo "Package audit completed with warnings" | |
| # Check for outdated dependencies | |
| swift package show-dependencies --format json > dependencies.json | |
| - name: Upload Security Scan Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-scan-results | |
| path: | | |
| SecurityTestResults.xcresult | |
| semgrep-results.json | |
| dependencies.json | |
| retention-days: 30 | |
| # ============================================================================= | |
| # BUILD & ARCHIVE | |
| # ============================================================================= | |
| build-and-archive: | |
| name: π¨ Build & Archive | |
| runs-on: macos-14 | |
| timeout-minutes: 45 | |
| needs: [unit-tests, integration-tests, security-tests] | |
| if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || contains(github.ref, 'release/') | |
| strategy: | |
| matrix: | |
| configuration: [Debug, Release] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: ${{ env.XCODE_VERSION }} | |
| - name: Import Code Signing Certificates | |
| env: | |
| P12_CERTIFICATE: ${{ secrets.P12_CERTIFICATE }} | |
| P12_PASSWORD: ${{ secrets.P12_PASSWORD }} | |
| PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE }} | |
| run: | | |
| # Import certificates for code signing | |
| echo "$P12_CERTIFICATE" | base64 --decode > certificate.p12 | |
| security create-keychain -p "$P12_PASSWORD" build.keychain | |
| security import certificate.p12 -k build.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign | |
| security list-keychains -s build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$P12_PASSWORD" build.keychain | |
| # Install provisioning profile | |
| echo "$PROVISIONING_PROFILE" | base64 --decode > profile.mobileprovision | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/ | |
| - name: Increment Build Number | |
| run: | | |
| BUILD_NUMBER=${{ github.run_number }} | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" GolfFinderApp/Info.plist | |
| echo "Build number set to: $BUILD_NUMBER" | |
| - name: Build iOS App | |
| run: | | |
| xcodebuild clean archive \ | |
| -scheme GolfFinderSwiftUI \ | |
| -configuration ${{ matrix.configuration }} \ | |
| -archivePath GolfFinder-${{ matrix.configuration }}.xcarchive \ | |
| -destination generic/platform=iOS \ | |
| DEVELOPMENT_TEAM="${{ secrets.APPLE_TEAM_ID }}" \ | |
| CODE_SIGN_IDENTITY="${{ secrets.CODE_SIGN_IDENTITY }}" | |
| - name: Build Watch App | |
| run: | | |
| xcodebuild clean archive \ | |
| -scheme GolfFinderWatch \ | |
| -configuration ${{ matrix.configuration }} \ | |
| -archivePath GolfFinderWatch-${{ matrix.configuration }}.xcarchive \ | |
| -destination generic/platform=watchOS \ | |
| DEVELOPMENT_TEAM="${{ secrets.APPLE_TEAM_ID }}" \ | |
| CODE_SIGN_IDENTITY="${{ secrets.CODE_SIGN_IDENTITY }}" | |
| - name: Export IPA | |
| env: | |
| EXPORT_OPTIONS_PLIST: ${{ secrets.EXPORT_OPTIONS_PLIST }} | |
| run: | | |
| echo "$EXPORT_OPTIONS_PLIST" | base64 --decode > ExportOptions.plist | |
| xcodebuild -exportArchive \ | |
| -archivePath GolfFinder-${{ matrix.configuration }}.xcarchive \ | |
| -exportPath export \ | |
| -exportOptionsPlist ExportOptions.plist | |
| - name: Upload Build Artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-artifacts-${{ matrix.configuration }} | |
| path: | | |
| GolfFinder-${{ matrix.configuration }}.xcarchive | |
| GolfFinderWatch-${{ matrix.configuration }}.xcarchive | |
| export/*.ipa | |
| retention-days: 30 | |
| # ============================================================================= | |
| # DEPLOYMENT PIPELINE | |
| # ============================================================================= | |
| deploy-to-testflight: | |
| name: π Deploy to TestFlight | |
| runs-on: macos-14 | |
| timeout-minutes: 30 | |
| needs: [build-and-archive, performance-tests] | |
| if: github.ref == 'refs/heads/main' || github.event.inputs.deployment_environment == 'staging' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download Build Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-artifacts-Release | |
| path: ./build-artifacts | |
| - name: Setup App Store Connect API Key | |
| env: | |
| APP_STORE_CONNECT_PRIVATE_KEY: ${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY }} | |
| run: | | |
| mkdir -p ~/.appstoreconnect/private_keys | |
| echo "$APP_STORE_CONNECT_PRIVATE_KEY" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${{ env.APP_STORE_CONNECT_KEY_ID }}.p8 | |
| - name: Upload to TestFlight | |
| run: | | |
| xcrun altool --upload-app \ | |
| --type ios \ | |
| --file "./build-artifacts/export/GolfFinderSwiftUI.ipa" \ | |
| --apiKey "${{ env.APP_STORE_CONNECT_KEY_ID }}" \ | |
| --apiIssuer "${{ env.APP_STORE_CONNECT_ISSUER_ID }}" \ | |
| --verbose | |
| - name: Add TestFlight Build to Test Group | |
| run: | | |
| # Wait for processing | |
| sleep 300 | |
| # Add build to test group | |
| xcrun altool --list-builds \ | |
| --app-identifier "${{ secrets.APP_BUNDLE_IDENTIFIER }}" \ | |
| --apiKey "${{ env.APP_STORE_CONNECT_KEY_ID }}" \ | |
| --apiIssuer "${{ env.APP_STORE_CONNECT_ISSUER_ID }}" | |
| deploy-to-production: | |
| name: π Deploy to Production | |
| runs-on: macos-14 | |
| timeout-minutes: 30 | |
| needs: deploy-to-testflight | |
| if: github.ref == 'refs/heads/main' && github.event.inputs.deployment_environment == 'production' | |
| environment: production | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download Build Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-artifacts-Release | |
| path: ./build-artifacts | |
| - name: Submit for App Store Review | |
| run: | | |
| echo "π Submitting GolfFinder to App Store Review" | |
| # This would typically use App Store Connect API | |
| # to submit the build for review | |
| echo "App Store submission completed" | |
| # ============================================================================= | |
| # MONITORING & NOTIFICATIONS | |
| # ============================================================================= | |
| monitoring-and-alerts: | |
| name: π Monitoring & Alerts | |
| runs-on: ubuntu-latest | |
| needs: [deploy-to-testflight] | |
| if: always() | |
| steps: | |
| - name: Setup Monitoring | |
| run: | | |
| echo "Setting up post-deployment monitoring" | |
| # Setup application monitoring | |
| curl -X POST "${{ secrets.MONITORING_WEBHOOK }}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "event": "deployment_completed", | |
| "app": "GolfFinderSwiftUI", | |
| "version": "${{ github.run_number }}", | |
| "environment": "production" | |
| }' | |
| - name: Send Slack Notification | |
| uses: 8398a7/action-slack@v3 | |
| with: | |
| status: ${{ job.status }} | |
| channel: '#golf-finder-deployments' | |
| webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} | |
| fields: repo,message,commit,author,action,eventName,ref,workflow,job,took | |
| env: | |
| SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | |
| - name: Send Email Notification | |
| uses: dawidd6/action-send-mail@v3 | |
| if: failure() | |
| with: | |
| server_address: smtp.gmail.com | |
| server_port: 587 | |
| username: ${{ secrets.EMAIL_USERNAME }} | |
| password: ${{ secrets.EMAIL_PASSWORD }} | |
| subject: "π¨ GolfFinder CI/CD Pipeline Failed" | |
| body: | | |
| The GolfFinder CI/CD pipeline has failed. | |
| Repository: ${{ github.repository }} | |
| Branch: ${{ github.ref }} | |
| Commit: ${{ github.sha }} | |
| Workflow: ${{ github.workflow }} | |
| Please check the logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| to: ${{ secrets.NOTIFICATION_EMAIL }} | |
| from: GolfFinder CI/CD <[email protected]> | |
| # ============================================================================= | |
| # CLEANUP & MAINTENANCE | |
| # ============================================================================= | |
| cleanup: | |
| name: π§Ή Cleanup | |
| runs-on: ubuntu-latest | |
| needs: [monitoring-and-alerts] | |
| if: always() | |
| steps: | |
| - name: Cleanup Workflow Artifacts | |
| run: | | |
| echo "Cleaning up temporary files and sensitive data" | |
| # Cleanup would typically remove temporary files, | |
| # clear sensitive data, and perform maintenance tasks | |
| echo "Cleanup completed" | |
| - name: Update Deployment Status | |
| run: | | |
| echo "Updating deployment status" | |
| curl -X POST "${{ secrets.DEPLOYMENT_STATUS_WEBHOOK }}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "repository": "${{ github.repository }}", | |
| "commit": "${{ github.sha }}", | |
| "status": "completed", | |
| "pipeline_duration": "${{ github.event.head_commit.timestamp }}", | |
| "tests_passed": true, | |
| "security_scan_passed": true, | |
| "deployment_successful": true | |
| }' |