2026-04-25 임대 클라우드 Mac(HK / JP / KR / SG / US)에서 xcodebuild test 코드 커버리지, xcresult→JUnit, PR 게이트
iOS·macOS 팀은 임대 Apple Silicon Mac mini M4에서 헤드리스 xcodebuild test를 돌려도 PR을 단일 종료 코드와 벤더 UI 빨강/초록만으로 머지하는 경우가 많습니다. 이 2026-04-25 글은 “테스트 통과”와 “이번 주 품질 변화를 설명”의 간극을 메웁니다: -resultBundlePath를 격리 빌드 루트 아래 작업별 디렉터리로, -enableCodeCoverage YES로 LLVM profdata, JUnit XML 내보내기(xcresulttool 또는 신뢰하는 래퍼), xccov나 대시보드 파서로 지키는 라인 비율 정책. 테스트 플랜 + 병렬 xcresult를 대체하지 않고 보완합니다. 컴파일러 게이트는 Swift 6 strict concurrency로. 여기서는 테스트 산출물·머지 신호입니다. 같은 날 OpenClaw: OpenClaw doctor·모델 허용 목록.
종료 코드 0 외에 PR 게이트가 봐야 할 것
건강한 게이트는 세 가지 묶음을 옮깁니다: (1) PR 시스템이 테스트·플레이크를 주석할 junit(xunit); (2) Xcode 심층 분석용 병합된 또는 단일 .xcresult를 xcresult 격리 티켓과 같은 보존으로 압축 아티팩트에; (3) 머지 베이스와 델타할 커버리지 요약(정책에 따라 라인/분기). HK / JP / KR / SG / US에서 여러 SSH 호스트로 퍼지면 목적지 샤딩 뒤 집계 메트릭으로 게이트를 정의하세요—정책이 일부 타깃만 명시하지 않는 한 한 샤드의 profdata만 이야기로 삼지 마세요. 지연은 메타데이터의 머신 풀 라벨과 짝을 이루어야 합니다.
중요한 xcodebuild 플래그: 결과 번들, 커버리지, destination
DEVELOPER_DIR=/Applications/Xcode.app와 이름이 붙은 시뮬레이터 -destination을 고정하세요. 이름 없는 “최신 iOS”에 떠다니지 마세요.
DEVELOPER_DIR=/Applications/Xcode.app xcodebuild test -workspace App.xcworkspace -scheme App -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.2' -enableCodeCoverage YES -resultBundlePath "$CI_ROOT/Test-$(date +%s).xcresult" -derivedDataPath "$CI_DERIVED/job-$CI_JOB_ID" -parallel-testing-enabled YES CODE_SIGNING_ALLOWED=YES
샤드 작업에서는 -only-testing / -skip-testing을 조정하고 병합을 아는 코디네이터 작업으로 마무리합니다. -retry-tests-on-failure는 문서화된 플레이크 예산이 있을 때만—무한 재시도는 서명·키체인 문제를 가립니다. 별도 레인에 Swift 6 strict가 있으면 스킴 분할이 진짜가 아니면 같은 단위 테스트를 두 번 세지 마세요.
.xcresult에서 JUnit: 헤드리스에서 남는 내보내기
macOS CI는 xcresulttool을 노출합니다: 테스트·진단을 JSON 또는 JUnit으로. (1) -resultBundlePath는 런마다 고유이고 공유 NFS 심링크 아래 두지 마세요; (2) 실행 후 xcresulttool get --format json; (3) JUnit 변환—얇은 Ruby/Node 어댑터를 고정하는 팀이 많습니다. 각 testcase에 안정적인 testsuite·classname을 붙여 PR UI가 재시도를 중복 제거하게 하세요. 여러 xcresult 병합은 Xcode merge 또는 문서화된 시간 순서. 동일 식별자에서 testStatus가 충돌하면 거부. 원시 xcresult는 시뮬레이터 심층 분석처럼 콜드 스토리지로. XML만 남기지 마세요.
LLVM profdata, xccov, 방어 가능한 임계값
-enableCodeCoverage YES이면 컴파일러·링커가 xcrun llvm-profdata merge와 xcrun xccov view --report로 볼 데이터를 냅니다. 실무적으로는 자사 앱·코어 프레임워크에 바닥을 두고 생성 코드·서드파티는 체크인한 제외 목록으로—미기재 서드파티가 예산을 조용히 먹지 않게.셀프호스티드 러너 이동 후에도 같은 git SHA의 소스 해시는 맞아야 하고 증분 커버리지는 한 호스트가 타깃을 건너뛰면 어긋날 수 있습니다. 같은 밤 dSYM 업로드를 바꾸면 dSYM 파이프라인이 배포했다고 믿는 bitcode/LLVM 산출물과 일치하는지 확인하세요.
xccov가 profdata 경로를 열 수 없을 때 빌드를 실패시키세요—조용히 커버리지를 0%로 두고 통과시키는 것은 2026년에 테스트 안 된 diff를 낸 뒤 대시보드 탓하기입니다.
샤드된 test: 게이트 전에 병합
-only-testing:Target/Class나 destination으로 나누면 샤드마다 profdata·xcresult가 있습니다. 코디네이터 머지 게이트는: (1) 모든 샤드가 끝나 아티팩트를 올렸는지; (2) 단일 xccov 전에 profdata 병합; (3) JUnit 집계, 의도적으로 샤드에 없는 스위트는 skipped. 인프라 선점으로 샤드를 잃으면 서면의 “누락 샤드 허용”이 없으면(드물고 기본 아님) 머지는 실패. M4 팬아웃과 함께: 병렬은 데이터 평면(아티팩트+커버리지)이 한 보고서로 직렬화될 때만 가치가 있습니다.
증상 / 계층 / 조치
| 증상 | 계층 | 조치·검증 |
|---|---|---|
| 테스트는 돌았는데 커버리지 0% | 빌드 설정·타깃 멤버십 | scheme에서 Code Coverage, 타깃이 커버리지 플래그로 빌드되는지 |
| JUnit 비었는데 UI는 통과 | 도구 내보내기 | 호스트 Xcode 버전에서 xcresulttool 출력 검증 |
| 두 호스트 라인 비율 크게 다름 | 브랜치·증분·샤드 | 게이트에서 증분 끄기, profdata 병합, destination 고정 |
같은 호스트의 관련 런북
같은 Mac이 OpenClaw gateway도 돌리면 에이전트 간 단일 /tmp를 공유하지 마세요—TMPDIR은 작업별여야 합니다. 릴리스 빌드는 원격 archive와 App Store Connect API IPA 내보내기가 같은 신뢰 하류입니다.
FAQ: 다리전 Mac 풀의 품질 게이트
| 질문 | 실무 답 |
|---|---|
| 브랜치 커버리지로 블록? | 언어 믹스가 지원하면. PM에게는 라인 비율이 설명 쉬움. |
| xcresult zip 보존 기간? | 인시던트 SLA에 맞추—14일+가 흔한 시작. |
| 매트릭스에서 미동 먼저 아시아? | 대화형 재현은 커미터 다수 리전에 가깝게. 풀 매트릭스는 릴리스에. |
이 부하에 Mac mini M4를 임대하는 이유
시뮬레이터·커버리지는 GPU보다 CPU+NVMe+inode에 자주 묶입니다. MacXCode 지역의 베어메탈 Mac mini M4는 예측 가능한 I/O와 여러 CoreSimulator 루트를 웜 유지할 RAM을 주고 OpenClaw gateway와 시끄러운 이웃을 나누지 않습니다. p95에 두 번째 레인이 필요하면 플랜으로 확장하세요. 가끔 GUI 확인은 VNC 브레이크글래스—2026 주간 리듬에는 SSH+아티팩트가 주역이어야 합니다.