project-auto-wizard 0.12.2 → 0.13.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.
- 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 +7 -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 +397 -97
- package/payload/version.yml.template +4 -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 +17 -10
- package/src/commands/dry-run.js +54 -1
- package/src/commands/full.js +127 -50
- package/src/commands/interactive-flutter.js +1 -1
- package/src/commands/interactive.js +124 -56
- package/src/commands/purge.js +59 -17
- package/src/commands/status.js +16 -1
- package/src/commands/uninstall.js +58 -13
- 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/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 +90 -47
- package/src/core/deploy-style.js +83 -11
- package/src/core/detect-fs.js +127 -24
- package/src/core/detect.js +131 -47
- package/src/core/errors.js +3 -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-plan.js +75 -19
- package/src/core/types.js +113 -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 +122 -49
- 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
|
@@ -48,9 +48,17 @@ on:
|
|
|
48
48
|
repository_dispatch:
|
|
49
49
|
types: [build-ios-app]
|
|
50
50
|
|
|
51
|
+
# 레포 기본 권한이 read여도 빌드 진행 댓글을 달 수 있게 필요한 권한을 직접 선언한다
|
|
52
|
+
permissions:
|
|
53
|
+
contents: read
|
|
54
|
+
issues: write
|
|
55
|
+
pull-requests: write
|
|
56
|
+
|
|
51
57
|
# 프로젝트별 설정 (아래 값들을 수정하세요)
|
|
52
58
|
env:
|
|
53
|
-
|
|
59
|
+
# Flutter SDK 버전 — 비워 두면 stable 채널 최신을 쓴다(최신 flutter create 프로젝트의 SDK 제약과 맞음).
|
|
60
|
+
# 특정 버전에 고정하려면 "3.38.9"처럼 적는다. pubspec.yaml의 environment.sdk 범위를 만족해야 한다.
|
|
61
|
+
FLUTTER_VERSION: ""
|
|
54
62
|
XCODE_VERSION: "26.0"
|
|
55
63
|
PROJECT_TYPE: "flutter"
|
|
56
64
|
# Flutter 루트 경로(레포 루트 기준). 단일레포면 ".", 모노레포면 "app" 등 — 설치 시 자동 설정
|
|
@@ -205,6 +213,41 @@ jobs:
|
|
|
205
213
|
- name: Pull latest changes
|
|
206
214
|
run: git pull origin ${{ github.event_name == 'repository_dispatch' && github.event.client_payload.branch_name || github.ref_name }}
|
|
207
215
|
|
|
216
|
+
# 인증서 import·빌드 전에 설정 누락을 한 번에 알려 준다 — 없으면 macOS 러너에서 한참 빌드한 뒤에야 엉뚱한 단계에서 실패한다
|
|
217
|
+
- name: 배포 설정 사전 검증
|
|
218
|
+
env:
|
|
219
|
+
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
220
|
+
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
221
|
+
IOS_PROVISIONING_PROFILE_NAME: ${{ secrets.IOS_PROVISIONING_PROFILE_NAME }}
|
|
222
|
+
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
223
|
+
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
|
|
224
|
+
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
|
|
225
|
+
run: |
|
|
226
|
+
FAILED=0
|
|
227
|
+
MISSING=""
|
|
228
|
+
for name in APPLE_CERTIFICATE_BASE64 APPLE_PROVISIONING_PROFILE_BASE64 IOS_PROVISIONING_PROFILE_NAME \
|
|
229
|
+
APP_STORE_CONNECT_API_KEY_ID APP_STORE_CONNECT_ISSUER_ID APP_STORE_CONNECT_API_KEY_BASE64; do
|
|
230
|
+
[ -n "${!name}" ] || MISSING="$MISSING $name"
|
|
231
|
+
done
|
|
232
|
+
if [ -n "$MISSING" ]; then
|
|
233
|
+
echo "::error::필수 GitHub Secret이 비어 있습니다:$MISSING (워크플로우 상단 주석 참고)"
|
|
234
|
+
FAILED=1
|
|
235
|
+
fi
|
|
236
|
+
if [ ! -f ios/ExportOptions.plist ]; then
|
|
237
|
+
echo "::error::ios/ExportOptions.plist가 없습니다 — 저장소에 추가(커밋)하세요."
|
|
238
|
+
FAILED=1
|
|
239
|
+
elif grep -Eq '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist; then
|
|
240
|
+
echo "::error::ios/ExportOptions.plist에 채워지지 않은 플레이스홀더가 남아 있습니다 — 팀 ID·번들 ID·프로비저닝 프로파일 이름으로 바꿔 커밋하세요."
|
|
241
|
+
grep -En '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist
|
|
242
|
+
FAILED=1
|
|
243
|
+
fi
|
|
244
|
+
if [ ! -f ios/fastlane/Fastfile ]; then
|
|
245
|
+
echo "::error::ios/fastlane/Fastfile이 없습니다 — 저장소에 추가(커밋)하세요."
|
|
246
|
+
FAILED=1
|
|
247
|
+
fi
|
|
248
|
+
[ "$FAILED" -eq 0 ] || exit 1
|
|
249
|
+
echo "✅ 배포 설정 확인 완료"
|
|
250
|
+
|
|
208
251
|
- name: Select Xcode version
|
|
209
252
|
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
210
253
|
|
|
@@ -521,6 +564,7 @@ jobs:
|
|
|
521
564
|
- name: Set up Flutter
|
|
522
565
|
uses: subosito/flutter-action@v2
|
|
523
566
|
with:
|
|
567
|
+
channel: stable
|
|
524
568
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
525
569
|
cache: true
|
|
526
570
|
|
|
@@ -546,8 +590,13 @@ jobs:
|
|
|
546
590
|
|
|
547
591
|
- name: Install CocoaPods
|
|
548
592
|
run: |
|
|
549
|
-
|
|
550
|
-
|
|
593
|
+
# 플러그인이 없는 기본 프로젝트는 Podfile이 없다 — 플러그인이 생기면 flutter build가 Podfile을 만든다
|
|
594
|
+
if [ -f ios/Podfile ]; then
|
|
595
|
+
gem install cocoapods
|
|
596
|
+
(cd ios && pod install)
|
|
597
|
+
else
|
|
598
|
+
echo "ℹ️ ios/Podfile이 없어 pod install을 건너뜁니다 (CocoaPods 플러그인 없음)"
|
|
599
|
+
fi
|
|
551
600
|
|
|
552
601
|
- name: Import Code-Signing Certificates
|
|
553
602
|
uses: Apple-Actions/import-codesign-certs@v2
|
|
@@ -52,7 +52,7 @@ on:
|
|
|
52
52
|
deploy_mode:
|
|
53
53
|
description: "배포 모드 (store_only=TestFlight까지 / store_prepare=ASC 제출직전 / store_submit=심사 자동제출)"
|
|
54
54
|
required: false
|
|
55
|
-
default: "store_only"
|
|
55
|
+
default: "store_only" # @wizard auto:ios-deploy-mode
|
|
56
56
|
type: choice
|
|
57
57
|
options:
|
|
58
58
|
- store_only
|
|
@@ -64,7 +64,9 @@ env:
|
|
|
64
64
|
FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
|
|
65
65
|
# 환경변수 전달 방식 (dart-define | dotenv) — 설치 시 선택값으로 자동 설정
|
|
66
66
|
ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
|
|
67
|
-
|
|
67
|
+
# Flutter SDK 버전 — 비워 두면 stable 채널 최신을 쓴다(최신 flutter create 프로젝트의 SDK 제약과 맞음).
|
|
68
|
+
# 특정 버전에 고정하려면 "3.38.9"처럼 적는다. pubspec.yaml의 environment.sdk 범위를 만족해야 한다.
|
|
69
|
+
FLUTTER_VERSION: ""
|
|
68
70
|
XCODE_VERSION: "26.0"
|
|
69
71
|
PROJECT_TYPE: "flutter"
|
|
70
72
|
|
|
@@ -96,11 +98,46 @@ jobs:
|
|
|
96
98
|
- name: Checkout repository
|
|
97
99
|
uses: actions/checkout@v7
|
|
98
100
|
with:
|
|
99
|
-
ref:
|
|
101
|
+
ref: "{{MAIN_BRANCH}}"
|
|
100
102
|
fetch-depth: 0
|
|
101
103
|
|
|
102
104
|
- name: Pull latest changes
|
|
103
|
-
run: git pull origin
|
|
105
|
+
run: git pull origin {{MAIN_BRANCH}}
|
|
106
|
+
|
|
107
|
+
# 인증서 import·빌드 전에 설정 누락을 한 번에 알려 준다 — 없으면 macOS 러너에서 한참 빌드한 뒤에야 엉뚱한 단계에서 실패한다
|
|
108
|
+
- name: 배포 설정 사전 검증
|
|
109
|
+
env:
|
|
110
|
+
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
111
|
+
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
112
|
+
IOS_PROVISIONING_PROFILE_NAME: ${{ secrets.IOS_PROVISIONING_PROFILE_NAME }}
|
|
113
|
+
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
114
|
+
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
|
|
115
|
+
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
|
|
116
|
+
run: |
|
|
117
|
+
FAILED=0
|
|
118
|
+
MISSING=""
|
|
119
|
+
for name in APPLE_CERTIFICATE_BASE64 APPLE_PROVISIONING_PROFILE_BASE64 IOS_PROVISIONING_PROFILE_NAME \
|
|
120
|
+
APP_STORE_CONNECT_API_KEY_ID APP_STORE_CONNECT_ISSUER_ID APP_STORE_CONNECT_API_KEY_BASE64; do
|
|
121
|
+
[ -n "${!name}" ] || MISSING="$MISSING $name"
|
|
122
|
+
done
|
|
123
|
+
if [ -n "$MISSING" ]; then
|
|
124
|
+
echo "::error::필수 GitHub Secret이 비어 있습니다:$MISSING (워크플로우 상단 주석 참고)"
|
|
125
|
+
FAILED=1
|
|
126
|
+
fi
|
|
127
|
+
if [ ! -f ios/ExportOptions.plist ]; then
|
|
128
|
+
echo "::error::ios/ExportOptions.plist가 없습니다 — 저장소에 추가(커밋)하세요."
|
|
129
|
+
FAILED=1
|
|
130
|
+
elif grep -Eq '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist; then
|
|
131
|
+
echo "::error::ios/ExportOptions.plist에 채워지지 않은 플레이스홀더가 남아 있습니다 — 팀 ID·번들 ID·프로비저닝 프로파일 이름으로 바꿔 커밋하세요."
|
|
132
|
+
grep -En '__[A-Z][A-Z0-9_]*__' ios/ExportOptions.plist
|
|
133
|
+
FAILED=1
|
|
134
|
+
fi
|
|
135
|
+
if [ ! -f ios/fastlane/Fastfile ]; then
|
|
136
|
+
echo "::error::ios/fastlane/Fastfile이 없습니다 — 저장소에 추가(커밋)하세요."
|
|
137
|
+
FAILED=1
|
|
138
|
+
fi
|
|
139
|
+
[ "$FAILED" -eq 0 ] || exit 1
|
|
140
|
+
echo "✅ 배포 설정 확인 완료"
|
|
104
141
|
|
|
105
142
|
- name: Select Xcode version
|
|
106
143
|
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
@@ -132,6 +169,7 @@ jobs:
|
|
|
132
169
|
- name: Set up Flutter
|
|
133
170
|
uses: subosito/flutter-action@v2
|
|
134
171
|
with:
|
|
172
|
+
channel: stable
|
|
135
173
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
136
174
|
cache: true
|
|
137
175
|
|
|
@@ -157,8 +195,13 @@ jobs:
|
|
|
157
195
|
|
|
158
196
|
- name: Install CocoaPods
|
|
159
197
|
run: |
|
|
160
|
-
|
|
161
|
-
|
|
198
|
+
# 플러그인이 없는 기본 프로젝트는 Podfile이 없다 — 플러그인이 생기면 flutter build가 Podfile을 만든다
|
|
199
|
+
if [ -f ios/Podfile ]; then
|
|
200
|
+
gem install cocoapods
|
|
201
|
+
(cd ios && pod install)
|
|
202
|
+
else
|
|
203
|
+
echo "ℹ️ ios/Podfile이 없어 pod install을 건너뜁니다 (CocoaPods 플러그인 없음)"
|
|
204
|
+
fi
|
|
162
205
|
|
|
163
206
|
- name: 현재 버전 정보 가져오기
|
|
164
207
|
id: current_version
|
|
@@ -227,11 +270,11 @@ jobs:
|
|
|
227
270
|
- name: Checkout repository
|
|
228
271
|
uses: actions/checkout@v7
|
|
229
272
|
with:
|
|
230
|
-
ref:
|
|
273
|
+
ref: "{{MAIN_BRANCH}}"
|
|
231
274
|
fetch-depth: 0
|
|
232
275
|
|
|
233
276
|
- name: Pull latest changes
|
|
234
|
-
run: git pull origin
|
|
277
|
+
run: git pull origin {{MAIN_BRANCH}}
|
|
235
278
|
|
|
236
279
|
- name: Select Xcode version
|
|
237
280
|
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
|
|
@@ -276,6 +319,7 @@ jobs:
|
|
|
276
319
|
- name: Set up Flutter
|
|
277
320
|
uses: subosito/flutter-action@v2
|
|
278
321
|
with:
|
|
322
|
+
channel: stable
|
|
279
323
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
280
324
|
cache: true
|
|
281
325
|
|
|
@@ -301,8 +345,13 @@ jobs:
|
|
|
301
345
|
|
|
302
346
|
- name: Install CocoaPods
|
|
303
347
|
run: |
|
|
304
|
-
|
|
305
|
-
|
|
348
|
+
# 플러그인이 없는 기본 프로젝트는 Podfile이 없다 — 플러그인이 생기면 flutter build가 Podfile을 만든다
|
|
349
|
+
if [ -f ios/Podfile ]; then
|
|
350
|
+
gem install cocoapods
|
|
351
|
+
(cd ios && pod install)
|
|
352
|
+
else
|
|
353
|
+
echo "ℹ️ ios/Podfile이 없어 pod install을 건너뜁니다 (CocoaPods 플러그인 없음)"
|
|
354
|
+
fi
|
|
306
355
|
|
|
307
356
|
- name: Import Code-Signing Certificates
|
|
308
357
|
uses: Apple-Actions/import-codesign-certs@v2
|
|
@@ -387,7 +436,7 @@ jobs:
|
|
|
387
436
|
- name: Checkout repository
|
|
388
437
|
uses: actions/checkout@v7
|
|
389
438
|
with:
|
|
390
|
-
ref:
|
|
439
|
+
ref: "{{MAIN_BRANCH}}"
|
|
391
440
|
fetch-depth: 0
|
|
392
441
|
|
|
393
442
|
- name: Setup App Store Connect API Key
|
|
@@ -40,6 +40,9 @@ jobs:
|
|
|
40
40
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
|
41
41
|
uses: dorny/paths-filter@v4
|
|
42
42
|
with:
|
|
43
|
+
# push는 이번 push 범위(직전 커밋 before 대비)만 본다. 비워 두면 기본 브랜치 대비 누적 diff가 된다.
|
|
44
|
+
# 새 브랜치 첫 push(before가 0)와 PR은 빈 값 → 기본 동작(기본 브랜치·PR base 대비)
|
|
45
|
+
base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
|
|
43
46
|
filters: |
|
|
44
47
|
project:
|
|
45
48
|
- '${{ 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: 코드 체크아웃
|
|
@@ -59,7 +66,8 @@ jobs:
|
|
|
59
66
|
- name: Go 설정
|
|
60
67
|
uses: actions/setup-go@v7
|
|
61
68
|
with:
|
|
62
|
-
go-version-file: go.mod
|
|
69
|
+
go-version-file: ${{ env.PROJECT_PATH }}/go.mod
|
|
70
|
+
cache-dependency-path: ${{ env.PROJECT_PATH }}/go.sum
|
|
63
71
|
cache: true
|
|
64
72
|
|
|
65
73
|
- name: go build 검증
|
|
@@ -77,6 +85,7 @@ jobs:
|
|
|
77
85
|
uses: golangci/golangci-lint-action@v8
|
|
78
86
|
with:
|
|
79
87
|
version: latest
|
|
88
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
80
89
|
|
|
81
90
|
- name: 빌드 검증 완료
|
|
82
91
|
run: |
|
|
@@ -28,9 +28,13 @@ name: PROJECT-GO-PR-PREVIEW
|
|
|
28
28
|
env:
|
|
29
29
|
# 프로젝트 고유 식별자 (컨테이너명, 이미지명, 도메인에 사용)
|
|
30
30
|
PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
|
|
31
|
+
# 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
|
|
32
|
+
PROJECT_PATH: "." # @wizard auto:project-path
|
|
33
|
+
# 모노레포(PROJECT_PATH가 '.'이 아님)에서는 이미지·컨테이너·도메인 이름에 '-go'를 붙여
|
|
34
|
+
# 같은 레포의 다른 타입 서비스와 이름이 겹치지 않게 한다 (예: my-app-go)
|
|
31
35
|
|
|
32
36
|
# Docker 설정
|
|
33
|
-
DOCKERFILE_PATH: './Dockerfile'
|
|
37
|
+
DOCKERFILE_PATH: './Dockerfile' # PROJECT_PATH 기준 상대 경로
|
|
34
38
|
INTERNAL_PORT: '8080'
|
|
35
39
|
|
|
36
40
|
# 볼륨 마운트 설정 (프로젝트별 수정 필요, 빈값이면 마운트 안함)
|
|
@@ -227,8 +231,45 @@ jobs:
|
|
|
227
231
|
with:
|
|
228
232
|
ref: ${{ steps.pr.outputs.ref }}
|
|
229
233
|
|
|
234
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
235
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
236
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
237
|
+
env:
|
|
238
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
239
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
240
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
241
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
242
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
243
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
244
|
+
DOCKERFILE: ${{ env.DOCKERFILE_PATH }}
|
|
245
|
+
run: |
|
|
246
|
+
MISSING=""
|
|
247
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
248
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
249
|
+
done
|
|
250
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
251
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
252
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
253
|
+
else
|
|
254
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
255
|
+
fi
|
|
256
|
+
FAILED=false
|
|
257
|
+
if [ -n "$MISSING" ]; then
|
|
258
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
259
|
+
FAILED=true
|
|
260
|
+
fi
|
|
261
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
262
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
263
|
+
FAILED=true
|
|
264
|
+
fi
|
|
265
|
+
if [ "$FAILED" = "true" ]; then
|
|
266
|
+
exit 1
|
|
267
|
+
fi
|
|
268
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
269
|
+
|
|
230
270
|
# [영역 2] 환경변수 파일 생성
|
|
231
271
|
- name: "[필수] .env 파일 생성"
|
|
272
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
232
273
|
run: |
|
|
233
274
|
cat << 'EOF' > .env
|
|
234
275
|
${{ secrets.ENV_FILE }}
|
|
@@ -247,10 +288,10 @@ jobs:
|
|
|
247
288
|
- name: Docker 이미지 빌드 & Push
|
|
248
289
|
uses: docker/build-push-action@v5
|
|
249
290
|
with:
|
|
250
|
-
context: .
|
|
251
|
-
file: ${{ env.DOCKERFILE_PATH }}
|
|
291
|
+
context: ${{ env.PROJECT_PATH }}
|
|
292
|
+
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
252
293
|
push: true
|
|
253
|
-
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:pr-${{ github.event.issue.number }}
|
|
294
|
+
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}:pr-${{ github.event.issue.number }}
|
|
254
295
|
cache-from: type=gha
|
|
255
296
|
cache-to: type=gha,mode=max
|
|
256
297
|
|
|
@@ -319,7 +360,7 @@ jobs:
|
|
|
319
360
|
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
320
361
|
|
|
321
362
|
PR_NUMBER=${{ github.event.issue.number }}
|
|
322
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
363
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
323
364
|
CONTAINER_NAME="${PROJECT_NAME}-pr-${PR_NUMBER}"
|
|
324
365
|
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:pr-${PR_NUMBER}"
|
|
325
366
|
DOMAIN="${PROJECT_NAME}-pr-${PR_NUMBER}.${{ env.PREVIEW_DOMAIN_SUFFIX }}"
|
|
@@ -446,7 +487,7 @@ jobs:
|
|
|
446
487
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
447
488
|
const deployDuration = minutes > 0 ? `${minutes}분 ${seconds}초` : `${seconds}초`;
|
|
448
489
|
|
|
449
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
490
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
450
491
|
const domainSuffix = '${{ env.PREVIEW_DOMAIN_SUFFIX }}';
|
|
451
492
|
const previewPort = '${{ env.PREVIEW_PORT }}';
|
|
452
493
|
const apiDocsPath = '${{ env.API_DOCS_PATH }}';
|
|
@@ -514,7 +555,7 @@ jobs:
|
|
|
514
555
|
with:
|
|
515
556
|
script: |
|
|
516
557
|
const commentId = ${{ steps.progress.outputs.comment_id || 0 }};
|
|
517
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
558
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
518
559
|
const prNumber = context.issue.number;
|
|
519
560
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
520
561
|
|
|
@@ -551,6 +592,7 @@ jobs:
|
|
|
551
592
|
`**[📋 빌드/배포 로그 확인](${runUrl})**`,
|
|
552
593
|
'',
|
|
553
594
|
'### 🔍 가능한 원인',
|
|
595
|
+
'- 필수 Secret(DOCKERHUB_*, SERVER_*) 미등록 또는 Dockerfile 없음 → 로그의 "배포 사전 점검" 단계 확인',
|
|
554
596
|
'- Docker 이미지 빌드 실패 (Go 의존성/빌드 문제)',
|
|
555
597
|
'- 컨테이너 시작 실패 (애플리케이션 기동 오류)',
|
|
556
598
|
'- Health Check 타임아웃 (120초 내 기동 완료 안됨)',
|
|
@@ -793,8 +835,46 @@ jobs:
|
|
|
793
835
|
with:
|
|
794
836
|
ref: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
795
837
|
|
|
838
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
839
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
840
|
+
if: steps.check_branch.outputs.exists == 'true'
|
|
841
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
842
|
+
env:
|
|
843
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
844
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
845
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
846
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
847
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
848
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
849
|
+
DOCKERFILE: ${{ env.DOCKERFILE_PATH }}
|
|
850
|
+
run: |
|
|
851
|
+
MISSING=""
|
|
852
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
853
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
854
|
+
done
|
|
855
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
856
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
857
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
858
|
+
else
|
|
859
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
860
|
+
fi
|
|
861
|
+
FAILED=false
|
|
862
|
+
if [ -n "$MISSING" ]; then
|
|
863
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
864
|
+
FAILED=true
|
|
865
|
+
fi
|
|
866
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
867
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
868
|
+
FAILED=true
|
|
869
|
+
fi
|
|
870
|
+
if [ "$FAILED" = "true" ]; then
|
|
871
|
+
exit 1
|
|
872
|
+
fi
|
|
873
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
874
|
+
|
|
796
875
|
# [영역 2] 환경변수 파일 생성
|
|
797
876
|
- name: "[필수] .env 파일 생성"
|
|
877
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
798
878
|
if: steps.check_branch.outputs.exists == 'true'
|
|
799
879
|
run: |
|
|
800
880
|
cat << 'EOF' > .env
|
|
@@ -817,10 +897,10 @@ jobs:
|
|
|
817
897
|
if: steps.check_branch.outputs.exists == 'true'
|
|
818
898
|
uses: docker/build-push-action@v5
|
|
819
899
|
with:
|
|
820
|
-
context: .
|
|
821
|
-
file: ${{ env.DOCKERFILE_PATH }}
|
|
900
|
+
context: ${{ env.PROJECT_PATH }}
|
|
901
|
+
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
822
902
|
push: true
|
|
823
|
-
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:pr-${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
903
|
+
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}:pr-${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
824
904
|
cache-from: type=gha
|
|
825
905
|
cache-to: type=gha,mode=max
|
|
826
906
|
|
|
@@ -894,7 +974,7 @@ jobs:
|
|
|
894
974
|
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
895
975
|
|
|
896
976
|
ISSUE_NUMBER=${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
897
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
977
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
898
978
|
CONTAINER_NAME="${PROJECT_NAME}-pr-${ISSUE_NUMBER}"
|
|
899
979
|
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:pr-${ISSUE_NUMBER}"
|
|
900
980
|
DOMAIN="${PROJECT_NAME}-pr-${ISSUE_NUMBER}.${{ env.PREVIEW_DOMAIN_SUFFIX }}"
|
|
@@ -1023,7 +1103,7 @@ jobs:
|
|
|
1023
1103
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
1024
1104
|
const deployDuration = minutes > 0 ? `${minutes}분 ${seconds}초` : `${seconds}초`;
|
|
1025
1105
|
|
|
1026
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
1106
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1027
1107
|
const domainSuffix = '${{ env.PREVIEW_DOMAIN_SUFFIX }}';
|
|
1028
1108
|
const previewPort = '${{ env.PREVIEW_PORT }}';
|
|
1029
1109
|
const apiDocsPath = '${{ env.API_DOCS_PATH }}';
|
|
@@ -1092,7 +1172,7 @@ jobs:
|
|
|
1092
1172
|
with:
|
|
1093
1173
|
script: |
|
|
1094
1174
|
const commentId = ${{ steps.progress.outputs.comment_id || 0 }};
|
|
1095
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
1175
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1096
1176
|
const issueNumber = ${{ needs.get-branch-from-issue.outputs.issue_number }};
|
|
1097
1177
|
const branchName = '${{ needs.get-branch-from-issue.outputs.branch_name }}';
|
|
1098
1178
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
@@ -1127,6 +1207,7 @@ jobs:
|
|
|
1127
1207
|
`**[📋 빌드/배포 로그 확인](${runUrl})**`,
|
|
1128
1208
|
'',
|
|
1129
1209
|
'### 🔍 가능한 원인',
|
|
1210
|
+
'- 필수 Secret(DOCKERHUB_*, SERVER_*) 미등록 또는 Dockerfile 없음 → 로그의 "배포 사전 점검" 단계 확인',
|
|
1130
1211
|
'- Docker 이미지 빌드 실패 (Go 의존성/빌드 문제)',
|
|
1131
1212
|
'- 컨테이너 시작 실패 (애플리케이션 기동 오류)',
|
|
1132
1213
|
'- Health Check 타임아웃 (120초 내 기동 완료 안됨)',
|
|
@@ -1205,7 +1286,7 @@ jobs:
|
|
|
1205
1286
|
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
1206
1287
|
|
|
1207
1288
|
PR_NUMBER=${{ steps.pr_number.outputs.number }}
|
|
1208
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
1289
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
1209
1290
|
CONTAINER_NAME="${PROJECT_NAME}-pr-${PR_NUMBER}"
|
|
1210
1291
|
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:pr-${PR_NUMBER}"
|
|
1211
1292
|
|
|
@@ -1233,7 +1314,7 @@ jobs:
|
|
|
1233
1314
|
with:
|
|
1234
1315
|
script: |
|
|
1235
1316
|
const number = ${{ steps.pr_number.outputs.number }};
|
|
1236
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
1317
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1237
1318
|
|
|
1238
1319
|
const body = [
|
|
1239
1320
|
'## 🗑️ Preview 환경 삭제 완료!',
|
|
@@ -1276,7 +1357,7 @@ jobs:
|
|
|
1276
1357
|
export PATH=$PATH:/usr/local/bin
|
|
1277
1358
|
|
|
1278
1359
|
NUMBER=${{ github.event.issue.number }}
|
|
1279
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
1360
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
1280
1361
|
CONTAINER_NAME="${PROJECT_NAME}-pr-${NUMBER}"
|
|
1281
1362
|
|
|
1282
1363
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
@@ -1306,7 +1387,7 @@ jobs:
|
|
|
1306
1387
|
export PATH=$PATH:/usr/local/bin
|
|
1307
1388
|
|
|
1308
1389
|
NUMBER=${{ github.event.issue.number }}
|
|
1309
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
1390
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
1310
1391
|
CONTAINER_NAME="${PROJECT_NAME}-pr-${NUMBER}"
|
|
1311
1392
|
docker ps --filter "name=${CONTAINER_NAME}" --format "{{.Names}}" | grep -q "${CONTAINER_NAME}"
|
|
1312
1393
|
|
|
@@ -1315,7 +1396,7 @@ jobs:
|
|
|
1315
1396
|
with:
|
|
1316
1397
|
script: |
|
|
1317
1398
|
const number = context.issue.number;
|
|
1318
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
1399
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1319
1400
|
const domainSuffix = '${{ env.PREVIEW_DOMAIN_SUFFIX }}';
|
|
1320
1401
|
const previewPort = '${{ env.PREVIEW_PORT }}';
|
|
1321
1402
|
const domain = `${projectName}-pr-${number}.${domainSuffix}`;
|
|
@@ -1505,7 +1586,45 @@ jobs:
|
|
|
1505
1586
|
with:
|
|
1506
1587
|
ref: ${{ needs.check-command.outputs.custom_branch }}
|
|
1507
1588
|
|
|
1589
|
+
# 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
|
|
1590
|
+
- name: 배포 사전 점검 (Secret·Dockerfile)
|
|
1591
|
+
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1592
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
1593
|
+
env:
|
|
1594
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
1595
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
1596
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
1597
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
1598
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
1599
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
1600
|
+
DOCKERFILE: ${{ env.DOCKERFILE_PATH }}
|
|
1601
|
+
run: |
|
|
1602
|
+
MISSING=""
|
|
1603
|
+
for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
|
|
1604
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
1605
|
+
done
|
|
1606
|
+
# SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
|
|
1607
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
1608
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
1609
|
+
else
|
|
1610
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
1611
|
+
fi
|
|
1612
|
+
FAILED=false
|
|
1613
|
+
if [ -n "$MISSING" ]; then
|
|
1614
|
+
echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
|
|
1615
|
+
FAILED=true
|
|
1616
|
+
fi
|
|
1617
|
+
if [ ! -f "$DOCKERFILE" ]; then
|
|
1618
|
+
echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
|
|
1619
|
+
FAILED=true
|
|
1620
|
+
fi
|
|
1621
|
+
if [ "$FAILED" = "true" ]; then
|
|
1622
|
+
exit 1
|
|
1623
|
+
fi
|
|
1624
|
+
echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
|
|
1625
|
+
|
|
1508
1626
|
- name: "[필수] .env 파일 생성"
|
|
1627
|
+
working-directory: ${{ env.PROJECT_PATH }}
|
|
1509
1628
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1510
1629
|
run: |
|
|
1511
1630
|
cat << 'EOF' > .env
|
|
@@ -1533,16 +1652,16 @@ jobs:
|
|
|
1533
1652
|
SUFFIX="pr-${{ steps.branch_info.outputs.container_number }}"
|
|
1534
1653
|
fi
|
|
1535
1654
|
echo "suffix=$SUFFIX" >> $GITHUB_OUTPUT
|
|
1536
|
-
echo "name=${{ env.PROJECT_NAME }}-${SUFFIX}" >> $GITHUB_OUTPUT
|
|
1655
|
+
echo "name=${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}-${SUFFIX}" >> $GITHUB_OUTPUT
|
|
1537
1656
|
|
|
1538
1657
|
- name: Docker 이미지 빌드 & Push
|
|
1539
1658
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1540
1659
|
uses: docker/build-push-action@v5
|
|
1541
1660
|
with:
|
|
1542
|
-
context: .
|
|
1543
|
-
file: ${{ env.DOCKERFILE_PATH }}
|
|
1661
|
+
context: ${{ env.PROJECT_PATH }}
|
|
1662
|
+
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
1544
1663
|
push: true
|
|
1545
|
-
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:${{ steps.container.outputs.suffix }}
|
|
1664
|
+
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}:${{ steps.container.outputs.suffix }}
|
|
1546
1665
|
cache-from: type=gha
|
|
1547
1666
|
cache-to: type=gha,mode=max
|
|
1548
1667
|
|
|
@@ -1615,7 +1734,7 @@ jobs:
|
|
|
1615
1734
|
fi
|
|
1616
1735
|
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
1617
1736
|
|
|
1618
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
1737
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
1619
1738
|
CONTAINER_NAME="${{ steps.container.outputs.name }}"
|
|
1620
1739
|
CONTAINER_SUFFIX="${{ steps.container.outputs.suffix }}"
|
|
1621
1740
|
IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${CONTAINER_SUFFIX}"
|
|
@@ -1739,7 +1858,7 @@ jobs:
|
|
|
1739
1858
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
1740
1859
|
const deployDuration = minutes > 0 ? `${minutes}분 ${seconds}초` : `${seconds}초`;
|
|
1741
1860
|
|
|
1742
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
1861
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1743
1862
|
const domainSuffix = '${{ env.PREVIEW_DOMAIN_SUFFIX }}';
|
|
1744
1863
|
const previewPort = '${{ env.PREVIEW_PORT }}';
|
|
1745
1864
|
const apiDocsPath = '${{ env.API_DOCS_PATH }}';
|
|
@@ -1841,6 +1960,7 @@ jobs:
|
|
|
1841
1960
|
`**[📋 빌드/배포 로그 확인](${runUrl})**`,
|
|
1842
1961
|
'',
|
|
1843
1962
|
'### 🔍 가능한 원인',
|
|
1963
|
+
'- 필수 Secret(DOCKERHUB_*, SERVER_*) 미등록 또는 Dockerfile 없음 → 로그의 "배포 사전 점검" 단계 확인',
|
|
1844
1964
|
'- Docker 이미지 빌드 실패 (Go 의존성/빌드 문제)',
|
|
1845
1965
|
'- 컨테이너 시작 실패 (애플리케이션 기동 오류)',
|
|
1846
1966
|
'- Health Check 타임아웃 (120초 내 기동 완료 안됨)',
|
|
@@ -1886,7 +2006,7 @@ jobs:
|
|
|
1886
2006
|
with:
|
|
1887
2007
|
script: |
|
|
1888
2008
|
const branchName = '${{ needs.check-command.outputs.custom_branch }}';
|
|
1889
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
2009
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
1890
2010
|
|
|
1891
2011
|
// 브랜치명에서 Issue 번호 추출 (#번호 패턴)
|
|
1892
2012
|
const issueMatch = branchName.match(/#(\d+)/);
|
|
@@ -1936,7 +2056,7 @@ jobs:
|
|
|
1936
2056
|
echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
|
|
1937
2057
|
|
|
1938
2058
|
CONTAINER_NAME="${{ steps.container_info.outputs.container_name }}"
|
|
1939
|
-
PROJECT_NAME="${{ env.PROJECT_NAME }}"
|
|
2059
|
+
PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
|
|
1940
2060
|
|
|
1941
2061
|
# 컨테이너명에서 suffix 추출
|
|
1942
2062
|
SUFFIX="${CONTAINER_NAME#${PROJECT_NAME}-}"
|
|
@@ -2002,7 +2122,7 @@ jobs:
|
|
|
2002
2122
|
with:
|
|
2003
2123
|
script: |
|
|
2004
2124
|
const branchName = '${{ needs.check-command.outputs.custom_branch }}';
|
|
2005
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
2125
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
2006
2126
|
|
|
2007
2127
|
// 브랜치명에서 Issue 번호 추출 (#번호 패턴)
|
|
2008
2128
|
const issueMatch = branchName.match(/#(\d+)/);
|
|
@@ -2060,7 +2180,7 @@ jobs:
|
|
|
2060
2180
|
script: |
|
|
2061
2181
|
const branchName = '${{ needs.check-command.outputs.custom_branch }}';
|
|
2062
2182
|
const containerName = '${{ steps.container_info.outputs.container_name }}';
|
|
2063
|
-
const projectName = '${{ env.PROJECT_NAME }}';
|
|
2183
|
+
const projectName = '${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}';
|
|
2064
2184
|
const domainSuffix = '${{ env.PREVIEW_DOMAIN_SUFFIX }}';
|
|
2065
2185
|
const previewPort = '${{ env.PREVIEW_PORT }}';
|
|
2066
2186
|
const domain = `${containerName}.${domainSuffix}`;
|