CI별 사용법
어느 CI에서든, git 없는 폴더에서든 API 키 하나 + 명령 한 줄
어느 CI든 방법은 같습니다. CI 비밀 변수 XENOCI_API_KEY에 API 키를 넣고 xenoci build --script ./ci.sh 한 줄을 실행합니다. 작업 폴더가 임대 맥으로 올라가 빌드되고, 로그가 실시간으로 출력됩니다. 빌드 종료 코드가 그대로 돌아오므로 CI 단계의 성공·실패가 빌드 결과대로 정해집니다. CI 작업을 중단하면 빌드도 취소됩니다.
xenoci는 설치 스크립트로 받는 실행 파일 하나입니다. Node나 git이 없는 에이전트에서도 동작하며, 설치 스크립트가 SHA256SUMS로 체크섬을 확인합니다. Linux(x64·arm64, glibc·musl), macOS(Apple silicon), Windows(x64)를 지원합니다. Node가 있는 곳에서는 npx github:xeno-ci/build build --script ./ci.sh도 같은 동작입니다.
curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh업로드되는 파일
git 저장소이면 git이 추적하거나 무시하지 않는 파일을 올립니다. git이 없으면 폴더의 .gitignore를 따릅니다. .gitignore도 없으면 build/·*.xcarchive·*.xcresult·*.ipa·*.dSYM·Carthage/Build·.gradle·__pycache__·.venv·.idea·fastlane 산출물을 뺍니다. .git·DerivedData·Pods·node_modules·.build·.swiftpm·xcuserdata·.DS_Store는 항상 빠집니다. 최대 2GB이고, 두 번째 빌드부터는 바뀐 파일만 보냅니다.
GitHub Actions
Action을 쓰면 업로드 없이 임대 맥이 그 커밋만 직접 받습니다.
- uses: xeno-ci/build@v1
with:
api-key: ${{ secrets.XENOCI_API_KEY }}
script: ./ci.shJenkins
플러그인은 필요 없습니다. Manage Jenkins → Credentials에 종류 Secret text, ID xenoci-api-key로 API 키를 등록합니다. 저장소의 Jenkinsfile은 다음과 같습니다. withCredentials는 Credentials Binding 플러그인으로, 기본 설치에 들어 있습니다. 로그에서 키는 ****로 가려집니다.
pipeline {
agent any
options { timestamps() }
stages {
stage('macOS build') {
steps {
withEnv(["PATH+XENOCI=${env.HOME}/.local/bin"]) {
sh 'command -v xenoci || curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh'
withCredentials([string(credentialsId: 'xenoci-api-key', variable: 'XENOCI_API_KEY')]) {
sh 'xenoci build --script ./ci.sh'
}
}
}
}
}
}프리스타일 잡을 쓸 때는 Build Environment에서 Use secret text(s) or file(s)를 켜고, Secret text 변수 XENOCI_API_KEY에 같은 자격 증명을 연결합니다. 그다음 Build Steps → Execute shell에 다음을 넣습니다.
export PATH="$HOME/.local/bin:$PATH"
command -v xenoci || curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
xenoci build --script ./ci.shGitLab CI
Settings → CI/CD → Variables에 XENOCI_API_KEY를 Masked로 추가합니다. .gitlab-ci.yml:
macos-build:
image: alpine:3.20
script:
- wget -qO- https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
- xenoci build --script ./ci.shBitbucket Pipelines
Repository settings → Repository variables에 XENOCI_API_KEY를 Secured로 추가합니다. bitbucket-pipelines.yml:
pipelines:
default:
- step:
name: macOS build
image: alpine:3.20
script:
- wget -qO- https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
- xenoci build --script ./ci.shCircleCI
Project Settings → Environment Variables에 XENOCI_API_KEY를 추가합니다. .circleci/config.yml:
version: 2.1
jobs:
macos-build:
docker:
- image: cimg/base:stable
steps:
- checkout
- run: curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
- run: ~/.local/bin/xenoci build --script ./ci.sh
workflows:
build:
jobs: [macos-build]Buildkite
에이전트 환경 변수나 시크릿 관리 도구로 XENOCI_API_KEY를 넣습니다. pipeline.yml:
steps:
- label: ":apple: macOS build"
command: |
command -v xenoci || curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
xenoci build --script ./ci.sh사내 서버 셸·git 없는 폴더
cron이나 사내 빌드 서버, 압축을 푼 프로젝트 폴더에서도 같습니다. git이 없어도 됩니다.
curl -fsSL https://github.com/Xeno-CI/build/releases/latest/download/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
export XENOCI_API_KEY='발급한 API 키'
cd MyApp # 압축을 푼 폴더도 됩니다 (git 필요 없음)
xenoci build --script ./ci.sh
echo "종료 코드 $?"Windows(PowerShell)에서는 다음과 같이 설치합니다.
irm https://github.com/Xeno-CI/build/releases/latest/download/install.ps1 | iex
$env:XENOCI_API_KEY = '발급한 API 키'
xenoci build --script ./ci.shCLI 없이 curl만으로
아무것도 설치할 수 없는 환경에서는 HTTP API를 직접 호출합니다. 폴더 업로드, 빌드 제출, 로그 스트리밍, 결과 조회 순서입니다. 로그 요청은 새 출력이 생길 때까지 최대 wait초 기다린 뒤 본문을 돌려줍니다. 다음 위치는 X-Next-Offset, 상태는 X-Build-State, 끝난 뒤 종료 코드는 X-Exit-Code 헤더로 알려줍니다.
API=https://app.xenoci.com/api/ci/v1
AUTH="Authorization: Bearer $XENOCI_API_KEY"
# 1. 폴더를 tar.gz로 올립니다 (.git·DerivedData·Pods·node_modules는 서버가 뺍니다)
UP=$(tar -czf - . | curl -fsS "$API/uploads/tar?project=myapp" -H "$AUTH" \
-H 'Content-Type: application/gzip' --data-binary @- | sed -n 's/.*"upload_id":"\([^"]*\)".*/\1/p')
# 2. 빌드를 제출합니다
ID=$(curl -fsS "$API/builds" -H "$AUTH" -H 'Content-Type: application/json' \
-d "{\"upload_id\":\"$UP\",\"script\":\"bash ci.sh\"}" | sed -n 's/.*"id":"\(rb_[^"]*\)".*/\1/p')
# 3. 끝날 때까지 로그를 이어서 받습니다 (한 번에 최대 20초 대기)
OFF=0; STATE=queued
while :; do
curl -fsS -D /tmp/xenoci.h "$API/builds/$ID/log?format=text&offset=$OFF&wait=20" -H "$AUTH"
hdr() { tr -d '\r' < /tmp/xenoci.h | awk -F': ' -v k="$1" 'tolower($1)==k {print $2}'; }
OFF=$(hdr x-next-offset); STATE=$(hdr x-build-state)
case $STATE in succeeded|failed|cancelled|expired) break ;; esac
done
# 4. 빌드 종료 코드로 끝냅니다 (취소·만료는 1)
CODE=$(hdr x-exit-code); exit "${CODE:-1}"PowerShell(Windows 10 이상에는 tar가 들어 있습니다):
$ErrorActionPreference = 'Stop'
$api = 'https://app.xenoci.com/api/ci/v1'
$h = @{ Authorization = "Bearer $env:XENOCI_API_KEY" }
$tgz = Join-Path ([IO.Path]::GetTempPath()) 'xenoci-src.tgz'
tar -czf $tgz -C . .
$up = Invoke-RestMethod -Method Post -Uri "$api/uploads/tar?project=myapp" -Headers $h -ContentType 'application/gzip' -InFile $tgz
$body = @{ upload_id = $up.upload_id; script = 'bash ci.sh' } | ConvertTo-Json
$b = Invoke-RestMethod -Method Post -Uri "$api/builds" -Headers $h -ContentType 'application/json' -Body $body
$off = 0
do {
$r = Invoke-WebRequest -UseBasicParsing -Headers $h -Uri "$api/builds/$($b.id)/log?format=text&offset=$off&wait=20"
[Console]::Out.Write($r.Content)
$off = [long]"$($r.Headers['X-Next-Offset'])"
$state = "$($r.Headers['X-Build-State'])"
} until ($state -in 'succeeded', 'failed', 'cancelled', 'expired')
$code = "$($r.Headers['X-Exit-Code'])"
if ($code) { exit [int]$code } else { exit 1 }업로드 없이 공개 git 주소에서 바로 빌드하려면 빌드 제출 본문에 upload_id 대신 repo_url과 ref를 넣습니다. 빌드 상태는 GET /api/ci/v1/builds/<id>, 취소는 POST /api/ci/v1/builds/<id>/cancel입니다.