CI/CD for Swift Projects: GitHub Actions from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction to CI/CD for Swift Projects

\n

Modern development of mobile and desktop applications in Swift requires not only high-quality code but also a reliable process for integrating and delivering changes. Continuous Integration (CI) and Continuous Delivery (CD) are practices that allow you to automate the building, testing, and deployment of applications. GitHub Actions is a built-in GitHub tool that is ideal for Swift projects running on iOS and macOS.

\n

In this article, we will cover the complete cycle of setting up CI/CD for Swift: from basic configuration to deployment to the App Store and TestFlight. You will learn how to speed up development, avoid the "human factor," and ensure the stability of your application.

\n\n

Key Components of CI/CD for Swift

\n

Before moving on to the setup, it is important to understand the stages that make up the pipeline for Swift projects:

\n
    \n
  • Build — compiling the project using Xcode or xcodebuild.
  • \n
  • Test — running unit tests and UI tests.
  • \n
  • Lint — checking code style (e.g., using SwiftLint).
  • \n
  • Archive — creating an .ipa or .app file for deployment.
  • \n
  • Deploy — sending the build to TestFlight or the App Store.
  • \n
\n

GitHub Actions allows you to combine all these steps into a single YAML file stored in the repository.

\n\n

Setting Up GitHub Actions for Swift: Step-by-Step Guide

\n\n

1. Creating a Workflow File

\n

Create a folder .github/workflows in the root of your repository and add a file ci.yml:

\n
name: Swift CI/CD\n\non:\n  push:\n    branches: [ main, develop ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build-and-test:\n    runs-on: macos-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Select Xcode version\n      run: sudo xcode-select -s /Applications/Xcode_15.0.app/Contents/Developer\n\n    - name: Build and test\n      run: |\n        xcodebuild clean test \\\n          -project YourApp.xcodeproj \\\n          -scheme YourApp \\\n          -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.0' \\\n          -resultBundlePath TestResults \\\n          CODE_SIGNING_ALLOWED=NO\n    - name: Upload test results\n      uses: actions/upload-artifact@v4\n      with:\n        name: test-results\n        path: TestResults.xcresult
\n

This workflow runs on every push to main and develop, as well as on pull requests. It performs a clean build and runs all tests on an iPhone 15 simulator with iOS 17.

\n\n

2. Adding Linting and Static Analysis

\n

To maintain a consistent code style, add a step with SwiftLint:

\n
- name: Run SwiftLint\n  run: |\n    brew install swiftlint\n    swiftlint --strict
\n

If you use SPM (Swift Package Manager), you can add static analysis using swift analyze (available in Swift 5.9+):

\n
- name: Static analysis\n  run: swift analyze --strict
\n\n

3. Setting Up CD: Deployment to TestFlight

\n

For automatic delivery of builds to TestFlight, you will need certificates and provisioning profiles. The safest way is to use GitHub Secrets to store the keys:

\n
jobs:\n  deploy:\n    needs: build-and-test\n    runs-on: macos-latest\n    if: github.ref == 'refs/heads/main'\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Install provisioning profile\n      env:\n        PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}\n      run: |\n        echo "$PROVISIONING_PROFILE" | base64 --decode > ~/Library/MobileDevice/Provisioning\\ Profiles/profile.mobileprovision\n\n    - name: Build and archive\n      run: |\n        xcodebuild archive \\\n          -project YourApp.xcodeproj \\\n          -scheme YourApp \\\n          -archivePath $                

Blogs

Book Recommendations