project-auto-wizard 0.10.0 → 0.11.0

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.
Files changed (46) hide show
  1. package/README.md +83 -4
  2. package/package.json +1 -1
  3. package/payload/config/breaking-changes.json +24 -1
  4. package/payload/flutter-app/android/fastlane/Fastfile.playstore +86 -0
  5. package/payload/flutter-app/ios/ExportOptions.plist +31 -0
  6. package/payload/flutter-app/ios/fastlane/Fastfile +117 -0
  7. package/payload/scripts/__pycache__/changelog_manager.cpython-314.pyc +0 -0
  8. package/payload/scripts/__pycache__/issue_helper.cpython-314.pyc +0 -0
  9. package/payload/scripts/__pycache__/version_manager.cpython-314.pyc +0 -0
  10. package/payload/version.yml.template +1 -0
  11. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +48 -20
  12. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +44 -19
  13. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +28 -36
  14. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +32 -45
  15. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +123 -32
  16. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +56 -41
  17. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +61 -40
  18. package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -0
  19. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +47 -0
  20. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +47 -0
  21. package/payload/workflows/react/PROJECT-REACT-CI.yaml +47 -0
  22. package/payload/workflows/spring/nexus/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +1 -0
  23. package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-CI.yml +47 -0
  24. package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +1 -0
  25. package/src/cli/args.js +37 -0
  26. package/src/cli/help.js +4 -0
  27. package/src/commands/doctor.js +55 -2
  28. package/src/commands/dry-run.js +10 -0
  29. package/src/commands/full.js +28 -3
  30. package/src/commands/interactive-flutter.js +95 -0
  31. package/src/commands/interactive.js +51 -5
  32. package/src/commands/status.js +20 -2
  33. package/src/context.js +6 -0
  34. package/src/core/breaking.js +7 -3
  35. package/src/core/copy/flutter-app.js +42 -0
  36. package/src/core/copy/workflows.js +21 -9
  37. package/src/core/detect-fs.js +9 -1
  38. package/src/core/flutter-options.js +118 -0
  39. package/src/core/installed-stores.js +12 -0
  40. package/src/core/version-yml.js +40 -5
  41. package/src/core/wizard-env.js +26 -4
  42. package/src/index.js +32 -1
  43. package/src/ui/env-plan.js +8 -5
  44. package/src/ui/prompts.js +88 -3
  45. package/src/ui/status-cards.js +13 -1
  46. package/src/ui/summary.js +24 -5
@@ -5,17 +5,14 @@
5
5
  #
6
6
  # 이 워크플로우는 Flutter iOS 앱을 빌드하여 TestFlight에 자동 배포합니다.
7
7
  #
8
- # ★ 마법사 우선 아키텍처 ★
9
- # - 빌드에 필요한 설정 파일들은 웹 마법사가 생성합니다
10
- # - 워크플로우는 마법사가 생성한 파일들을 그대로 사용합니다
11
- # - 마법사 경로: .github/util/flutter/ios-testflight-setup-wizard/index.html
12
- # (브라우저에서 열어서 사용)
8
+ # 설정 파일(ios/fastlane/Fastfile, ios/ExportOptions.plist)은 project-auto-wizard가
9
+ # 없을 때만 설치하며, 이미 있으면 덮어쓰지 않습니다.
13
10
  #
14
11
  # 빌드 파이프라인:
15
12
  # 1. flutter build ios --no-codesign (Flutter 빌드)
16
13
  # 2. xcodebuild archive (Xcode 아카이브 생성)
17
14
  # 3. xcodebuild -exportArchive (IPA 생성, ExportOptions.plist 사용)
18
- # 4. fastlane deploy (마법사 생성 Fastfile 사용, DEPLOY_MODE에 따라 TestFlight/심사 제출)
15
+ # 4. fastlane deploy (ios/fastlane/Fastfile 사용, DEPLOY_MODE에 따라 TestFlight/심사 제출)
19
16
  #
20
17
  # ===================================================================
21
18
  # 🔑 필수 GitHub Secrets
@@ -31,6 +28,8 @@
31
28
  # APP_STORE_CONNECT_API_KEY_ID: API Key ID (10자리)
32
29
  # APP_STORE_CONNECT_ISSUER_ID: Issuer ID (UUID 형식)
33
30
  # APP_STORE_CONNECT_API_KEY_BASE64: AuthKey_XXXXXX.p8 파일 (base64 인코딩)
31
+ # IOS_BUNDLE_ID (Secret 우선, 없으면 Variable): 앱 번들 ID —
32
+ # store_prepare/store_submit을 쓰면 필수(비어 있으면 Fastfile이 명확한 오류로 중단)
34
33
  #
35
34
  # 📝 환경 설정 (선택):
36
35
  # ENV_FILE (선택): .env 파일 내용
@@ -40,17 +39,13 @@
40
39
  # 🛠️ 초기 설정 방법
41
40
  # ===================================================================
42
41
  #
43
- # 1. 웹 마법사 실행:
44
- # 브라우저에서 .github/util/flutter/ios-testflight-setup-wizard/index.html 열기
45
- # → 필요한 정보 입력 후 설정 파일 다운로드
42
+ # 1. GitHub Secrets 설정 (위 목록 참고)
46
43
  #
47
- # 2. GitHub Secrets 설정 (위 목록 참고)
48
- #
49
- # 3. 생성된 파일 커밋:
44
+ # 2. ios/ExportOptions.plist의 플레이스홀더(팀 ID·번들 ID·프로비저닝 프로파일 이름)를 채워 커밋:
50
45
  # git add ios/
51
46
  # git commit -m "chore: iOS TestFlight 배포 설정"
52
47
  #
53
- # 4. {{MAIN_BRANCH}} 브랜치로 푸시하여 배포 시작
48
+ # 3. {{MAIN_BRANCH}} 브랜치로 푸시하여 배포 시작
54
49
  #
55
50
  # ===================================================================
56
51
 
@@ -59,6 +54,7 @@ name: PROJECT-iOS-TestFlight-Deploy
59
54
  on:
60
55
  push:
61
56
  branches: ["{{MAIN_BRANCH}}"]
57
+ # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
62
58
  workflow_dispatch:
63
59
  inputs:
64
60
  deploy_mode:
@@ -76,6 +72,8 @@ on:
76
72
  # ============================================
77
73
  env:
78
74
  FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
75
+ # 환경변수 전달 방식 (dart-define | dotenv) — 설치 시 선택값으로 자동 설정
76
+ ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
79
77
  FLUTTER_VERSION: "3.35.5"
80
78
  XCODE_VERSION: "26.0"
81
79
  PROJECT_TYPE: "flutter"
@@ -83,7 +81,7 @@ env:
83
81
  # ============================================
84
82
  # 📝 환경 파일 설정
85
83
  # ============================================
86
- # .env 파일 생성 경로 (프로젝트 루트 기준)
84
+ # dotenv 모드에서 .env 파일을 만들 경로 (Flutter 루트 기준)
87
85
  ENV_FILE_PATH: ".env"
88
86
 
89
87
  # ============================================
@@ -94,7 +92,7 @@ env:
94
92
  # ============================================
95
93
  # 📝 배포 모드 (store_only | store_prepare | store_submit)
96
94
  # ============================================
97
- DEPLOY_MODE: ${{ github.event.inputs.deploy_mode || vars.IOS_DEPLOY_MODE || 'store_only' }}
95
+ DEPLOY_MODE: ${{ github.event.inputs.deploy_mode || vars.IOS_DEPLOY_MODE || 'store_only' }} # @wizard fallback:ios-deploy-mode
98
96
 
99
97
  jobs:
100
98
  prepare-build:
@@ -123,12 +121,19 @@ jobs:
123
121
  - name: Select Xcode version
124
122
  run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
125
123
 
126
- - name: Create .env file
124
+ - name: Prepare env file
125
+ env:
126
+ ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
127
127
  run: |
128
- cat << 'EOF' > ${{ env.ENV_FILE_PATH }}
129
- ${{ secrets.ENV_FILE || secrets.ENV }}
130
- EOF
131
- echo "✅ ${{ env.ENV_FILE_PATH }} file created"
128
+ if [ "$ENV_MODE" = "dotenv" ]; then
129
+ printf '%s\n' "$ENV_CONTENT" > "$ENV_FILE_PATH"
130
+ echo "✅ $ENV_FILE_PATH file created"
131
+ elif [ -n "$ENV_CONTENT" ]; then
132
+ DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
133
+ printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
134
+ echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
135
+ echo "dart-define file prepared"
136
+ fi
132
137
 
133
138
  - name: Create Secrets.xcconfig file
134
139
  run: |
@@ -150,7 +155,7 @@ jobs:
150
155
  uses: actions/cache@v6
151
156
  with:
152
157
  path: ~/.pub-cache
153
- key: ${{ runner.os }}-flutter-pub-${{ hashFiles('**/pubspec.lock') }}
158
+ key: ${{ runner.os }}-flutter-pub-${{ hashFiles(format('{0}/**/pubspec.lock', env.FLUTTER_PROJECT_DIR)) }}
154
159
  restore-keys: ${{ runner.os }}-flutter-pub-
155
160
 
156
161
  - name: Install dependencies
@@ -218,11 +223,10 @@ jobs:
218
223
  with:
219
224
  name: project-files
220
225
  path: |
221
- ${{ env.ENV_FILE_PATH }}
222
- ios/Flutter/Secrets.xcconfig
223
- pubspec.yaml
224
- lib/
225
- assets/
226
+ ${{ env.FLUTTER_PROJECT_DIR }}/ios/Flutter/Secrets.xcconfig
227
+ ${{ env.FLUTTER_PROJECT_DIR }}/pubspec.yaml
228
+ ${{ env.FLUTTER_PROJECT_DIR }}/lib/
229
+ ${{ env.FLUTTER_PROJECT_DIR }}/assets/
226
230
  retention-days: 1
227
231
  if-no-files-found: error
228
232
 
@@ -271,15 +275,20 @@ jobs:
271
275
  uses: actions/download-artifact@v8
272
276
  with:
273
277
  name: project-files
274
- path: .
278
+ path: ${{ env.FLUTTER_PROJECT_DIR }}
275
279
 
276
- - name: Ensure .env file exists
280
+ - name: Prepare env file
281
+ env:
282
+ ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
277
283
  run: |
278
- if [ ! -f "${{ env.ENV_FILE_PATH }}" ]; then
279
- cat << 'EOF' > ${{ env.ENV_FILE_PATH }}
280
- ${{ secrets.ENV_FILE || secrets.ENV }}
281
- EOF
282
- echo "✅ ${{ env.ENV_FILE_PATH }} file created (fallback)"
284
+ if [ "$ENV_MODE" = "dotenv" ]; then
285
+ printf '%s\n' "$ENV_CONTENT" > "$ENV_FILE_PATH"
286
+ echo "✅ $ENV_FILE_PATH file created"
287
+ elif [ -n "$ENV_CONTENT" ]; then
288
+ DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
289
+ printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
290
+ echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
291
+ echo "dart-define file prepared"
283
292
  fi
284
293
 
285
294
  - name: Set up Flutter
@@ -292,7 +301,7 @@ jobs:
292
301
  uses: actions/cache@v6
293
302
  with:
294
303
  path: ~/.pub-cache
295
- key: ${{ runner.os }}-flutter-pub-${{ hashFiles('**/pubspec.lock') }}
304
+ key: ${{ runner.os }}-flutter-pub-${{ hashFiles(format('{0}/**/pubspec.lock', env.FLUTTER_PROJECT_DIR)) }}
296
305
  restore-keys: ${{ runner.os }}-flutter-pub-
297
306
 
298
307
  - name: Install dependencies
@@ -333,6 +342,13 @@ jobs:
333
342
  if [ ! -f "ExportOptions.plist" ]; then
334
343
  exit 1
335
344
  fi
345
+ # 설치기가 만든 템플릿의 플레이스홀더를 채우지 않으면 xcodebuild가 이해하기 어려운 오류로 끝난다
346
+ if grep -Eq '__[A-Z][A-Z0-9_]*__' ExportOptions.plist; then
347
+ echo "❌ ios/ExportOptions.plist에 채워지지 않은 플레이스홀더가 남아 있습니다:"
348
+ grep -En '__[A-Z][A-Z0-9_]*__' ExportOptions.plist
349
+ echo "팀 ID·번들 ID·프로비저닝 프로파일 이름으로 바꿔 커밋한 뒤 다시 실행하세요."
350
+ exit 1
351
+ fi
336
352
 
337
353
  - name: Flutter build (no codesign)
338
354
  env:
@@ -341,7 +357,8 @@ jobs:
341
357
  run: |
342
358
  flutter build ios --release --no-codesign \
343
359
  --build-name="${{ needs.prepare-build.outputs.version }}" \
344
- --build-number="${{ needs.prepare-build.outputs.build_number }}"
360
+ --build-number="${{ needs.prepare-build.outputs.build_number }}" \
361
+ ${DART_DEFINE_FILE:+--dart-define-from-file="$DART_DEFINE_FILE"}
345
362
 
346
363
  - name: Create Archive
347
364
  env:
@@ -376,7 +393,7 @@ jobs:
376
393
  if-no-files-found: error
377
394
 
378
395
  # ============================================
379
- # TestFlight 배포 (마법사 생성 Fastfile 사용)
396
+ # TestFlight 배포 (ios/fastlane/Fastfile 사용)
380
397
  # ============================================
381
398
  deploy-testflight:
382
399
  name: TestFlight 배포
@@ -414,8 +431,7 @@ jobs:
414
431
  run: |
415
432
  if [ ! -f "ios/fastlane/Fastfile" ]; then
416
433
  echo "❌ ios/fastlane/Fastfile이 없습니다!"
417
- echo "웹 마법사를 실행하여 설정 파일을 생성하세요:"
418
- echo " 브라우저에서 .github/util/flutter/ios-testflight-setup-wizard/index.html 열기"
434
+ echo "ios/fastlane/Fastfile을 저장소에 추가(커밋)하세요. 필요한 Secrets는 워크플로우 상단 주석을 참고하세요."
419
435
  exit 1
420
436
  fi
421
437
  echo "✅ Fastfile 확인됨: ios/fastlane/Fastfile"
@@ -423,8 +439,13 @@ jobs:
423
439
  - name: Install Fastlane
424
440
  working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/ios
425
441
  run: |
426
- # multi_json: google-apis transitive 의존성이 선언 누락한 upstream 버그 회피 (gemspec 미선언 → Gem::LoadError)
427
- printf 'source "https://rubygems.org"\ngem "fastlane"\ngem "multi_json"\n' > Gemfile
442
+ # 저장소의 Gemfile에 fastlane이 있으면 그대로 쓴다 (Gemfile.lock 커밋 권장). 없으면 생성한다.
443
+ if [ -f Gemfile ] && grep -Eq "['\"]fastlane['\"]" Gemfile; then
444
+ echo "ℹ️ 저장소의 Gemfile을 사용합니다"
445
+ else
446
+ # multi_json: google-apis transitive 의존성이 선언 누락한 upstream 버그 회피 (gemspec 미선언 → Gem::LoadError)
447
+ printf 'source "https://rubygems.org"\ngem "fastlane"\ngem "multi_json"\n' > Gemfile
448
+ fi
428
449
  bundle install
429
450
  echo "✅ Fastlane installed (Bundler)"
430
451
 
@@ -30,14 +30,42 @@ on:
30
30
  env:
31
31
  # 프로젝트 고유 식별자
32
32
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
33
+ # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
34
+ PROJECT_PATH: "." # @wizard auto:project-path
33
35
 
34
36
  jobs:
37
+ # ===================================================================
38
+ # 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
39
+ # ===================================================================
40
+ changes:
41
+ name: 변경 감지
42
+ runs-on: ubuntu-latest
43
+ permissions:
44
+ contents: read
45
+ pull-requests: read
46
+ outputs:
47
+ project: ${{ steps.filter.outputs.project }}
48
+ steps:
49
+ - name: Checkout repository
50
+ uses: actions/checkout@v7
51
+
52
+ - name: 프로젝트 경로 변경 여부 판별
53
+ id: filter
54
+ if: ${{ github.event_name != 'workflow_dispatch' }}
55
+ uses: dorny/paths-filter@v4
56
+ with:
57
+ filters: |
58
+ project:
59
+ - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
60
+
35
61
  # ===================================================================
36
62
  # 빌드 검증 작업
37
63
  # ===================================================================
38
64
  build-check:
39
65
  name: Go 빌드 검증
40
66
  runs-on: ubuntu-latest
67
+ needs: changes
68
+ if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
41
69
 
42
70
  steps:
43
71
  # 1. 소스코드 체크아웃
@@ -80,3 +108,22 @@ jobs:
80
108
  echo " 🌿 브랜치: ${{ github.ref_name }}"
81
109
  echo " 📝 커밋: ${{ github.sha }}"
82
110
  echo " ⏰ 검증 시간: $(date '+%Y-%m-%d %H:%M:%S')"
111
+
112
+ # ===================================================================
113
+ # CI Gate (required check로 등록할 단일 job)
114
+ # ===================================================================
115
+ ci-gate:
116
+ name: CI Gate
117
+ if: ${{ always() }}
118
+ needs: [changes, build-check]
119
+ runs-on: ubuntu-latest
120
+ steps:
121
+ - name: 결과 집계
122
+ env:
123
+ RESULTS: ${{ toJSON(needs.*.result) }}
124
+ run: |
125
+ echo "needs 결과: $RESULTS"
126
+ if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
127
+ echo "실패하거나 취소된 job이 있습니다."
128
+ exit 1
129
+ fi
@@ -37,6 +37,8 @@ env:
37
37
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
38
38
  NODE_VERSION: "20.15.0"
39
39
  ENV_FILE: ".env"
40
+ # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
41
+ PROJECT_PATH: "." # @wizard auto:project-path
40
42
 
41
43
  permissions:
42
44
  contents: read
@@ -44,9 +46,35 @@ permissions:
44
46
  issues: write
45
47
 
46
48
  jobs:
49
+ # ===================================================================
50
+ # 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
51
+ # ===================================================================
52
+ changes:
53
+ name: 변경 감지
54
+ runs-on: ubuntu-latest
55
+ permissions:
56
+ contents: read
57
+ pull-requests: read
58
+ outputs:
59
+ project: ${{ steps.filter.outputs.project }}
60
+ steps:
61
+ - name: Checkout repository
62
+ uses: actions/checkout@v7
63
+
64
+ - name: 프로젝트 경로 변경 여부 판별
65
+ id: filter
66
+ if: ${{ github.event_name != 'workflow_dispatch' }}
67
+ uses: dorny/paths-filter@v4
68
+ with:
69
+ filters: |
70
+ project:
71
+ - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
72
+
47
73
  build:
48
74
  name: Next.js 애플리케이션 빌드
49
75
  runs-on: ubuntu-latest
76
+ needs: changes
77
+ if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
50
78
 
51
79
  steps:
52
80
  # 1. 소스코드 체크아웃
@@ -184,3 +212,22 @@ jobs:
184
212
  echo " 🕐 시간: $(date '+%Y-%m-%d %H:%M:%S UTC')"
185
213
  echo ""
186
214
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
215
+
216
+ # ===================================================================
217
+ # CI Gate (required check로 등록할 단일 job)
218
+ # ===================================================================
219
+ ci-gate:
220
+ name: CI Gate
221
+ if: ${{ always() }}
222
+ needs: [changes, build]
223
+ runs-on: ubuntu-latest
224
+ steps:
225
+ - name: 결과 집계
226
+ env:
227
+ RESULTS: ${{ toJSON(needs.*.result) }}
228
+ run: |
229
+ echo "needs 결과: $RESULTS"
230
+ if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
231
+ echo "실패하거나 취소된 job이 있습니다."
232
+ exit 1
233
+ fi
@@ -29,14 +29,42 @@ on:
29
29
  env:
30
30
  # 프로젝트 고유 식별자 (컨테이너명, 이미지명, 도메인에 사용)
31
31
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
32
+ # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
33
+ PROJECT_PATH: "." # @wizard auto:project-path
32
34
 
33
35
  jobs:
36
+ # ===================================================================
37
+ # 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
38
+ # ===================================================================
39
+ changes:
40
+ name: 변경 감지
41
+ runs-on: ubuntu-latest
42
+ permissions:
43
+ contents: read
44
+ pull-requests: read
45
+ outputs:
46
+ project: ${{ steps.filter.outputs.project }}
47
+ steps:
48
+ - name: Checkout repository
49
+ uses: actions/checkout@v7
50
+
51
+ - name: 프로젝트 경로 변경 여부 판별
52
+ id: filter
53
+ if: ${{ github.event_name != 'workflow_dispatch' }}
54
+ uses: dorny/paths-filter@v4
55
+ with:
56
+ filters: |
57
+ project:
58
+ - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
59
+
34
60
  # ===================================================================
35
61
  # 빌드 검증 작업
36
62
  # ===================================================================
37
63
  build-check:
38
64
  name: Python FastAPI 빌드 검증
39
65
  runs-on: ubuntu-latest
66
+ needs: changes
67
+ if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
40
68
 
41
69
  steps:
42
70
  # 1. 소스코드 체크아웃
@@ -77,3 +105,22 @@ jobs:
77
105
  echo " 🌿 브랜치: ${{ github.ref_name }}"
78
106
  echo " 📝 커밋: ${{ github.sha }}"
79
107
  echo " ⏰ 검증 시간: $(date '+%Y-%m-%d %H:%M:%S')"
108
+
109
+ # ===================================================================
110
+ # CI Gate (required check로 등록할 단일 job)
111
+ # ===================================================================
112
+ ci-gate:
113
+ name: CI Gate
114
+ if: ${{ always() }}
115
+ needs: [changes, build-check]
116
+ runs-on: ubuntu-latest
117
+ steps:
118
+ - name: 결과 집계
119
+ env:
120
+ RESULTS: ${{ toJSON(needs.*.result) }}
121
+ run: |
122
+ echo "needs 결과: $RESULTS"
123
+ if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
124
+ echo "실패하거나 취소된 job이 있습니다."
125
+ exit 1
126
+ fi
@@ -36,6 +36,8 @@ env:
36
36
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
37
37
  NODE_VERSION: "20.15.0"
38
38
  ENV_FILE: ".env"
39
+ # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
40
+ PROJECT_PATH: "." # @wizard auto:project-path
39
41
 
40
42
  permissions:
41
43
  contents: read
@@ -43,9 +45,35 @@ permissions:
43
45
  issues: write
44
46
 
45
47
  jobs:
48
+ # ===================================================================
49
+ # 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
50
+ # ===================================================================
51
+ changes:
52
+ name: 변경 감지
53
+ runs-on: ubuntu-latest
54
+ permissions:
55
+ contents: read
56
+ pull-requests: read
57
+ outputs:
58
+ project: ${{ steps.filter.outputs.project }}
59
+ steps:
60
+ - name: Checkout repository
61
+ uses: actions/checkout@v7
62
+
63
+ - name: 프로젝트 경로 변경 여부 판별
64
+ id: filter
65
+ if: ${{ github.event_name != 'workflow_dispatch' }}
66
+ uses: dorny/paths-filter@v4
67
+ with:
68
+ filters: |
69
+ project:
70
+ - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
71
+
46
72
  build:
47
73
  name: React/Next.js 애플리케이션 빌드
48
74
  runs-on: ubuntu-latest
75
+ needs: changes
76
+ if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
49
77
 
50
78
  steps:
51
79
  # 1. 소스코드 체크아웃
@@ -193,3 +221,22 @@ jobs:
193
221
  echo "❌ 빌드 중 오류가 발생했습니다."
194
222
  echo "💡 Actions 탭에서 'build-log' 아티팩트를 다운로드하여 전체 로그를 확인하세요."
195
223
  fi
224
+
225
+ # ===================================================================
226
+ # CI Gate (required check로 등록할 단일 job)
227
+ # ===================================================================
228
+ ci-gate:
229
+ name: CI Gate
230
+ if: ${{ always() }}
231
+ needs: [changes, build]
232
+ runs-on: ubuntu-latest
233
+ steps:
234
+ - name: 결과 집계
235
+ env:
236
+ RESULTS: ${{ toJSON(needs.*.result) }}
237
+ run: |
238
+ echo "needs 결과: $RESULTS"
239
+ if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
240
+ echo "실패하거나 취소된 job이 있습니다."
241
+ exit 1
242
+ fi
@@ -35,6 +35,7 @@ on:
35
35
  branches: ["{{MAIN_BRANCH}}"]
36
36
  tags:
37
37
  - 'v*.*.*'
38
+ # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
38
39
  workflow_dispatch:
39
40
 
40
41
  concurrency:
@@ -26,11 +26,39 @@ permissions:
26
26
 
27
27
  env:
28
28
  JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:@jdk
29
+ # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
30
+ PROJECT_PATH: "." # @wizard auto:project-path
29
31
 
30
32
  jobs:
33
+ # ===================================================================
34
+ # 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
35
+ # ===================================================================
36
+ changes:
37
+ name: 변경 감지
38
+ runs-on: ubuntu-latest
39
+ permissions:
40
+ contents: read
41
+ pull-requests: read
42
+ outputs:
43
+ project: ${{ steps.filter.outputs.project }}
44
+ steps:
45
+ - name: Checkout repository
46
+ uses: actions/checkout@v7
47
+
48
+ - name: 프로젝트 경로 변경 여부 판별
49
+ id: filter
50
+ if: ${{ github.event_name != 'workflow_dispatch' }}
51
+ uses: dorny/paths-filter@v4
52
+ with:
53
+ filters: |
54
+ project:
55
+ - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
56
+
31
57
  build-check:
32
58
  name: Build Verification
33
59
  runs-on: ubuntu-latest
60
+ needs: changes
61
+ if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
34
62
 
35
63
  steps:
36
64
  - name: Checkout Repository
@@ -318,3 +346,22 @@ jobs:
318
346
  run: |
319
347
  echo "❌ 빌드가 실패했습니다. 위의 에러 메시지를 확인해주세요."
320
348
  exit 1
349
+
350
+ # ===================================================================
351
+ # CI Gate (required check로 등록할 단일 job)
352
+ # ===================================================================
353
+ ci-gate:
354
+ name: CI Gate
355
+ if: ${{ always() }}
356
+ needs: [changes, build-check]
357
+ runs-on: ubuntu-latest
358
+ steps:
359
+ - name: 결과 집계
360
+ env:
361
+ RESULTS: ${{ toJSON(needs.*.result) }}
362
+ run: |
363
+ echo "needs 결과: $RESULTS"
364
+ if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
365
+ echo "실패하거나 취소된 job이 있습니다."
366
+ exit 1
367
+ fi
@@ -15,6 +15,7 @@ on:
15
15
  branches: ["{{MAIN_BRANCH}}"]
16
16
  tags:
17
17
  - 'v*.*.*'
18
+ # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
18
19
 
19
20
  concurrency:
20
21
  group: nexus-publish-${{ github.ref }}
package/src/cli/args.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // CLI 인자 파싱 (.sh top-level while-case 등가) — template_integrator.sh 842~920.
2
2
  import { VALID_TYPES, VALID_MODES } from "../context.js";
3
3
  import { DEPLOY_STYLES, isDeployStyle, NO_DEPLOY_STYLE } from "../core/deploy-style.js";
4
+ import {
5
+ ENV_MODES, DEPLOY_MODES, STORE_PLATFORMS, NO_STORE, isEnvMode, isDeployMode, parseStoreList,
6
+ } from "../core/flutter-options.js";
4
7
 
5
8
  // argv(process.argv.slice(2)) → 파싱 결과. 오류 시 throw(호출부에서 exit 1).
6
9
  export function parseArgs(argv) {
@@ -16,6 +19,10 @@ export function parseArgs(argv) {
16
19
  mainBranch: "", // 릴리스 브랜치 (--main-branch). 빈값=감지된 default branch
17
20
  developBranch: "", // 개발 브랜치 (--develop-branch). 빈값=develop
18
21
  deployStyle: "", // 서버 배포 방식 (--deploy-style). 빈값=version.yml 저장값 → simple
22
+ flutterEnvMode: "", // Flutter 환경변수 방식 (--flutter-env-mode). 빈값=저장값 → 신규 dart-define/기존 dotenv
23
+ flutterStore: null, // Flutter 스토어 배포 대상 string[] (--flutter-store). null=미지정, none → []
24
+ androidDeployMode: "", // Play Store 배포 모드 (--android-deploy-mode). 빈값=저장값 → store_only
25
+ iosDeployMode: "", // iOS 배포 모드 (--ios-deploy-mode). 빈값=저장값 → store_only
19
26
  force: false,
20
27
  help: false,
21
28
  showVersion: false, // -v/--version → 패키지 버전 출력 (npm 관례)
@@ -84,6 +91,36 @@ export function parseArgs(argv) {
84
91
  }
85
92
  result.deployStyle = v; break;
86
93
  }
94
+ case "--flutter-env-mode": {
95
+ const v = args.shift();
96
+ if (!isEnvMode(v)) {
97
+ throw new CliError(`--flutter-env-mode 값이 올바르지 않습니다: ${v ?? "(없음)"} (${ENV_MODES.join(" | ")})`);
98
+ }
99
+ result.flutterEnvMode = v; break;
100
+ }
101
+ case "--flutter-store": {
102
+ const v = args.shift();
103
+ // 빈 문자열은 parseStoreList가 []로 보지만, 스토어를 안 고르겠다는 뜻은 명시적인 none으로만 받는다.
104
+ const stores = v ? parseStoreList(v) : null;
105
+ if (stores === null) {
106
+ throw new CliError(`--flutter-store 값이 올바르지 않습니다: ${v || "(없음)"} (${[STORE_PLATFORMS.join(","), ...STORE_PLATFORMS, NO_STORE].join(" | ")})`);
107
+ }
108
+ result.flutterStore = stores; break;
109
+ }
110
+ case "--android-deploy-mode": {
111
+ const v = args.shift();
112
+ if (!isDeployMode(v)) {
113
+ throw new CliError(`--android-deploy-mode 값이 올바르지 않습니다: ${v ?? "(없음)"} (${DEPLOY_MODES.join(" | ")})`);
114
+ }
115
+ result.androidDeployMode = v; break;
116
+ }
117
+ case "--ios-deploy-mode": {
118
+ const v = args.shift();
119
+ if (!isDeployMode(v)) {
120
+ throw new CliError(`--ios-deploy-mode 값이 올바르지 않습니다: ${v ?? "(없음)"} (${DEPLOY_MODES.join(" | ")})`);
121
+ }
122
+ result.iosDeployMode = v; break;
123
+ }
87
124
  case "--nexus":
88
125
  if (seenFlags.has("--no-nexus")) throw new CliError("--nexus와 --no-nexus는 동시에 지정할 수 없습니다");
89
126
  seenFlags.add("--nexus"); result.includeNexus = true; break;
package/src/cli/help.js CHANGED
@@ -17,6 +17,10 @@ export const HELP_TEXT = `project-auto-wizard — One command DevOps: GitHub-nat
17
17
  --main-branch B 릴리스 브랜치 (기본: 감지된 default branch)
18
18
  --develop-branch B 개발 브랜치 (기본: develop). 릴리스 브랜치와 같으면 trunk-based 모드
19
19
  --deploy-style STYLE 서버 배포 방식: simple | nginx | traefik | none (기본: simple)
20
+ --flutter-env-mode MODE Flutter 환경변수 방식: dart-define | dotenv (기본: 신규 설치 dart-define, 기존 설치는 저장값·dotenv 유지)
21
+ --flutter-store CSV Flutter 스토어 배포 대상: android,ios | android | ios | none (기본: 둘 다 설치)
22
+ --android-deploy-mode MODE Play Store 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
23
+ --ios-deploy-mode MODE iOS 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
20
24
  --nexus / --no-nexus 라이브러리 publish 워크플로우 포함/제외 (Nexus + GitHub Packages)
21
25
  --secret-backup / --no-secret-backup Secret 백업 워크플로우 포함/제외
22
26
  --semver-auto / --no-semver-auto 커밋 타입 기반 자동 major/minor/patch 승격 (기본: 사용함)