Skip to content

[FEAT] release를 TestFlight 검증 빌드 재사용으로 전환 #9

[FEAT] release를 TestFlight 검증 빌드 재사용으로 전환

[FEAT] release를 TestFlight 검증 빌드 재사용으로 전환 #9

name: TestFlight Deploy
on:
pull_request:
branches: [main]
types: [closed]
workflow_dispatch:
concurrency:
group: testflight-deploy
cancel-in-progress: false
jobs:
# ──────────────────────────────────────────────────────────
# Deploy (TestFlight)
# ──────────────────────────────────────────────────────────
deploy:
# PR 이 머지된 경우 또는 수동 실행일 때만 동작 (단순 close 는 스킵)
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
runs-on: macos-15
# 서명 단계가 매달려도 러너를 오래 점유하지 않도록 상한을 둔다
# (concurrency 가 cancel-in-progress: false 라 멈춘 잡이 후속 배포를 전부 막는다)
timeout-minutes: 60
env:
# Appfile / Fastfile
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
APPLE_ID: ${{ secrets.APPLE_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
# match
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_KEYCHAIN_PASSWORD: ${{ secrets.MATCH_KEYCHAIN_PASSWORD }}
# 러너에 이미 있는 login 키체인은 비밀번호를 알 수 없어 match 의 set-key-partition-list 가 실패한다
# → 전용 키체인을 새로 만들어 쓴다 (Matchfile 이 이 값을 참조)
MATCH_KEYCHAIN_NAME: build.keychain
# 인증서 repo(private) 클론용 토큰 — Deploy 스텝에서 MATCH_GIT_BASIC_AUTHORIZATION 로 인코딩
CONFIG_PRIVATE_REPO_TOKEN: ${{ secrets.CONFIG_PRIVATE_REPO_TOKEN }}
# App Store Connect API (Fastfile 변수명)
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
# App Store Connect API (Matchfile 변수명 호환)
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
steps:
- uses: actions/checkout@v4
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Setup mise & tuist
uses: jdx/mise-action@v2
# 커밋된 tuisttool 바이너리는 로컬 macOS 26 기준으로 빌드되어 macos-15 러너에서 로드 불가
# → 러너 OS에 맞게 소스에서 재컴파일 (Install dependencies·fastlane 의 ./tuisttool 호출 대비)
- name: Build tuisttool
run: swiftc TuistTool.swift -o tuisttool
- name: Setup Ruby & fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true
- name: Download private xcconfig
run: |
echo "GITHUB_ACCESS_TOKEN=${CONFIG_PRIVATE_REPO_TOKEN}" > .env
make download-privates
# 생성 실패를 무시하면 러너의 기존 키체인을 그대로 쓰게 되고, 비밀번호 불일치로
# codesign 이 뜰 수 없는 승인 팝업을 기다리며 무한 대기한다. 실패 시 즉시 잡을 멈춘다.
- name: Prepare keychain
run: |
security create-keychain -p "$MATCH_KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -lut 21600 build.keychain
security unlock-keychain -p "$MATCH_KEYCHAIN_PASSWORD" build.keychain
# xcodebuild 가 시스템 인증서를 찾을 수 있도록 login 키체인도 검색 목록에 남긴다
security list-keychains -d user -s build.keychain login.keychain-db
security default-keychain -s build.keychain
# SPM 의존성 설치 (fastlane 의 ensure_workspace 가 generate 하기 전 선행)
- name: Install dependencies
run: ./tuisttool install
- name: Deploy to TestFlight
run: |
# match 가 private 인증서 repo 를 클론할 때 사용할 basic auth 헤더 생성
# (base64 는 긴 토큰에서 줄바꿈이 삽입되므로 제거)
export MATCH_GIT_BASIC_AUTHORIZATION=$(printf 'x-access-token:%s' "${CONFIG_PRIVATE_REPO_TOKEN}" | base64 | tr -d '\n')
bundle exec fastlane beta