Files
tabatago/docs/ci-cd-setup.md
Millian Lamiaux 560b056dc9
All checks were successful
CI / Detect Changes (push) Successful in 3s
CI / Admin Web CI (push) Has been skipped
CI / YouTube Worker (push) Has been skipped
CI / Deploy (push) Has been skipped
fix: update workflow references to .github/ and gitignore xcuserstate
Update AGENTS.md and docs/ci-cd-setup.md from .gitea/workflows to .github/workflows

Add *.xcuserstate to .gitignore

Remove tracked UserInterfaceState.xcuserstate from git (preserve on disk)
2026-07-04 16:46:09 +02:00

6.5 KiB

CI/CD Setup — iPhone Deploy Workflow

This guide covers setting up a Gitea Actions macOS runner to automatically build, test, and deploy TabataGo to a physical iPhone on every PR to main.

Prerequisites

Hardware

  • Mac running macOS 15 (Sequoia) or later
  • Xcode 26+ installed (required for iOS 26.0 / watchOS 11.0 targets)
  • iPhone (iOS 26+) with the Firebase App Tester app installed

Software

  • Gitea Actions Runner installed and registered
  • brew (Homebrew) installed
  • xcodegenbrew install xcodegen (also installed automatically by the workflow)

1. Register the macOS Runner

# On the Mac:
./act_runner register \
  --instance https://gitea.1000co.fr \
  --token <RUNNER_TOKEN> \
  --name "macos-runner" \
  --labels macos

# Start the runner
./act_runner daemon

Important: The runner must have the label macos because the workflow uses runs-on: macos.

2. Configure Secrets

Add these secrets in the Gitea repository:
Settings → Actions → Secrets

Secret Name Description How to Get
FIREBASE_APP_ID Firebase App ID (iOS app) Firebase Console → Project Settings → General → App ID
FIREBASE_SERVICE_ACCOUNT Base64-encoded Firebase service account JSON key See Firebase Setup below
GITEA_TOKEN Gitea API token with repo + pull request scope Gitea → Settings → Applications → Generate Token

Gitea Token Permissions

The token needs:

  • read:repository — to read PR metadata
  • write:issue — to post LGTM comments
  • write:pull_request — to merge approved PRs

3. Xcode Signing

The workflow uses automatic code signing. Ensure:

  1. The Mac runner is signed into an Apple Developer account in Xcode:

    # Verify:
    xcrun security find-identity -v -p codesigning
    
  2. The Apple ID used must be part of the team 2MJF39L8VY (configured in ExportOptions.plist).

  3. For first-time setup, open Xcode on the runner Mac and sign in:

    Xcode → Settings → Accounts → Add Apple ID
    

4. Workflow Overview

The workflow at .github/workflows/pr-iphone-deploy.yml triggers on PRs to main:

PR Opened / Updated
       ↓
  Checkout + XcodeGen generate
       ↓
  Resolve SPM packages
       ↓
  Build + Archive IPA
       ↓
  Upload to Firebase App Distribution
       ↓
  Post "Ready to test" comment on PR
       ↓
  Wait for LGTM → Auto-merge

5. Manual Test Run

To test the workflow locally on the runner Mac:

# Simulate the build:
cd tabatago-swift
xcodegen generate
xcodebuild build \
  -project TabataGo.xcodeproj \
  -target TabataGo \
  -sdk iphoneos \
  -destination "generic/platform=iOS" \
  -configuration Release \
  -allowProvisioningUpdates \
  -skipPackagePluginValidation \
  CODE_SIGN_STYLE=Automatic

6. Firebase App Distribution Setup

6.1 Create a Firebase Project

  1. Go to Firebase Console
  2. Click Add project (or select an existing one)
  3. Follow the wizard to create the project (Google Analytics is optional)

6.2 Enable App Distribution

  1. In the Firebase Console, open your project
  2. Navigate to App Distribution in the left sidebar
  3. Click Get started to enable the service

6.3 Get the App ID

  1. Go to Project Settings (gear icon) → General
  2. Scroll down to Your apps → find the iOS app
  3. Copy the App ID (looks like 1:123456789012:ios:abc123def456)

6.4 Create a Service Account

  1. Go to Project SettingsService accounts
  2. Click Create service account (or use Firebase Admin SDK → Generate new private key)
  3. Give it a name like github-actions-deploy
  4. Assign the role: Firebase App Distribution Admin
  5. Click Generate new private key → download the JSON file

6.5 Encode the Service Account Key

# Convert the JSON key to a base64 string (single line, no wrapping)
base64 -i firebase-key.json | tr -d '\n'

Copy the output — this is your FIREBASE_SERVICE_ACCOUNT secret value.

6.6 Add Testers and Groups

  1. In Firebase Console, go to App DistributionTesters & Groups
  2. Click Add group → name it millian-test
  3. Click Add testers → enter Millian's email
  4. Add the tester to the millian-test group

6.7 Install the Firebase App Tester on the iPhone

  1. Send an invite to Millian's iPhone from the Firebase Console
  2. Millian accepts the invite and installs the Firebase App Tester app from the App Store
  3. Open the app and sign in with the invited Google account
  4. The app will now receive builds pushed from the CI workflow

Troubleshooting

Issue Solution
"Code signing failed" Sign into Xcode on the runner Mac, verify team membership
"No provisioning profile" Run -allowProvisioningUpdates or open project in Xcode once
xcodegen: command not found brew install xcodegen (workflow handles this)
Runner doesn't pick up job Verify runner label is macos and runner is connected
Token permission errors Ensure GITEA_TOKEN has write:issue and write:pull_request scopes
Firebase upload fails Verify FIREBASE_APP_ID and FIREBASE_SERVICE_ACCOUNT secrets are set correctly
"App not found" in Firebase Check that the iOS app is registered in Firebase with the correct bundle ID
Testers don't receive build Verify tester is in the millian-test group and has accepted the invite

Compilation Error Troubleshooting

xcodegen Clearing Signing Team

After running xcodegen generate, the .xcodeproj may have a cleared signing team. Always re-check your team settings:

cd tabatago-swift
xcodegen generate
# Then check that project.yml has the correct team ID in settings

Complication Targets Missing Team ID

Targets like TabataGoWatchWidget (watchOS complications) require an explicit team ID in project.yml settings. If you see signing errors for the widget target:

  1. Open tabatago-swift/project.yml
  2. Find the TabataGoWatchWidget target section
  3. Ensure it has an explicit settings: block with the team ID:
    target: TabataGoWatchWidget
      settings:
        base:
          DEVELOPMENT_TEAM: "2MJF39L8VY"
    

General Build Debugging

  • Run xcodegen generate before every build to ensure the project is in sync
  • Check xcodebuild output for specific file/line errors
  • Verify SPM packages resolve: xcodebuild -resolvePackageDependencies