엔지니어링 가이드

클라우드 Mac CI용 Xcode Scheme 공유와 진입점 검증

클라우드 Mac CI용 Xcode Scheme 공유와 진입점 검증

팀이 프로젝트를 클라우드 Mac에 체크아웃한 뒤 가장 과소평가하기 쉬운 문제는 컴파일 오류가 아닙니다. 파이프라인이 예상한 Scheme을 아예 찾지 못하거나, 이름이 같은 Scheme이 원격 환경에서 다른 대상을 실행하는 문제입니다. 로컬 Xcode는 개발자 디렉터리의 사용자 설정을 읽지만, 깨끗한 CI 작업 공간은 저장소에 포함된 파일만 인식합니다. 빌드 진입점을 안정적으로 유지하려면 Scheme도 스크립트와 의존성 잠금 파일처럼 버전 관리하고 검증해야 합니다.

Scheme을 CI 인터페이스로 취급하기

파이프라인에서 호출할 수 있는 Scheme은 최소한 네 가지를 정의합니다. 빌드할 Target, 사용할 Build Configuration, 테스트할 Test Bundle, 그리고 Archive에 적용할 구성입니다. Xcode 메뉴에 이름이 표시된다고 해서 이 정보가 저장소에 커밋된 것은 아닙니다.

먼저 공유 파일이 존재하는지 확인합니다.

find . \( -path "*/xcshareddata/xcschemes/*.xcscheme" \
  -o -path "*/xcuserdata/*/xcschemes/*.xcscheme" \) -print

xcuserdata에 있는 Scheme은 사용자 설정이므로 CI 진입점으로 사용할 수 없습니다. Xcode의 Manage Schemes에서 Shared를 활성화한 다음, 파일이 아래 경로 중 하나에 생성되었는지 확인합니다.

App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
App.xcworkspace/xcshareddata/xcschemes/App.xcscheme

이어서 git statusgit check-ignore -v로 파일이 추적되고 있는지, 지나치게 광범위한 *.xcuser* 또는 xcshareddata 무시 규칙에 잘못 포함되지 않았는지 확인합니다.

“로컬에서 보인다”는 것은 현재 사용자 디렉터리에 설정이 있다는 뜻일 뿐입니다. “CI에서 사용할 수 있다”는 사실은 깨끗하게 체크아웃한 디렉터리의 명령줄 결과로 입증해야 합니다.

Workspace, Scheme 및 구성 고정하기

파이프라인에서 Xcode의 자동 프로젝트 선택에 의존해서는 안 됩니다. CocoaPods, 통합 프로젝트 또는 로컬 Package가 있으면 .xcodeproj.xcworkspace를 열었을 때 결과가 달라질 수 있습니다. 세 가지 진입점 값을 CI 변수에 명시적으로 지정합니다.

WORKSPACE="App.xcworkspace"
SCHEME="App"
CONFIGURATION="Release"

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -list

-list 출력에는 예상한 Scheme이 포함되어야 합니다. 그런 다음 사람이 로그를 읽는 데만 의존하지 않도록 JSON 출력을 사용해 자동 검증합니다.

xcodebuild -workspace "$WORKSPACE" -list -json > xcode-list.json
python3 - <<'PY'
import json
data = json.load(open("xcode-list.json"))
schemes = data.get("workspace", {}).get("schemes", [])
if "App" not in schemes:
    raise SystemExit("Required Xcode scheme is missing")
PY

저장소에서 개발, 스테이징, 프로덕션 진입점을 모두 유지한다면 App-Dev, App-Staging, App-Release처럼 용도를 드러내는 이름을 사용해야 합니다. 스크립트가 목록 순서에 따라 첫 번째 Scheme을 선택하게 해서는 안 됩니다. 의존성을 추가하면 순서가 바뀔 수 있습니다.

Build, Test 및 Archive를 개별적으로 검증하기

공유에 성공했다는 것은 Scheme이 “보인다”는 문제만 해결할 뿐, 각 동작이 올바르다는 사실까지 입증하지는 않습니다. 검증을 다음 세 단계로 나누는 것이 좋습니다.

해석된 빌드 설정 확인하기

먼저 최종 설정을 내보내고 PRODUCT_BUNDLE_IDENTIFIER, CONFIGURATION, SDKROOT, SUPPORTED_PLATFORMS 및 산출물 디렉터리를 중점적으로 확인합니다.

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -showBuildSettings > build-settings.txt

grep -E "PRODUCT_BUNDLE_IDENTIFIER|CONFIGURATION =|SDKROOT|SUPPORTED_PLATFORMS" \
  build-settings.txt

여기에는 Scheme, 프로젝트 설정, 명령줄 인수를 병합한 결과가 표시되므로 project.pbxproj를 직접 확인하는 것보다 실제 실행 환경에 가깝습니다.

테스트 진입점 검증하기

테스트 단계에서는 먼저 테스트 가능한 산출물을 빌드한 뒤 테스트를 실행합니다. 이렇게 하면 “컴파일 진입점이 잘못된 문제”와 “테스트 실행 실패”를 구분할 수 있습니다.

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  build-for-testing

시뮬레이터 이름은 현재 시스템에서 실행한 xcrun simctl list devices available 결과를 사용해야 합니다. 개인 컴퓨터에만 있는 기기를 하드코딩해서는 안 됩니다. 팀에서 특정 런타임을 고정해야 한다면 Xcode 버전과 대상 OS 버전도 함께 기록해야 합니다.

아카이브 동작을 별도로 확인하기

Archive는 Run이나 Test와 다른 구성을 사용할 수 있습니다. 먼저 .xcscheme에서 ArchiveAction의 구성을 확인한 다음, 통제된 작업에서 실제 아카이브를 실행합니다.

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -archivePath "$PWD/artifacts/App.xcarchive" \
  archive

일반 build의 성공으로 Archive 검증을 대신해서는 안 됩니다. 리소스 처리, 스크립트 단계, 아카이브 설정과 관련된 문제는 이 과정에서만 드러나는 경우가 많습니다.

로컬 상태를 제거한 뒤 다시 검증하기

가장 신뢰할 수 있는 검증 방법은 DerivedData를 삭제하는 것이 아니라 새 디렉터리에 저장소를 다시 복제하는 것입니다. 이렇게 하면 커밋되지 않은 Scheme, 로컬 심볼릭 링크, 추적되지 않는 설정 및 암묵적 의존성을 한꺼번에 찾아낼 수 있습니다.

ROOT="$(mktemp -d)"
git clone --no-local . "$ROOT/repo"
cd "$ROOT/repo"
git submodule update --init --recursive
xcodebuild -workspace App.xcworkspace -scheme App -list

프로젝트가 생성 단계에 의존한다면 빌드 전에 생성 명령을 실행하고 결과가 안정적인지 확인해야 합니다. 운영 문서에 “먼저 Xcode로 프로젝트를 한 번 연다”는 절차를 넣지 마십시오. 이런 단계는 무인 작업으로 전환할 수 없으며 누락된 파일을 감추기도 합니다.

깨끗한 환경에서의 검증에는 최소한 다음 항목이 포함되어야 합니다.

검사 항목 통과 기준
Scheme 가시성 xcodebuild -list -json이 지정된 이름을 반환함
파일 위치 및 추적 상태 Scheme이 xcshareddata에 있으며 Git에서 추적됨
빌드 구성 명령줄에서 해석된 결과가 파이프라인의 예상과 일치함
테스트 진입점 build-for-testing으로 테스트 산출물을 생성할 수 있음
아카이브 진입점 일반 iOS 대상을 사용해 .xcarchive를 생성할 수 있음
비대화식 실행 Xcode를 열거나 개인 디렉터리를 읽을 필요가 없음

병합 전에 진입점 변경 차단하기

Scheme은 XML 파일이므로 병합 충돌을 일반 텍스트 충돌처럼 처리하기 쉽습니다. 그 결과 이름은 남아 있어도 Testable이나 BuildActionEntry가 사라질 수 있습니다. 병합 요청에 가벼운 검사를 추가해 공유 파일의 존재 여부를 확인하고, xcuserdata 커밋을 금지하며, xcodebuild -list -json을 실행할 수 있습니다.

Scheme의 Pre-actions와 Post-actions도 확인해야 합니다. 스크립트가 절대 경로, 대화형 Shell 설정 또는 특정 개발자의 컴퓨터에만 있는 도구를 참조하면 원격 실행은 여전히 실패합니다. 스크립트는 SRCROOT 등의 빌드 변수를 기준으로 파일을 찾아야 하며, 의존성이 없을 때는 명확한 오류와 함께 종료해야 합니다.

최종 검증 기준은 간단합니다. 빈 디렉터리에서 저장소를 가져온 뒤 문서에 명시된 Xcode 버전과 명령만 제공해도 Scheme을 열거하고, 설정을 해석하며, 테스트 산출물을 빌드하고, 아카이브까지 완료할 수 있어야 합니다. 이 조건을 충족해야 G-Mini의 클라우드 Mac이 특정 개발자 컴퓨터의 우연한 상태를 재현하는 대신 저장소에 정의된 진입점을 실행한다고 볼 수 있습니다.

자주 묻는 질문

로컬 Xcode에서는 보이는데 클라우드 Mac CI에서 Scheme을 찾지 못하는 이유는 무엇인가요?

Scheme이 xcuserdata에만 저장됐을 가능성이 큽니다. xcshareddata/xcschemes에 공유 파일을 만들고 Git에 커밋해야 새 CI 체크아웃에서도 확인할 수 있습니다.

Scheme을 공유하면 Archive 검증은 생략해도 되나요?

아니요. 공유는 Scheme의 가시성만 보장합니다. Release 구성, Archive 대상과 사전 동작을 확인하고 깨끗한 체크아웃에서 실제 Archive를 한 번 이상 실행해야 합니다.

전용 물리 노드

다음 빌드 큐를 위한 클라우드 Mac

두 가지 M4 구성과 5개 노드를 비교하고, 실제 작업 주기에 맞춰 일간·주간·월간·분기 임대를 선택하세요.

클라우드 Mac 요금제 선택