Files
tabatago/docs/ci-cd-setup.md
millianlmx c1cbc02826 fix: improve iOS CI workflow with pipefail, fix Python indentation, add setup docs
- Add set -o pipefail for proper build error detection
- Replace PIPESTATUS with $? (works correctly with pipefail)
- Fix Python indentation in inline scripts (avoids YAML linter false positives)
- Remove MergeTitle from Gitea merge API call (uses default)
- Add docs/ci-cd-setup.md with Mac runner and secrets setup guide
2026-06-26 20:42:58 +00:00

9.3 KiB
Raw Blame History

TabataGo CI/CD Setup Guide

How to set up the Mac self-hosted runner and configure secrets for the PR → iPhone → LGTM workflow.

Overview

The pr-iphone-deploy.yml workflow (.gitea/workflows/) automates the test-and-merge cycle for every PR targeting main:

  1. Build — Checks out the PR, generates the Xcode project via XcodeGen, and builds the TabataGo app for Millian's iPhone (device build).
  2. Comment — Posts a "Ready to test" comment on the PR.
  3. Wait for LGTM — Polls PR comments for up to 2 hours waiting for Millian to reply LGTM (merge) or KO (block).
  4. Auto-merge — Merges the PR automatically when LGTM is received.
┌────────────┐     ┌──────────────┐     ┌──────────────┐
│ PR opened  │ ──► │ Build iPhone │ ──► │ Wait LGTM/KO │
│ / updated  │     │  (macOS CI)  │     │  (poll 2h)   │
└────────────┘     └──────────────┘     └──┬────────┬──┘
                                           │        │
                                      LGTM │        │ KO
                                           ▼        ▼
                                     ┌────────┐ ┌────────┐
                                     │ Merge  │ │ Block  │
                                     │   PR   │ │  PR    │
                                     └────────┘ └────────┘

1. Set Up the Mac Runner

You need a macOS machine (macOS 15+, Xcode 26+) registered as a self-hosted Gitea Actions runner.

1.1 Prerequisites on the Mac

# Xcode 26+ (from App Store or Apple Developer)
sudo xcode-select -s /Applications/Xcode.app

# XcodeGen (project generator)
brew install xcodegen

# Python 3 (pre-installed on macOS, used by poll script)
python3 --version  # should be 3.x

# Xcode must be signed into an Apple Developer account for automatic signing
# Open Xcode → Settings → Accounts → Add your Apple ID

1.2 Register the Runner in Gitea

  1. Go to your Gitea repo: Settings → Actions → Runners

  2. Click Create new runner

  3. Follow the instructions to download and configure the runner binary. Use the label macos (this must match runs-on: macos in the workflow):

    # On the Mac, after downloading the runner:
    ./act_runner register \
      --instance https://gitea.1000co.fr \
      --token <RUNNER_TOKEN_FROM_GITEA> \
      --name mac-runner \
      --labels macos
    
  4. Start the runner (as a background service):

    ./act_runner daemon
    

    For persistence across reboots, create a LaunchAgent:

    <!-- ~/Library/LaunchAgents/com.tabatago.runner.plist -->
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
      "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>Label</key>
      <string>com.tabatago.runner</string>
      <key>ProgramArguments</key>
      <array>
        <string>/path/to/act_runner</string>
        <string>daemon</string>
      </array>
      <key>WorkingDirectory</key>
      <string>/path/to/runner</string>
      <key>RunAtLoad</key>
      <true/>
      <key>KeepAlive</key>
      <true/>
    </dict>
    </plist>
    

    Then load it:

    launchctl load ~/Library/LaunchAgents/com.tabatago.runner.plist
    

1.3 Verify the Runner

Check that the runner appears as Idle in: Gitea → Settings → Actions → Runners


2. Configure Required Secrets

Go to Gitea → Settings → Actions → Secrets and add:

2.1 IPHONE_UDID

The UDID (Unique Device Identifier) of Millian's iPhone. This tells Xcode which physical device to build for.

# Find the UDID on the Mac when the iPhone is connected via USB:
xcrun xctrace list devices
# Look for the iPhone line, e.g.:
# Millian's iPhone (26.0) (00008110-XXXXXXXXXXXX)

# Or in Finder: select the iPhone in the sidebar → click the serial number
# line until it switches to UDID
Secret Name Value Example
IPHONE_UDID 00008110-00123456789ABC01

2.2 GITEA_TOKEN

A Gitea personal access token with read/write permissions on the repo.

Create it at: Gitea → Settings → Applications → Generate Token

Required permissions:

  • read:repository — read PR info, comments
  • write:issue — post comments on PRs
  • write:pull_request — merge PRs
Secret Name Value Example
GITEA_TOKEN e20fd3de2f79b324afde5049e7bafd60a...

3. Code Signing Setup

The workflow uses automatic code signing (CODE_SIGN_STYLE=Automatic with -allowProvisioningUpdates). This requires:

  1. Apple ID signed into Xcode on the Mac runner
  2. The iPhone UDID registered in the Apple Developer account
  3. A valid provisioning profile for com.tabatago (Debug)

To set up:

# On the Mac runner, open Xcode and sign in:
# Xcode → Settings → Accounts → + → Apple ID

# Verify the team is available:
cd tabatago-swift
xcodegen generate
xcodebuild -showBuildSettings -scheme TabataGo -sdk iphoneos | grep DEVELOPMENT_TEAM

If automatic signing doesn't work (first-time setup), you may need to open the project in Xcode once manually to let it create the provisioning profile.


4. How the Workflow Works

Trigger

The workflow runs on:

  • pull_request events on main
  • Types: opened, synchronize (new commits pushed), reopened

Build Job (build-deploy)

Step What it does
Checkout Clones the PR branch
Setup Xcode Selects Xcode.app, prints version
Install XcodeGen brew install xcodegen if not present
Generate project xcodegen generate in tabatago-swift/
Build for iPhone xcodebuild build for device UDID from secret
Post comment Posts a "Ready to test" message on the PR

The build runs with set -o pipefail so that any compilation error causes the job to fail. The last 40 lines of build output are shown; the full log is saved to build/xcodebuild.log.

Approval Job (wait-approval)

  • Polls the Gitea API every 30 seconds for new PR comments
  • Timeout: 120 minutes (240 iterations × 30s)
  • LGTM detection: Case-insensitive match for lgtm anywhere in the comment body
  • KO detection: Exact case-insensitive match for a standalone ko comment
  • On LGTM → merges the PR via Gitea API
  • On KO → fails the workflow (exit code 1)
  • On timeout → fails the workflow (exit code 1)

Comment Format

Reply on the PR with just:

  • LGTM — approve and auto-merge
  • KO — block the PR

5. Troubleshooting

Runner doesn't pick up jobs

  • Check the runner label: must be macos exactly
  • Check Settings → Actions → Runners — runner must be Idle, not Offline
  • Run ./act_runner daemon in a terminal to see logs

Build fails with signing error

error: No profiles for 'com.tabatago' were found
  • Open Xcode on the Mac runner, sign into your Apple ID
  • Build once in Xcode to generate the provisioning profile
  • Verify the iPhone UDID is correct

Build fails with "device not found"

error: Unable to find a device matching the provided destination specifier
  • Check that IPHONE_UDID secret matches the actual device UDID
  • The device must be registered in your Apple Developer account

Comment not posted / LGTM not detected

  • Verify GITEA_TOKEN has the required permissions (read/write issues + PRs)
  • Check the Gitea instance URL: https://gitea.1000co.fr
  • Ensure the token hasn't expired

Workflow runs on every PR push, canceling previous runs

This is intentional — the concurrency setting cancels in-progress runs for the same PR when new commits are pushed. This prevents queue buildup.


6. File Locations

tabatago/
├── .gitea/
│   └── workflows/
│       └── pr-iphone-deploy.yml   ← iPhone build + LGTM workflow
├── .github/
│   └── workflows/
│       └── ci.yml                 ← Admin web + YouTube worker CI
└── docs/
    └── ci-cd-setup.md             ← This document

7. Required Tools on the Mac Runner

Tool Version Install
macOS 15+
Xcode 26.0+ App Store or Apple Developer
XcodeGen latest brew install xcodegen
Python 3 3.x Pre-installed on macOS
curl any Pre-installed on macOS
git any Pre-installed on macOS

See Also