project-auto-wizard 0.12.0 → 0.12.1

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 (78) hide show
  1. package/README.md +3 -7
  2. package/package.json +1 -1
  3. package/payload/config/breaking-changes.json +1 -1
  4. package/payload/scripts/__pycache__/changelog_manager.cpython-314.pyc +0 -0
  5. package/payload/scripts/__pycache__/issue_helper.cpython-314.pyc +0 -0
  6. package/payload/scripts/__pycache__/version_manager.cpython-314.pyc +0 -0
  7. package/payload/scripts/changelog_manager.py +1 -1
  8. package/payload/scripts/version_manager.py +2 -2
  9. package/payload/version.yml.template +0 -2
  10. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +0 -3
  11. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +1 -4
  12. package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +3 -6
  13. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +0 -12
  14. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +2 -5
  15. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +3 -7
  16. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +7 -34
  17. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +2 -25
  18. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +2 -20
  19. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +5 -30
  20. package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +0 -4
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +7 -51
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +5 -29
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +9 -29
  24. package/payload/workflows/go/PROJECT-GO-CI.yaml +5 -28
  25. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +19 -99
  26. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +18 -89
  27. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +11 -41
  28. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +9 -45
  29. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +1 -27
  30. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +14 -97
  31. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +14 -92
  32. package/payload/workflows/react/PROJECT-REACT-CI.yaml +11 -40
  33. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +9 -43
  34. package/payload/workflows/spring/{nexus/PROJECT-SPRING-NEXUS-CI.yml → PROJECT-SPRING-CI.yml} +2 -25
  35. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +19 -63
  36. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +19 -59
  37. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +23 -86
  38. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +20 -80
  39. package/src/cli/args.js +1 -15
  40. package/src/cli/help.js +0 -2
  41. package/src/commands/doctor.js +5 -5
  42. package/src/commands/dry-run.js +1 -1
  43. package/src/commands/full.js +9 -10
  44. package/src/commands/interactive-flutter.js +1 -1
  45. package/src/commands/interactive.js +25 -46
  46. package/src/commands/purge.js +2 -2
  47. package/src/commands/status.js +4 -6
  48. package/src/commands/uninstall.js +3 -4
  49. package/src/context.js +4 -6
  50. package/src/core/assets.js +2 -2
  51. package/src/core/baseline.js +1 -1
  52. package/src/core/branches.js +3 -3
  53. package/src/core/breaking-check.js +1 -1
  54. package/src/core/breaking.js +1 -1
  55. package/src/core/copy/flutter-app.js +2 -2
  56. package/src/core/copy/gitignore.js +8 -8
  57. package/src/core/copy/workflows.js +24 -69
  58. package/src/core/deploy-style.js +2 -2
  59. package/src/core/detect-fs.js +11 -11
  60. package/src/core/detect.js +7 -7
  61. package/src/core/flutter-options.js +1 -1
  62. package/src/core/installed-stores.js +1 -1
  63. package/src/core/logger.js +1 -1
  64. package/src/core/paths-resolve.js +1 -1
  65. package/src/core/removal-plan.js +4 -4
  66. package/src/core/verify.js +3 -3
  67. package/src/core/version-yml.js +17 -33
  68. package/src/core/wizard-env.js +4 -4
  69. package/src/index.js +12 -14
  70. package/src/ui/banner.js +2 -2
  71. package/src/ui/env-plan.js +10 -16
  72. package/src/ui/prompts.js +9 -14
  73. package/src/ui/status-cards.js +10 -12
  74. package/src/ui/summary.js +9 -9
  75. package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +0 -210
  76. package/payload/workflows/spring/nexus/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +0 -92
  77. package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +0 -70
  78. package/src/core/options-ask.js +0 -102
@@ -1,14 +1,10 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # ===================================================================
3
2
  # Spring Boot CI/CD 배포 (SSH + Docker)
4
- # ===================================================================
5
3
  #
6
4
  # deploy 브랜치 푸시 시 Docker 이미지를 빌드하고
7
5
  # SSH로 접속 가능한 서버(Synology·AWS EC2·VPS 등)에 자동 배포합니다.
8
6
  #
9
- # ===================================================================
10
- # 🔑 필수 GitHub Secrets
11
- # ===================================================================
7
+ # 필수 GitHub Secrets
12
8
  # APPLICATION_PROD_YML (선택): application-prod.yml 내용
13
9
  # DOCKERHUB_USERNAME: DockerHub 사용자명
14
10
  # DOCKERHUB_TOKEN: DockerHub 액세스 토큰
@@ -16,51 +12,45 @@
16
12
  # SERVER_USER: SSH 사용자명
17
13
  # SERVER_PASSWORD: SSH 비밀번호 (SSH_AUTH_METHOD=password일 때)
18
14
  # SSH_KEY: SSH 개인키 .pem 내용 (SSH_AUTH_METHOD=key일 때, AWS EC2 등)
19
- # ===================================================================
20
15
  #
21
- # 🔧 환경변수 설정 (env 섹션에서 설정)
22
- # ===================================================================
16
+ # 환경변수 설정 (env 섹션에서 설정)
23
17
  #
24
- # 🌐 포트 및 컨테이너:
18
+ # 포트 및 컨테이너:
25
19
  # CONTAINER_INTERNAL_PORT: Spring Boot 내부 포트 (기본: 8080)
26
20
  # DEPLOY_PORT: 배포 포트
27
21
  # CONTAINER_NAME: 컨테이너 이름 (기본: PROJECT_NAME)
28
22
  #
29
- # 📦 볼륨 마운트:
23
+ # 볼륨 마운트:
30
24
  # ENABLE_VOLUME_MOUNT: 볼륨 마운트 활성화 (true/false)
31
25
  # VOLUME_HOST_PATH: 호스트 볼륨 경로
32
26
  # VOLUME_CONTAINER_PATH: 컨테이너 내부 마운트 경로
33
27
  #
34
- # 🔌 SSH 연결:
28
+ # SSH 연결:
35
29
  # SSH_PORT: SSH 포트 (기본: 2022)
36
30
  # SSH_COMMAND_TIMEOUT: SSH 명령 타임아웃 (기본: 600s)
37
31
  # SSH_CONNECTION_TIMEOUT: SSH 연결 타임아웃 (기본: 60s)
38
32
  #
39
- # ⏱️ 헬스체크:
33
+ # 헬스체크:
40
34
  # HEALTHCHECK_WAIT_SECONDS: 초기화 대기 시간 (기본: 10초)
41
35
  # HEALTHCHECK_PATH: HTTP 엔드포인트 경로 (비어있으면 로그만 사용)
42
36
  # HEALTHCHECK_MAX_RETRIES: HTTP 재시도 횟수 (기본: 5회)
43
37
  # HEALTHCHECK_RETRY_INTERVAL: 재시도 간격 (기본: 3초)
44
38
  # HEALTHCHECK_LOG_PATTERN: Fallback 로그 검색 패턴
45
39
  #
46
- # 💡 HEALTHCHECK_PATH 예시:
40
+ # HEALTHCHECK_PATH 예시:
47
41
  # Spring Boot (Actuator): "/actuator/health"
48
42
  # 커스텀: "/api/v1/health"
49
43
  #
50
- # 💡 HEALTHCHECK_LOG_PATTERN 예시:
44
+ # HEALTHCHECK_LOG_PATTERN 예시:
51
45
  # Spring Boot: "Tomcat started on port"
52
- # ===================================================================
53
46
  #
54
- # 🌿 브랜치별 배포:
47
+ # 브랜치별 배포:
55
48
  # - deploy 브랜치: 자동 배포 (DEPLOY_PORT 사용)
56
49
  # - {{MAIN_BRANCH}} 브랜치: 수동 실행만 가능
57
- # ===================================================================
58
50
 
59
51
  name: PROJECT-SPRING-SIMPLE-CICD
60
52
 
61
- # ===================================================================
62
53
  # 트리거 설정
63
- # ===================================================================
64
54
  # deploy 브랜치에 push할 때 자동으로 CI/CD가 실행됩니다.
65
55
  # {{MAIN_BRANCH}} 브랜치는 workflow_dispatch로 수동 실행만 가능합니다.
66
56
  on:
@@ -70,49 +60,46 @@ on:
70
60
  # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
71
61
  workflow_dispatch: # 수동 실행 허용
72
62
 
73
- # ===================================================================
74
- # 환경 변수 설정
75
- # ===================================================================
76
63
  env:
77
- # 🔧 프로젝트 설정 - 실제 프로젝트명으로 변경하세요
64
+ # 프로젝트 설정 - 실제 프로젝트명으로 변경하세요
78
65
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
79
66
 
80
- # ☁️ Spring Boot 설정
67
+ # Spring Boot 설정
81
68
  SPRING_PROFILE: "prod"
82
69
  JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:@jdk
83
70
  GRADLE_OPTS: "-Dspring.profiles.active=prod"
84
71
 
85
- # 📁 경로 설정
72
+ # 경로 설정
86
73
  APPLICATION_YML_DIR: "__APPLICATION_YML_DIR__" # @wizard auto:spring-app-yml-dir
87
74
  DOCKERFILE_PATH: "./Dockerfile"
88
75
 
89
- # 🌐 포트 설정
76
+ # 포트 설정
90
77
  CONTAINER_INTERNAL_PORT: "8080" # Spring Boot 내부 포트 (고정값)
91
78
  DEPLOY_PORT: "__DEPLOY_PORT__" # @wizard ask:8080
92
79
 
93
- # 🐳 컨테이너 이름 설정
80
+ # 컨테이너 이름 설정
94
81
  # 비워두면 PROJECT_NAME을 기본값으로 사용 (예: mapsy-back)
95
82
  # 커스텀 이름을 원하면 직접 입력 (예: "my-custom-container")
96
83
  CONTAINER_NAME: ""
97
84
 
98
- # 📦 볼륨 마운트 설정
85
+ # 볼륨 마운트 설정
99
86
  # true: 볼륨 마운트 활성화 (디렉토리 없으면 자동 생성)
100
87
  # false: 볼륨 마운트 비활성화 (기본값)
101
88
  ENABLE_VOLUME_MOUNT: "false" # @wizard ask:false
102
89
  VOLUME_HOST_PATH: "/volume1/projects/__PROJECT_NAME__" # @wizard ask:/volume1/projects/__PROJECT_NAME__
103
90
  VOLUME_CONTAINER_PATH: "/mnt/__PROJECT_NAME__" # @wizard ask:/mnt/__PROJECT_NAME__
104
91
 
105
- # 🔐 SSH 인증 방식: "password"(Synology·일반 서버) | "key"(AWS EC2·.pem)
92
+ # SSH 인증 방식: "password"(Synology·일반 서버) | "key"(AWS EC2·.pem)
106
93
  # password → SERVER_PASSWORD secret 사용
107
94
  # key → SSH_KEY secret 사용 (.pem 파일 전체 내용을 secret 값으로)
108
95
  SSH_AUTH_METHOD: "password" # @wizard ask:password
109
96
 
110
- # 🔌 SSH 연결 설정
97
+ # SSH 연결 설정
111
98
  SSH_PORT: "__SSH_PORT__" # @wizard ask:2022
112
99
  SSH_COMMAND_TIMEOUT: "600s" # SSH 명령 실행 타임아웃
113
100
  SSH_CONNECTION_TIMEOUT: "60s" # SSH 연결 타임아웃
114
101
 
115
- # ⏱️ 헬스체크 설정
102
+ # 헬스체크 설정
116
103
  HEALTHCHECK_WAIT_SECONDS: "10" # 컨테이너 초기화 대기 시간 (초)
117
104
  HEALTHCHECK_PATH: "/actuator/health" # HTTP 엔드포인트 경로 (비어있으면 로그 패턴만 사용)
118
105
  HEALTHCHECK_MAX_RETRIES: "5" # HTTP 재시도 횟수
@@ -120,19 +107,15 @@ env:
120
107
  HEALTHCHECK_LOG_PATTERN: "Tomcat started on port" # Fallback 로그 검색 패턴
121
108
 
122
109
  jobs:
123
- # ===================================================================
124
110
  # 빌드 작업
125
- # ===================================================================
126
111
  build:
127
112
  name: Spring Boot 애플리케이션 빌드
128
113
  runs-on: ubuntu-latest
129
114
 
130
115
  steps:
131
- # 1. 소스코드 체크아웃
132
116
  - name: 코드 체크아웃
133
117
  uses: actions/checkout@v7
134
118
 
135
- # 2. Java 개발 환경 설정
136
119
  - name: Java 설정
137
120
  uses: actions/setup-java@v5
138
121
  with:
@@ -140,43 +123,34 @@ jobs:
140
123
  distribution: 'temurin'
141
124
  cache: 'gradle'
142
125
 
143
- # 3. Gradle 실행 권한 부여
144
126
  - name: Gradle Wrapper 실행권한 부여
145
127
  run: chmod +x gradlew
146
128
 
147
- # 4. Spring Boot 운영 환경 설정 파일 생성
148
129
  # GitHub Secrets에서 APPLICATION_PROD_YML 값을 읽어와서
149
130
  # 리소스 디렉토리에 파일로 생성
150
131
  - name: application-prod.yml 생성
151
132
  run: |
152
- # 리소스 디렉토리 생성 (환경변수 사용)
153
133
  mkdir -p ${{ env.APPLICATION_YML_DIR }}
154
134
 
155
- # GitHub Secrets의 APPLICATION_PROD_YML 내용을 파일로 저장
156
135
  cat << 'EOF' > ./${{ env.APPLICATION_YML_DIR }}/application-prod.yml
157
136
  ${{ secrets.APPLICATION_PROD_YML }}
158
137
  EOF
159
138
 
160
139
  echo "✅ application-prod.yml 파일 생성 완료 (${{ env.APPLICATION_YML_DIR }})"
161
140
 
162
- # 5. Gradle 빌드 실행
163
141
  # 테스트는 제외하고 운영 프로파일로 빌드
164
142
  - name: Build with Gradle
165
143
  run: ./gradlew clean build -x test ${{ env.GRADLE_OPTS }}
166
144
 
167
- # 6. Docker 빌드 환경 설정
168
145
  - name: Docker 빌드환경 설정
169
146
  uses: docker/setup-buildx-action@v3
170
147
 
171
- # 7. DockerHub 로그인
172
148
  - name: DockerHub 로그인
173
149
  uses: docker/login-action@v3
174
150
  with:
175
151
  username: ${{ secrets.DOCKERHUB_USERNAME }}
176
152
  password: ${{ secrets.DOCKERHUB_TOKEN }}
177
153
 
178
- # 8. Docker 레이어 캐싱 설정
179
- # 빌드 속도 향상을 위한 캐시 설정
180
154
  - name: Cache Docker layers
181
155
  uses: actions/cache@v6
182
156
  with:
@@ -185,7 +159,6 @@ jobs:
185
159
  restore-keys: |
186
160
  ${{ runner.os }}-buildx-
187
161
 
188
- # 9. Docker 이미지 빌드 및 푸시
189
162
  # 브랜치명을 태그로 사용하여 환경별로 이미지 관리
190
163
  - name: Docker 이미지 빌드 및 푸시
191
164
  uses: docker/build-push-action@v5
@@ -197,22 +170,18 @@ jobs:
197
170
  cache-from: type=local,src=/tmp/.buildx-cache
198
171
  cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
199
172
 
200
- # 10. Docker 캐시 정리
201
173
  - name: Move Docker cache
202
174
  run: |
203
175
  rm -rf /tmp/.buildx-cache
204
176
  mv /tmp/.buildx-cache-new /tmp/.buildx-cache
205
177
 
206
- # ===================================================================
207
178
  # 배포 작업
208
- # ===================================================================
209
179
  deploy:
210
180
  name: 원격 서버 배포
211
181
  needs: build
212
182
  runs-on: ubuntu-latest
213
183
 
214
184
  steps:
215
- # SSH를 통한 원격 서버 배포 실행
216
185
  - name: Deploy
217
186
  uses: appleboy/ssh-action@v1.0.3
218
187
  env:
@@ -227,14 +196,12 @@ jobs:
227
196
  script: |
228
197
  set -e
229
198
 
230
- # ============================================================
231
199
  # 배포 환경 변수 설정
232
- # ============================================================
233
200
  echo "🔧 환경변수 설정.."
234
201
  export PATH=$PATH:/usr/local/bin
235
202
  export PW=${{ secrets.SERVER_PASSWORD }}
236
203
 
237
- # 🔐 SSH 인증 방식에 따른 sudo 추상화
204
+ # SSH 인증 방식에 따른 sudo 추상화
238
205
  # password 모드: echo $PW | sudo -S (Synology 등 sudo 비밀번호 필요 서버)
239
206
  # key 모드: sudo 직접 (AWS EC2 등 passwordless sudo 서버)
240
207
  SSH_AUTH_METHOD="${SSH_AUTH_METHOD:-password}"
@@ -245,15 +212,11 @@ jobs:
245
212
  fi
246
213
  echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
247
214
 
248
- # GitHub에서 전달받은 브랜치명
249
215
  BRANCH=${{ github.ref_name }}
250
216
 
251
- # 프로젝트 설정
252
217
  PROJECT_NAME="${{ env.PROJECT_NAME }}"
253
218
 
254
- # ============================================================
255
219
  # 포트 및 컨테이너명 설정
256
- # ============================================================
257
220
  PORT=${{ env.DEPLOY_PORT }}
258
221
 
259
222
  # 컨테이너 이름 설정 (환경변수가 비어있으면 PROJECT_NAME을 기본값으로 사용)
@@ -267,7 +230,6 @@ jobs:
267
230
 
268
231
  echo "🚀 배포 환경으로 배포합니다 (브랜치: $BRANCH)"
269
232
 
270
- # 설정 정보 출력
271
233
  echo "📋 배포 설정 정보:"
272
234
  echo " - 브랜치: $BRANCH"
273
235
  echo " - 프로젝트: $PROJECT_NAME"
@@ -275,18 +237,13 @@ jobs:
275
237
  echo " - 포트: $PORT"
276
238
  echo " - Docker 이미지: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
277
239
 
278
- # ============================================================
279
240
  # Docker 이미지 풀 (Pull)
280
- # ============================================================
281
241
  echo "⬇️ Docker 이미지 풀: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
282
242
  SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
283
243
 
284
- # ============================================================
285
244
  # 기존 컨테이너 정리
286
- # ============================================================
287
245
  echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
288
246
 
289
- # 동일한 이름의 컨테이너가 존재하는지 확인
290
247
  if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
291
248
  echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
292
249
  SUDO docker rm -f $CONTAINER_NAME
@@ -295,15 +252,11 @@ jobs:
295
252
  echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
296
253
  fi
297
254
 
298
- # ============================================================
299
255
  # 새 컨테이너 실행
300
- # ============================================================
301
256
  echo "🚀 새로운 컨테이너 $CONTAINER_NAME 실행 중..."
302
257
 
303
- # 볼륨 마운트 옵션 설정
304
258
  VOLUME_MOUNT_OPTION=""
305
259
  if [ "${{ env.ENABLE_VOLUME_MOUNT }}" == "true" ]; then
306
- # 디렉토리가 없으면 생성
307
260
  if [ ! -d "${{ env.VOLUME_HOST_PATH }}" ]; then
308
261
  echo "📁 볼륨 마운트 디렉토리 생성: ${{ env.VOLUME_HOST_PATH }}"
309
262
  SUDO mkdir -p "${{ env.VOLUME_HOST_PATH }}"
@@ -314,11 +267,6 @@ jobs:
314
267
  echo "ℹ️ 볼륨 마운트 비활성화됨"
315
268
  fi
316
269
 
317
- # Docker 컨테이너 실행
318
- # - 포트 매핑: ${PORT}:${{ env.CONTAINER_INTERNAL_PORT }} (외부:내부)
319
- # - 시간대: Asia/Seoul
320
- # - Spring 프로파일: ${{ env.SPRING_PROFILE }}
321
- # - 볼륨 마운트: ENABLE_VOLUME_MOUNT=true일 때만 활성화
322
270
  SUDO docker run -d \
323
271
  -p ${PORT}:${{ env.CONTAINER_INTERNAL_PORT }} \
324
272
  --name $CONTAINER_NAME \
@@ -328,9 +276,7 @@ jobs:
328
276
  $VOLUME_MOUNT_OPTION \
329
277
  ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
330
278
 
331
- # ============================================================
332
279
  # 컨테이너 헬스체크
333
- # ============================================================
334
280
  echo "⏳ 컨테이너 초기화 대기 중... (${{ env.HEALTHCHECK_WAIT_SECONDS }}초)"
335
281
  sleep ${{ env.HEALTHCHECK_WAIT_SECONDS }}
336
282
 
@@ -398,14 +344,11 @@ jobs:
398
344
  fi
399
345
  fi
400
346
 
401
- # 최종 성공 메시지
402
347
  if [ "$HEALTHCHECK_SUCCESS" = "true" ]; then
403
348
  echo "✅ 헬스체크 완료: 컨테이너 $CONTAINER_NAME 이(가) 정상적으로 실행 중입니다"
404
349
  fi
405
350
 
406
- # ============================================================
407
351
  # 배포 완료 확인
408
- # ============================================================
409
352
  echo "✅ 배포가 성공적으로 완료되었습니다!"
410
353
  echo ""
411
354
  echo "📋 배포 결과 요약:"
@@ -417,10 +360,7 @@ jobs:
417
360
  echo ""
418
361
  echo "🔗 접속 URL: http://${{ secrets.SERVER_HOST }}:${PORT}"
419
362
 
420
- # ===================================================================
421
- # 📝 사용 방법
422
- # ===================================================================
363
+ # 사용 방법
423
364
  # 1. GitHub Secrets 설정 (DOCKERHUB_*, SERVER_*)
424
365
  # 2. env 섹션에서 PROJECT_NAME, DEPLOY_PORT 설정
425
366
  # 3. deploy 브랜치에 push → 자동 CI/CD 실행
426
- # ===================================================================
package/src/cli/args.js CHANGED
@@ -12,8 +12,6 @@ export function parseArgs(argv) {
12
12
  version: "", // 통합 대상 프로젝트의 초기 버전 (--project-version)
13
13
  types: [],
14
14
  primaryType: "",
15
- includeNexus: null, // null=미설정
16
- includeSecretBackup: null,
17
15
  includeSemverAuto: null, // --semver-auto / --no-semver-auto (기본 true — 미지정 시 다운스트림에서 해석)
18
16
  includeCopilotAi: null, // --copilot / --no-copilot (기본 false — AI Credits를 소비하는 opt-in)
19
17
  pathsCsv: "", // "flutter=app,react=client" 원문 (정규화는 resolve 단계)
@@ -42,7 +40,7 @@ export function parseArgs(argv) {
42
40
  keepScripts: false,
43
41
  };
44
42
  const args = [...argv];
45
- const seenFlags = new Set(); // L7: --nexus류 상호 모순 플래그 검증용
43
+ const seenFlags = new Set(); // --semver-auto/--copilot류 상호 모순 플래그 검증용
46
44
  while (args.length > 0) {
47
45
  const a = args.shift();
48
46
  switch (a) {
@@ -122,18 +120,6 @@ export function parseArgs(argv) {
122
120
  }
123
121
  result.iosDeployMode = v; break;
124
122
  }
125
- case "--nexus":
126
- if (seenFlags.has("--no-nexus")) throw new CliError("--nexus와 --no-nexus는 동시에 지정할 수 없습니다");
127
- seenFlags.add("--nexus"); result.includeNexus = true; break;
128
- case "--no-nexus":
129
- if (seenFlags.has("--nexus")) throw new CliError("--nexus와 --no-nexus는 동시에 지정할 수 없습니다");
130
- seenFlags.add("--no-nexus"); result.includeNexus = false; break;
131
- case "--secret-backup":
132
- if (seenFlags.has("--no-secret-backup")) throw new CliError("--secret-backup과 --no-secret-backup은 동시에 지정할 수 없습니다");
133
- seenFlags.add("--secret-backup"); result.includeSecretBackup = true; break;
134
- case "--no-secret-backup":
135
- if (seenFlags.has("--secret-backup")) throw new CliError("--secret-backup과 --no-secret-backup은 동시에 지정할 수 없습니다");
136
- seenFlags.add("--no-secret-backup"); result.includeSecretBackup = false; break;
137
123
  case "--semver-auto":
138
124
  if (seenFlags.has("--no-semver-auto")) throw new CliError("--semver-auto와 --no-semver-auto는 동시에 지정할 수 없습니다");
139
125
  seenFlags.add("--semver-auto"); result.includeSemverAuto = true; break;
package/src/cli/help.js CHANGED
@@ -21,8 +21,6 @@ export const HELP_TEXT = `project-auto-wizard — One command DevOps: GitHub-nat
21
21
  --flutter-store CSV Flutter 스토어 배포 대상: android,ios | android | ios | none (기본: 둘 다 설치)
22
22
  --android-deploy-mode MODE Play Store 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
23
23
  --ios-deploy-mode MODE iOS 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
24
- --nexus / --no-nexus 라이브러리 publish 워크플로우 포함/제외 (Nexus + GitHub Packages)
25
- --secret-backup / --no-secret-backup Secret 백업 워크플로우 포함/제외
26
24
  --semver-auto / --no-semver-auto 커밋 타입 기반 자동 major/minor/patch 승격 (기본: 사용함)
27
25
  --copilot / --no-copilot Copilot으로 AI 요약 생성 (기본: 사용 안 함, GitHub Copilot AI Credits 소비)
28
26
  --force full 실행에 필수 (모든 확인 생략, 비대화형 기본값 사용)
@@ -1,7 +1,7 @@
1
1
  // doctor 명령 — 로컬 환경 진단(읽기 전용, 규칙 기반). gh CLI에 위임해 원격 상태를 점검한다.
2
2
  // AI 진단은 포함하지 않는다(스펙 §4에서 검토 후 기각 — 복잡도 대비 이득 낮음).
3
3
  //
4
- // 출력 설계(이슈 #29) — `flutter doctor` 패턴을 차용한다.
4
+ // 출력 설계 — `flutter doctor` 패턴을 차용한다.
5
5
  // ① 항목 라벨에 purpose("무엇을 위한 설정인지")를 병기한다. `WORKFLOW_PAT`만 보고는 그게
6
6
  // 자기 릴리스 흐름의 무엇을 담당하는지 알 수 없다 — flutter의
7
7
  // `Android toolchain - develop for Android devices`와 같은 이유다.
@@ -44,7 +44,7 @@ export function runDoctor(cwd = process.cwd(), { exec = defaultExec } = {}) {
44
44
  note: ["이 폴더엔 아직 설치되지 않았습니다 — 지금 설치하면 됩니다."],
45
45
  });
46
46
 
47
- // Flutter 스토어 배포 파일 점검 (이슈 #131) — 로컬 파일만 보므로 gh 조회 결과와 무관하게 수행한다.
47
+ // Flutter 스토어 배포 파일 점검 — 로컬 파일만 보므로 gh 조회 결과와 무관하게 수행한다.
48
48
  if (installed) for (const item of flutterStoreChecks(cwd)) add(item);
49
49
 
50
50
  const ghVersion = exec("gh", ["--version"]);
@@ -91,7 +91,7 @@ export function runDoctor(cwd = process.cwd(), { exec = defaultExec } = {}) {
91
91
 
92
92
  const perm = exec("gh", ["api", `repos/${owner}/${repo}/actions/permissions/workflow`, "--jq", ".default_workflow_permissions"]);
93
93
  const permValue = (perm.stdout || "").trim();
94
- // 이 값은 "워크플로우가 permissions를 생략했을 때 적용되는 기본값"이지 상한이 아니다(#34).
94
+ // 이 값은 "워크플로우가 permissions를 생략했을 때 적용되는 기본값"이지 상한이 아니다.
95
95
  // 마법사가 설치하는 워크플로우는 전부 자체 permissions를 선언하므로(회귀 가드:
96
96
  // tests/node/payload-workflow-permissions.test.js) read여도 정상 동작한다 — 이 레포 자체가
97
97
  // read인데 VERSION-CONTROL이 버전 커밋 push에 성공하는 것이 그 증거다.
@@ -126,7 +126,7 @@ export function runDoctor(cwd = process.cwd(), { exec = defaultExec } = {}) {
126
126
  : {
127
127
  // 조치가 필요 없으므로 WARN이 아니라 INFO다 — 위 Workflow permissions 항목과 동일 이유:
128
128
  // 폴백(wait-for-merge-and-trigger-release / Trigger NPM-PUBLISH)이 GITHUB_TOKEN만으로
129
- // 파이프라인을 끝까지 이어가므로, 없는 장애를 경고로 띄우지 않는다(이슈 #105).
129
+ // 파이프라인을 끝까지 이어가므로, 없는 장애를 경고로 띄우지 않는다.
130
130
  name: "WORKFLOW_PAT secret", label: "WORKFLOW_PAT", purpose: "자동 태그·Release 발행", status: "INFO",
131
131
  note: [
132
132
  "secret이 없어도 폴백이 자동으로 이어받아 태그·Release까지 진행됩니다 — 실제 병합 후 최대 ~20초 정도 더 걸릴 뿐입니다.",
@@ -176,7 +176,7 @@ const PLATFORM_ROW_NAME = { android: "Flutter Android 배포 파일", ios: "Flut
176
176
  const PLACEHOLDER_RE = /__[A-Z][A-Z0-9_]*__/g; // 감지 규칙은 ExportOptions.plist 템플릿·IOS-TESTFLIGHT 검증과 동일
177
177
  const EXPORT_OPTIONS_REL = STORE_APP_FILES.ios.find((rel) => rel.endsWith("ExportOptions.plist"));
178
178
 
179
- // Flutter 스토어 배포 진단 — 선택한 플랫폼의 필수 파일과 ExportOptions.plist 플레이스홀더 (이슈 #131).
179
+ // Flutter 스토어 배포 진단 — 선택한 플랫폼의 필수 파일과 ExportOptions.plist 플레이스홀더.
180
180
  // 스토어 시크릿 등록 여부는 이번 범위 밖이다. 반환: doctor 결과 행 배열.
181
181
  function flutterStoreChecks(cwd) {
182
182
  const existing = parseExisting(readFileSync(join(cwd, PATHS.versionFile), "utf8"));
@@ -1,5 +1,5 @@
1
1
  // --dry-run 미리보기 — 실제 파일을 쓰지 않고 무엇이 바뀔지 계산한다.
2
- // full/uninstall 두 모드 지원 (issue #70 — 부분 설치·되돌리기 모드 제거).
2
+ // full/uninstall 두 모드 지원 (부분 설치·되돌리기 모드 제거).
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { PATHS } from "../core/paths.js";
@@ -1,6 +1,6 @@
1
1
  // full 모드 오케스트레이터 (.sh execute_integration full case 등가).
2
2
  // 복사 순서: workflows(+env 치환) → flutter 앱 파일 → version.yml → readme → scripts → gitignore(조건부)
3
- // gitignore는 충돌 백업 부산물(.bak/.template.yaml)이 이번 실행에서 실제로 생겼을 때만 갱신한다 — issue #7.
3
+ // gitignore는 충돌 백업 부산물(.bak/.template.yaml)이 이번 실행에서 실제로 생겼을 때만 갱신한다.
4
4
  // (원본의 util/issue/discussion/setup-guide/config 설치는 project-auto-wizard 스코프에서 제외 — DESIGN-SPEC §2)
5
5
  import { join } from "node:path";
6
6
  import { existsSync, readFileSync, readdirSync } from "node:fs";
@@ -20,18 +20,17 @@ import { cleanupOtherDeployWorkflows, DEFAULT_DEPLOY_STYLE } from "../core/deplo
20
20
  import { cleanupDeselectedStoreWorkflows } from "../core/flutter-options.js";
21
21
  import { log, maskValue } from "../core/logger.js";
22
22
 
23
- // context: { version, types, paths:Map, branch, versionCode, includeNexus, includeSecretBackup,
23
+ // context: { version, types, paths:Map, branch, versionCode,
24
24
  // force, repoName, resolvers, now, today }
25
25
  // payloadRoot: 패키지 payload/ 루트. targetRoot: 통합 대상.
26
26
  export function runFull(context, payloadRoot, targetRoot = ".", hooks = {}) {
27
27
  const { version, types = [], paths = new Map(), branch = "main", versionCode = 1,
28
28
  force = true, now, today, templateVersion = "unknown",
29
- includeNexus = false, includeSecretBackup = false,
30
29
  includeSemverAuto } = context;
31
30
 
32
31
  // project_paths 마커 계산 (.sh existing_marker_in_dir 등가).
33
32
  // 대표 마커명이 아니라 그 폴더에 실제로 있는 파일을 쓴다 — build.gradle.kts만 있는 레포의
34
- // version.yml에 "# build.gradle"이라고 적히면 감지 로그와 같은 종류의 거짓말이 된다 (이슈 #77).
33
+ // version.yml에 "# build.gradle"이라고 적히면 감지 로그와 같은 종류의 거짓말이 된다.
35
34
  const pathMarkers = new Map();
36
35
  for (const [t, p] of paths) {
37
36
  const marker = existingMarkerInDir(t, join(targetRoot, p || "."));
@@ -55,11 +54,11 @@ export function runFull(context, payloadRoot, targetRoot = ".", hooks = {}) {
55
54
  for (const f of flutterApp.created) log.info("flutter-app", "create", f);
56
55
  for (const f of flutterApp.kept) log.info("flutter-app", "keep", `${f} (기존 파일 유지)`);
57
56
 
58
- // 기존 version.yml의 알려지지 않은 최상위 필드를 재생성 시 보존한다 (issue #20 M8).
57
+ // 기존 version.yml의 알려지지 않은 최상위 필드를 재생성 시 보존한다.
59
58
  const vyPath = join(targetRoot, PATHS.versionFile);
60
59
  const extraTopLevel = existsSync(vyPath) ? parseExisting(readFileSync(vyPath, "utf8")).extraTopLevel : [];
61
60
 
62
- // 2. version.yml 생성 (payload/version.yml.template 렌더링 — 전체 재생성 전략 D4)
61
+ // 2. version.yml 생성 (payload/version.yml.template 렌더링 — 전체 재생성)
63
62
  writeText(join(targetRoot, PATHS.versionFile),
64
63
  renderVersionYml(context, readVersionYmlTemplate(payloadRoot), { pathMarkers, deployValues, extraTopLevel }));
65
64
 
@@ -72,10 +71,10 @@ export function runFull(context, payloadRoot, targetRoot = ".", hooks = {}) {
72
71
  copyScripts(payloadRoot, targetRoot);
73
72
 
74
73
  // 5. gitignore — 워크플로우 충돌 처리가 .bak나 .template.yaml을 실제로 만든 경우에만 갱신한다.
75
- // 충돌 없는 설치(대부분의 최초 설치)는 .gitignore를 전혀 건드리지 않는다 — issue #7.
74
+ // 충돌 없는 설치(대부분의 최초 설치)는 .gitignore를 전혀 건드리지 않는다.
76
75
  const gitignoreUpdated0 = wfCounters.backupAdded > 0 || wfCounters.templateAdded > 0;
77
76
 
78
- // 6. 이전 배포 방식 정리 (이슈 #80) — 방식을 바꿔 재설치하면 이전 CD가 남아 배포가 두 번 돈다.
77
+ // 6. 이전 배포 방식 정리 — 방식을 바꿔 재설치하면 이전 CD가 남아 배포가 두 번 돈다.
79
78
  // 옛 baseline이 살아 있는 지금이 "사용자가 손댔는가"를 판정할 수 있는 유일한 시점이다.
80
79
  const previousBaseline = readBaseline(targetRoot);
81
80
  const cleanup = cleanupOtherDeployWorkflows(
@@ -108,7 +107,7 @@ export function runFull(context, payloadRoot, targetRoot = ".", hooks = {}) {
108
107
  const gitignoreUpdated = gitignoreUpdated0 || cleanup.backedUp.length > 0 || storeCleanup.backedUp.length > 0;
109
108
  if (gitignoreUpdated) ensureGitignore(targetRoot);
110
109
 
111
- // 7. baseline 기록 (issue #69) — 다음 업데이트에서 "누가 바꿨는지"를 가를 기준점.
110
+ // 7. baseline 기록 — 다음 업데이트에서 "누가 바꿨는지"를 가를 기준점.
112
111
  // env 치환까지 전부 끝난 뒤에 해시해야 디스크 내용이 최종형이다. 그래서 copyWorkflows 안이
113
112
  // 아니라 여기서 기록한다.
114
113
  // 기존 baseline은 병합 대상 — 이번에 건드리지 않은 파일의 기준점을 잃지 않는다.
@@ -122,7 +121,7 @@ export function runFull(context, payloadRoot, targetRoot = ".", hooks = {}) {
122
121
  previous: previousBaseline,
123
122
  });
124
123
 
125
- // 8. 설치 후 검증 (이슈 #81, #80) — 디스크에 실제로 쓰인 내용을 다시 읽어 확인한다.
124
+ // 8. 설치 후 검증 — 디스크에 실제로 쓰인 내용을 다시 읽어 확인한다.
126
125
  // 미치환 플레이스홀더가 남았는지, 어떤 Secret이 있어야 워크플로우가 도는지.
127
126
  // 설치를 실패시키지는 않는다 — 사실을 알려주는 것이 목적이고, 판단은 사용자 몫이다.
128
127
  const wfDir = join(targetRoot, PATHS.workflowsDir);
@@ -1,4 +1,4 @@
1
- // 대화형 마법사의 Flutter 옵션 질문 (이슈 #131) — 환경변수 방식 · 스토어 배포 대상 · 배포 모드.
1
+ // 대화형 마법사의 Flutter 옵션 질문 — 환경변수 방식 · 스토어 배포 대상 · 배포 모드.
2
2
  // 상태는 { envMode, stores, androidDeployMode, iosDeployMode } 불변 객체로 주고받는다.
3
3
  // envMode·*DeployMode의 ""와 stores의 null = 미결정 (stores의 빈 배열 = "스토어 배포 안 함"으로 이미 결정됨).
4
4
  // 이미 결정된 값은 다시 묻지 않는다 (version.yml 저장값 재질문 생략 규약). ESC(취소)는 항상 기본값: