From b54ebf60b50747b909907773c4e5b5f0b3413058 Mon Sep 17 00:00:00 2001 From: Admin Date: Mon, 9 Mar 2026 12:19:01 +0500 Subject: [PATCH] ci: add macOS act_runner config and setup script for iOS host runner --- scripts/runner-config-mac.yaml | 48 +++++++++++ scripts/setup_runner_mac.sh | 149 +++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 scripts/runner-config-mac.yaml create mode 100755 scripts/setup_runner_mac.sh diff --git a/scripts/runner-config-mac.yaml b/scripts/runner-config-mac.yaml new file mode 100644 index 0000000..0c3232b --- /dev/null +++ b/scripts/runner-config-mac.yaml @@ -0,0 +1,48 @@ +log: + level: info + +runner: + file: .runner + # Keep capacity at 1 — iOS builds are heavy, no benefit running in parallel on one machine + capacity: 1 + envs: + env_file: .env + timeout: 3h + shutdown_timeout: 0s + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + github_mirror: '' + labels: + - "macos-latest:host" + - "macos-14:host" + +cache: + enabled: true + # Cache data stored in act_runner working directory + dir: "" + # Must be the LAN IP of this Mac — job processes connect back to this address. + # Run: ipconfig getifaddr en0 + # Replace with your actual LAN IP before starting the runner. + host: "192.168.1.100" + port: 8088 + external_server: "" + +container: + # Not used — all jobs run on host (macos-latest:host label). + # These settings are inert but kept for completeness. + network: "" + privileged: false + options: + workdir_parent: + valid_volumes: [] + docker_host: "" + force_pull: false + force_rebuild: false + require_docker: false + docker_timeout: 0s + +host: + # Working directory for host-mode jobs. + # If empty, $HOME/.cache/act/ is used. + workdir_parent: diff --git a/scripts/setup_runner_mac.sh b/scripts/setup_runner_mac.sh new file mode 100755 index 0000000..d028f36 --- /dev/null +++ b/scripts/setup_runner_mac.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ── setup_runner_mac.sh ─────────────────────────────────────────────────────── +# Sets up act_runner as a host-mode runner on macOS for iOS CI/CD. +# Installs the binary, generates a config, registers against Gitea, +# and installs a LaunchDaemon so the runner starts at boot. +# +# Usage: sudo ./setup_runner_mac.sh +# Example: sudo ./setup_runner_mac.sh mac-runner-1 +# ───────────────────────────────────────────────────────────────────────────── + +usage() { + echo "Usage: sudo $0 " + exit 1 +} + +[[ $# -ne 1 ]] && usage +[[ "$EUID" -ne 0 ]] && { echo "ERROR: run with sudo"; exit 1; } + +RUNNER_NAME="$1" +GITEA_URL="https://gitea.kalekber.cc/" +REGISTRATION_TOKEN="AboxpDKWx7gizwJ9xeheHVqKjj9J9N9BgyX96wvu" +CACHE_PORT=8088 +INSTALL_DIR="/usr/local/bin" +WORK_DIR="/var/lib/act_runner" +CONFIG_PATH="/etc/act_runner/config.yaml" +LAUNCHDAEMON_PLIST="/Library/LaunchDaemons/com.gitea.act_runner.plist" + +# ── detect Mac LAN IP ───────────────────────────────────────────────────────── +HOST_IP=$(ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null || echo "") +if [[ -z "$HOST_IP" ]]; then + echo "ERROR: could not detect LAN IP via en0/en1. Set cache.host manually in $CONFIG_PATH" + HOST_IP="127.0.0.1" +fi +echo "Host LAN IP: $HOST_IP" + +# ── download act_runner binary ──────────────────────────────────────────────── +ARCH=$(uname -m) +if [[ "$ARCH" == "arm64" ]]; then + BINARY_URL="https://dl.gitea.com/act_runner/latest/act_runner-darwin-arm64" +else + BINARY_URL="https://dl.gitea.com/act_runner/latest/act_runner-darwin-amd64" +fi + +echo "Downloading act_runner for $ARCH..." +curl -fsSL "$BINARY_URL" -o "$INSTALL_DIR/act_runner" +chmod +x "$INSTALL_DIR/act_runner" +echo "Installed: $("$INSTALL_DIR/act_runner" --version)" + +# ── create working directory ────────────────────────────────────────────────── +mkdir -p "$WORK_DIR" +mkdir -p "$(dirname "$CONFIG_PATH")" + +# ── generate and patch config ───────────────────────────────────────────────── +"$INSTALL_DIR/act_runner" generate-config > "$CONFIG_PATH" + +# Patch labels, cache host/port, and capacity +python3 - "$CONFIG_PATH" "$HOST_IP" "$CACHE_PORT" <<'PYEOF' +import sys, re + +path, host_ip, port = sys.argv[1], sys.argv[2], sys.argv[3] +with open(path) as f: + content = f.read() + +# labels +content = re.sub( + r'(labels:\s*\n)(\s+-.*\n)+', + 'labels:\n - "macos-latest:host"\n - "macos-14:host"\n', + content +) +# cache enabled +content = re.sub(r'(cache:.*?\n\s+enabled:\s*)false', r'\g<1>true', content, flags=re.DOTALL) +# cache host +content = re.sub(r'( host:\s*)""', f' host: "{host_ip}"', content) +# cache port +content = re.sub(r'( port:\s*)\d+', f' port: {port}', content) +# capacity +content = re.sub(r'( capacity:\s*)\d+', r' capacity: 1', content) + +with open(path, 'w') as f: + f.write(content) + +print(f"Config patched: labels=macos-latest:host, cache={host_ip}:{port}") +PYEOF + +# ── register runner ─────────────────────────────────────────────────────────── +echo "Registering runner '$RUNNER_NAME'..." +"$INSTALL_DIR/act_runner" register \ + --no-interactive \ + --config "$CONFIG_PATH" \ + --instance "$GITEA_URL" \ + --token "$REGISTRATION_TOKEN" \ + --name "$RUNNER_NAME" \ + --labels "macos-latest:host,macos-14:host" + +# Copy .runner file to work dir if it was created in cwd +[[ -f ".runner" ]] && cp .runner "$WORK_DIR/.runner" + +# ── install LaunchDaemon ────────────────────────────────────────────────────── +# PATH must include Homebrew + Xcode tools so xcodebuild, xcrun, npm, etc. are found. +HOMEBREW_PREFIX=$([ "$ARCH" = "arm64" ] && echo "/opt/homebrew" || echo "/usr/local") + +cat > "$LAUNCHDAEMON_PLIST" < + + + + Label + com.gitea.act_runner + ProgramArguments + + ${INSTALL_DIR}/act_runner + daemon + --config + ${CONFIG_PATH} + + RunAtLoad + + KeepAlive + + WorkingDirectory + ${WORK_DIR} + StandardOutPath + ${WORK_DIR}/act_runner.log + StandardErrorPath + ${WORK_DIR}/act_runner.err + EnvironmentVariables + + PATH + ${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Xcode.app/Contents/Developer/usr/bin + HOME + ${WORK_DIR} + + + +PLIST + +echo "LaunchDaemon written to $LAUNCHDAEMON_PLIST" + +# ── load the daemon ─────────────────────────────────────────────────────────── +launchctl unload "$LAUNCHDAEMON_PLIST" 2>/dev/null || true +launchctl load "$LAUNCHDAEMON_PLIST" +echo "Runner '$RUNNER_NAME' started via LaunchDaemon" +echo "" +echo "Useful commands:" +echo " View logs: tail -f $WORK_DIR/act_runner.log" +echo " Stop runner: sudo launchctl unload $LAUNCHDAEMON_PLIST" +echo " Start runner: sudo launchctl load $LAUNCHDAEMON_PLIST"