본문으로 건너뛰기

ci.sh 예시

그대로 복사해 쓰는 빌드 스크립트 세 가지, iOS 앱 시뮬레이터 테스트, Swift 패키지 swift test, React Native와 Expo iOS 빌드

프로젝트 폴더에 ci.sh를 만들고 xenocast build --script ./ci.sh로 보냅니다, 아래 세 스크립트는 2026년 10월 15일 XenoCI 러너(Xcode 27.0, xenocast 1.6.9)에서 그대로 돌려 성공한 것입니다

예시확인한 잡실행과금
iOS 앱 시뮬레이터 테스트job_pbDVw4aF5yAFe4oO5I5o152초3분
Swift 패키지 swift testjob_07AsHL2ptkLDyNJ06OUL18초1분
React Native와 Expo iOS 빌드job_5q8azEez4HZ1oqZKZ9vy150초3분

스크립트는 set -euo pipefail로 첫 실패에서 멈추고, 잡의 종료 코드는 스크립트의 종료 코드와 같습니다

iOS 앱 시뮬레이터 테스트

Xcode 프로젝트나 워크스페이스를 찾아 iPhone 17e 시뮬레이터에서 테스트합니다, 서명은 하지 않습니다

#!/bin/bash
# iOS 앱: 시뮬레이터에서 단위 테스트
set -euo pipefail

SCHEME="HelloApp"          # 프로젝트의 스킴 이름
SIM="iPhone 17e"           # Xcode 27.0 의 시뮬레이터

if ls *.xcworkspace >/dev/null 2>&1; then
  FLAG=(-workspace "$(ls -d *.xcworkspace | head -1)")
else
  FLAG=(-project "$(ls -d *.xcodeproj | head -1)")
fi

xcodebuild "${FLAG[@]}" -scheme "$SCHEME" \
  -destination "platform=iOS Simulator,name=$SIM" \
  -resultBundlePath TestResults.xcresult \
  CODE_SIGNING_ALLOWED=NO test
xenocast build --script ./ci.sh --xcode 27.0 --timeout 30 --artifacts 'TestResults.xcresult'
  • SCHEME은 프로젝트의 스킴 이름으로 바꿉니다, 내 Mac의 프로젝트 폴더에서 xcodebuild -list를 실행하면 Schemes: 아래에 이름이 나옵니다(Xcode에서는 Product › Scheme › Manage Schemes)
  • 스킴은 Manage Schemes에서 Shared를 켜서 xcshareddata/xcschemes 아래에 저장하고 소스와 함께 올려야 러너가 찾습니다, 이 컴퓨터에만 있는 스킴은 러너에서 does not contain a scheme으로 실패합니다
  • 프로젝트가 하위 폴더에 있으면(예: ios/App.xcodeproj) 스크립트 맨 위에 cd ios를 넣거나, FLAG=(-project ios/App.xcodeproj)처럼 경로를 직접 적습니다, 프로젝트가 여럿이면 같은 방법으로 하나를 고릅니다
  • Xcode 26.6으로 돌릴 때는 --xcode 26.6과 그 런타임의 기기 이름을 씁니다(iOS 시뮬레이터)
  • 실패한 테스트는 결과물 TestResults.xcresult에서 확인합니다

Swift 패키지 swift test

Package.swift가 있는 폴더에서 빌드하고 테스트합니다

#!/bin/bash
# Swift 패키지: swift test
set -euo pipefail

swift --version
swift build
swift test
xenocast build --script ./ci.sh --xcode 27.0 --timeout 15

XCTest와 Swift Testing(import Testing) 모두 swift test로 돕니다

React Native와 Expo iOS 빌드

Node 22를 잡 안에서 받고 의존성, CocoaPods를 설치한 뒤 시뮬레이터용으로 빌드합니다, Expo 프로젝트에 ios/가 없으면 expo prebuild로 만듭니다, 서명은 하지 않습니다

#!/bin/bash
# React Native, Expo: iOS 시뮬레이터 빌드(서명 없음)
set -euo pipefail
work="$PWD"

# 1. Node 22 (VM 에 없어 잡 안에서 받음)
curl -fsSL https://nodejs.org/dist/latest-v22.x/SHASUMS256.txt -o node-checksums.txt
node_archive=$(awk '/ node-v[0-9.]+-darwin-arm64.tar.gz$/ {print $2}' node-checksums.txt)
curl -fsSL "https://nodejs.org/dist/latest-v22.x/$node_archive" -o "$node_archive"
grep " $node_archive\$" node-checksums.txt | shasum -a 256 -c -
mkdir -p node-runtime && tar -xzf "$node_archive" -C node-runtime --strip-components=1
export PATH="$work/node-runtime/bin:$PATH"

# 2. JavaScript 의존성
npm ci

# 3. Expo 는 ios/ 가 없으면 만듦
[ -d ios ] || npx --no-install expo prebuild --platform ios --no-install

# 4. CocoaPods
(cd ios && pod install)

# 5. 시뮬레이터 빌드, 워크스페이스와 스킴은 ios/ 에서 찾음
WS=$(ls -d ios/*.xcworkspace | head -1)
SCHEME=$(basename "$WS" .xcworkspace)
xcodebuild -workspace "$WS" -scheme "$SCHEME" -configuration Debug \
  -destination 'generic/platform=iOS Simulator' \
  -derivedDataPath build/rn CODE_SIGNING_ALLOWED=NO build
xenocast build --script ./ci.sh --xcode 27.0 --timeout 45
  • package-lock.json이 있어야 npm ci가 됩니다, yarn이나 pnpm을 쓰면 그 명령으로 바꿉니다
  • Expo는 app.json의 ios.bundleIdentifier가 있어야 prebuild가 됩니다
  • 확인한 프로젝트는 create-expo-app 빈 템플릿(Expo 57, React Native 0.86)입니다, 더 자세한 설정은 React Native iOS 빌드와 Expo 빌드에 있습니다

다음 단계