Repository navigation
153 lines (136 loc) · 7.54 KB
/
Copy pathcd-beta-external.yml
File metadata and controls
153 lines (136 loc) · 7.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
name: Deploy to TestFlight (External)
on:
push:
branches: ["release/**"] # 릴리스 브랜치(release/1.0.0 등) push 시 외부 테스터 배포
workflow_dispatch:
inputs:
changelog:
description: "외부 테스터에게 보일 '테스트 사항'(비우면 기본 문구)"
required: false
type: string
concurrency:
group: cd-external
cancel-in-progress: false
jobs:
beta_external:
name: TestFlight 외부 테스트 배포
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: true # CoreML 모델 가중치(weight.bin)가 LFS 추적 → 안 받으면 포인터가 번들돼 로드 실패
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "latest-stable"
- name: Install mise
uses: jdx/mise-action@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler: "latest"
bundler-cache: true
- name: Create Secrets.xcconfig
env:
BASE_URL: ${{ secrets.BASE_URL }}
BASE_URL_DEV: ${{ secrets.BASE_URL_DEV }}
CLARITY_PROJECT_ID: ${{ secrets.CLARITY_PROJECT_ID }}
DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
run: |
mkdir -p XCConfig
# xcconfig 은 값 안의 "//" 를 주석 처리하므로 스킴의 "://" 에 $() 를 끼워 회피.
# (이미 회피형이면 "://" 가 없어 그대로 통과 — 멱등)
BASE_URL_ESC=$(printf '%s' "${BASE_URL}" | sed 's#://#:/$()/#')
# 개발 서버(infra locals.tf: dev.api_domain). 시크릿 미등록 시 기본값.
BASE_URL_DEV_ESC=$(printf '%s' "${BASE_URL_DEV:-https://dev.nursemate.app}" | sed 's#://#:/$()/#')
# 카카오 키가 비면 URL 스킴이 "kakao" 한 단어로 들어간다. 앱은 멀쩡히 빌드·실행되고
# 카카오 로그인만 복귀하지 못해서, TestFlight 에 올린 뒤에야 드러나는 조용한 실패다.
if [ -z "${KAKAO_NATIVE_APP_KEY}" ]; then
echo "::error::KAKAO_NATIVE_APP_KEY 시크릿이 없습니다 — 카카오 로그인 복귀 URL 스킴이 'kakao' 로만 들어갑니다."
exit 1
fi
cat > XCConfig/Secrets.xcconfig << EOF
BASE_URL_DEBUG = ${BASE_URL_DEV_ESC}
BASE_URL_RELEASE = ${BASE_URL_ESC}
CLARITY_PROJECT_ID = ${CLARITY_PROJECT_ID}
DEVELOPMENT_TEAM = ${DEVELOPMENT_TEAM}
KAKAO_NATIVE_APP_KEY = ${KAKAO_NATIVE_APP_KEY}
EOF
# GOOGLE_REVERSED_CLIENT_ID_* 는 여기서 쓰지 않는다 —
# 아래 "Write GoogleService-Info.plist" 단계가 plist 에서 직접 뽑아 덧붙인다.
- name: Write GoogleService-Info.plist
env:
GOOGLE_SERVICE_INFO_PLIST: ${{ secrets.GOOGLE_SERVICE_INFO_PLIST }}
GOOGLE_SERVICE_INFO_PLIST_DEV: ${{ secrets.GOOGLE_SERVICE_INFO_PLIST_DEV }}
run: |
# plist 는 빌드 구성별로 Firebase/<구성>/ 에 둔다.
# Project.swift 의 "Firebase 구성 선택" 스크립트가 FIREBASE_ENV 를 보고 번들로 복사한다.
mkdir -p Projects/App/Firebase/Release Projects/App/Firebase/Debug
echo "$GOOGLE_SERVICE_INFO_PLIST" | base64 --decode > Projects/App/Firebase/Release/GoogleService-Info.plist
# Debug 구성(Xcode 디버그·beta_internal)은 dev Firebase 프로젝트를 쓴다.
# 시크릿이 없다고 Release(prod) plist 로 대신 채우면, 내부 빌드가 조용히 prod 로 붙어
# 운영 Analytics 를 오염시키고 BASE_URL(dev)과 어긋나 App Check 401 이 난다.
# 잘못된 프로젝트로 나가느니 여기서 멈춘다.
if [ -z "$GOOGLE_SERVICE_INFO_PLIST_DEV" ]; then
echo "::error::GOOGLE_SERVICE_INFO_PLIST_DEV 시크릿이 없습니다 — 내부 빌드가 prod Firebase 로 나갑니다."
exit 1
fi
echo "$GOOGLE_SERVICE_INFO_PLIST_DEV" | base64 --decode > Projects/App/Firebase/Debug/GoogleService-Info.plist
# 구글 로그인 복귀 URL 스킴(NM-410)은 plist 의 REVERSED_CLIENT_ID 와 반드시 같아야 한다.
# 별도 시크릿으로 두면 plist 만 갱신했을 때 한쪽이 옛 값으로 남아 조용히 어긋나므로,
# 방금 쓴 plist 에서 직접 뽑아 Secrets.xcconfig 에 덧붙인다(단일 출처).
# Firebase 콘솔에서 Google 공급자가 꺼져 있으면 plist 에 이 키가 없다 —
# 그때는 빈 값이 들어가고 구글 버튼만 실패한다(카카오·애플은 영향 없음).
reversed_client_id() {
plutil -extract REVERSED_CLIENT_ID raw -o - "$1" 2>/dev/null || true
}
{
echo "GOOGLE_REVERSED_CLIENT_ID_DEBUG = $(reversed_client_id Projects/App/Firebase/Debug/GoogleService-Info.plist)"
echo "GOOGLE_REVERSED_CLIENT_ID_RELEASE = $(reversed_client_id Projects/App/Firebase/Release/GoogleService-Info.plist)"
} >> XCConfig/Secrets.xcconfig
# 같은 종류의 조용한 실패 — plist 에 REVERSED_CLIENT_ID 가 없으면(콘솔에서 Google 공급자가
# 꺼진 프로젝트의 plist) 구글 로그인만 복귀하지 못한다. 빌드는 성공하므로 여기서 막는다.
for config in Debug Release; do
if [ -z "$(reversed_client_id "Projects/App/Firebase/$config/GoogleService-Info.plist")" ]; then
echo "::error::$config 의 GoogleService-Info.plist 에 REVERSED_CLIENT_ID 가 없습니다 — Firebase 콘솔에서 Google 공급자를 켜고 plist 를 다시 받아 시크릿을 갱신하세요."
exit 1
fi
done
- name: Write API Key
env:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
run: |
echo "$APP_STORE_CONNECT_API_KEY_CONTENT" | base64 --decode > /tmp/AuthKey_raw.p8
OPENSSL=$(brew --prefix openssl@3)/bin/openssl
$OPENSSL pkey -traditional -in /tmp/AuthKey_raw.p8 -out /tmp/AuthKey.p8
mkdir -p ~/.appstoreconnect/private_keys
cp /tmp/AuthKey_raw.p8 ~/.appstoreconnect/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8
- name: Cache SPM packages
uses: actions/cache@v4
with:
path: |
.build
~/.tuist/Cache
key: ${{ runner.os }}-spm-${{ hashFiles('Tuist/Package.swift') }}
restore-keys: |
${{ runner.os }}-spm-
- name: Install Swift Packages
run: tuist install
- name: Tuist generate
run: tuist generate --no-open
- name: Deploy to TestFlight (External)
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
BUILD_NUMBER: ${{ github.run_number }}
CHANGELOG: ${{ github.event.inputs.changelog }}
run: bundle exec fastlane beta_external