project-auto-wizard 0.12.2 → 0.13.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.ja.md +165 -0
- package/README.ko.md +165 -0
- package/README.md +107 -286
- package/README.zh-CN.md +165 -0
- package/bin/project-auto-wizard.js +1 -2
- package/package.json +9 -3
- package/payload/config/breaking-changes.json +24 -0
- package/payload/config/wizard-prompts.yml +45 -0
- package/payload/scripts/changelog_manager.py +141 -46
- package/payload/scripts/issue_helper.py +34 -5
- package/payload/scripts/version_manager.py +482 -107
- package/payload/version.yml.template +5 -2
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +39 -9
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +165 -38
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +14 -5
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +220 -6
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +89 -3
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +78 -16
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +72 -16
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +62 -20
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +51 -13
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +75 -11
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +52 -3
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +60 -11
- package/payload/workflows/go/PROJECT-GO-CI.yaml +10 -1
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +148 -28
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +45 -4
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +25 -3
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +83 -9
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +70 -6
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +148 -28
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +45 -4
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +25 -3
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +84 -10
- package/payload/workflows/spring/PROJECT-SPRING-CI.yml +13 -3
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +47 -5
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +47 -5
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +153 -30
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +47 -5
- package/src/cli/args.js +33 -24
- package/src/cli/help.js +16 -4
- package/src/commands/doctor.js +26 -60
- package/src/commands/dry-run.js +59 -5
- package/src/commands/full.js +135 -55
- package/src/commands/install-settings.js +51 -0
- package/src/commands/interactive-flutter.js +1 -1
- package/src/commands/interactive.js +135 -69
- package/src/commands/purge.js +50 -21
- package/src/commands/status.js +18 -12
- package/src/commands/uninstall.js +22 -22
- package/src/context.js +5 -5
- package/src/core/baseline.js +20 -5
- package/src/core/branches.js +19 -1
- package/src/core/branding.js +1 -1
- package/src/core/breaking-check.js +14 -19
- package/src/core/breaking.js +7 -3
- package/src/core/copy/app-files.js +28 -0
- package/src/core/copy/gitignore.js +20 -12
- package/src/core/copy/readme.js +24 -5
- package/src/core/copy/simple.js +52 -13
- package/src/core/copy/workflows.js +133 -111
- package/src/core/deploy-style.js +83 -11
- package/src/core/detect-fs.js +127 -24
- package/src/core/detect.js +177 -47
- package/src/core/errors.js +3 -0
- package/src/core/flutter-doctor.js +49 -0
- package/src/core/flutter-hooks.js +29 -0
- package/src/core/flutter-options.js +4 -3
- package/src/core/fsutil.js +23 -6
- package/src/core/logger.js +55 -19
- package/src/core/paths-resolve.js +50 -47
- package/src/core/paths.js +26 -1
- package/src/core/release-options.js +23 -0
- package/src/core/removal-exec.js +67 -0
- package/src/core/removal-plan.js +75 -19
- package/src/core/types.js +136 -0
- package/src/core/verify.js +85 -19
- package/src/core/version-yml.js +42 -8
- package/src/core/wizard-env.js +21 -14
- package/src/core/wizard-labels.js +34 -25
- package/src/index.js +128 -60
- package/src/ui/ansi.js +3 -1
- package/src/ui/banner.js +12 -8
- package/src/ui/env-plan.js +68 -44
- package/src/ui/prompts.js +22 -12
- package/src/ui/readline-engine.js +109 -22
- package/src/ui/status-cards.js +10 -5
- package/src/ui/summary.js +71 -33
- 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
|
@@ -8,8 +8,13 @@
|
|
|
8
8
|
# DOCKERHUB_TOKEN: DockerHub 액세스 토큰
|
|
9
9
|
# SERVER_HOST: 배포 서버 주소
|
|
10
10
|
# SERVER_USER: SSH 사용자명
|
|
11
|
-
# SERVER_PASSWORD: SSH 비밀번호
|
|
11
|
+
# SERVER_PASSWORD: SSH 비밀번호 (SSH_AUTH_METHOD=password일 때)
|
|
12
|
+
# SSH_KEY: SSH 개인키 .pem 내용 (SSH_AUTH_METHOD=key일 때, AWS EC2 등)
|
|
12
13
|
# PROJECT_DEPLOY_PORT (선택): 배포 포트 (기본: 3000)
|
|
14
|
+
#
|
|
15
|
+
# 환경변수 (env 섹션에서 설정)
|
|
16
|
+
# SSH_AUTH_METHOD: SSH 인증 방식 password | key (기본: password)
|
|
17
|
+
# SSH_PORT (기본: 2022), SSH_COMMAND_TIMEOUT (기본: 600s), SSH_CONNECTION_TIMEOUT (기본: 60s)
|
|
13
18
|
|
|
14
19
|
name: PROJECT-REACT-CICD
|
|
15
20
|
|
|
@@ -22,24 +27,76 @@ on:
|
|
|
22
27
|
|
|
23
28
|
env:
|
|
24
29
|
PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
|
|
30
|
+
# 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
|
|
31
|
+
PROJECT_PATH: "." # @wizard auto:project-path
|
|
25
32
|
DOCKER_IMAGE_PREFIX: "front-container"
|
|
26
33
|
NODE_VERSION: "20.15.0"
|
|
27
34
|
ENV_FILE_NAME: ".env"
|
|
28
35
|
|
|
36
|
+
# SSH 인증 방식: "password"(Synology·일반 서버) | "key"(AWS EC2·.pem)
|
|
37
|
+
# password → SERVER_PASSWORD secret 사용
|
|
38
|
+
# key → SSH_KEY secret 사용 (.pem 파일 전체 내용을 secret 값으로)
|
|
39
|
+
SSH_AUTH_METHOD: "password" # @wizard ask:password
|
|
40
|
+
|
|
41
|
+
SSH_PORT: "__SSH_PORT__" # @wizard ask:2022
|
|
42
|
+
SSH_COMMAND_TIMEOUT: "600s" # SSH 명령 실행 타임아웃
|
|
43
|
+
SSH_CONNECTION_TIMEOUT: "60s" # SSH 연결 타임아웃
|
|
44
|
+
|
|
29
45
|
jobs:
|
|
30
46
|
build:
|
|
31
47
|
name: React/Next.js 애플리케이션 빌드
|
|
32
48
|
runs-on: ubuntu-latest
|
|
49
|
+
# 모노레포(--paths)면 그 하위 폴더에서 빌드한다
|
|
50
|
+
defaults:
|
|
51
|
+
run:
|
|
52
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
33
53
|
|
|
34
54
|
steps:
|
|
35
55
|
- name: 코드 체크아웃
|
|
36
56
|
uses: actions/checkout@v7
|
|
37
57
|
|
|
58
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
59
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
60
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
61
|
+
env:
|
|
62
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
63
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
64
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
65
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
66
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
67
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
68
|
+
DOCKERFILE: Dockerfile
|
|
69
|
+
run: |
|
|
70
|
+
MISSING=""
|
|
71
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
72
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
73
|
+
done
|
|
74
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
75
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
76
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
77
|
+
else
|
|
78
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
79
|
+
fi
|
|
80
|
+
FAILED=false
|
|
81
|
+
if [ -n "$MISSING" ]; then
|
|
82
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
83
|
+
FAILED=true
|
|
84
|
+
fi
|
|
85
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
86
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
87
|
+
FAILED=true
|
|
88
|
+
fi
|
|
89
|
+
if [ "$FAILED" = "true" ]; then
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
93
|
+
|
|
38
94
|
- name: Node.js 설정
|
|
39
95
|
uses: actions/setup-node@v7
|
|
40
96
|
with:
|
|
41
97
|
node-version: ${{ env.NODE_VERSION }}
|
|
42
98
|
cache: 'npm'
|
|
99
|
+
cache-dependency-path: ${{ env.PROJECT_PATH }}/package-lock.json
|
|
43
100
|
|
|
44
101
|
- name: 환경변수 파일 생성 (${{ env.ENV_FILE_NAME }})
|
|
45
102
|
run: |
|
|
@@ -72,7 +129,7 @@ jobs:
|
|
|
72
129
|
- name: Next.js 빌드 캐싱
|
|
73
130
|
uses: actions/cache@v6
|
|
74
131
|
with:
|
|
75
|
-
path: .next/cache
|
|
132
|
+
path: ${{ env.PROJECT_PATH }}/.next/cache
|
|
76
133
|
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
|
|
77
134
|
restore-keys: |
|
|
78
135
|
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
|
|
@@ -101,8 +158,8 @@ jobs:
|
|
|
101
158
|
- name: Docker 이미지 빌드 및 푸시
|
|
102
159
|
uses: docker/build-push-action@v5
|
|
103
160
|
with:
|
|
104
|
-
context: .
|
|
105
|
-
file:
|
|
161
|
+
context: ${{ env.PROJECT_PATH }}
|
|
162
|
+
file: ${{ env.PROJECT_PATH }}/Dockerfile
|
|
106
163
|
push: true
|
|
107
164
|
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}-${{ env.DOCKER_IMAGE_PREFIX }}:${{ github.ref_name }}
|
|
108
165
|
cache-from: type=local,src=/tmp/.buildx-cache
|
|
@@ -121,11 +178,17 @@ jobs:
|
|
|
121
178
|
steps:
|
|
122
179
|
- name: Deploy
|
|
123
180
|
uses: appleboy/ssh-action@v1.0.3
|
|
181
|
+
env:
|
|
182
|
+
SSH_AUTH_METHOD: ${{ env.SSH_AUTH_METHOD }}
|
|
124
183
|
with:
|
|
125
184
|
host: ${{ secrets.SERVER_HOST }}
|
|
126
185
|
username: ${{ secrets.SERVER_USER }}
|
|
127
186
|
password: ${{ secrets.SERVER_PASSWORD }}
|
|
128
|
-
|
|
187
|
+
key: ${{ secrets.SSH_KEY }}
|
|
188
|
+
port: ${{ env.SSH_PORT }}
|
|
189
|
+
command_timeout: ${{ env.SSH_COMMAND_TIMEOUT }}
|
|
190
|
+
timeout: ${{ env.SSH_CONNECTION_TIMEOUT }}
|
|
191
|
+
envs: SSH_AUTH_METHOD
|
|
129
192
|
script: |
|
|
130
193
|
set -e
|
|
131
194
|
|
|
@@ -134,6 +197,17 @@ jobs:
|
|
|
134
197
|
export PATH=$PATH:/usr/local/bin
|
|
135
198
|
export PW=${{ secrets.SERVER_PASSWORD }}
|
|
136
199
|
|
|
200
|
+
# SSH 인증 방식에 따른 sudo 추상화
|
|
201
|
+
# password 모드: echo $PW | sudo -S (Synology 등 sudo 비밀번호 필요 서버)
|
|
202
|
+
# key 모드: sudo 직접 (AWS EC2 등 passwordless sudo 서버)
|
|
203
|
+
SSH_AUTH_METHOD="${SSH_AUTH_METHOD:-password}"
|
|
204
|
+
if [ "${SSH_AUTH_METHOD}" = "key" ]; then
|
|
205
|
+
SUDO() { sudo "$@"; }
|
|
206
|
+
else
|
|
207
|
+
SUDO() { echo "$PW" | sudo -S "$@"; }
|
|
208
|
+
fi
|
|
209
|
+
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
210
|
+
|
|
137
211
|
# GitHub에서 전달받은 브랜치명
|
|
138
212
|
BRANCH=${{ github.ref_name }}
|
|
139
213
|
|
|
@@ -172,15 +246,15 @@ jobs:
|
|
|
172
246
|
|
|
173
247
|
# Docker 이미지 풀 (Pull)
|
|
174
248
|
echo "⬇️ Docker 이미지 풀: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
|
|
175
|
-
|
|
249
|
+
SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
|
|
176
250
|
|
|
177
251
|
# 기존 컨테이너 정리
|
|
178
252
|
echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
|
|
179
253
|
|
|
180
254
|
# 동일한 이름의 컨테이너가 존재하는지 확인
|
|
181
|
-
if
|
|
255
|
+
if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
|
|
182
256
|
echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
|
|
183
|
-
|
|
257
|
+
SUDO docker rm -f $CONTAINER_NAME
|
|
184
258
|
echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 삭제되었습니다."
|
|
185
259
|
else
|
|
186
260
|
echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
|
|
@@ -189,7 +263,7 @@ jobs:
|
|
|
189
263
|
# 새 컨테이너 실행
|
|
190
264
|
echo "🚀 새로운 컨테이너 $CONTAINER_NAME 실행 중..."
|
|
191
265
|
|
|
192
|
-
|
|
266
|
+
SUDO docker run -d \
|
|
193
267
|
-p ${PORT}:3000 \
|
|
194
268
|
--name $CONTAINER_NAME \
|
|
195
269
|
-e TZ=Asia/Seoul \
|
|
@@ -213,7 +287,7 @@ jobs:
|
|
|
213
287
|
# 현재 설정: {{MAIN_BRANCH}} 브랜치에 push할 때 자동 배포
|
|
214
288
|
#
|
|
215
289
|
# 브랜치별 포트:
|
|
216
|
-
# -
|
|
290
|
+
# - {{MAIN_BRANCH}}: 3000 (PROJECT_DEPLOY_PORT secret으로 변경 가능)
|
|
217
291
|
#
|
|
218
292
|
# 필요한 Secrets:
|
|
219
293
|
# - REACT_ENV_FILE, DOCKERHUB_*, SERVER_* (필수)
|
|
@@ -41,6 +41,9 @@ jobs:
|
|
|
41
41
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
|
42
42
|
uses: dorny/paths-filter@v4
|
|
43
43
|
with:
|
|
44
|
+
# push는 이번 push 범위(직전 커밋 before 대비)만 본다. 비워 두면 기본 브랜치 대비 누적 diff가 된다.
|
|
45
|
+
# 새 브랜치 첫 push(before가 0)와 PR은 빈 값 → 기본 동작(기본 브랜치·PR base 대비)
|
|
46
|
+
base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
|
|
44
47
|
filters: |
|
|
45
48
|
project:
|
|
46
49
|
- '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
|
|
@@ -50,6 +53,10 @@ jobs:
|
|
|
50
53
|
runs-on: ubuntu-latest
|
|
51
54
|
needs: changes
|
|
52
55
|
if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
|
|
56
|
+
# 모노레포(--paths)면 그 하위 폴더에서 빌드한다
|
|
57
|
+
defaults:
|
|
58
|
+
run:
|
|
59
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
53
60
|
|
|
54
61
|
steps:
|
|
55
62
|
- name: Checkout Repository
|
|
@@ -80,7 +87,8 @@ jobs:
|
|
|
80
87
|
run: |
|
|
81
88
|
set +e
|
|
82
89
|
./gradlew compileJava compileTestJava 2>&1 | tee compile_output.txt
|
|
83
|
-
|
|
90
|
+
# $?는 tee의 종료 코드라 gradle 결과는 PIPESTATUS로 읽는다
|
|
91
|
+
echo "compile_exit_code=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT
|
|
84
92
|
set -e
|
|
85
93
|
continue-on-error: true
|
|
86
94
|
|
|
@@ -89,7 +97,8 @@ jobs:
|
|
|
89
97
|
run: |
|
|
90
98
|
set +e
|
|
91
99
|
./gradlew test 2>&1 | tee test_output.txt
|
|
92
|
-
|
|
100
|
+
# $?는 tee의 종료 코드라 gradle 결과는 PIPESTATUS로 읽는다
|
|
101
|
+
echo "test_exit_code=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT
|
|
93
102
|
set -e
|
|
94
103
|
continue-on-error: true
|
|
95
104
|
|
|
@@ -98,7 +107,8 @@ jobs:
|
|
|
98
107
|
run: |
|
|
99
108
|
set +e
|
|
100
109
|
./gradlew build -x test 2>&1 | tee build_output.txt
|
|
101
|
-
|
|
110
|
+
# $?는 tee의 종료 코드라 gradle 결과는 PIPESTATUS로 읽는다
|
|
111
|
+
echo "build_exit_code=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT
|
|
102
112
|
set -e
|
|
103
113
|
continue-on-error: true
|
|
104
114
|
|
|
@@ -70,6 +70,10 @@ on:
|
|
|
70
70
|
env:
|
|
71
71
|
# 프로젝트 설정 - 실제 프로젝트명으로 변경하세요
|
|
72
72
|
PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
|
|
73
|
+
# 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
|
|
74
|
+
PROJECT_PATH: "." # @wizard auto:project-path
|
|
75
|
+
# 모노레포(PROJECT_PATH가 '.'이 아님)에서는 이미지·컨테이너·도메인 이름에 '-spring'를 붙여
|
|
76
|
+
# 같은 레포의 다른 타입 서비스와 이름이 겹치지 않게 한다 (예: my-app-spring)
|
|
73
77
|
SERVICE_DOMAIN: "__SERVICE_DOMAIN__" # @wizard ask:example.com
|
|
74
78
|
|
|
75
79
|
# Spring Boot 설정
|
|
@@ -79,7 +83,7 @@ env:
|
|
|
79
83
|
|
|
80
84
|
# 경로 설정
|
|
81
85
|
APPLICATION_YML_DIR: "__APPLICATION_YML_DIR__" # @wizard auto:spring-app-yml-dir
|
|
82
|
-
DOCKERFILE_PATH: "./Dockerfile"
|
|
86
|
+
DOCKERFILE_PATH: "./Dockerfile" # PROJECT_PATH 기준 상대 경로
|
|
83
87
|
|
|
84
88
|
# 포트 및 컨테이너 설정
|
|
85
89
|
# BLUE/GREEN은 서버에서 번갈아 뜨는 두 컨테이너의 호스트 포트다 — 다른 서비스와 겹치면 배포가 실패한다.
|
|
@@ -126,6 +130,42 @@ jobs:
|
|
|
126
130
|
- name: 코드 체크아웃
|
|
127
131
|
uses: actions/checkout@v7
|
|
128
132
|
|
|
133
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
134
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
135
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
136
|
+
env:
|
|
137
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
138
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
139
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
140
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
141
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
142
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
143
|
+
DOCKERFILE: ${{ env.DOCKERFILE_PATH }}
|
|
144
|
+
run: |
|
|
145
|
+
MISSING=""
|
|
146
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
147
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
148
|
+
done
|
|
149
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
150
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
151
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
152
|
+
else
|
|
153
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
154
|
+
fi
|
|
155
|
+
FAILED=false
|
|
156
|
+
if [ -n "$MISSING" ]; then
|
|
157
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
158
|
+
FAILED=true
|
|
159
|
+
fi
|
|
160
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
161
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
162
|
+
FAILED=true
|
|
163
|
+
fi
|
|
164
|
+
if [ "$FAILED" = "true" ]; then
|
|
165
|
+
exit 1
|
|
166
|
+
fi
|
|
167
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
168
|
+
|
|
129
169
|
- name: Java 설정
|
|
130
170
|
uses: actions/setup-java@v5
|
|
131
171
|
with:
|
|
@@ -134,6 +174,7 @@ jobs:
|
|
|
134
174
|
cache: 'gradle'
|
|
135
175
|
|
|
136
176
|
- name: Gradle Wrapper 실행권한 부여
|
|
177
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
137
178
|
run: chmod +x gradlew
|
|
138
179
|
|
|
139
180
|
- name: application-prod.yml 생성
|
|
@@ -145,6 +186,7 @@ jobs:
|
|
|
145
186
|
echo "✅ application-prod.yml 파일 생성 완료 (${{ env.APPLICATION_YML_DIR }})"
|
|
146
187
|
|
|
147
188
|
- name: Build with Gradle
|
|
189
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
148
190
|
run: ./gradlew clean build -x test ${{ env.GRADLE_OPTS }}
|
|
149
191
|
|
|
150
192
|
- name: Docker 빌드환경 설정
|
|
@@ -167,10 +209,10 @@ jobs:
|
|
|
167
209
|
- name: Docker 이미지 빌드 및 푸시
|
|
168
210
|
uses: docker/build-push-action@v5
|
|
169
211
|
with:
|
|
170
|
-
context: .
|
|
171
|
-
file: ${{ env.DOCKERFILE_PATH }}
|
|
212
|
+
context: ${{ env.PROJECT_PATH }}
|
|
213
|
+
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
172
214
|
push: true
|
|
173
|
-
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:${{ github.ref_name }}
|
|
215
|
+
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-spring', env.PROJECT_NAME) || env.PROJECT_NAME }}:${{ github.ref_name }}
|
|
174
216
|
cache-from: type=local,src=/tmp/.buildx-cache
|
|
175
217
|
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
|
176
218
|
|
|
@@ -189,7 +231,7 @@ jobs:
|
|
|
189
231
|
- name: Deploy
|
|
190
232
|
uses: appleboy/ssh-action@v1.0.3
|
|
191
233
|
env:
|
|
192
|
-
PROJECT_NAME: ${{ env.PROJECT_NAME }}
|
|
234
|
+
PROJECT_NAME: ${{ env.PROJECT_PATH != '.' && format('{0}-spring', env.PROJECT_NAME) || env.PROJECT_NAME }}
|
|
193
235
|
SERVICE_DOMAIN: ${{ env.SERVICE_DOMAIN }}
|
|
194
236
|
SPRING_PROFILE: ${{ env.SPRING_PROFILE }}
|
|
195
237
|
CONTAINER_INTERNAL_PORT: ${{ env.CONTAINER_INTERNAL_PORT }}
|
|
@@ -66,6 +66,10 @@ on:
|
|
|
66
66
|
env:
|
|
67
67
|
# 프로젝트 설정 - 실제 프로젝트명으로 변경하세요
|
|
68
68
|
PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
|
|
69
|
+
# 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
|
|
70
|
+
PROJECT_PATH: "." # @wizard auto:project-path
|
|
71
|
+
# 모노레포(PROJECT_PATH가 '.'이 아님)에서는 이미지·컨테이너·도메인 이름에 '-spring'를 붙여
|
|
72
|
+
# 같은 레포의 다른 타입 서비스와 이름이 겹치지 않게 한다 (예: my-app-spring)
|
|
69
73
|
SERVICE_DOMAIN: "__SERVICE_DOMAIN__" # @wizard ask:example.com
|
|
70
74
|
|
|
71
75
|
# Spring Boot 설정
|
|
@@ -75,7 +79,7 @@ env:
|
|
|
75
79
|
|
|
76
80
|
# 경로 설정
|
|
77
81
|
APPLICATION_YML_DIR: "__APPLICATION_YML_DIR__" # @wizard auto:spring-app-yml-dir
|
|
78
|
-
DOCKERFILE_PATH: "./Dockerfile"
|
|
82
|
+
DOCKERFILE_PATH: "./Dockerfile" # PROJECT_PATH 기준 상대 경로
|
|
79
83
|
|
|
80
84
|
# 포트 및 컨테이너 설정
|
|
81
85
|
CONTAINER_INTERNAL_PORT: "8080"
|
|
@@ -118,6 +122,42 @@ jobs:
|
|
|
118
122
|
- name: 코드 체크아웃
|
|
119
123
|
uses: actions/checkout@v7
|
|
120
124
|
|
|
125
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
126
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
127
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
128
|
+
env:
|
|
129
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
130
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
131
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
132
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
133
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
134
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
135
|
+
DOCKERFILE: ${{ env.DOCKERFILE_PATH }}
|
|
136
|
+
run: |
|
|
137
|
+
MISSING=""
|
|
138
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
139
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
140
|
+
done
|
|
141
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
142
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
143
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
144
|
+
else
|
|
145
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
146
|
+
fi
|
|
147
|
+
FAILED=false
|
|
148
|
+
if [ -n "$MISSING" ]; then
|
|
149
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
150
|
+
FAILED=true
|
|
151
|
+
fi
|
|
152
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
153
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
154
|
+
FAILED=true
|
|
155
|
+
fi
|
|
156
|
+
if [ "$FAILED" = "true" ]; then
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
160
|
+
|
|
121
161
|
- name: Java 설정
|
|
122
162
|
uses: actions/setup-java@v5
|
|
123
163
|
with:
|
|
@@ -126,6 +166,7 @@ jobs:
|
|
|
126
166
|
cache: 'gradle'
|
|
127
167
|
|
|
128
168
|
- name: Gradle Wrapper 실행권한 부여
|
|
169
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
129
170
|
run: chmod +x gradlew
|
|
130
171
|
|
|
131
172
|
- name: application-prod.yml 생성
|
|
@@ -137,6 +178,7 @@ jobs:
|
|
|
137
178
|
echo "✅ application-prod.yml 파일 생성 완료 (${{ env.APPLICATION_YML_DIR }})"
|
|
138
179
|
|
|
139
180
|
- name: Build with Gradle
|
|
181
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
140
182
|
run: ./gradlew clean build -x test ${{ env.GRADLE_OPTS }}
|
|
141
183
|
|
|
142
184
|
- name: Docker 빌드환경 설정
|
|
@@ -159,10 +201,10 @@ jobs:
|
|
|
159
201
|
- name: Docker 이미지 빌드 및 푸시
|
|
160
202
|
uses: docker/build-push-action@v5
|
|
161
203
|
with:
|
|
162
|
-
context: .
|
|
163
|
-
file: ${{ env.DOCKERFILE_PATH }}
|
|
204
|
+
context: ${{ env.PROJECT_PATH }}
|
|
205
|
+
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
164
206
|
push: true
|
|
165
|
-
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:${{ github.ref_name }}
|
|
207
|
+
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-spring', env.PROJECT_NAME) || env.PROJECT_NAME }}:${{ github.ref_name }}
|
|
166
208
|
cache-from: type=local,src=/tmp/.buildx-cache
|
|
167
209
|
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
|
168
210
|
|
|
@@ -181,7 +223,7 @@ jobs:
|
|
|
181
223
|
- name: Deploy
|
|
182
224
|
uses: appleboy/ssh-action@v1.0.3
|
|
183
225
|
env:
|
|
184
|
-
PROJECT_NAME: ${{ env.PROJECT_NAME }}
|
|
226
|
+
PROJECT_NAME: ${{ env.PROJECT_PATH != '.' && format('{0}-spring', env.PROJECT_NAME) || env.PROJECT_NAME }}
|
|
185
227
|
SERVICE_DOMAIN: ${{ env.SERVICE_DOMAIN }}
|
|
186
228
|
CONTAINER_INTERNAL_PORT: ${{ env.CONTAINER_INTERNAL_PORT }}
|
|
187
229
|
SPRING_PROFILE: ${{ env.SPRING_PROFILE }}
|