| 1 | #!/bin/sh |
| 2 | |
| 3 | # π€ Xcode Cloud post-clone hook. |
| 4 | # |
| 5 | # The Xcode project is NOT committed to this repo β it is generated from |
| 6 | # ios/project.yml by XcodeGen (see ios/.gitignore). Xcode Cloud clones the repo |
| 7 | # and then expects to find ios/LChat.xcodeproj, so we regenerate it here, right |
| 8 | # after the clone and before dependency resolution + the build. |
| 9 | # |
| 10 | # LOCATION MATTERS: Xcode Cloud only runs ci_scripts/ when it sits next to the |
| 11 | # Xcode project/workspace. The project lives in ios/, so this folder must be |
| 12 | # ios/ci_scripts/ β NOT the repo root. (A repo-root ci_scripts is silently |
| 13 | # ignored for a subdirectory project, which looks like "the hook never ran".) |
| 14 | # |
| 15 | # Xcode Cloud runs this from the ci_scripts/ directory and exports |
| 16 | # CI_PRIMARY_REPOSITORY_PATH pointing at the cloned checkout root. Homebrew is |
| 17 | # preinstalled on the runners, so we install XcodeGen with it. |
| 18 | # |
| 19 | # Scope: iOS only for now (scheme "LChat"). The Mac scheme (LChatMac) pulls in |
| 20 | # Sparkle and an "Embed eleven CLI" step that shells out to `go build`; when we |
| 21 | # add Mac to Xcode Cloud this script will also need to install Go 1.25. Left out |
| 22 | # deliberately until then. |
| 23 | |
| 24 | set -eu |
| 25 | |
| 26 | echo "ββββββββββββ ci_post_clone: start ββββββββββββ" |
| 27 | echo "pwd = $(pwd)" |
| 28 | echo "script = $0" |
| 29 | echo "CI_PRIMARY_REPOSITORY_PATH = ${CI_PRIMARY_REPOSITORY_PATH:-<unset>}" |
| 30 | echo "CI_WORKSPACE = ${CI_WORKSPACE:-<unset>}" |
| 31 | echo "CI_BUILD_NUMBER = ${CI_BUILD_NUMBER:-<unset>}" |
| 32 | |
| 33 | # Don't let brew spend minutes auto-updating itself/formulae on every build. |
| 34 | export HOMEBREW_NO_AUTO_UPDATE=1 |
| 35 | export HOMEBREW_NO_INSTALL_CLEANUP=1 |
| 36 | |
| 37 | # The ios/ directory holds project.yml. Prefer the documented repo-root env var; |
| 38 | # fall back to the parent of this script's dir (this script lives in ios/ci_scripts). |
| 39 | if [ -n "${CI_PRIMARY_REPOSITORY_PATH:-}" ]; then |
| 40 | IOS_DIR="$CI_PRIMARY_REPOSITORY_PATH/ios" |
| 41 | else |
| 42 | IOS_DIR="$(cd "$(dirname "$0")/.." && pwd)" |
| 43 | echo "βΈ CI_PRIMARY_REPOSITORY_PATH unset β derived IOS_DIR from script dir" |
| 44 | fi |
| 45 | echo "IOS_DIR = $IOS_DIR" |
| 46 | |
| 47 | if [ ! -f "$IOS_DIR/project.yml" ]; then |
| 48 | echo "β ERROR: $IOS_DIR/project.yml not found β repo layout is not what we expect" >&2 |
| 49 | exit 1 |
| 50 | fi |
| 51 | |
| 52 | if ! command -v xcodegen >/dev/null 2>&1; then |
| 53 | echo "βΈ installing xcodegen via Homebrew" |
| 54 | brew install xcodegen |
| 55 | fi |
| 56 | echo "xcodegen at $(command -v xcodegen) β $(xcodegen --version)" |
| 57 | |
| 58 | cd "$IOS_DIR" |
| 59 | echo "ββββββββ ios/ before generate ββββββββ" |
| 60 | ls -la |
| 61 | |
| 62 | # TestFlight rejects a re-uploaded build number, so stamp Xcode Cloud's |
| 63 | # monotonic CI_BUILD_NUMBER into CURRENT_PROJECT_VERSION before generating. |
| 64 | # CFBundleVersion is driven from that build setting (see project.yml), so this |
| 65 | # flows through to the app and both extensions. Only touches project.yml when |
| 66 | # running under Xcode Cloud (CI_BUILD_NUMBER set) β local generates are unchanged. |
| 67 | if [ -n "${CI_BUILD_NUMBER:-}" ]; then |
| 68 | echo "βΈ stamping build number $CI_BUILD_NUMBER into project.yml" |
| 69 | sed -i '' -E "s/^([[:space:]]*CURRENT_PROJECT_VERSION:[[:space:]]*).*/\1\"$CI_BUILD_NUMBER\"/" project.yml |
| 70 | fi |
| 71 | |
| 72 | xcodegen generate |
| 73 | |
| 74 | echo "ββββββββ ios/ after generate ββββββββ" |
| 75 | ls -la |
| 76 | |
| 77 | if [ ! -d "$IOS_DIR/LChat.xcodeproj" ]; then |
| 78 | echo "β ERROR: xcodegen ran but $IOS_DIR/LChat.xcodeproj does not exist" >&2 |
| 79 | exit 1 |
| 80 | fi |
| 81 | echo "ββββββββ generated schemes ββββββββ" |
| 82 | ls -la "$IOS_DIR/LChat.xcodeproj/xcshareddata/xcschemes/" || true |
| 83 | echo "β project present: $IOS_DIR/LChat.xcodeproj" |
| 84 | |
| 85 | # Xcode Cloud's build step runs with automatic package resolution DISABLED |
| 86 | # (environment-wide), so it demands a Package.resolved already inside the |
| 87 | # project and refuses to resolve one itself. Our .xcodeproj is generated fresh |
| 88 | # (and gitignored), and we can't resolve on the runner either (same disabled |
| 89 | # state β `xcodebuild -resolvePackageDependencies` exits 74 there). So we ship a |
| 90 | # committed Package.resolved next to this script and stage it into the generated |
| 91 | # workspace. Xcode Cloud then finds it and never needs to resolve. |
| 92 | # |
| 93 | # KEEP IN SYNC with the Sparkle pin in project.yml: when Sparkle's version |
| 94 | # changes, regenerate locally and re-copy β |
| 95 | # cd ios && xcodebuild -resolvePackageDependencies -project LChat.xcodeproj -scheme LChat |
| 96 | # cp LChat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ci_scripts/Package.resolved |
| 97 | SRC_RESOLVED="$IOS_DIR/ci_scripts/Package.resolved" |
| 98 | SWIFTPM_DIR="$IOS_DIR/LChat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm" |
| 99 | echo "ββββββββ staging committed Package.resolved ββββββββ" |
| 100 | if [ ! -f "$SRC_RESOLVED" ]; then |
| 101 | echo "β ERROR: $SRC_RESOLVED missing β commit it (see comment above)" >&2 |
| 102 | exit 1 |
| 103 | fi |
| 104 | mkdir -p "$SWIFTPM_DIR" |
| 105 | cp "$SRC_RESOLVED" "$SWIFTPM_DIR/Package.resolved" |
| 106 | echo "β staged Package.resolved:" |
| 107 | cat "$SWIFTPM_DIR/Package.resolved" |
| 108 | echo "ββββββββββββ ci_post_clone: done ββββββββββββ" |
| 109 | |