| new file mode 100755 |
| index 0000000..9c5b190 |
| --- /dev/null |
| +++ b/ios/ci_scripts/ci_post_clone.sh |
| @@ -0,0 +1,108 @@ |
| +#!/bin/sh |
| + |
| +# 🤖 Xcode Cloud post-clone hook. |
| +# |
| +# The Xcode project is NOT committed to this repo — it is generated from |
| +# ios/project.yml by XcodeGen (see ios/.gitignore). Xcode Cloud clones the repo |
| +# and then expects to find ios/LChat.xcodeproj, so we regenerate it here, right |
| +# after the clone and before dependency resolution + the build. |
| +# |
| +# LOCATION MATTERS: Xcode Cloud only runs ci_scripts/ when it sits next to the |
| +# Xcode project/workspace. The project lives in ios/, so this folder must be |
| +# ios/ci_scripts/ — NOT the repo root. (A repo-root ci_scripts is silently |
| +# ignored for a subdirectory project, which looks like "the hook never ran".) |
| +# |
| +# Xcode Cloud runs this from the ci_scripts/ directory and exports |
| +# CI_PRIMARY_REPOSITORY_PATH pointing at the cloned checkout root. Homebrew is |
| +# preinstalled on the runners, so we install XcodeGen with it. |
| +# |
| +# Scope: iOS only for now (scheme "LChat"). The Mac scheme (LChatMac) pulls in |
| +# Sparkle and an "Embed eleven CLI" step that shells out to `go build`; when we |
| +# add Mac to Xcode Cloud this script will also need to install Go 1.25. Left out |
| +# deliberately until then. |
| + |
| +set -eu |
| + |
| +echo "════════════ ci_post_clone: start ════════════" |
| +echo "pwd = $(pwd)" |
| +echo "script = $0" |
| +echo "CI_PRIMARY_REPOSITORY_PATH = ${CI_PRIMARY_REPOSITORY_PATH:-<unset>}" |
| +echo "CI_WORKSPACE = ${CI_WORKSPACE:-<unset>}" |
| +echo "CI_BUILD_NUMBER = ${CI_BUILD_NUMBER:-<unset>}" |
| + |
| +# Don't let brew spend minutes auto-updating itself/formulae on every build. |
| +export HOMEBREW_NO_AUTO_UPDATE=1 |
| +export HOMEBREW_NO_INSTALL_CLEANUP=1 |
| + |
| +# The ios/ directory holds project.yml. Prefer the documented repo-root env var; |
| +# fall back to the parent of this script's dir (this script lives in ios/ci_scripts). |
| +if [ -n "${CI_PRIMARY_REPOSITORY_PATH:-}" ]; then |
| + IOS_DIR="$CI_PRIMARY_REPOSITORY_PATH/ios" |
| +else |
| + IOS_DIR="$(cd "$(dirname "$0")/.." && pwd)" |
| + echo "▸ CI_PRIMARY_REPOSITORY_PATH unset — derived IOS_DIR from script dir" |
| +fi |
| +echo "IOS_DIR = $IOS_DIR" |
| + |
| +if [ ! -f "$IOS_DIR/project.yml" ]; then |
| + echo "✗ ERROR: $IOS_DIR/project.yml not found — repo layout is not what we expect" >&2 |
| + exit 1 |
| +fi |
| + |
| +if ! command -v xcodegen >/dev/null 2>&1; then |
| + echo "▸ installing xcodegen via Homebrew" |
| + brew install xcodegen |
| +fi |
| +echo "xcodegen at $(command -v xcodegen) — $(xcodegen --version)" |
| + |
| +cd "$IOS_DIR" |
| +echo "──────── ios/ before generate ────────" |
| +ls -la |
| + |
| +# TestFlight rejects a re-uploaded build number, so stamp Xcode Cloud's |
| +# monotonic CI_BUILD_NUMBER into CURRENT_PROJECT_VERSION before generating. |
| +# CFBundleVersion is driven from that build setting (see project.yml), so this |
| +# flows through to the app and both extensions. Only touches project.yml when |
| +# running under Xcode Cloud (CI_BUILD_NUMBER set) — local generates are unchanged. |
| +if [ -n "${CI_BUILD_NUMBER:-}" ]; then |
| + echo "▸ stamping build number $CI_BUILD_NUMBER into project.yml" |
| + sed -i '' -E "s/^([[:space:]]*CURRENT_PROJECT_VERSION:[[:space:]]*).*/\1\"$CI_BUILD_NUMBER\"/" project.yml |
| +fi |
| + |
| +xcodegen generate |
| + |
| +echo "──────── ios/ after generate ────────" |
| +ls -la |
| + |
| +if [ ! -d "$IOS_DIR/LChat.xcodeproj" ]; then |
| + echo "✗ ERROR: xcodegen ran but $IOS_DIR/LChat.xcodeproj does not exist" >&2 |
| + exit 1 |
| +fi |
| +echo "──────── generated schemes ────────" |
| +ls -la "$IOS_DIR/LChat.xcodeproj/xcshareddata/xcschemes/" || true |
| +echo "✓ project present: $IOS_DIR/LChat.xcodeproj" |
| + |
| +# Xcode Cloud's build step runs with automatic package resolution DISABLED |
| +# (environment-wide), so it demands a Package.resolved already inside the |
| +# project and refuses to resolve one itself. Our .xcodeproj is generated fresh |
| +# (and gitignored), and we can't resolve on the runner either (same disabled |
| +# state — `xcodebuild -resolvePackageDependencies` exits 74 there). So we ship a |
| +# committed Package.resolved next to this script and stage it into the generated |
| +# workspace. Xcode Cloud then finds it and never needs to resolve. |
| +# |
| +# KEEP IN SYNC with the Sparkle pin in project.yml: when Sparkle's version |
| +# changes, regenerate locally and re-copy — |
| +# cd ios && xcodebuild -resolvePackageDependencies -project LChat.xcodeproj -scheme LChat |
| +# cp LChat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ci_scripts/Package.resolved |
| +SRC_RESOLVED="$IOS_DIR/ci_scripts/Package.resolved" |
| +SWIFTPM_DIR="$IOS_DIR/LChat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm" |
| +echo "──────── staging committed Package.resolved ────────" |
| +if [ ! -f "$SRC_RESOLVED" ]; then |
| + echo "✗ ERROR: $SRC_RESOLVED missing — commit it (see comment above)" >&2 |
| + exit 1 |
| +fi |
| +mkdir -p "$SWIFTPM_DIR" |
| +cp "$SRC_RESOLVED" "$SWIFTPM_DIR/Package.resolved" |
| +echo "✓ staged Package.resolved:" |
| +cat "$SWIFTPM_DIR/Package.resolved" |
| +echo "════════════ ci_post_clone: done ════════════" |