project-auto-wizard 0.13.3 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/bin/project-auto-wizard.js +18 -4
  3. package/package.json +2 -2
  4. package/payload/config/breaking-changes.json +28 -14
  5. package/payload/config/wizard-prompts.yml +102 -46
  6. package/payload/flutter-app/android/fastlane/Fastfile.playstore +44 -32
  7. package/payload/flutter-app/ios/ExportOptions.plist +8 -8
  8. package/payload/flutter-app/ios/fastlane/Fastfile +57 -43
  9. package/payload/scripts/changelog_manager.py +296 -257
  10. package/payload/scripts/issue_helper.py +54 -50
  11. package/payload/scripts/messages.py +2279 -0
  12. package/payload/scripts/truncate_release_notes.py +7 -6
  13. package/payload/scripts/version_manager.py +64 -61
  14. package/payload/version.yml.template +2 -1
  15. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +17 -12
  16. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +59 -34
  17. package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +17 -15
  18. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +17 -10
  19. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +54 -44
  20. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +24 -17
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +194 -184
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +226 -213
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +46 -42
  24. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +334 -241
  25. package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +152 -128
  26. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +246 -188
  27. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +353 -238
  28. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +96 -85
  29. package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -36
  30. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +945 -508
  31. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +155 -133
  32. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +76 -60
  33. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +97 -77
  34. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +62 -47
  35. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +942 -505
  36. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +148 -126
  37. package/payload/workflows/react/PROJECT-REACT-CI.yaml +86 -70
  38. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +112 -92
  39. package/payload/workflows/spring/PROJECT-SPRING-CI.yml +112 -82
  40. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +180 -150
  41. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +161 -131
  42. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +970 -549
  43. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +193 -162
  44. package/src/cli/args.js +98 -52
  45. package/src/cli/help.js +8 -41
  46. package/src/commands/doctor.js +85 -89
  47. package/src/commands/dry-run.js +63 -43
  48. package/src/commands/full.js +79 -77
  49. package/src/commands/install-settings.js +16 -15
  50. package/src/commands/interactive-flutter.js +20 -19
  51. package/src/commands/interactive.js +135 -132
  52. package/src/commands/purge.js +47 -42
  53. package/src/commands/status.js +36 -36
  54. package/src/commands/uninstall.js +43 -41
  55. package/src/context.js +12 -11
  56. package/src/core/assets.js +12 -11
  57. package/src/core/baseline.js +27 -27
  58. package/src/core/branches.js +29 -27
  59. package/src/core/branding.js +7 -6
  60. package/src/core/breaking-check.js +22 -21
  61. package/src/core/breaking.js +15 -8
  62. package/src/core/copy/app-files.js +5 -4
  63. package/src/core/copy/flutter-app.js +8 -8
  64. package/src/core/copy/gitignore.js +58 -50
  65. package/src/core/copy/readme.js +45 -35
  66. package/src/core/copy/simple.js +16 -15
  67. package/src/core/copy/workflows.js +131 -124
  68. package/src/core/deploy-style.js +51 -48
  69. package/src/core/detect-fs.js +57 -57
  70. package/src/core/detect.js +67 -65
  71. package/src/core/errors.js +2 -2
  72. package/src/core/flutter-doctor.js +17 -16
  73. package/src/core/flutter-hooks.js +33 -32
  74. package/src/core/flutter-options.js +34 -33
  75. package/src/core/fsutil.js +12 -12
  76. package/src/core/installed-stores.js +4 -4
  77. package/src/core/logger.js +42 -40
  78. package/src/core/paths-resolve.js +88 -86
  79. package/src/core/paths.js +10 -10
  80. package/src/core/release-options.js +8 -8
  81. package/src/core/removal-exec.js +14 -13
  82. package/src/core/removal-plan.js +37 -37
  83. package/src/core/types.js +47 -47
  84. package/src/core/verify.js +44 -38
  85. package/src/core/version-yml.js +76 -68
  86. package/src/core/wizard-env.js +46 -46
  87. package/src/core/wizard-labels.js +63 -41
  88. package/src/i18n/catalog/en/cli.js +50 -0
  89. package/src/i18n/catalog/en/commands.js +187 -0
  90. package/src/i18n/catalog/en/copy.js +19 -0
  91. package/src/i18n/catalog/en/core.js +74 -0
  92. package/src/i18n/catalog/en/core2.js +15 -0
  93. package/src/i18n/catalog/en/ui.js +221 -0
  94. package/src/i18n/catalog/en.js +12 -0
  95. package/src/i18n/catalog/index.js +5 -0
  96. package/src/i18n/catalog/ko/cli.js +50 -0
  97. package/src/i18n/catalog/ko/commands.js +187 -0
  98. package/src/i18n/catalog/ko/copy.js +19 -0
  99. package/src/i18n/catalog/ko/core.js +74 -0
  100. package/src/i18n/catalog/ko/core2.js +15 -0
  101. package/src/i18n/catalog/ko/ui.js +221 -0
  102. package/src/i18n/catalog/ko.js +10 -0
  103. package/src/i18n/index.js +44 -0
  104. package/src/i18n/languages.js +9 -0
  105. package/src/index.js +128 -94
  106. package/src/ui/ansi.js +7 -7
  107. package/src/ui/banner.js +7 -6
  108. package/src/ui/env-plan.js +82 -81
  109. package/src/ui/prompts.js +97 -122
  110. package/src/ui/readline-engine.js +59 -58
  111. package/src/ui/status-cards.js +37 -31
  112. package/src/ui/summary.js +89 -88
@@ -1,14 +1,14 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # Next.js CI (빌드 검증)
3
- # {{DEVELOP_BRANCH}} 브랜치 push·PR 시 npm ci, npm test(test 스크립트가 있을 때), npm run build로 검증합니다. node_modules와 .next/cache를 캐싱합니다.
2
+ # Next.js CI (build verification)
3
+ # On push/PR to the {{DEVELOP_BRANCH}} branch, verifies with npm ci, npm test (when a test script exists) and npm run build. Caches node_modules and .next/cache.
4
4
  #
5
5
  # GitHub Secrets
6
- # ENV_FILE (선택): .env 파일 내용. CI는 빌드 검증 목적이므로 배포 관련 Secrets는 불필요
6
+ # ENV_FILE (optional): contents of the .env file. CI only verifies the build, so no deploy-related Secrets are needed
7
7
  #
8
- # 프로젝트별 설정 (env 섹션)
9
- # PROJECT_NAME : 프로젝트 이름
10
- # NODE_VERSION : Node.js 버전 (기본: 20.15.0)
11
- # ENV_FILE : 환경변수 파일명 (기본: .env)
8
+ # Project settings (env section)
9
+ # PROJECT_NAME : project name
10
+ # NODE_VERSION : Node.js version (default: 20.15.0)
11
+ # ENV_FILE : environment file name (default: .env)
12
12
 
13
13
  name: PROJECT-NEXT-CI
14
14
 
@@ -23,7 +23,7 @@ env:
23
23
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
24
24
  NODE_VERSION: "20.15.0"
25
25
  ENV_FILE: ".env"
26
- # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
26
+ # Subdirectory of this project in a monorepo ('.' means always verify)
27
27
  PROJECT_PATH: "." # @wizard auto:project-path
28
28
 
29
29
  permissions:
@@ -32,9 +32,9 @@ permissions:
32
32
  issues: write
33
33
 
34
34
  jobs:
35
- # Job: 변경 감지 (모노레포에서 이 프로젝트 경로가 바뀌었는지 판별)
35
+ # Job: change detection (in a monorepo, checks whether this project's path changed)
36
36
  changes:
37
- name: 변경 감지
37
+ name: Detect changes
38
38
  runs-on: ubuntu-latest
39
39
  permissions:
40
40
  contents: read
@@ -45,45 +45,46 @@ jobs:
45
45
  - name: Checkout repository
46
46
  uses: actions/checkout@v7
47
47
 
48
- - name: 프로젝트 경로 변경 여부 판별
48
+ - name: Check whether the project path changed
49
49
  id: filter
50
50
  if: ${{ github.event_name != 'workflow_dispatch' }}
51
51
  uses: dorny/paths-filter@v4
52
52
  with:
53
- # push는 이번 push 범위(직전 커밋 before 대비)만 본다. 비워 두면 기본 브랜치 대비 누적 diff가 된다.
54
- # 새 브랜치 첫 push(before가 0)와 PR은 빈 값 → 기본 동작(기본 브랜치·PR base 대비)
53
+ # A push only looks at this push's range (against the previous commit, 'before'). Left empty it would be the cumulative diff against the default branch.
54
+ # The first push of a new branch (before is 0) and PRs get an empty value -> default behavior (against the default branch / PR base)
55
55
  base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
56
56
  filters: |
57
57
  project:
58
58
  - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
59
59
 
60
60
  build:
61
- name: Next.js 애플리케이션 빌드
61
+ name: Build Next.js application
62
62
  runs-on: ubuntu-latest
63
63
  needs: changes
64
64
  if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
65
- # 모노레포(--paths)면 그 하위 폴더에서 빌드한다
65
+ # In a monorepo (--paths), build inside that subfolder
66
66
  defaults:
67
67
  run:
68
68
  working-directory: ${{ env.PROJECT_PATH }}
69
69
 
70
70
  steps:
71
- - name: 코드 체크아웃
71
+ - name: Checkout repository
72
72
  uses: actions/checkout@v7
73
73
 
74
- - name: 환경변수 파일 생성 (${{ env.ENV_FILE }})
74
+ - name: Create environment file (${{ env.ENV_FILE }})
75
75
  run: |
76
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
76
77
  echo -e "${{ secrets.ENV_FILE || secrets.ENV }}" > ${{ env.ENV_FILE }}
77
- echo "✅ ${{ env.ENV_FILE }} 파일 생성 완료"
78
+ m cicd.env_file_created file="${{ env.ENV_FILE }}"
78
79
 
79
- - name: Node.js 설정
80
+ - name: Set up Node.js
80
81
  uses: actions/setup-node@v7
81
82
  with:
82
83
  node-version: ${{ env.NODE_VERSION }}
83
84
  cache: "npm"
84
85
  cache-dependency-path: ${{ env.PROJECT_PATH }}/package-lock.json
85
86
 
86
- - name: npm 의존성 캐싱
87
+ - name: Cache npm dependencies
87
88
  uses: actions/cache@v6
88
89
  with:
89
90
  path: ~/.npm
@@ -91,7 +92,7 @@ jobs:
91
92
  restore-keys: |
92
93
  ${{ runner.os }}-npm-
93
94
 
94
- - name: node_modules 캐싱
95
+ - name: Cache node_modules
95
96
  id: node-modules-cache
96
97
  uses: actions/cache@v6
97
98
  with:
@@ -100,16 +101,17 @@ jobs:
100
101
  restore-keys: |
101
102
  ${{ runner.os }}-node-modules-
102
103
 
103
- - name: 의존성 설치
104
+ - name: Install dependencies
104
105
  if: steps.node-modules-cache.outputs.cache-hit != 'true'
105
106
  run: |
106
- echo "📦 의존성 설치 중..."
107
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
108
+ m cibuild.node_deps_installing
107
109
  npm ci
108
- echo "✅ 의존성 설치 완료"
110
+ m cibuild.node_deps_done
109
111
 
110
- # Next.js 빌드 캐싱 (.next/cache)
111
- # 증분 빌드를 위해 .next/cache 폴더를 캐싱합니다
112
- - name: Next.js 빌드 캐싱
112
+ # Cache the Next.js build (.next/cache)
113
+ # Caches the .next/cache folder for incremental builds
114
+ - name: Cache Next.js build
113
115
  uses: actions/cache@v6
114
116
  with:
115
117
  path: ${{ env.PROJECT_PATH }}/.next/cache
@@ -118,66 +120,69 @@ jobs:
118
120
  ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
119
121
  ${{ runner.os }}-nextjs-
120
122
 
121
- # package.json에 test 스크립트가 있을 때만 실행한다 (npm init 기본값 "no test specified"는 없는 것으로 본다)
122
- - name: 테스트 실행
123
+ # Runs only when package.json has a test script (the npm init default "no test specified" counts as none)
124
+ - name: Run tests
123
125
  run: |
126
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
124
127
  TEST_SCRIPT=$(node -p "(require('./package.json').scripts || {}).test || ''")
125
128
  if [ -z "$TEST_SCRIPT" ] || echo "$TEST_SCRIPT" | grep -q "no test specified"; then
126
- echo "::notice::package.json에 test 스크립트가 없어 테스트를 건너뜁니다"
129
+ m cibuild.node_no_test_script
127
130
  exit 0
128
131
  fi
129
- echo "🧪 npm test 실행: $TEST_SCRIPT"
130
- # CI=true: watch 모드로 대기하는 테스트 러너(react-scripts 등)를 한 번만 실행
132
+ m cibuild.node_test_run script="$TEST_SCRIPT"
133
+ # CI=true: run watch-mode test runners (react-scripts, etc.) only once
131
134
  CI=true npm test
132
135
 
133
- - name: 프로젝트 빌드
136
+ - name: Build project
134
137
  id: build
135
138
  run: |
136
- echo "🔨 Next.js 빌드 시작..."
137
- echo "프로젝트: ${{ env.PROJECT_NAME }}"
138
- echo "Node.js: ${{ env.NODE_VERSION }}"
139
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
140
+ m cibuild.node_build_start_next
141
+ m cibuild.node_build_project project="${{ env.PROJECT_NAME }}"
142
+ m cibuild.node_build_node node="${{ env.NODE_VERSION }}"
139
143
  echo ""
140
144
 
141
- # 빌드 실행 및 로그 저장
145
+ # Run the build and save the log
142
146
  npm run build > build_log.txt 2>&1 || {
143
147
  echo "build_failed=true" >> $GITHUB_OUTPUT
144
148
  echo "status=failed" >> $GITHUB_OUTPUT
145
149
  echo ""
146
- echo "❌ 빌드 실패"
150
+ m cibuild.node_build_failed
147
151
  exit 0
148
152
  }
149
153
 
150
154
  echo "build_failed=false" >> $GITHUB_OUTPUT
151
155
  echo "status=success" >> $GITHUB_OUTPUT
152
- echo "✅ 빌드 완료"
156
+ m cibuild.node_build_ok
153
157
 
154
- # 빌드 결과 확인
158
+ # Check the build output
155
159
  if [ -d ".next" ]; then
156
160
  echo ""
157
- echo "📁 빌드 결과물:"
158
- echo " - .next/ 폴더 생성됨"
161
+ m cibuild.node_build_output
162
+ m cibuild.node_build_next_dir
159
163
  du -sh .next/ || true
160
164
  fi
161
165
 
162
- - name: 빌드 에러 로그 출력
166
+ - name: Print build error log
163
167
  if: steps.build.outputs.build_failed == 'true'
164
168
  run: |
169
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
165
170
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
166
- echo "❌ 빌드 실패 - 에러 로그"
171
+ m cibuild.node_errlog_title
167
172
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
168
173
  echo ""
169
174
 
170
175
  if [ -f "build_log.txt" ]; then
171
176
  tail -n 50 build_log.txt
172
177
  else
173
- echo "에러 로그 파일을 찾을 수 없습니다."
178
+ m cibuild.node_errlog_missing
174
179
  fi
175
180
 
176
181
  echo ""
177
182
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
178
183
  exit 1
179
184
 
180
- - name: 빌드 로그 업로드
185
+ - name: Upload build log
181
186
  if: always()
182
187
  uses: actions/upload-artifact@v7
183
188
  with:
@@ -185,41 +190,52 @@ jobs:
185
190
  path: ${{ env.PROJECT_PATH }}/build_log.txt
186
191
  retention-days: 7
187
192
 
188
- - name: 빌드 결과 요약
193
+ - name: Build result summary
189
194
  if: always()
190
195
  run: |
196
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
191
197
  echo ""
192
198
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
193
199
  if [ "${{ steps.build.outputs.status }}" = "success" ]; then
194
- echo "🎉 Next.js 빌드 완료!"
200
+ m cibuild.node_result_next_ok
195
201
  else
196
- echo "❌ Next.js 빌드 실패"
202
+ m cibuild.node_result_next_fail
197
203
  fi
198
204
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
199
205
  echo ""
200
- echo "📊 빌드 결과:"
201
- echo " 📦 프로젝트: ${{ env.PROJECT_NAME }}"
202
- echo " 📌 Node.js 버전: ${{ env.NODE_VERSION }}"
203
- echo " 🆙 빌드 상태: ${{ steps.build.outputs.status }}"
204
- echo " 🌿 브랜치: ${{ github.ref_name }}"
205
- echo " 📝 커밋: ${{ github.sha }}"
206
- echo " 🕐 시간: $(date '+%Y-%m-%d %H:%M:%S UTC')"
206
+ m cibuild.node_result_title
207
+ m cibuild.node_result_project project="${{ env.PROJECT_NAME }}"
208
+ m cibuild.node_result_node node="${{ env.NODE_VERSION }}"
209
+ m cibuild.node_result_status status="${{ steps.build.outputs.status }}"
210
+ m cibuild.node_result_branch branch="${{ github.ref_name }}"
211
+ m cibuild.node_result_commit sha="${{ github.sha }}"
212
+ m cibuild.node_result_time time="$(date '+%Y-%m-%d %H:%M:%S UTC')"
207
213
  echo ""
208
214
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
209
215
 
210
- # Job: CI Gate (required check로 등록할 단일 job)
216
+ # Job: CI Gate (the single job to register as a required check)
211
217
  ci-gate:
212
218
  name: CI Gate
213
219
  if: ${{ always() }}
214
220
  needs: [changes, build]
215
221
  runs-on: ubuntu-latest
216
222
  steps:
217
- - name: 결과 집계
223
+ # Only the message catalog is needed here, so check out just that
224
+ - name: Checkout message catalog
225
+ uses: actions/checkout@v7
226
+ with:
227
+ sparse-checkout: |
228
+ .github/scripts/messages.py
229
+ version.yml
230
+ sparse-checkout-cone-mode: false
231
+
232
+ - name: Aggregate results
218
233
  env:
219
234
  RESULTS: ${{ toJSON(needs.*.result) }}
220
235
  run: |
221
- echo "needs 결과: $RESULTS"
236
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
237
+ m cibuild.gate_results results="$RESULTS"
222
238
  if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
223
- echo "실패하거나 취소된 job이 있습니다."
239
+ m cibuild.gate_failed
224
240
  exit 1
225
241
  fi
@@ -1,20 +1,20 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # Next.js CI/CD 배포
3
- # {{MAIN_BRANCH}} 브랜치 푸시 시 Docker 이미지를 빌드하고 배포합니다. SSR 지원을 위해 Node.js 런타임 컨테이너로 배포됩니다.
2
+ # Next.js CI/CD deployment
3
+ # Builds a Docker image and deploys it when the {{MAIN_BRANCH}} branch is pushed. Deployed as a Node.js runtime container to support SSR.
4
4
  #
5
5
  # GitHub Secrets
6
- # ENV_FILE: .env 파일 내용
7
- # DOCKERHUB_USERNAME: DockerHub 사용자명
8
- # DOCKERHUB_TOKEN: DockerHub 액세스 토큰
9
- # SERVER_HOST: 배포 서버 주소
10
- # SERVER_USER: SSH 사용자명
11
- # SERVER_PASSWORD: SSH 비밀번호 (SSH_AUTH_METHOD=password일 때)
12
- # SSH_KEY: SSH 개인키 .pem 내용 (SSH_AUTH_METHOD=key일 때, AWS EC2 등)
13
- # PROJECT_DEPLOY_PORT (선택): 배포 포트 (기본: 3000)
6
+ # ENV_FILE: contents of the .env file
7
+ # DOCKERHUB_USERNAME: DockerHub username
8
+ # DOCKERHUB_TOKEN: DockerHub access token
9
+ # SERVER_HOST: deploy server address
10
+ # SERVER_USER: SSH username
11
+ # SERVER_PASSWORD: SSH password (when SSH_AUTH_METHOD=password)
12
+ # SSH_KEY: contents of the SSH private key .pem (when SSH_AUTH_METHOD=key, e.g. AWS EC2)
13
+ # PROJECT_DEPLOY_PORT (optional): deploy port (default: 3000)
14
14
  #
15
- # 환경변수 (env 섹션에서 설정)
16
- # SSH_AUTH_METHOD: SSH 인증 방식 password | key (기본: password)
17
- # SSH_PORT (기본: 2022), SSH_COMMAND_TIMEOUT (기본: 600s), SSH_CONNECTION_TIMEOUT (기본: 60s)
15
+ # Environment variables (set in the env section)
16
+ # SSH_AUTH_METHOD: SSH auth method password | key (default: password)
17
+ # SSH_PORT (default: 2022), SSH_COMMAND_TIMEOUT (default: 600s), SSH_CONNECTION_TIMEOUT (default: 60s)
18
18
 
19
19
  name: PROJECT-NEXT-CICD
20
20
 
@@ -22,41 +22,42 @@ on:
22
22
  push:
23
23
  branches:
24
24
  - "{{MAIN_BRANCH}}"
25
- # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
25
+ # @wizard paths-anchor (for a monorepo the integrator injects the paths filter here)
26
26
  workflow_dispatch:
27
27
 
28
28
  env:
29
29
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
30
- # 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
30
+ # Subdirectory of this project in a monorepo (--paths). Base for the build and Docker context ('.' means the repo root)
31
31
  PROJECT_PATH: "." # @wizard auto:project-path
32
32
  DOCKER_IMAGE_PREFIX: "nextjs-container"
33
33
  NODE_VERSION: "20.15.0"
34
34
  ENV_FILE_NAME: ".env"
35
35
 
36
- # SSH 인증 방식: "password"(Synology·일반 서버) | "key"(AWS EC2·.pem)
37
- # password → SERVER_PASSWORD secret 사용
38
- # key → SSH_KEY secret 사용 (.pem 파일 전체 내용을 secret 값으로)
36
+ # SSH auth method: "password" (Synology, generic servers) | "key" (AWS EC2, .pem)
37
+ # password -> uses the SERVER_PASSWORD secret
38
+ # key -> uses the SSH_KEY secret (the whole .pem file content as the secret value)
39
39
  SSH_AUTH_METHOD: "password" # @wizard ask:password
40
40
 
41
41
  SSH_PORT: "__SSH_PORT__" # @wizard ask:2022
42
- SSH_COMMAND_TIMEOUT: "600s" # SSH 명령 실행 타임아웃
43
- SSH_CONNECTION_TIMEOUT: "60s" # SSH 연결 타임아웃
42
+ SSH_COMMAND_TIMEOUT: "600s" # SSH command execution timeout
43
+ SSH_CONNECTION_TIMEOUT: "60s" # SSH connection timeout
44
44
 
45
45
  jobs:
46
46
  build:
47
- name: Next.js 애플리케이션 빌드
47
+ name: Build Next.js application
48
48
  runs-on: ubuntu-latest
49
- # 모노레포(--paths)면 그 하위 폴더에서 빌드한다
49
+ # In a monorepo (--paths), build inside that subfolder
50
50
  defaults:
51
51
  run:
52
52
  working-directory: ${{ env.PROJECT_PATH }}
53
53
 
54
54
  steps:
55
- - name: 코드 체크아웃
55
+ - name: Checkout repository
56
56
  uses: actions/checkout@v7
57
57
 
58
- # 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
59
- - name: 배포 사전 점검 (Secret·Dockerfile)
58
+ # If a required Secret or the Dockerfile is missing, report the missing item and stop
59
+ # instead of failing later with a third-party error such as docker login
60
+ - name: Deploy pre-check (Secrets and Dockerfile)
60
61
  working-directory: ${{ env.PROJECT_PATH }}
61
62
  env:
62
63
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -67,11 +68,12 @@ jobs:
67
68
  SSH_KEY: ${{ secrets.SSH_KEY }}
68
69
  DOCKERFILE: Dockerfile
69
70
  run: |
71
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
70
72
  MISSING=""
71
73
  for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
72
74
  [ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
73
75
  done
74
- # SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
76
+ # SSH_AUTH_METHOD=key needs SSH_KEY, otherwise SERVER_PASSWORD is required
75
77
  if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
76
78
  [ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
77
79
  else
@@ -79,33 +81,34 @@ jobs:
79
81
  fi
80
82
  FAILED=false
81
83
  if [ -n "$MISSING" ]; then
82
- echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
84
+ echo "::error title=$(m cicd.precheck_secret_title)::$(m cicd.precheck_secret_body missing="$MISSING")"
83
85
  FAILED=true
84
86
  fi
85
87
  if [ ! -f "$DOCKERFILE" ]; then
86
- echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
88
+ echo "::error title=$(m cicd.precheck_dockerfile_title)::$(m cicd.precheck_dockerfile_body path="${PROJECT_PATH}/${DOCKERFILE#./}")"
87
89
  FAILED=true
88
90
  fi
89
91
  if [ "$FAILED" = "true" ]; then
90
92
  exit 1
91
93
  fi
92
- echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
94
+ m cicd.precheck_ok
93
95
 
94
- - name: Node.js 설정
96
+ - name: Set up Node.js
95
97
  uses: actions/setup-node@v7
96
98
  with:
97
99
  node-version: ${{ env.NODE_VERSION }}
98
100
  cache: 'npm'
99
101
  cache-dependency-path: ${{ env.PROJECT_PATH }}/package-lock.json
100
102
 
101
- - name: 환경변수 파일 생성 (${{ env.ENV_FILE_NAME }})
103
+ - name: Create environment file (${{ env.ENV_FILE_NAME }})
102
104
  run: |
105
+ m() { (cd "$GITHUB_WORKSPACE" && python3 .github/scripts/messages.py get "$@"); }
103
106
  cat << 'EOF' > ./${{ env.ENV_FILE_NAME }}
104
107
  ${{ secrets.ENV_FILE || secrets.ENV }}
105
108
  EOF
106
- echo "✅ ${{ env.ENV_FILE_NAME }} 파일 생성 완료"
109
+ m cicd.env_file_created file="${{ env.ENV_FILE_NAME }}"
107
110
 
108
- - name: npm 의존성 캐싱
111
+ - name: Cache npm dependencies
109
112
  uses: actions/cache@v6
110
113
  with:
111
114
  path: ~/.npm
@@ -113,7 +116,7 @@ jobs:
113
116
  restore-keys: |
114
117
  ${{ runner.os }}-npm-
115
118
 
116
- - name: node_modules 캐싱
119
+ - name: Cache node_modules
117
120
  id: node-modules-cache
118
121
  uses: actions/cache@v6
119
122
  with:
@@ -122,11 +125,11 @@ jobs:
122
125
  restore-keys: |
123
126
  ${{ runner.os }}-node-modules-
124
127
 
125
- - name: 의존성 설치
128
+ - name: Install dependencies
126
129
  if: steps.node-modules-cache.outputs.cache-hit != 'true'
127
130
  run: npm ci
128
131
 
129
- - name: Next.js 빌드 캐싱
132
+ - name: Cache Next.js build
130
133
  uses: actions/cache@v6
131
134
  with:
132
135
  path: ${{ env.PROJECT_PATH }}/.next/cache
@@ -138,10 +141,10 @@ jobs:
138
141
  - name: Build with npm
139
142
  run: npm run build
140
143
 
141
- - name: Docker 빌드환경 설정
144
+ - name: Set up Docker Buildx
142
145
  uses: docker/setup-buildx-action@v3
143
146
 
144
- - name: DockerHub 로그인
147
+ - name: Log in to DockerHub
145
148
  uses: docker/login-action@v3
146
149
  with:
147
150
  username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -155,7 +158,7 @@ jobs:
155
158
  restore-keys: |
156
159
  ${{ runner.os }}-buildx-
157
160
 
158
- - name: Docker 이미지 빌드 및 푸시
161
+ - name: Build and push Docker image
159
162
  uses: docker/build-push-action@v5
160
163
  with:
161
164
  context: ${{ env.PROJECT_PATH }}
@@ -171,11 +174,25 @@ jobs:
171
174
  mv /tmp/.buildx-cache-new /tmp/.buildx-cache
172
175
 
173
176
  deploy:
174
- name: 원격 서버 배포
177
+ name: Deploy to remote server
175
178
  needs: build
176
179
  runs-on: ubuntu-latest
177
180
 
178
181
  steps:
182
+ # The deploy script runs on the remote server, so the messages are resolved here
183
+ # and handed to it through env vars (PAW_M_*)
184
+ - name: Checkout message catalog
185
+ uses: actions/checkout@v7
186
+ with:
187
+ sparse-checkout: |
188
+ .github/scripts/messages.py
189
+ version.yml
190
+ sparse-checkout-cone-mode: false
191
+
192
+ - name: Load messages
193
+ run: |
194
+ python3 .github/scripts/messages.py dump cicd. | PYTHONIOENCODING=utf-8 python3 -c 'import json,sys; [print("PAW_M_" + k.replace(".", "_") + "=" + v) for k, v in json.load(sys.stdin).items()]' >> "$GITHUB_ENV"
195
+
179
196
  - name: Deploy
180
197
  uses: appleboy/ssh-action@v1.0.3
181
198
  env:
@@ -192,65 +209,68 @@ jobs:
192
209
  script: |
193
210
  set -e
194
211
 
195
- # 배포 환경 변수 설정
196
- echo "🔧 환경변수 설정.."
212
+ # Fill the {name} placeholders of a message template (usage: m "template" name=value ...)
213
+ m() { local s="$1" kv; shift; for kv in "$@"; do s="${s//\{${kv%%=*}\}/${kv#*=}}"; done; printf '%s\n' "$s"; }
214
+
215
+ # Set deploy environment variables
216
+ m "${{ env.PAW_M_cicd_setup_env }}"
197
217
  export PATH=$PATH:/usr/local/bin
198
218
  export PW=${{ secrets.SERVER_PASSWORD }}
199
219
 
200
- # SSH 인증 방식에 따른 sudo 추상화
201
- # password 모드: echo $PW | sudo -S (Synology 등 sudo 비밀번호 필요 서버)
202
- # key 모드: sudo 직접 (AWS EC2 등 passwordless sudo 서버)
220
+ # sudo abstraction per SSH auth method
221
+ # password mode: echo $PW | sudo -S (servers that need a sudo password, e.g. Synology)
222
+ # key mode: plain sudo (passwordless-sudo servers, e.g. AWS EC2)
203
223
  SSH_AUTH_METHOD="${SSH_AUTH_METHOD:-password}"
204
224
  if [ "${SSH_AUTH_METHOD}" = "key" ]; then
205
225
  SUDO() { sudo "$@"; }
206
226
  else
207
227
  SUDO() { echo "$PW" | sudo -S "$@"; }
208
228
  fi
209
- echo "🔐 SSH 인증 방식: ${SSH_AUTH_METHOD}"
229
+ m "${{ env.PAW_M_cicd_ssh_auth }}" method="${SSH_AUTH_METHOD}"
210
230
 
211
231
  BRANCH=${{ github.ref_name }}
212
232
  PROJECT_NAME="${{ env.PROJECT_NAME }}"
213
233
 
214
- # 브랜치별 포트 및 컨테이너명 설정
234
+ # Per-branch port and container name
215
235
  PORT=3000
216
236
  CONTAINER_NAME="${PROJECT_NAME}-nextjs"
217
237
 
218
238
  if [ "$BRANCH" == "{{MAIN_BRANCH}}" ]; then
219
239
  PORT=${{ secrets.PROJECT_DEPLOY_PORT || '3000' }}
220
240
  CONTAINER_NAME="${PROJECT_NAME}-nextjs-deploy"
221
- echo "🚀 배포 환경으로 배포합니다 (브랜치: $BRANCH)"
241
+ m "${{ env.PAW_M_cicd_deploy_start }}" branch="$BRANCH"
222
242
  else
223
- echo "⚠️ 지원하지 않는 브랜치입니다: $BRANCH"
243
+ m "${{ env.PAW_M_cicd_branch_unsupported }}" branch="$BRANCH"
224
244
  exit 1
225
245
  fi
226
246
 
227
- echo "📋 배포 설정 정보:"
228
- echo " - 브랜치: $BRANCH"
229
- echo " - 프로젝트: $PROJECT_NAME"
230
- echo " - 컨테이너 이름: $CONTAINER_NAME"
231
- echo " - 포트: $PORT"
232
- echo " - Docker 이미지: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
247
+ m "${{ env.PAW_M_cicd_config_title }}"
248
+ m "${{ env.PAW_M_cicd_config_branch }}" branch="$BRANCH"
249
+ m "${{ env.PAW_M_cicd_config_project }}" project="$PROJECT_NAME"
250
+ m "${{ env.PAW_M_cicd_config_container }}" container="$CONTAINER_NAME"
251
+ m "${{ env.PAW_M_cicd_config_port }}" port="$PORT"
252
+ m "${{ env.PAW_M_cicd_config_image }}" image="${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
233
253
 
234
- # Docker 이미지 풀 (Pull)
235
- echo "⬇️ Docker 이미지 풀..."
254
+ # Pull the Docker image
255
+ m "${{ env.PAW_M_cicd_pull_image_short }}"
236
256
  SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
237
257
 
238
- # 기존 컨테이너 정리
239
- echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
258
+ # Clean up the existing container
259
+ m "${{ env.PAW_M_cicd_container_check }}" container="$CONTAINER_NAME"
240
260
 
241
261
  if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
242
- echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
262
+ m "${{ env.PAW_M_cicd_container_exists }}" container="$CONTAINER_NAME"
243
263
  SUDO docker rm -f $CONTAINER_NAME
244
- echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 삭제되었습니다."
264
+ m "${{ env.PAW_M_cicd_container_removed }}" container="$CONTAINER_NAME"
245
265
  else
246
- echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
266
+ m "${{ env.PAW_M_cicd_container_none }}" container="$CONTAINER_NAME"
247
267
  fi
248
268
 
249
- # 새 컨테이너 실행
250
- echo "🚀 새로운 컨테이너 $CONTAINER_NAME 실행 중..."
269
+ # Start the new container
270
+ m "${{ env.PAW_M_cicd_container_run }}" container="$CONTAINER_NAME"
251
271
 
252
- # Next.js는 SSR을 위해 Node.js 서버가 필요합니다
253
- # standalone 모드 사용 시 node server.js로 실행
272
+ # Next.js needs a Node.js server for SSR
273
+ # With standalone mode, run it with node server.js
254
274
  SUDO docker run -d \
255
275
  -p ${PORT}:3000 \
256
276
  --name $CONTAINER_NAME \
@@ -260,19 +280,19 @@ jobs:
260
280
  --restart unless-stopped \
261
281
  ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
262
282
 
263
- # 배포 완료 확인
264
- echo "✅ 배포가 성공적으로 완료되었습니다!"
283
+ # Confirm the deployment
284
+ m "${{ env.PAW_M_cicd_deploy_done }}"
265
285
  echo ""
266
- echo "📋 배포 결과 요약:"
267
- echo " 🎯 프로젝트: $PROJECT_NAME"
268
- echo " 🌿 브랜치: $BRANCH"
269
- echo " 🐳 컨테이너: $CONTAINER_NAME"
270
- echo " 🌐 포트: $PORT"
271
- echo " ⏰ 배포 시간: $(date '+%Y-%m-%d %H:%M:%S')"
286
+ m "${{ env.PAW_M_cicd_summary_title }}"
287
+ m "${{ env.PAW_M_cicd_summary_project }}" project="$PROJECT_NAME"
288
+ m "${{ env.PAW_M_cicd_summary_branch }}" branch="$BRANCH"
289
+ m "${{ env.PAW_M_cicd_summary_container }}" container="$CONTAINER_NAME"
290
+ m "${{ env.PAW_M_cicd_summary_port }}" port="$PORT"
291
+ m "${{ env.PAW_M_cicd_summary_time }}" time="$(date '+%Y-%m-%d %H:%M:%S')"
272
292
  echo ""
273
- echo "🔗 접속 URL: http://${{ secrets.SERVER_HOST }}:${PORT}"
293
+ m "${{ env.PAW_M_cicd_summary_url }}" url="http://${{ secrets.SERVER_HOST }}:${PORT}"
274
294
 
275
- # Next.js Dockerfile 예시 (standalone 모드)
295
+ # Next.js Dockerfile example (standalone mode)
276
296
  #
277
297
  # # Stage 1: Dependencies
278
298
  # FROM node:20-alpine AS deps
@@ -304,7 +324,7 @@ jobs:
304
324
  # ENV PORT 3000
305
325
  # CMD ["node", "server.js"]
306
326
  #
307
- # next.config.js에 standalone 설정 추가:
327
+ # Add the standalone setting to next.config.js:
308
328
  # module.exports = {
309
329
  # output: 'standalone',
310
330
  # }