project-auto-wizard 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/bin/project-auto-wizard.js +19 -0
- package/package.json +36 -0
- package/payload/coderabbit.yaml +19 -0
- package/payload/config/breaking-changes.json +1 -0
- package/payload/config/wizard-prompts.yml +62 -0
- package/payload/scripts/changelog_manager.py +726 -0
- package/payload/scripts/version_manager.py +617 -0
- package/payload/version.yml.template +48 -0
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +303 -0
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +293 -0
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +289 -0
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +192 -0
- package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +209 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +591 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +700 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +308 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +992 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +689 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +987 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +471 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-SUH-LAB-APP-BUILD-TRIGGER.yaml +500 -0
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +185 -0
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +271 -0
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +81 -0
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +2191 -0
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +386 -0
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +194 -0
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +255 -0
- package/payload/workflows/spring/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +84 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-CI.yml +316 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +58 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +535 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +437 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +2277 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +425 -0
- package/src/cli/args.js +95 -0
- package/src/cli/help.js +27 -0
- package/src/commands/full.js +53 -0
- package/src/commands/interactive.js +276 -0
- package/src/commands/revert.js +60 -0
- package/src/commands/version.js +31 -0
- package/src/commands/workflows.js +49 -0
- package/src/context.js +26 -0
- package/src/core/assets.js +47 -0
- package/src/core/branches.js +60 -0
- package/src/core/branding.js +15 -0
- package/src/core/breaking-check.js +65 -0
- package/src/core/breaking.js +26 -0
- package/src/core/copy/coderabbit.js +26 -0
- package/src/core/copy/gitignore.js +55 -0
- package/src/core/copy/readme.js +30 -0
- package/src/core/copy/simple.js +23 -0
- package/src/core/copy/workflows.js +233 -0
- package/src/core/detect-fs.js +106 -0
- package/src/core/detect.js +62 -0
- package/src/core/fsutil.js +46 -0
- package/src/core/options-ask.js +99 -0
- package/src/core/paths-resolve.js +261 -0
- package/src/core/paths.js +16 -0
- package/src/core/version-yml.js +190 -0
- package/src/core/wizard-env.js +101 -0
- package/src/core/wizard-labels.js +107 -0
- package/src/index.js +162 -0
- package/src/ui/ansi.js +26 -0
- package/src/ui/banner.js +29 -0
- package/src/ui/env-plan.js +207 -0
- package/src/ui/prompts.js +99 -0
- package/src/ui/readline-engine.js +257 -0
- package/src/ui/status-cards.js +56 -0
- package/src/ui/summary.js +127 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# Flutter Android Firebase App Distribution 배포
|
|
3
|
+
# ===================================================================
|
|
4
|
+
#
|
|
5
|
+
# {{MAIN_BRANCH}} 브랜치 푸시 시 Android AAB를 빌드하고
|
|
6
|
+
# Firebase App Distribution에 자동 배포합니다.
|
|
7
|
+
#
|
|
8
|
+
# PlayStore CICD와 동일한 빌드 과정(AAB + 버전 검증)을 거친 후
|
|
9
|
+
# Play Store 대신 Firebase App Distribution에 업로드합니다.
|
|
10
|
+
#
|
|
11
|
+
# ===================================================================
|
|
12
|
+
# 🔑 필수 GitHub Secrets
|
|
13
|
+
# ===================================================================
|
|
14
|
+
#
|
|
15
|
+
# 🔐 Release Keystore:
|
|
16
|
+
# RELEASE_KEYSTORE_BASE64: 서명용 keystore (base64)
|
|
17
|
+
# RELEASE_KEYSTORE_PASSWORD: keystore 비밀번호
|
|
18
|
+
# RELEASE_KEY_ALIAS: key alias
|
|
19
|
+
# RELEASE_KEY_PASSWORD: key 비밀번호
|
|
20
|
+
#
|
|
21
|
+
# 🔥 Firebase:
|
|
22
|
+
# FIREBASE_SERVICE_ACCOUNT_JSON_BASE64: Firebase 서비스 계정 JSON (base64)
|
|
23
|
+
#
|
|
24
|
+
# 📝 환경 설정 (선택):
|
|
25
|
+
# ENV_FILE 또는 ENV: .env 파일 내용 (둘 중 하나, ENV_FILE 우선)
|
|
26
|
+
# GOOGLE_SERVICES_JSON: Firebase google-services.json
|
|
27
|
+
#
|
|
28
|
+
# 🪄 빠른 설정: .github/util/flutter/firebase-wizard/firebase-wizard.html을
|
|
29
|
+
# 브라우저에서 열어 5단계 마법사로 Firebase 배포를 자동 설정할 수 있습니다.
|
|
30
|
+
#
|
|
31
|
+
# ===================================================================
|
|
32
|
+
#
|
|
33
|
+
# 🔧 프로젝트별 설정 (env 섹션에서 수정)
|
|
34
|
+
# ===================================================================
|
|
35
|
+
# APP_ARTIFACT_NAME : 프로젝트 이름
|
|
36
|
+
# FLUTTER_VERSION : Flutter SDK 버전
|
|
37
|
+
# JAVA_VERSION : Java 버전
|
|
38
|
+
# FIREBASE_APP_ID : Firebase 앱 ID (Firebase Console에서 확인)
|
|
39
|
+
# FIREBASE_TESTER_GROUP : Firebase 테스터 그룹명
|
|
40
|
+
# ===================================================================
|
|
41
|
+
#
|
|
42
|
+
# 🛠️ 사전 설정:
|
|
43
|
+
# 1. Firebase Console → App Distribution → 테스터 그룹 생성
|
|
44
|
+
# 2. Firebase 서비스 계정 JSON 생성 (base64 인코딩)
|
|
45
|
+
# 3. GitHub Secrets에 FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 등록
|
|
46
|
+
# 4. env 섹션의 FIREBASE_APP_ID, FIREBASE_TESTER_GROUP 수정
|
|
47
|
+
#
|
|
48
|
+
# ===================================================================
|
|
49
|
+
|
|
50
|
+
name: PROJECT-FLUTTER-ANDROID-FIREBASE-APPDIST-CICD
|
|
51
|
+
|
|
52
|
+
on:
|
|
53
|
+
push:
|
|
54
|
+
branches: ["{{MAIN_BRANCH}}"]
|
|
55
|
+
workflow_dispatch:
|
|
56
|
+
|
|
57
|
+
env:
|
|
58
|
+
# ============================================
|
|
59
|
+
# 🔧 프로젝트별 설정 (아래 값들을 수정하세요)
|
|
60
|
+
# ============================================
|
|
61
|
+
# 프로젝트 이름
|
|
62
|
+
APP_ARTIFACT_NAME: "__APP_ARTIFACT_NAME__" # @wizard ask:@repo
|
|
63
|
+
# Flutter/Java 버전
|
|
64
|
+
FLUTTER_VERSION: "3.35.5"
|
|
65
|
+
JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:17
|
|
66
|
+
PROJECT_TYPE: "flutter"
|
|
67
|
+
# Firebase App Distribution 설정
|
|
68
|
+
FIREBASE_APP_ID: "your-firebase-app-id"
|
|
69
|
+
FIREBASE_TESTER_GROUP: "testers"
|
|
70
|
+
|
|
71
|
+
jobs:
|
|
72
|
+
prepare-build:
|
|
73
|
+
name: 환경 설정 및 준비
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
# CHANGELOG 워크플로우가 성공한 경우에만 실행
|
|
76
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name != 'workflow_run' }}
|
|
77
|
+
|
|
78
|
+
outputs:
|
|
79
|
+
version: ${{ steps.current_version.outputs.version }}
|
|
80
|
+
version_code: ${{ steps.current_version.outputs.version_code }}
|
|
81
|
+
project_type: ${{ steps.current_version.outputs.project_type }}
|
|
82
|
+
|
|
83
|
+
steps:
|
|
84
|
+
- name: Checkout repository
|
|
85
|
+
uses: actions/checkout@v5
|
|
86
|
+
with:
|
|
87
|
+
ref: main
|
|
88
|
+
fetch-depth: 0
|
|
89
|
+
|
|
90
|
+
- name: Pull latest changes
|
|
91
|
+
run: git pull origin main
|
|
92
|
+
|
|
93
|
+
- name: Create .env file
|
|
94
|
+
env:
|
|
95
|
+
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
96
|
+
run: |
|
|
97
|
+
printf '%s\n' "$ENV_CONTENT" > .env
|
|
98
|
+
echo ".env file created"
|
|
99
|
+
|
|
100
|
+
- name: Set up Flutter
|
|
101
|
+
uses: subosito/flutter-action@v2
|
|
102
|
+
with:
|
|
103
|
+
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
104
|
+
cache: true
|
|
105
|
+
|
|
106
|
+
- name: Cache Flutter dependencies
|
|
107
|
+
uses: actions/cache@v4
|
|
108
|
+
with:
|
|
109
|
+
path: ~/.pub-cache
|
|
110
|
+
key: ${{ runner.os }}-flutter-pub-${{ hashFiles('**/pubspec.lock') }}
|
|
111
|
+
restore-keys: ${{ runner.os }}-flutter-pub-
|
|
112
|
+
|
|
113
|
+
- name: Install dependencies
|
|
114
|
+
run: flutter pub get
|
|
115
|
+
|
|
116
|
+
# version_manager.py를 사용하여 현재 버전 정보 가져오기
|
|
117
|
+
- name: 현재 버전 정보 가져오기
|
|
118
|
+
id: current_version
|
|
119
|
+
run: |
|
|
120
|
+
# VERSION 가져오기 (x.y.z 형식)
|
|
121
|
+
VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
|
|
122
|
+
|
|
123
|
+
# VERSION_CODE 가져오기 (version.yml에서 관리되는 단순 증가 번호)
|
|
124
|
+
VERSION_CODE=$(python3 .github/scripts/version_manager.py get-code | tail -n 1)
|
|
125
|
+
|
|
126
|
+
# 결과 출력
|
|
127
|
+
echo "✅ VERSION: $VERSION"
|
|
128
|
+
echo "✅ VERSION_CODE: $VERSION_CODE"
|
|
129
|
+
echo "🔧 프로젝트 타입: ${{ env.PROJECT_TYPE }}"
|
|
130
|
+
|
|
131
|
+
# GitHub outputs 설정
|
|
132
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
133
|
+
echo "version_code=$VERSION_CODE" >> $GITHUB_OUTPUT
|
|
134
|
+
echo "project_type=${{ env.PROJECT_TYPE }}" >> $GITHUB_OUTPUT
|
|
135
|
+
|
|
136
|
+
# 환경변수로도 설정 (스크립트에서 사용)
|
|
137
|
+
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
|
138
|
+
echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
|
|
139
|
+
echo "TODAY=$(date '+%Y-%m-%d')" >> $GITHUB_ENV
|
|
140
|
+
echo "TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
|
|
141
|
+
echo "PROJECT_TYPE=${{ env.PROJECT_TYPE }}" >> $GITHUB_ENV
|
|
142
|
+
|
|
143
|
+
# CHANGELOG.json에서 릴리즈 노트 추출 - changelog_manager.py 사용
|
|
144
|
+
- name: 릴리즈 노트 생성
|
|
145
|
+
id: release_notes
|
|
146
|
+
run: |
|
|
147
|
+
VERSION="${{ steps.current_version.outputs.version }}"
|
|
148
|
+
|
|
149
|
+
if [ -f "CHANGELOG.json" ]; then
|
|
150
|
+
echo "📄 CHANGELOG.json에서 v$VERSION 릴리즈 노트 추출 중..."
|
|
151
|
+
# CHANGELOG.md 생성
|
|
152
|
+
python3 ./.github/scripts/changelog_manager.py generate-md
|
|
153
|
+
|
|
154
|
+
# changelog_manager.py export로 릴리즈 노트 추출
|
|
155
|
+
python3 ./.github/scripts/changelog_manager.py export --version $VERSION --output final_release_notes.txt
|
|
156
|
+
|
|
157
|
+
if [ -s final_release_notes.txt ]; then
|
|
158
|
+
echo "✅ 릴리즈 노트 추출 성공!"
|
|
159
|
+
echo "📋 추출된 릴리즈 노트:"
|
|
160
|
+
echo "----------------------------------------"
|
|
161
|
+
cat final_release_notes.txt
|
|
162
|
+
echo "----------------------------------------"
|
|
163
|
+
echo "RELEASE_NOTES_FOUND=true" >> $GITHUB_ENV
|
|
164
|
+
else
|
|
165
|
+
echo "❌ 릴리즈 노트 추출 실패"
|
|
166
|
+
echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
|
|
167
|
+
echo "v$VERSION 업데이트" > final_release_notes.txt
|
|
168
|
+
fi
|
|
169
|
+
else
|
|
170
|
+
echo "⚠️ CHANGELOG.json 파일이 없습니다. 기본 릴리즈 노트를 사용합니다."
|
|
171
|
+
echo "RELEASE_NOTES_FOUND=false" >> $GITHUB_ENV
|
|
172
|
+
echo "v$VERSION 업데이트" > final_release_notes.txt
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# 릴리즈 노트를 아티팩트로 업로드
|
|
176
|
+
- name: Upload release notes
|
|
177
|
+
uses: actions/upload-artifact@v4
|
|
178
|
+
with:
|
|
179
|
+
name: release-notes
|
|
180
|
+
path: final_release_notes.txt
|
|
181
|
+
retention-days: 1
|
|
182
|
+
|
|
183
|
+
# 프로젝트 파일들을 아티팩트로 업로드
|
|
184
|
+
# .env는 보안상 아티팩트에 포함하지 않고, 각 job에서 secrets로 재생성
|
|
185
|
+
- name: Upload project files
|
|
186
|
+
uses: actions/upload-artifact@v4
|
|
187
|
+
with:
|
|
188
|
+
name: project-files
|
|
189
|
+
path: |
|
|
190
|
+
pubspec.yaml
|
|
191
|
+
lib/
|
|
192
|
+
assets/
|
|
193
|
+
retention-days: 1
|
|
194
|
+
|
|
195
|
+
build-android:
|
|
196
|
+
name: Android AAB 빌드
|
|
197
|
+
runs-on: ubuntu-latest
|
|
198
|
+
needs: prepare-build
|
|
199
|
+
|
|
200
|
+
steps:
|
|
201
|
+
- name: Checkout repository
|
|
202
|
+
uses: actions/checkout@v5
|
|
203
|
+
with:
|
|
204
|
+
ref: main
|
|
205
|
+
fetch-depth: 0
|
|
206
|
+
|
|
207
|
+
- name: Pull latest changes
|
|
208
|
+
run: git pull origin main
|
|
209
|
+
|
|
210
|
+
# 프로젝트 파일들 다운로드
|
|
211
|
+
- name: Download project files
|
|
212
|
+
uses: actions/download-artifact@v4
|
|
213
|
+
with:
|
|
214
|
+
name: project-files
|
|
215
|
+
path: .
|
|
216
|
+
|
|
217
|
+
# .env 파일 생성 (보안을 위해 아티팩트가 아닌 시크릿에서 생성)
|
|
218
|
+
- name: Create .env file
|
|
219
|
+
env:
|
|
220
|
+
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
221
|
+
run: |
|
|
222
|
+
printf '%s\n' "$ENV_CONTENT" > .env
|
|
223
|
+
echo "✅ .env 파일 생성됨 (크기: $(wc -c < .env) bytes)"
|
|
224
|
+
|
|
225
|
+
# Release Keystore 설정
|
|
226
|
+
- name: Setup Release Keystore
|
|
227
|
+
run: |
|
|
228
|
+
mkdir -p android/app/keystore
|
|
229
|
+
echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 -d > android/app/keystore/key.jks
|
|
230
|
+
echo "✅ Release Keystore 생성 완료"
|
|
231
|
+
ls -la android/app/keystore/
|
|
232
|
+
|
|
233
|
+
# key.properties 생성 (Release 서명 정보)
|
|
234
|
+
- name: Create key.properties
|
|
235
|
+
run: |
|
|
236
|
+
cat > android/key.properties << EOF
|
|
237
|
+
storeFile=app/keystore/key.jks
|
|
238
|
+
storePassword=${{ secrets.RELEASE_KEYSTORE_PASSWORD }}
|
|
239
|
+
keyAlias=${{ secrets.RELEASE_KEY_ALIAS }}
|
|
240
|
+
keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }}
|
|
241
|
+
EOF
|
|
242
|
+
echo "✅ key.properties 생성 완료"
|
|
243
|
+
cat android/key.properties
|
|
244
|
+
|
|
245
|
+
# Google-services.json 생성
|
|
246
|
+
- name: Create Google-services.json
|
|
247
|
+
run: |
|
|
248
|
+
cat << 'EOF' > android/app/google-services.json
|
|
249
|
+
${{ secrets.GOOGLE_SERVICES_JSON }}
|
|
250
|
+
EOF
|
|
251
|
+
echo "✅ Google-services.json 생성 완료"
|
|
252
|
+
|
|
253
|
+
- name: Set up Flutter
|
|
254
|
+
uses: subosito/flutter-action@v2
|
|
255
|
+
with:
|
|
256
|
+
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
257
|
+
cache: true
|
|
258
|
+
|
|
259
|
+
- name: Cache Flutter dependencies
|
|
260
|
+
uses: actions/cache@v4
|
|
261
|
+
with:
|
|
262
|
+
path: ~/.pub-cache
|
|
263
|
+
key: ${{ runner.os }}-flutter-pub-${{ hashFiles('**/pubspec.lock') }}
|
|
264
|
+
restore-keys: ${{ runner.os }}-flutter-pub-
|
|
265
|
+
|
|
266
|
+
- name: Install dependencies
|
|
267
|
+
run: flutter pub get
|
|
268
|
+
|
|
269
|
+
- name: Set up Java
|
|
270
|
+
uses: actions/setup-java@v4
|
|
271
|
+
with:
|
|
272
|
+
distribution: "temurin"
|
|
273
|
+
java-version: ${{ env.JAVA_VERSION }}
|
|
274
|
+
|
|
275
|
+
- name: Cache Gradle dependencies
|
|
276
|
+
uses: actions/cache@v4
|
|
277
|
+
with:
|
|
278
|
+
path: |
|
|
279
|
+
~/.gradle/caches
|
|
280
|
+
~/.gradle/wrapper
|
|
281
|
+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle*', '**/gradle-wrapper.properties') }}
|
|
282
|
+
restore-keys: |
|
|
283
|
+
${{ runner.os }}-gradle-
|
|
284
|
+
|
|
285
|
+
# Android build.gradle.kts 수정 (release 서명 설정)
|
|
286
|
+
- name: Configure Android build for release
|
|
287
|
+
run: |
|
|
288
|
+
# build.gradle.kts에 release 서명 설정이 없으면 추가
|
|
289
|
+
if ! grep -q "signingConfigs" android/app/build.gradle.kts; then
|
|
290
|
+
echo "⚠️ build.gradle.kts에 서명 설정 추가 필요"
|
|
291
|
+
# 서명 설정은 이미 되어있다고 가정 (수동으로 미리 설정해야 함)
|
|
292
|
+
fi
|
|
293
|
+
echo "✅ Android 빌드 설정 확인 완료"
|
|
294
|
+
|
|
295
|
+
# pubspec.yaml은 x.y.z 형식 그대로 유지
|
|
296
|
+
# Flutter build 명령어의 --build-name, --build-number 플래그가 pubspec.yaml을 오버라이드함
|
|
297
|
+
|
|
298
|
+
# Flutter build appbundle (AAB 생성)
|
|
299
|
+
- name: Build Android App Bundle (AAB)
|
|
300
|
+
run: |
|
|
301
|
+
VERSION_NAME="${{ needs.prepare-build.outputs.version }}"
|
|
302
|
+
VERSION_CODE="${{ needs.prepare-build.outputs.version_code }}"
|
|
303
|
+
|
|
304
|
+
echo "=========================================="
|
|
305
|
+
echo "🚀 AAB 빌드 시작"
|
|
306
|
+
echo "=========================================="
|
|
307
|
+
echo "🎯 빌드 버전: $VERSION_NAME"
|
|
308
|
+
echo "🎯 빌드 코드: $VERSION_CODE"
|
|
309
|
+
|
|
310
|
+
# 입력 검증
|
|
311
|
+
if [ -z "$VERSION_NAME" ] || [ -z "$VERSION_CODE" ]; then
|
|
312
|
+
echo "❌ VERSION_NAME 또는 VERSION_CODE가 비어있습니다!"
|
|
313
|
+
exit 1
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# Flutter 환경 정보 출력
|
|
317
|
+
echo "🔍 Flutter 환경 정보:"
|
|
318
|
+
flutter --version
|
|
319
|
+
flutter doctor -v | head -20
|
|
320
|
+
|
|
321
|
+
# 빌드 디렉토리 정리
|
|
322
|
+
echo "🧹 이전 빌드 결과물 정리..."
|
|
323
|
+
rm -rf build/app/outputs/bundle/release/
|
|
324
|
+
mkdir -p build/app/outputs/bundle/release/
|
|
325
|
+
|
|
326
|
+
# Flutter clean 및 pub get
|
|
327
|
+
echo "🔄 Flutter clean 및 의존성 재설치..."
|
|
328
|
+
flutter clean
|
|
329
|
+
flutter pub get
|
|
330
|
+
|
|
331
|
+
# local.properties에 버전 정보 추가 (Flutter 플래그가 무시되는 문제 해결)
|
|
332
|
+
echo "🔧 local.properties에 버전 정보 설정..."
|
|
333
|
+
|
|
334
|
+
# 기존 local.properties가 있으면 버전 정보 제거
|
|
335
|
+
if [ -f "android/local.properties" ]; then
|
|
336
|
+
grep -v "flutter.versionName\|flutter.versionCode" android/local.properties > android/local.properties.tmp || true
|
|
337
|
+
mv android/local.properties.tmp android/local.properties
|
|
338
|
+
else
|
|
339
|
+
touch android/local.properties
|
|
340
|
+
fi
|
|
341
|
+
|
|
342
|
+
# 버전 정보 추가
|
|
343
|
+
echo "flutter.versionName=$VERSION_NAME" >> android/local.properties
|
|
344
|
+
echo "flutter.versionCode=$VERSION_CODE" >> android/local.properties
|
|
345
|
+
|
|
346
|
+
echo "✅ local.properties 업데이트 완료"
|
|
347
|
+
echo "📋 버전 정보: VERSION_NAME=$VERSION_NAME, VERSION_CODE=$VERSION_CODE"
|
|
348
|
+
|
|
349
|
+
# Gradle 성능 최적화 설정
|
|
350
|
+
export GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4"
|
|
351
|
+
export JAVA_OPTS="-Xmx4g"
|
|
352
|
+
echo "✅ Gradle 최적화 설정 완료"
|
|
353
|
+
|
|
354
|
+
# Flutter build 명령어에 버전 정보 전달
|
|
355
|
+
# --build-name과 --build-number 플래그가 pubspec.yaml의 version을 오버라이드함
|
|
356
|
+
# pubspec.yaml은 x.y.z 형식 유지, VERSION_CODE는 version.yml에서 자동 관리
|
|
357
|
+
echo "🔨 Flutter build 실행..."
|
|
358
|
+
echo "📋 명령어: flutter build appbundle --release --build-name=$VERSION_NAME --build-number=$VERSION_CODE --verbose"
|
|
359
|
+
echo "⏱️ 빌드 시작 시간: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
360
|
+
|
|
361
|
+
flutter build appbundle \
|
|
362
|
+
--release \
|
|
363
|
+
--build-name="$VERSION_NAME" \
|
|
364
|
+
--build-number="$VERSION_CODE" \
|
|
365
|
+
--verbose
|
|
366
|
+
|
|
367
|
+
BUILD_EXIT_CODE=$?
|
|
368
|
+
|
|
369
|
+
if [ $BUILD_EXIT_CODE -ne 0 ]; then
|
|
370
|
+
echo "❌ Flutter build 실패! Exit code: $BUILD_EXIT_CODE"
|
|
371
|
+
echo "🔍 빌드 디렉토리 상태:"
|
|
372
|
+
find build/ -name "*.aab" -o -name "*.apk" 2>/dev/null || echo "AAB/APK 파일을 찾을 수 없습니다"
|
|
373
|
+
exit 1
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
echo "✅ Flutter build 성공!"
|
|
377
|
+
|
|
378
|
+
# 빌드 결과 확인
|
|
379
|
+
echo "🔍 빌드 결과 확인:"
|
|
380
|
+
ls -lah build/app/outputs/bundle/release/
|
|
381
|
+
|
|
382
|
+
# AAB 파일 존재 확인
|
|
383
|
+
AAB_FILE="build/app/outputs/bundle/release/app-release.aab"
|
|
384
|
+
if [ ! -f "$AAB_FILE" ]; then
|
|
385
|
+
echo "❌ AAB 파일이 생성되지 않았습니다!"
|
|
386
|
+
echo "🔍 전체 빌드 디렉토리 내용:"
|
|
387
|
+
find build/ -type f -name "*.aab" -o -name "*.apk" 2>/dev/null || echo "AAB/APK 파일을 찾을 수 없습니다"
|
|
388
|
+
echo "🔍 outputs 디렉토리 구조:"
|
|
389
|
+
find build/app/outputs/ -type f 2>/dev/null || echo "outputs 디렉토리가 없습니다"
|
|
390
|
+
exit 1
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
echo "✅ AAB 파일 생성 확인"
|
|
394
|
+
echo "📱 AAB 파일 크기: $(du -h "$AAB_FILE" | cut -f1)"
|
|
395
|
+
echo "📋 AAB 파일 정보: $(ls -lah "$AAB_FILE")"
|
|
396
|
+
|
|
397
|
+
# bundletool 다운로드 및 설치
|
|
398
|
+
echo "📦 bundletool 다운로드 중..."
|
|
399
|
+
BUNDLETOOL_VERSION="1.15.6"
|
|
400
|
+
BUNDLETOOL_URL="https://github.com/google/bundletool/releases/download/${BUNDLETOOL_VERSION}/bundletool-all-${BUNDLETOOL_VERSION}.jar"
|
|
401
|
+
|
|
402
|
+
echo "📋 다운로드 URL: $BUNDLETOOL_URL"
|
|
403
|
+
wget -q "$BUNDLETOOL_URL" -O bundletool.jar
|
|
404
|
+
|
|
405
|
+
if [ ! -f "bundletool.jar" ]; then
|
|
406
|
+
echo "❌ bundletool 다운로드 실패"
|
|
407
|
+
echo "🔄 대체 URL로 재시도..."
|
|
408
|
+
wget -q "https://github.com/google/bundletool/releases/latest/download/bundletool-all-1.15.6.jar" -O bundletool.jar
|
|
409
|
+
|
|
410
|
+
if [ ! -f "bundletool.jar" ]; then
|
|
411
|
+
echo "❌ bundletool 다운로드 완전 실패"
|
|
412
|
+
exit 1
|
|
413
|
+
fi
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
echo "✅ bundletool 다운로드 완료"
|
|
417
|
+
echo "📋 bundletool 파일 크기: $(du -h bundletool.jar | cut -f1)"
|
|
418
|
+
|
|
419
|
+
# Java 환경 확인
|
|
420
|
+
echo "🔍 Java 환경 확인:"
|
|
421
|
+
java -version
|
|
422
|
+
|
|
423
|
+
# AAB 파일 내부의 실제 버전 정보 확인
|
|
424
|
+
# Flutter CLI 플래그로 전달한 VERSION_CODE가 제대로 적용되었는지 검증
|
|
425
|
+
echo "=========================================="
|
|
426
|
+
echo "🔍 AAB 파일 내부 버전 정보 검증"
|
|
427
|
+
echo "=========================================="
|
|
428
|
+
|
|
429
|
+
# AndroidManifest.xml에서 버전 정보 추출
|
|
430
|
+
echo "📋 AAB에서 실제 버전 정보 추출 중..."
|
|
431
|
+
echo "📋 실행할 명령어: java -jar bundletool.jar dump manifest --bundle='$AAB_FILE'"
|
|
432
|
+
|
|
433
|
+
MANIFEST_OUTPUT=$(java -jar bundletool.jar dump manifest --bundle="$AAB_FILE" 2>&1)
|
|
434
|
+
MANIFEST_EXIT_CODE=$?
|
|
435
|
+
|
|
436
|
+
echo "📋 bundletool 실행 결과 (Exit code: $MANIFEST_EXIT_CODE):"
|
|
437
|
+
echo "$MANIFEST_OUTPUT"
|
|
438
|
+
|
|
439
|
+
if [ $MANIFEST_EXIT_CODE -eq 0 ]; then
|
|
440
|
+
echo "✅ Manifest 추출 성공"
|
|
441
|
+
|
|
442
|
+
# 실제 버전 코드와 버전 이름 추출
|
|
443
|
+
ACTUAL_VERSION_CODE=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionCode="[0-9]*"' | grep -o '[0-9]*' | head -1)
|
|
444
|
+
ACTUAL_VERSION_NAME=$(echo "$MANIFEST_OUTPUT" | grep -o 'android:versionName="[^"]*"' | sed 's/android:versionName="//;s/"//' | head -1)
|
|
445
|
+
|
|
446
|
+
echo "🎯 버전 정보 비교:"
|
|
447
|
+
echo " 예상 VERSION_CODE: '$VERSION_CODE'"
|
|
448
|
+
echo " 실제 VERSION_CODE: '$ACTUAL_VERSION_CODE'"
|
|
449
|
+
echo " 예상 VERSION_NAME: '$VERSION_NAME'"
|
|
450
|
+
echo " 실제 VERSION_NAME: '$ACTUAL_VERSION_NAME'"
|
|
451
|
+
|
|
452
|
+
# VERSION_CODE 검증 - version.yml에서 관리되는 단순 증가 번호
|
|
453
|
+
if [ -z "$ACTUAL_VERSION_CODE" ]; then
|
|
454
|
+
echo "❌ 치명적 오류: AAB에서 VERSION_CODE를 추출할 수 없습니다!"
|
|
455
|
+
echo "🔍 전체 Manifest 내용:"
|
|
456
|
+
echo "$MANIFEST_OUTPUT"
|
|
457
|
+
exit 1
|
|
458
|
+
elif [ "$ACTUAL_VERSION_CODE" != "$VERSION_CODE" ]; then
|
|
459
|
+
echo "❌ 치명적 오류: AAB의 VERSION_CODE가 예상과 다릅니다!"
|
|
460
|
+
echo " 이는 Google Play에서 '이미 사용된 버전 코드' 오류를 발생시킵니다."
|
|
461
|
+
echo ""
|
|
462
|
+
echo "🔍 디버깅 정보:"
|
|
463
|
+
echo " version.yml의 VERSION_CODE: $VERSION_CODE"
|
|
464
|
+
echo " AAB 파일 내부의 VERSION_CODE: $ACTUAL_VERSION_CODE"
|
|
465
|
+
echo ""
|
|
466
|
+
echo " Flutter build 명령어에 전달된 플래그:"
|
|
467
|
+
echo " --build-name='$VERSION_NAME'"
|
|
468
|
+
echo " --build-number='$VERSION_CODE'"
|
|
469
|
+
echo ""
|
|
470
|
+
echo " 전체 Manifest 내용:"
|
|
471
|
+
echo "$MANIFEST_OUTPUT" | grep -E "versionCode|versionName|package"
|
|
472
|
+
exit 1
|
|
473
|
+
else
|
|
474
|
+
echo "✅ VERSION_CODE 검증 성공: $ACTUAL_VERSION_CODE"
|
|
475
|
+
fi
|
|
476
|
+
|
|
477
|
+
# 버전 이름도 확인 (경고만)
|
|
478
|
+
if [ -z "$ACTUAL_VERSION_NAME" ]; then
|
|
479
|
+
echo "⚠️ 경고: AAB에서 VERSION_NAME을 추출할 수 없습니다"
|
|
480
|
+
elif [ "$ACTUAL_VERSION_NAME" != "$VERSION_NAME" ]; then
|
|
481
|
+
echo "⚠️ 경고: VERSION_NAME이 예상과 다릅니다 (치명적이지 않음)"
|
|
482
|
+
echo " 예상: '$VERSION_NAME', 실제: '$ACTUAL_VERSION_NAME'"
|
|
483
|
+
else
|
|
484
|
+
echo "✅ VERSION_NAME 검증 성공: $ACTUAL_VERSION_NAME"
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
else
|
|
488
|
+
echo "❌ bundletool로 Manifest 추출 실패"
|
|
489
|
+
echo "🔄 대체 방법으로 검증 시도..."
|
|
490
|
+
|
|
491
|
+
# unzip으로 직접 확인 시도
|
|
492
|
+
echo "📋 unzip을 사용한 직접 추출 시도..."
|
|
493
|
+
UNZIP_OUTPUT=$(unzip -p "$AAB_FILE" base/manifest/AndroidManifest.xml 2>/dev/null | strings | grep -E "versionCode|versionName")
|
|
494
|
+
|
|
495
|
+
if [ -n "$UNZIP_OUTPUT" ]; then
|
|
496
|
+
echo "✅ unzip으로 버전 정보 추출 성공:"
|
|
497
|
+
echo "$UNZIP_OUTPUT"
|
|
498
|
+
else
|
|
499
|
+
echo "❌ unzip을 사용한 직접 추출도 실패"
|
|
500
|
+
echo "⚠️ AAB 검증을 건너뛰고 계속 진행합니다."
|
|
501
|
+
fi
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
echo "=========================================="
|
|
505
|
+
echo "✅ AAB 빌드 및 검증 완료"
|
|
506
|
+
echo "🎯 최종 AAB: $AAB_FILE"
|
|
507
|
+
echo "📱 파일 크기: $(du -h "$AAB_FILE" | cut -f1)"
|
|
508
|
+
echo "=========================================="
|
|
509
|
+
|
|
510
|
+
# AAB 파일을 아티팩트로 업로드
|
|
511
|
+
- name: Upload AAB artifact
|
|
512
|
+
uses: actions/upload-artifact@v4
|
|
513
|
+
with:
|
|
514
|
+
name: android-aab
|
|
515
|
+
path: build/app/outputs/bundle/release/app-release.aab
|
|
516
|
+
retention-days: 1
|
|
517
|
+
|
|
518
|
+
deploy-firebase:
|
|
519
|
+
name: Firebase App Distribution 배포
|
|
520
|
+
runs-on: ubuntu-latest
|
|
521
|
+
needs: [prepare-build, build-android]
|
|
522
|
+
|
|
523
|
+
steps:
|
|
524
|
+
- name: Checkout repository
|
|
525
|
+
uses: actions/checkout@v5
|
|
526
|
+
with:
|
|
527
|
+
ref: main
|
|
528
|
+
fetch-depth: 0
|
|
529
|
+
|
|
530
|
+
# AAB 파일 다운로드
|
|
531
|
+
- name: Download AAB artifact
|
|
532
|
+
uses: actions/download-artifact@v4
|
|
533
|
+
with:
|
|
534
|
+
name: android-aab
|
|
535
|
+
path: build/app/outputs/bundle/release/
|
|
536
|
+
|
|
537
|
+
# 릴리즈 노트 다운로드
|
|
538
|
+
- name: Download release notes
|
|
539
|
+
uses: actions/download-artifact@v4
|
|
540
|
+
with:
|
|
541
|
+
name: release-notes
|
|
542
|
+
path: .
|
|
543
|
+
|
|
544
|
+
# Firebase 서비스 계정 설정
|
|
545
|
+
- name: Setup Firebase credentials file
|
|
546
|
+
run: |
|
|
547
|
+
echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON_BASE64 }}" | base64 --decode > firebase-service-account.json
|
|
548
|
+
echo "✅ Firebase 서비스 계정 JSON 파일 생성 완료"
|
|
549
|
+
|
|
550
|
+
# Firebase App Distribution release notes 길이 제한 (안전망)
|
|
551
|
+
- name: Truncate release notes
|
|
552
|
+
run: |
|
|
553
|
+
if [ -f "final_release_notes.txt" ]; then
|
|
554
|
+
# Firebase App Distribution release notes 길이 제한 안전망 (4000자)
|
|
555
|
+
bash ./.github/scripts/truncate_release_notes.sh final_release_notes.txt 4000 char
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
# Firebase App Distribution에 AAB 업로드
|
|
559
|
+
- name: Upload to Firebase App Distribution
|
|
560
|
+
id: firebase_upload
|
|
561
|
+
uses: wzieba/Firebase-Distribution-Github-Action@v1
|
|
562
|
+
with:
|
|
563
|
+
appId: ${{ env.FIREBASE_APP_ID }}
|
|
564
|
+
serviceCredentialsFile: firebase-service-account.json
|
|
565
|
+
groups: ${{ env.FIREBASE_TESTER_GROUP }}
|
|
566
|
+
file: build/app/outputs/bundle/release/app-release.aab
|
|
567
|
+
releaseNotesFile: final_release_notes.txt
|
|
568
|
+
|
|
569
|
+
# Firebase 인증 파일 삭제 (보안)
|
|
570
|
+
- name: Cleanup Firebase credentials
|
|
571
|
+
if: always()
|
|
572
|
+
run: rm -f firebase-service-account.json
|
|
573
|
+
|
|
574
|
+
# 성공 알림
|
|
575
|
+
- name: Notify Firebase Upload Success
|
|
576
|
+
if: success()
|
|
577
|
+
run: |
|
|
578
|
+
echo "✅ Firebase App Distribution 배포 성공!"
|
|
579
|
+
echo "버전: ${{ needs.prepare-build.outputs.version }} (${{ needs.prepare-build.outputs.version_code }})"
|
|
580
|
+
echo "커밋: ${{ github.sha }}"
|
|
581
|
+
echo ""
|
|
582
|
+
echo "📱 테스터 확인 방법:"
|
|
583
|
+
echo "1. Firebase App Tester 앱 실행"
|
|
584
|
+
echo "2. 앱 선택"
|
|
585
|
+
echo "3. 최신 빌드 다운로드"
|
|
586
|
+
|
|
587
|
+
- name: Notify on Failure
|
|
588
|
+
if: failure()
|
|
589
|
+
run: |
|
|
590
|
+
echo "❌ Firebase App Distribution 배포 실패!"
|
|
591
|
+
echo "로그를 확인해주세요."
|