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.
- package/README.md +3 -7
- package/package.json +1 -1
- package/payload/config/breaking-changes.json +1 -1
- package/payload/scripts/__pycache__/changelog_manager.cpython-314.pyc +0 -0
- package/payload/scripts/__pycache__/issue_helper.cpython-314.pyc +0 -0
- package/payload/scripts/__pycache__/version_manager.cpython-314.pyc +0 -0
- package/payload/scripts/changelog_manager.py +1 -1
- package/payload/scripts/version_manager.py +2 -2
- package/payload/version.yml.template +0 -2
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +0 -3
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +1 -4
- package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +3 -6
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +0 -12
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +2 -5
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +3 -7
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +7 -34
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +2 -25
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +2 -20
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +5 -30
- package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +0 -4
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +7 -51
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +5 -29
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +9 -29
- package/payload/workflows/go/PROJECT-GO-CI.yaml +5 -28
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +19 -99
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +18 -89
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +11 -41
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +9 -45
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +1 -27
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +14 -97
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +14 -92
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +11 -40
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +9 -43
- package/payload/workflows/spring/{nexus/PROJECT-SPRING-NEXUS-CI.yml → PROJECT-SPRING-CI.yml} +2 -25
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +19 -63
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +19 -59
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +23 -86
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +20 -80
- package/src/cli/args.js +1 -15
- package/src/cli/help.js +0 -2
- package/src/commands/doctor.js +5 -5
- package/src/commands/dry-run.js +1 -1
- package/src/commands/full.js +9 -10
- package/src/commands/interactive-flutter.js +1 -1
- package/src/commands/interactive.js +25 -46
- package/src/commands/purge.js +2 -2
- package/src/commands/status.js +4 -6
- package/src/commands/uninstall.js +3 -4
- package/src/context.js +4 -6
- package/src/core/assets.js +2 -2
- package/src/core/baseline.js +1 -1
- package/src/core/branches.js +3 -3
- package/src/core/breaking-check.js +1 -1
- package/src/core/breaking.js +1 -1
- package/src/core/copy/flutter-app.js +2 -2
- package/src/core/copy/gitignore.js +8 -8
- package/src/core/copy/workflows.js +24 -69
- package/src/core/deploy-style.js +2 -2
- package/src/core/detect-fs.js +11 -11
- package/src/core/detect.js +7 -7
- package/src/core/flutter-options.js +1 -1
- package/src/core/installed-stores.js +1 -1
- package/src/core/logger.js +1 -1
- package/src/core/paths-resolve.js +1 -1
- package/src/core/removal-plan.js +4 -4
- package/src/core/verify.js +3 -3
- package/src/core/version-yml.js +17 -33
- package/src/core/wizard-env.js +4 -4
- package/src/index.js +12 -14
- package/src/ui/banner.js +2 -2
- package/src/ui/env-plan.js +10 -16
- package/src/ui/prompts.js +9 -14
- package/src/ui/status-cards.js +10 -12
- package/src/ui/summary.js +9 -9
- package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +0 -210
- package/payload/workflows/spring/nexus/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +0 -92
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +0 -70
- 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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
40
|
+
# HEALTHCHECK_PATH 예시:
|
|
47
41
|
# Spring Boot (Actuator): "/actuator/health"
|
|
48
42
|
# 커스텀: "/api/v1/health"
|
|
49
43
|
#
|
|
50
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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(); //
|
|
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 실행에 필수 (모든 확인 생략, 비대화형 기본값 사용)
|
package/src/commands/doctor.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// doctor 명령 — 로컬 환경 진단(읽기 전용, 규칙 기반). gh CLI에 위임해 원격 상태를 점검한다.
|
|
2
2
|
// AI 진단은 포함하지 않는다(스펙 §4에서 검토 후 기각 — 복잡도 대비 이득 낮음).
|
|
3
3
|
//
|
|
4
|
-
// 출력 설계
|
|
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 스토어 배포 파일 점검
|
|
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를 생략했을 때 적용되는 기본값"이지 상한이
|
|
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
|
-
// 파이프라인을 끝까지 이어가므로, 없는 장애를 경고로 띄우지
|
|
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
|
|
179
|
+
// Flutter 스토어 배포 진단 — 선택한 플랫폼의 필수 파일과 ExportOptions.plist 플레이스홀더.
|
|
180
180
|
// 스토어 시크릿 등록 여부는 이번 범위 밖이다. 반환: doctor 결과 행 배열.
|
|
181
181
|
function flutterStoreChecks(cwd) {
|
|
182
182
|
const existing = parseExisting(readFileSync(join(cwd, PATHS.versionFile), "utf8"));
|
package/src/commands/dry-run.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// --dry-run 미리보기 — 실제 파일을 쓰지 않고 무엇이 바뀔지 계산한다.
|
|
2
|
-
// full/uninstall 두 모드 지원 (
|
|
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";
|
package/src/commands/full.js
CHANGED
|
@@ -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)이 이번 실행에서 실제로 생겼을 때만
|
|
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,
|
|
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"이라고 적히면 감지 로그와 같은 종류의 거짓말이
|
|
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의 알려지지 않은 최상위 필드를 재생성 시
|
|
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 렌더링 — 전체 재생성
|
|
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를 전혀 건드리지
|
|
74
|
+
// 충돌 없는 설치(대부분의 최초 설치)는 .gitignore를 전혀 건드리지 않는다.
|
|
76
75
|
const gitignoreUpdated0 = wfCounters.backupAdded > 0 || wfCounters.templateAdded > 0;
|
|
77
76
|
|
|
78
|
-
// 6. 이전 배포 방식 정리
|
|
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 기록
|
|
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. 설치 후 검증
|
|
124
|
+
// 8. 설치 후 검증 — 디스크에 실제로 쓰인 내용을 다시 읽어 확인한다.
|
|
126
125
|
// 미치환 플레이스홀더가 남았는지, 어떤 Secret이 있어야 워크플로우가 도는지.
|
|
127
126
|
// 설치를 실패시키지는 않는다 — 사실을 알려주는 것이 목적이고, 판단은 사용자 몫이다.
|
|
128
127
|
const wfDir = join(targetRoot, PATHS.workflowsDir);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 대화형 마법사의 Flutter 옵션 질문
|
|
1
|
+
// 대화형 마법사의 Flutter 옵션 질문 — 환경변수 방식 · 스토어 배포 대상 · 배포 모드.
|
|
2
2
|
// 상태는 { envMode, stores, androidDeployMode, iosDeployMode } 불변 객체로 주고받는다.
|
|
3
3
|
// envMode·*DeployMode의 ""와 stores의 null = 미결정 (stores의 빈 배열 = "스토어 배포 안 함"으로 이미 결정됨).
|
|
4
4
|
// 이미 결정된 값은 다시 묻지 않는다 (version.yml 저장값 재질문 생략 규약). ESC(취소)는 항상 기본값:
|