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.
Files changed (86) hide show
  1. package/README.ja.md +165 -0
  2. package/README.ko.md +165 -0
  3. package/README.md +107 -286
  4. package/README.zh-CN.md +165 -0
  5. package/bin/project-auto-wizard.js +1 -2
  6. package/package.json +7 -3
  7. package/payload/config/breaking-changes.json +24 -0
  8. package/payload/config/wizard-prompts.yml +45 -0
  9. package/payload/scripts/changelog_manager.py +141 -46
  10. package/payload/scripts/issue_helper.py +34 -5
  11. package/payload/scripts/version_manager.py +397 -97
  12. package/payload/version.yml.template +4 -2
  13. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +39 -9
  14. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +165 -38
  15. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +14 -5
  16. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +220 -6
  17. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +89 -3
  18. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +78 -16
  19. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +72 -16
  20. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +62 -20
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +51 -13
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +75 -11
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +52 -3
  24. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +60 -11
  25. package/payload/workflows/go/PROJECT-GO-CI.yaml +10 -1
  26. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +148 -28
  27. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +45 -4
  28. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +25 -3
  29. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +83 -9
  30. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +70 -6
  31. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +148 -28
  32. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +45 -4
  33. package/payload/workflows/react/PROJECT-REACT-CI.yaml +25 -3
  34. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +84 -10
  35. package/payload/workflows/spring/PROJECT-SPRING-CI.yml +13 -3
  36. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +47 -5
  37. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +47 -5
  38. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +153 -30
  39. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +47 -5
  40. package/src/cli/args.js +33 -24
  41. package/src/cli/help.js +16 -4
  42. package/src/commands/doctor.js +17 -10
  43. package/src/commands/dry-run.js +54 -1
  44. package/src/commands/full.js +127 -50
  45. package/src/commands/interactive-flutter.js +1 -1
  46. package/src/commands/interactive.js +124 -56
  47. package/src/commands/purge.js +59 -17
  48. package/src/commands/status.js +16 -1
  49. package/src/commands/uninstall.js +58 -13
  50. package/src/context.js +5 -5
  51. package/src/core/baseline.js +20 -5
  52. package/src/core/branches.js +19 -1
  53. package/src/core/branding.js +1 -1
  54. package/src/core/breaking-check.js +14 -19
  55. package/src/core/breaking.js +7 -3
  56. package/src/core/copy/gitignore.js +20 -12
  57. package/src/core/copy/readme.js +24 -5
  58. package/src/core/copy/simple.js +52 -13
  59. package/src/core/copy/workflows.js +90 -47
  60. package/src/core/deploy-style.js +83 -11
  61. package/src/core/detect-fs.js +127 -24
  62. package/src/core/detect.js +131 -47
  63. package/src/core/errors.js +3 -0
  64. package/src/core/flutter-options.js +4 -3
  65. package/src/core/fsutil.js +23 -6
  66. package/src/core/logger.js +55 -19
  67. package/src/core/paths-resolve.js +50 -47
  68. package/src/core/paths.js +26 -1
  69. package/src/core/release-options.js +23 -0
  70. package/src/core/removal-plan.js +75 -19
  71. package/src/core/types.js +113 -0
  72. package/src/core/verify.js +85 -19
  73. package/src/core/version-yml.js +42 -8
  74. package/src/core/wizard-env.js +21 -14
  75. package/src/core/wizard-labels.js +34 -25
  76. package/src/index.js +122 -49
  77. package/src/ui/ansi.js +3 -1
  78. package/src/ui/banner.js +12 -8
  79. package/src/ui/env-plan.js +68 -44
  80. package/src/ui/prompts.js +22 -12
  81. package/src/ui/readline-engine.js +109 -22
  82. package/src/ui/status-cards.js +10 -5
  83. package/src/ui/summary.js +71 -33
  84. package/payload/scripts/__pycache__/changelog_manager.cpython-314.pyc +0 -0
  85. package/payload/scripts/__pycache__/issue_helper.cpython-314.pyc +0 -0
  86. package/payload/scripts/__pycache__/version_manager.cpython-314.pyc +0 -0
@@ -32,6 +32,10 @@ on:
32
32
  env:
33
33
  # 프로젝트 고유 식별자
34
34
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
35
+ # 모노레포(--paths)에서 이 프로젝트가 있는 하위 경로. 빌드·Docker context의 기준 ('.'이면 레포 루트)
36
+ PROJECT_PATH: "." # @wizard auto:project-path
37
+ # 모노레포(PROJECT_PATH가 '.'이 아님)에서는 이미지·컨테이너·도메인 이름에 '-go'를 붙여
38
+ # 같은 레포의 다른 타입 서비스와 이름이 겹치지 않게 한다 (예: my-app-go)
35
39
 
36
40
  DEPLOY_PORT: "__DEPLOY_PORT__" # @wizard ask:8080
37
41
 
@@ -71,6 +75,42 @@ jobs:
71
75
  - name: 코드 체크아웃
72
76
  uses: actions/checkout@v7
73
77
 
78
+ # 필수 Secret·Dockerfile이 없으면 docker 로그인 같은 서드파티 오류 대신 빠진 항목을 알려 주고 멈춘다
79
+ - name: 배포 사전 점검 (Secret·Dockerfile)
80
+ working-directory: ${{ env.PROJECT_PATH }}
81
+ env:
82
+ DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
83
+ DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
84
+ SERVER_HOST: ${{ secrets.SERVER_HOST }}
85
+ SERVER_USER: ${{ secrets.SERVER_USER }}
86
+ SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
87
+ SSH_KEY: ${{ secrets.SSH_KEY }}
88
+ DOCKERFILE: Dockerfile
89
+ run: |
90
+ MISSING=""
91
+ for NAME in DOCKERHUB_USERNAME DOCKERHUB_TOKEN SERVER_HOST SERVER_USER; do
92
+ [ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
93
+ done
94
+ # SSH_AUTH_METHOD=key면 SSH_KEY, 아니면 SERVER_PASSWORD가 필요하다
95
+ if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
96
+ [ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
97
+ else
98
+ [ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
99
+ fi
100
+ FAILED=false
101
+ if [ -n "$MISSING" ]; then
102
+ echo "::error title=필수 Secret 누락::등록되지 않은 GitHub Secret:$MISSING — Settings → Secrets and variables → Actions에서 등록하세요"
103
+ FAILED=true
104
+ fi
105
+ if [ ! -f "$DOCKERFILE" ]; then
106
+ echo "::error title=Dockerfile 없음::${PROJECT_PATH}/${DOCKERFILE#./} 파일이 없습니다. 이 워크플로우는 Docker 이미지로 배포하므로 Dockerfile이 필요합니다 (서버 배포를 하지 않는다면 이 워크플로우 파일을 삭제하세요)"
107
+ FAILED=true
108
+ fi
109
+ if [ "$FAILED" = "true" ]; then
110
+ exit 1
111
+ fi
112
+ echo "✅ 사전 점검 통과: 필수 Secret과 Dockerfile이 모두 있습니다"
113
+
74
114
  - name: 디스크 공간 확보
75
115
  run: |
76
116
  echo "📊 빌드 전 디스크 사용량:"
@@ -89,6 +129,7 @@ jobs:
89
129
  df -h
90
130
 
91
131
  - name: .env 파일 생성
132
+ working-directory: ${{ env.PROJECT_PATH }}
92
133
  run: |
93
134
  cat > .env << 'EOF'
94
135
  ${{ secrets.ENV_FILE }}
@@ -107,10 +148,10 @@ jobs:
107
148
  - name: Docker 이미지 빌드 및 푸시
108
149
  uses: docker/build-push-action@v5
109
150
  with:
110
- context: .
111
- file: ./Dockerfile
151
+ context: ${{ env.PROJECT_PATH }}
152
+ file: ${{ env.PROJECT_PATH }}/Dockerfile
112
153
  push: true
113
- tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:${{ github.ref_name }}
154
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}:${{ github.ref_name }}
114
155
  # GitHub Actions 캐시 사용 (로컬 디스크 공간 절약)
115
156
  cache-from: type=gha
116
157
  cache-to: type=gha,mode=max
@@ -164,7 +205,7 @@ jobs:
164
205
 
165
206
  BRANCH=${{ github.ref_name }}
166
207
 
167
- PROJECT_NAME="${{ env.PROJECT_NAME }}"
208
+ PROJECT_NAME="${{ env.PROJECT_PATH != '.' && format('{0}-go', env.PROJECT_NAME) || env.PROJECT_NAME }}"
168
209
 
169
210
  # 포트 및 컨테이너명 설정
170
211
  PORT=${{ env.DEPLOY_PORT }}
@@ -1,6 +1,6 @@
1
1
  # project-auto-wizard:managed-workflow
2
2
  # Next.js CI (빌드 검증)
3
- # {{MAIN_BRANCH}} 브랜치 푸시 시 npm ci와 npm run build로 빌드를 검증합니다. node_modules와 .next/cache를 캐싱합니다.
3
+ # {{DEVELOP_BRANCH}} 브랜치 push·PR 시 npm ci, npm test(test 스크립트가 있을 때), npm run build로 검증합니다. node_modules와 .next/cache를 캐싱합니다.
4
4
  #
5
5
  # GitHub Secrets
6
6
  # ENV_FILE (선택): .env 파일 내용. CI는 빌드 검증 목적이므로 배포 관련 Secrets는 불필요
@@ -15,6 +15,8 @@ name: PROJECT-NEXT-CI
15
15
  on:
16
16
  push:
17
17
  branches: ["{{DEVELOP_BRANCH}}"]
18
+ pull_request:
19
+ branches: ["{{DEVELOP_BRANCH}}"]
18
20
  workflow_dispatch:
19
21
 
20
22
  env:
@@ -48,6 +50,9 @@ jobs:
48
50
  if: ${{ github.event_name != 'workflow_dispatch' }}
49
51
  uses: dorny/paths-filter@v4
50
52
  with:
53
+ # push는 이번 push 범위(직전 커밋 before 대비)만 본다. 비워 두면 기본 브랜치 대비 누적 diff가 된다.
54
+ # 새 브랜치 첫 push(before가 0)와 PR은 빈 값 → 기본 동작(기본 브랜치·PR base 대비)
55
+ base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
51
56
  filters: |
52
57
  project:
53
58
  - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
@@ -57,6 +62,10 @@ jobs:
57
62
  runs-on: ubuntu-latest
58
63
  needs: changes
59
64
  if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
65
+ # 모노레포(--paths)면 그 하위 폴더에서 빌드한다
66
+ defaults:
67
+ run:
68
+ working-directory: ${{ env.PROJECT_PATH }}
60
69
 
61
70
  steps:
62
71
  - name: 코드 체크아웃
@@ -72,6 +81,7 @@ jobs:
72
81
  with:
73
82
  node-version: ${{ env.NODE_VERSION }}
74
83
  cache: "npm"
84
+ cache-dependency-path: ${{ env.PROJECT_PATH }}/package-lock.json
75
85
 
76
86
  - name: npm 의존성 캐싱
77
87
  uses: actions/cache@v6
@@ -102,12 +112,24 @@ jobs:
102
112
  - name: Next.js 빌드 캐싱
103
113
  uses: actions/cache@v6
104
114
  with:
105
- path: .next/cache
115
+ path: ${{ env.PROJECT_PATH }}/.next/cache
106
116
  key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
107
117
  restore-keys: |
108
118
  ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
109
119
  ${{ runner.os }}-nextjs-
110
120
 
121
+ # package.json에 test 스크립트가 있을 때만 실행한다 (npm init 기본값 "no test specified"는 없는 것으로 본다)
122
+ - name: 테스트 실행
123
+ run: |
124
+ TEST_SCRIPT=$(node -p "(require('./package.json').scripts || {}).test || ''")
125
+ if [ -z "$TEST_SCRIPT" ] || echo "$TEST_SCRIPT" | grep -q "no test specified"; then
126
+ echo "::notice::package.json에 test 스크립트가 없어 테스트를 건너뜁니다"
127
+ exit 0
128
+ fi
129
+ echo "🧪 npm test 실행: $TEST_SCRIPT"
130
+ # CI=true: watch 모드로 대기하는 테스트 러너(react-scripts 등)를 한 번만 실행
131
+ CI=true npm test
132
+
111
133
  - name: 프로젝트 빌드
112
134
  id: build
113
135
  run: |
@@ -160,7 +182,7 @@ jobs:
160
182
  uses: actions/upload-artifact@v7
161
183
  with:
162
184
  name: build-log
163
- path: build_log.txt
185
+ path: ${{ env.PROJECT_PATH }}/build_log.txt
164
186
  retention-days: 7
165
187
 
166
188
  - name: 빌드 결과 요약
@@ -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-NEXT-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: "nextjs-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: 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: ./Dockerfile
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
- port: 2022
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
  BRANCH=${{ github.ref_name }}
138
212
  PROJECT_NAME="${{ env.PROJECT_NAME }}"
139
213
 
@@ -159,14 +233,14 @@ jobs:
159
233
 
160
234
  # Docker 이미지 풀 (Pull)
161
235
  echo "⬇️ Docker 이미지 풀..."
162
- echo $PW | sudo -S docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
236
+ SUDO docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
163
237
 
164
238
  # 기존 컨테이너 정리
165
239
  echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
166
240
 
167
- if sudo docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
241
+ if SUDO docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
168
242
  echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
169
- echo $PW | sudo -S docker rm -f $CONTAINER_NAME
243
+ SUDO docker rm -f $CONTAINER_NAME
170
244
  echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 삭제되었습니다."
171
245
  else
172
246
  echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
@@ -177,7 +251,7 @@ jobs:
177
251
 
178
252
  # Next.js는 SSR을 위해 Node.js 서버가 필요합니다
179
253
  # standalone 모드 사용 시 node server.js로 실행
180
- echo $PW | sudo -S docker run -d \
254
+ SUDO docker run -d \
181
255
  -p ${PORT}:3000 \
182
256
  --name $CONTAINER_NAME \
183
257
  -e TZ=Asia/Seoul \
@@ -1,7 +1,13 @@
1
1
  # project-auto-wizard:managed-workflow
2
- # Python FastAPI 빌드 검증 워크플로우 (CI Only)
3
- # - {{MAIN_BRANCH}} 브랜치에 push 시 Docker 빌드가 정상적으로 되는지만 검증
2
+ # Python 빌드 검증 워크플로우 (CI Only)
3
+ # - {{DEVELOP_BRANCH}} 브랜치 push/PR 시 의존성 설치 → pytest → (Dockerfile이 있으면) Docker 빌드로 검증
4
+ # - 의존성: requirements.txt가 있으면 그것을, 없으면 pyproject.toml/setup.py로 `pip install .`
5
+ # - 테스트: tests/·test/ 폴더나 test_*.py·*_test.py가 있을 때만 pytest 실행 (없으면 건너뜀)
6
+ # - Dockerfile이 없어도 실패하지 않는다 (Docker 빌드 검증만 건너뜀)
4
7
  # - 배포는 수행하지 않음 ({{MAIN_BRANCH}} 브랜치에서만 배포)
8
+ #
9
+ # GitHub Secrets
10
+ # - ENV_FILE (선택): .env 파일 내용 — 없으면 빈 .env로 검증합니다
5
11
 
6
12
  name: PROJECT-PYTHON-CI
7
13
 
@@ -19,6 +25,8 @@ env:
19
25
  PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
20
26
  # 모노레포에서 이 프로젝트가 있는 하위 경로 ('.'이면 항상 검증)
21
27
  PROJECT_PATH: "." # @wizard auto:project-path
28
+ # 테스트·의존성 설치에 쓸 Python 버전
29
+ PYTHON_VERSION: "3.12"
22
30
 
23
31
  jobs:
24
32
  changes:
@@ -38,15 +46,22 @@ jobs:
38
46
  if: ${{ github.event_name != 'workflow_dispatch' }}
39
47
  uses: dorny/paths-filter@v4
40
48
  with:
49
+ # push는 이번 push 범위(직전 커밋 before 대비)만 본다. 비워 두면 기본 브랜치 대비 누적 diff가 된다.
50
+ # 새 브랜치 첫 push(before가 0)와 PR은 빈 값 → 기본 동작(기본 브랜치·PR base 대비)
51
+ base: ${{ github.event_name == 'push' && github.event.before != '0000000000000000000000000000000000000000' && github.event.before || '' }}
41
52
  filters: |
42
53
  project:
43
54
  - '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
44
55
 
45
56
  build-check:
46
- name: Python FastAPI 빌드 검증
57
+ name: Python 빌드 검증
47
58
  runs-on: ubuntu-latest
48
59
  needs: changes
49
60
  if: ${{ github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true' }}
61
+ # 모노레포(--paths)면 그 하위 폴더에서 빌드한다
62
+ defaults:
63
+ run:
64
+ working-directory: ${{ env.PROJECT_PATH }}
50
65
 
51
66
  steps:
52
67
  - name: 코드 체크아웃
@@ -59,14 +74,63 @@ jobs:
59
74
  EOF
60
75
  echo "✅ .env 파일이 생성되었습니다"
61
76
 
77
+ - name: Python 설정
78
+ uses: actions/setup-python@v7
79
+ with:
80
+ python-version: ${{ env.PYTHON_VERSION }}
81
+
82
+ - name: 의존성 설치
83
+ run: |
84
+ python -m pip install --upgrade pip
85
+ if [ -f requirements.txt ]; then
86
+ pip install -r requirements.txt
87
+ elif [ -f pyproject.toml ] || [ -f setup.py ]; then
88
+ pip install .
89
+ else
90
+ echo "::notice::requirements.txt·pyproject.toml·setup.py가 없어 의존성 설치를 건너뜁니다"
91
+ fi
92
+ # 개발용 의존성은 있으면 함께 설치 (pytest 등)
93
+ if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
94
+
95
+ # 테스트가 없는 프로젝트는 실패가 아니라 건너뜀으로 처리한다
96
+ - name: 테스트 실행 (pytest)
97
+ run: |
98
+ if [ -d tests ] || [ -d test ] || [ -n "$(find . \( -path ./.venv -o -path ./venv -o -path ./node_modules -o -path ./.git \) -prune -o \( -name 'test_*.py' -o -name '*_test.py' \) -type f -print -quit)" ]; then
99
+ python -m pytest --version > /dev/null 2>&1 || pip install pytest
100
+ set +e
101
+ python -m pytest
102
+ code=$?
103
+ set -e
104
+ # 5 = 수집된 테스트 없음 → 실패로 보지 않는다
105
+ if [ "$code" -eq 5 ]; then
106
+ echo "::notice::수집된 테스트가 없어 pytest를 건너뜁니다"
107
+ exit 0
108
+ fi
109
+ exit "$code"
110
+ else
111
+ echo "::notice::테스트 파일(tests/, test_*.py 등)이 없어 pytest를 건너뜁니다"
112
+ fi
113
+
114
+ - name: Dockerfile 확인
115
+ id: dockerfile
116
+ run: |
117
+ if [ -f Dockerfile ]; then
118
+ echo "exists=true" >> "$GITHUB_OUTPUT"
119
+ else
120
+ echo "exists=false" >> "$GITHUB_OUTPUT"
121
+ echo "::notice::${{ env.PROJECT_PATH }}/Dockerfile이 없어 Docker 빌드 검증을 건너뜁니다"
122
+ fi
123
+
62
124
  - name: Docker 빌드환경 설정
125
+ if: steps.dockerfile.outputs.exists == 'true'
63
126
  uses: docker/setup-buildx-action@v3
64
127
 
65
128
  - name: Docker 이미지 빌드 검증
129
+ if: steps.dockerfile.outputs.exists == 'true'
66
130
  uses: docker/build-push-action@v5
67
131
  with:
68
- context: .
69
- file: ./Dockerfile
132
+ context: ${{ env.PROJECT_PATH }}
133
+ file: ${{ env.PROJECT_PATH }}/Dockerfile
70
134
  push: false # 푸시하지 않음 (빌드 검증만)
71
135
  tags: ${{ env.PROJECT_NAME }}:build-check
72
136
  cache-from: type=gha
@@ -74,7 +138,7 @@ jobs:
74
138
 
75
139
  - name: 빌드 검증 완료
76
140
  run: |
77
- echo "✅ Docker 빌드 검증이 성공적으로 완료되었습니다!"
141
+ echo "✅ Python 빌드 검증이 성공적으로 완료되었습니다!"
78
142
  echo ""
79
143
  echo "📋 빌드 정보:"
80
144
  echo " 🎯 프로젝트: ${{ env.PROJECT_NAME }}"