project-auto-wizard 0.1.5

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/bin/project-auto-wizard.js +19 -0
  4. package/package.json +36 -0
  5. package/payload/coderabbit.yaml +19 -0
  6. package/payload/config/breaking-changes.json +1 -0
  7. package/payload/config/wizard-prompts.yml +62 -0
  8. package/payload/scripts/changelog_manager.py +726 -0
  9. package/payload/scripts/version_manager.py +617 -0
  10. package/payload/version.yml.template +48 -0
  11. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +303 -0
  12. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +293 -0
  13. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +289 -0
  14. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +192 -0
  15. package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +209 -0
  16. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +591 -0
  17. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +700 -0
  18. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +308 -0
  19. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +992 -0
  20. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +689 -0
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +987 -0
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +471 -0
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-SUH-LAB-APP-BUILD-TRIGGER.yaml +500 -0
  24. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +185 -0
  25. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +271 -0
  26. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +81 -0
  27. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +2191 -0
  28. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +386 -0
  29. package/payload/workflows/react/PROJECT-REACT-CI.yaml +194 -0
  30. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +255 -0
  31. package/payload/workflows/spring/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +84 -0
  32. package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-CI.yml +316 -0
  33. package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +58 -0
  34. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +535 -0
  35. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +437 -0
  36. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +2277 -0
  37. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +425 -0
  38. package/src/cli/args.js +95 -0
  39. package/src/cli/help.js +27 -0
  40. package/src/commands/full.js +53 -0
  41. package/src/commands/interactive.js +276 -0
  42. package/src/commands/revert.js +60 -0
  43. package/src/commands/version.js +31 -0
  44. package/src/commands/workflows.js +49 -0
  45. package/src/context.js +26 -0
  46. package/src/core/assets.js +47 -0
  47. package/src/core/branches.js +60 -0
  48. package/src/core/branding.js +15 -0
  49. package/src/core/breaking-check.js +65 -0
  50. package/src/core/breaking.js +26 -0
  51. package/src/core/copy/coderabbit.js +26 -0
  52. package/src/core/copy/gitignore.js +55 -0
  53. package/src/core/copy/readme.js +30 -0
  54. package/src/core/copy/simple.js +23 -0
  55. package/src/core/copy/workflows.js +233 -0
  56. package/src/core/detect-fs.js +106 -0
  57. package/src/core/detect.js +62 -0
  58. package/src/core/fsutil.js +46 -0
  59. package/src/core/options-ask.js +99 -0
  60. package/src/core/paths-resolve.js +261 -0
  61. package/src/core/paths.js +16 -0
  62. package/src/core/version-yml.js +190 -0
  63. package/src/core/wizard-env.js +101 -0
  64. package/src/core/wizard-labels.js +107 -0
  65. package/src/index.js +162 -0
  66. package/src/ui/ansi.js +26 -0
  67. package/src/ui/banner.js +29 -0
  68. package/src/ui/env-plan.js +207 -0
  69. package/src/ui/prompts.js +99 -0
  70. package/src/ui/readline-engine.js +257 -0
  71. package/src/ui/status-cards.js +56 -0
  72. package/src/ui/summary.js +127 -0
@@ -0,0 +1,255 @@
1
+ # ===================================================================
2
+ # React CI/CD 배포
3
+ # ===================================================================
4
+ #
5
+ # {{MAIN_BRANCH}} 브랜치 푸시 시 Docker 이미지를 빌드하고 배포합니다.
6
+ #
7
+ # ===================================================================
8
+ # 🔑 필수 GitHub Secrets
9
+ # ===================================================================
10
+ # ENV_FILE: .env 파일 내용
11
+ # DOCKERHUB_USERNAME: DockerHub 사용자명
12
+ # DOCKERHUB_TOKEN: DockerHub 액세스 토큰
13
+ # SERVER_HOST: 배포 서버 주소
14
+ # SERVER_USER: SSH 사용자명
15
+ # SERVER_PASSWORD: SSH 비밀번호
16
+ # PROJECT_DEPLOY_PORT (선택): 배포 포트 (기본: 3000)
17
+ # ===================================================================
18
+
19
+ name: PROJECT-REACT-CICD
20
+
21
+ on:
22
+ push:
23
+ branches:
24
+ - "{{MAIN_BRANCH}}"
25
+ # @wizard paths-anchor (모노레포일 때 integrator가 paths 필터를 여기 주입)
26
+ workflow_dispatch:
27
+
28
+ env:
29
+ PROJECT_NAME: "__PROJECT_NAME__" # @wizard ask:@repo
30
+ DOCKER_IMAGE_PREFIX: "front-container"
31
+ NODE_VERSION: "20.15.0"
32
+ ENV_FILE_NAME: ".env"
33
+
34
+ jobs:
35
+ build:
36
+ name: React/Next.js 애플리케이션 빌드
37
+ runs-on: ubuntu-latest
38
+
39
+ steps:
40
+ # 1. 소스코드 체크아웃
41
+ - name: 코드 체크아웃
42
+ uses: actions/checkout@v5
43
+
44
+ # 2. Node.js 개발 환경 설정
45
+ - name: Node.js 설정
46
+ uses: actions/setup-node@v4
47
+ with:
48
+ node-version: ${{ env.NODE_VERSION }}
49
+ cache: 'npm'
50
+
51
+ # 3. 환경변수 파일 생성
52
+ - name: 환경변수 파일 생성 (${{ env.ENV_FILE_NAME }})
53
+ run: |
54
+ cat << 'EOF' > ./${{ env.ENV_FILE_NAME }}
55
+ ${{ secrets.ENV_FILE || secrets.ENV }}
56
+ EOF
57
+ echo "✅ ${{ env.ENV_FILE_NAME }} 파일 생성 완료"
58
+
59
+ # 4. npm 의존성 캐싱
60
+ - name: npm 의존성 캐싱
61
+ uses: actions/cache@v4
62
+ with:
63
+ path: ~/.npm
64
+ key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
65
+ restore-keys: |
66
+ ${{ runner.os }}-npm-
67
+
68
+ # 5. node_modules 캐싱
69
+ - name: node_modules 캐싱
70
+ id: node-modules-cache
71
+ uses: actions/cache@v4
72
+ with:
73
+ path: "**/node_modules"
74
+ key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }}
75
+ restore-keys: |
76
+ ${{ runner.os }}-node-modules-
77
+
78
+ # 6. 의존성 설치
79
+ - name: 의존성 설치
80
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
81
+ run: npm ci
82
+
83
+ # 7. Next.js 빌드 캐싱
84
+ - name: Next.js 빌드 캐싱
85
+ uses: actions/cache@v4
86
+ with:
87
+ path: .next/cache
88
+ key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
89
+ restore-keys: |
90
+ ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
91
+ ${{ runner.os }}-nextjs-
92
+
93
+ # 8. 프로젝트 빌드
94
+ - name: Build with npm
95
+ run: npm run build
96
+
97
+ # 9. Docker 빌드 환경 설정
98
+ - name: Docker 빌드환경 설정
99
+ uses: docker/setup-buildx-action@v3
100
+
101
+ # 10. DockerHub 로그인
102
+ - name: DockerHub 로그인
103
+ uses: docker/login-action@v3
104
+ with:
105
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
106
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
107
+
108
+ # 11. Docker 레이어 캐싱
109
+ - name: Cache Docker layers
110
+ uses: actions/cache@v4
111
+ with:
112
+ path: /tmp/.buildx-cache
113
+ key: ${{ runner.os }}-buildx-${{ hashFiles('Dockerfile') }}-${{ hashFiles('package-lock.json') }}
114
+ restore-keys: |
115
+ ${{ runner.os }}-buildx-
116
+
117
+ # 12. Docker 이미지 빌드 및 푸시
118
+ - name: Docker 이미지 빌드 및 푸시
119
+ uses: docker/build-push-action@v5
120
+ with:
121
+ context: .
122
+ file: ./Dockerfile
123
+ push: true
124
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}-${{ env.DOCKER_IMAGE_PREFIX }}:${{ github.ref_name }}
125
+ cache-from: type=local,src=/tmp/.buildx-cache
126
+ cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
127
+
128
+ # 13. Docker 캐시 정리
129
+ - name: Move Docker cache
130
+ run: |
131
+ rm -rf /tmp/.buildx-cache
132
+ mv /tmp/.buildx-cache-new /tmp/.buildx-cache
133
+
134
+ deploy:
135
+ name: 원격 서버 배포
136
+ needs: build
137
+ runs-on: ubuntu-latest
138
+
139
+ steps:
140
+ - name: Deploy
141
+ uses: appleboy/ssh-action@v1.0.3
142
+ with:
143
+ host: ${{ secrets.SERVER_HOST }}
144
+ username: ${{ secrets.SERVER_USER }}
145
+ password: ${{ secrets.SERVER_PASSWORD }}
146
+ port: 2022
147
+ script: |
148
+ set -e
149
+
150
+ # ============================================================
151
+ # 배포 환경 변수 설정
152
+ # ============================================================
153
+ echo "🔧 환경변수 설정.."
154
+ export PATH=$PATH:/usr/local/bin
155
+ export PW=${{ secrets.SERVER_PASSWORD }}
156
+
157
+ # GitHub에서 전달받은 브랜치명
158
+ BRANCH=${{ github.ref_name }}
159
+
160
+ # 프로젝트 설정
161
+ PROJECT_NAME="${{ env.PROJECT_NAME }}"
162
+
163
+ # ============================================================
164
+ # 브랜치별 포트 및 컨테이너명 설정
165
+ # ============================================================
166
+ # 기본값 설정
167
+ PORT=3000
168
+ CONTAINER_NAME="${PROJECT_NAME}-front"
169
+
170
+ # 브랜치에 따른 환경별 설정
171
+ if [ "$BRANCH" == "{{MAIN_BRANCH}}" ]; then
172
+ # 🚀 배포 환경 ({{MAIN_BRANCH}} 브랜치)
173
+ # GitHub Secrets의 PROJECT_DEPLOY_PORT 환경변수 사용
174
+ # 설정되어 있지 않으면 기본값 3000 사용
175
+ PORT=${{ secrets.PROJECT_DEPLOY_PORT || '3000' }}
176
+ CONTAINER_NAME="${PROJECT_NAME}-front-deploy"
177
+ echo "🚀 배포 환경으로 배포합니다 (브랜치: $BRANCH)"
178
+
179
+ else
180
+ # ⚠️ 기타 브랜치 (예상치 못한 브랜치)
181
+ echo "⚠️ 지원하지 않는 브랜치입니다: $BRANCH"
182
+ echo "이 워크플로우는 {{MAIN_BRANCH}} 브랜치만 지원합니다."
183
+ echo "on.push.branches에서 지원할 브랜치를 설정하세요."
184
+ exit 1
185
+ fi
186
+
187
+ # 설정 정보 출력
188
+ echo "📋 배포 설정 정보:"
189
+ echo " - 브랜치: $BRANCH"
190
+ echo " - 프로젝트: $PROJECT_NAME"
191
+ echo " - 컨테이너 이름: $CONTAINER_NAME"
192
+ echo " - 포트: $PORT"
193
+ echo " - Docker 이미지: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
194
+
195
+ # ============================================================
196
+ # Docker 이미지 풀 (Pull)
197
+ # ============================================================
198
+ echo "⬇️ Docker 이미지 풀: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}"
199
+ echo $PW | sudo -S docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
200
+
201
+ # ============================================================
202
+ # 기존 컨테이너 정리
203
+ # ============================================================
204
+ echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
205
+
206
+ # 동일한 이름의 컨테이너가 존재하는지 확인
207
+ if sudo docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
208
+ echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
209
+ echo $PW | sudo -S docker rm -f $CONTAINER_NAME
210
+ echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 삭제되었습니다."
211
+ else
212
+ echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
213
+ fi
214
+
215
+ # ============================================================
216
+ # 새 컨테이너 실행
217
+ # ============================================================
218
+ echo "🚀 새로운 컨테이너 $CONTAINER_NAME 실행 중..."
219
+
220
+ echo $PW | sudo -S docker run -d \
221
+ -p ${PORT}:3000 \
222
+ --name $CONTAINER_NAME \
223
+ -e TZ=Asia/Seoul \
224
+ -v /etc/localtime:/etc/localtime:ro \
225
+ ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}-${{ env.DOCKER_IMAGE_PREFIX }}:${BRANCH}
226
+
227
+ # ============================================================
228
+ # 배포 완료 확인
229
+ # ============================================================
230
+ echo "✅ 배포가 성공적으로 완료되었습니다!"
231
+ echo ""
232
+ echo "📋 배포 결과 요약:"
233
+ echo " 🎯 프로젝트: $PROJECT_NAME"
234
+ echo " 🌿 브랜치: $BRANCH"
235
+ echo " 🐳 컨테이너: $CONTAINER_NAME"
236
+ echo " 🌐 포트: $PORT"
237
+ echo " ⏰ 배포 시간: $(date '+%Y-%m-%d %H:%M:%S')"
238
+ echo ""
239
+ echo "🔗 접속 URL: http://${{ secrets.SERVER_HOST }}:${PORT}"
240
+
241
+ # ===================================================================
242
+ # 사용 예시 - {{MAIN_BRANCH}} 브랜치 사용
243
+ # ===================================================================
244
+ #
245
+ # 현재 설정: {{MAIN_BRANCH}} 브랜치에 push할 때 자동 배포
246
+ #
247
+ # 브랜치별 포트:
248
+ # - main: 3000 (PROJECT_DEPLOY_PORT secret으로 변경 가능)
249
+ #
250
+ # 필요한 Secrets:
251
+ # - REACT_ENV_FILE, DOCKERHUB_*, SERVER_* (필수)
252
+ # - PROJECT_DEPLOY_PORT (선택, 기본값: 3000)
253
+ #
254
+ # ===================================================================
255
+
@@ -0,0 +1,84 @@
1
+ # ===================================================================
2
+ # Spring GitHub Packages 라이브러리 배포 워크플로우
3
+ # ===================================================================
4
+ #
5
+ # Java 라이브러리 모듈을 GitHub Packages(Maven repo)에 자동 배포합니다.
6
+ # Nexus 없이 GitHub만으로 의존성 호스팅이 가능합니다.
7
+ #
8
+ # ⚠️ Java 라이브러리 모듈 배포 전용 CICD입니다.
9
+ # Spring Boot 애플리케이션 배포가 아닙니다.
10
+ #
11
+ # ===================================================================
12
+ # 🛠️ build.gradle 요구사항
13
+ # ===================================================================
14
+ # publishing.repositories.maven 블록에 GitHub Packages 항목 추가:
15
+ #
16
+ # maven {
17
+ # name = "GitHubPackages"
18
+ # url = uri("https://maven.pkg.github.com/${System.getenv('GITHUB_REPOSITORY')}")
19
+ # credentials {
20
+ # username = System.getenv("GITHUB_ACTOR")
21
+ # password = System.getenv("GITHUB_TOKEN")
22
+ # }
23
+ # }
24
+ #
25
+ # 💡 Free 계정 제한 (Private repo 기준):
26
+ # - 월 500MB 저장 + 1GB 전송 무료
27
+ # - Public repo는 무제한 무료
28
+ # ===================================================================
29
+
30
+ name: PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH
31
+
32
+ on:
33
+ push:
34
+ branches: ["{{MAIN_BRANCH}}"]
35
+ tags:
36
+ - 'v*.*.*'
37
+ workflow_dispatch:
38
+
39
+ concurrency:
40
+ group: github-packages-publish-${{ github.ref }}
41
+ cancel-in-progress: false
42
+
43
+ permissions:
44
+ contents: read
45
+ packages: write
46
+
47
+ jobs:
48
+ publish:
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v5
52
+
53
+ - name: Set up JDK 17
54
+ uses: actions/setup-java@v4
55
+ with:
56
+ java-version: '17'
57
+ distribution: 'temurin'
58
+
59
+ - name: Setup Gradle
60
+ uses: gradle/actions/setup-gradle@v4
61
+
62
+ - name: Get version
63
+ id: get_version
64
+ run: |
65
+ if [[ "${{ github.ref }}" == refs/tags/* ]]; then
66
+ TAG_NAME=${GITHUB_REF#refs/tags/}
67
+ VERSION=${TAG_NAME#v}
68
+ echo "🏷️ 태그에서 버전 추출: $VERSION"
69
+ else
70
+ VERSION=$(python3 .github/scripts/version_manager.py get | tail -n 1)
71
+ echo "📄 version.yml에서 버전 추출: $VERSION"
72
+ fi
73
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
74
+ echo "Publishing version $VERSION"
75
+
76
+ - name: Publish to GitHub Packages
77
+ env:
78
+ GITHUB_ACTOR: ${{ github.actor }}
79
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
80
+ GITHUB_REPOSITORY: ${{ github.repository }}
81
+ run: |
82
+ VERSION="${{ steps.get_version.outputs.version }}"
83
+ echo "🚀 Publishing version $VERSION to GitHub Packages"
84
+ ./gradlew publishMavenPublicationToGitHubPackagesRepository -Pversion=$VERSION
@@ -0,0 +1,316 @@
1
+ # ===================================================================
2
+ # Spring Nexus CI 워크플로우
3
+ # ===================================================================
4
+ #
5
+ # 🔑 필수 GitHub Secrets
6
+ # ===================================================================
7
+ # GRADLE_PROPERTIES: gradle.properties 파일 내용 (Nexus 인증 정보 포함)
8
+ # ===================================================================
9
+
10
+ name: PROJECT-SPRING-NEXUS-CI
11
+
12
+ on:
13
+ pull_request:
14
+ branches: ["{{DEVELOP_BRANCH}}"]
15
+ types: [opened, synchronize, reopened]
16
+ push:
17
+ branches: ["{{DEVELOP_BRANCH}}"]
18
+ workflow_dispatch:
19
+
20
+ permissions:
21
+ contents: read
22
+ pull-requests: write
23
+ issues: write
24
+ checks: write
25
+
26
+ jobs:
27
+ build-check:
28
+ name: Build Verification
29
+ runs-on: ubuntu-latest
30
+
31
+ steps:
32
+ - name: Checkout Repository
33
+ uses: actions/checkout@v5
34
+ with:
35
+ fetch-depth: 0
36
+
37
+ - name: Setup JDK 17
38
+ uses: actions/setup-java@v4
39
+ with:
40
+ java-version: '17'
41
+ distribution: 'temurin'
42
+
43
+ - name: Validate Gradle Wrapper
44
+ uses: gradle/wrapper-validation-action@v2
45
+ continue-on-error: true
46
+
47
+ - name: Create gradle.properties from secret
48
+ run: |
49
+ echo -e "${{ secrets.GRADLE_PROPERTIES }}" > gradle.properties
50
+
51
+ - name: Setup Gradle
52
+ uses: gradle/actions/setup-gradle@v4
53
+ with:
54
+ gradle-version: wrapper
55
+
56
+ - name: Clean Build Directory
57
+ run: ./gradlew clean
58
+
59
+ - name: Compile Sources
60
+ id: compile
61
+ run: |
62
+ set +e
63
+ ./gradlew compileJava compileTestJava 2>&1 | tee compile_output.txt
64
+ echo "compile_exit_code=$?" >> $GITHUB_OUTPUT
65
+ set -e
66
+ continue-on-error: true
67
+
68
+ - name: Run Tests
69
+ id: test
70
+ run: |
71
+ set +e
72
+ ./gradlew test 2>&1 | tee test_output.txt
73
+ echo "test_exit_code=$?" >> $GITHUB_OUTPUT
74
+ set -e
75
+ continue-on-error: true
76
+
77
+ - name: Build JAR
78
+ id: build
79
+ run: |
80
+ set +e
81
+ ./gradlew build -x test 2>&1 | tee build_output.txt
82
+ echo "build_exit_code=$?" >> $GITHUB_OUTPUT
83
+ set -e
84
+ continue-on-error: true
85
+
86
+ - name: Generate Build Report
87
+ id: report
88
+ if: always()
89
+ run: |
90
+ # 빌드 상태 확인 (exit code 기반)
91
+ COMPILE_STATUS="✅ 성공"
92
+ TEST_STATUS="✅ 성공"
93
+ BUILD_STATUS="✅ 성공"
94
+
95
+ # 컴파일 상태 확인
96
+ COMPILE_EXIT_CODE="${{ steps.compile.outputs.compile_exit_code }}"
97
+ if [ "$COMPILE_EXIT_CODE" != "0" ] && [ "$COMPILE_EXIT_CODE" != "" ]; then
98
+ COMPILE_STATUS="❌ 실패"
99
+ fi
100
+
101
+ # 테스트 상태 확인
102
+ TEST_EXIT_CODE="${{ steps.test.outputs.test_exit_code }}"
103
+ if [ "$TEST_EXIT_CODE" != "0" ] && [ "$TEST_EXIT_CODE" != "" ]; then
104
+ TEST_STATUS="❌ 실패"
105
+ fi
106
+
107
+ # 빌드 상태 확인
108
+ BUILD_EXIT_CODE="${{ steps.build.outputs.build_exit_code }}"
109
+ if [ "$BUILD_EXIT_CODE" != "0" ] && [ "$BUILD_EXIT_CODE" != "" ]; then
110
+ BUILD_STATUS="❌ 실패"
111
+ fi
112
+
113
+ # 전체 빌드 상태
114
+ OVERALL_STATUS="✅ 성공"
115
+ if [ "$COMPILE_EXIT_CODE" != "0" ] || [ "$TEST_EXIT_CODE" != "0" ] || [ "$BUILD_EXIT_CODE" != "0" ]; then
116
+ OVERALL_STATUS="❌ 실패"
117
+ fi
118
+
119
+ echo "compile_status=$COMPILE_STATUS" >> $GITHUB_OUTPUT
120
+ echo "test_status=$TEST_STATUS" >> $GITHUB_OUTPUT
121
+ echo "build_status=$BUILD_STATUS" >> $GITHUB_OUTPUT
122
+ echo "overall_status=$OVERALL_STATUS" >> $GITHUB_OUTPUT
123
+
124
+ - name: Extract Error Details
125
+ id: errors
126
+ if: always()
127
+ run: |
128
+ # 컴파일 에러 추출
129
+ if [ -f compile_output.txt ] && [ "${{ steps.compile.outputs.compile_exit_code }}" != "0" ]; then
130
+ echo "compile_errors<<EOF" >> $GITHUB_OUTPUT
131
+ echo "## 🚨 컴파일 에러" >> $GITHUB_OUTPUT
132
+ echo "" >> $GITHUB_OUTPUT
133
+ echo '```' >> $GITHUB_OUTPUT
134
+ grep -A 15 -B 15 "error\|Error\|ERROR\|FAILED\|Failed\|failed" compile_output.txt | head -60 >> $GITHUB_OUTPUT || echo "에러 로그를 찾을 수 없습니다." >> $GITHUB_OUTPUT
135
+ echo '```' >> $GITHUB_OUTPUT
136
+ echo "EOF" >> $GITHUB_OUTPUT
137
+ fi
138
+
139
+ # 테스트 에러 추출
140
+ if [ -f test_output.txt ] && [ "${{ steps.test.outputs.test_exit_code }}" != "0" ]; then
141
+ echo "test_errors<<EOF" >> $GITHUB_OUTPUT
142
+ echo "## 🧪 테스트 실패" >> $GITHUB_OUTPUT
143
+ echo "" >> $GITHUB_OUTPUT
144
+ echo '```' >> $GITHUB_OUTPUT
145
+ grep -A 15 -B 15 "FAILED\|Failed\|failed\|error\|Error\|ERROR" test_output.txt | head -60 >> $GITHUB_OUTPUT || echo "테스트 에러 로그를 찾을 수 없습니다." >> $GITHUB_OUTPUT
146
+ echo '```' >> $GITHUB_OUTPUT
147
+ echo "EOF" >> $GITHUB_OUTPUT
148
+ fi
149
+
150
+ # 빌드 에러 추출
151
+ if [ -f build_output.txt ] && [ "${{ steps.build.outputs.build_exit_code }}" != "0" ]; then
152
+ echo "build_errors<<EOF" >> $GITHUB_OUTPUT
153
+ echo "## 📦 빌드 에러" >> $GITHUB_OUTPUT
154
+ echo "" >> $GITHUB_OUTPUT
155
+ echo '```' >> $GITHUB_OUTPUT
156
+ grep -A 15 -B 15 "FAILED\|Failed\|failed\|error\|Error\|ERROR" build_output.txt | head -60 >> $GITHUB_OUTPUT || echo "빌드 에러 로그를 찾을 수 없습니다." >> $GITHUB_OUTPUT
157
+ echo '```' >> $GITHUB_OUTPUT
158
+ echo "EOF" >> $GITHUB_OUTPUT
159
+ fi
160
+
161
+ - name: Comment on PR (Success)
162
+ if: github.event_name == 'pull_request' && steps.report.outputs.overall_status == '✅ 성공'
163
+ uses: actions/github-script@v7
164
+ with:
165
+ github-token: ${{ secrets.GITHUB_TOKEN }}
166
+ script: |
167
+ const { data: comments } = await github.rest.issues.listComments({
168
+ owner: context.repo.owner,
169
+ repo: context.repo.repo,
170
+ issue_number: context.issue.number,
171
+ });
172
+
173
+ // 기존 봇 댓글 찾기
174
+ const botComment = comments.find(comment =>
175
+ comment.user.type === 'Bot' &&
176
+ comment.body.includes('🔧 CI Build Check')
177
+ );
178
+
179
+ const successMessage = `## 🔧 CI Build Check 결과
180
+
181
+ ### ✅ 빌드 성공!
182
+
183
+ | 단계 | 상태 |
184
+ |------|------|
185
+ | 컴파일 | ${{ steps.report.outputs.compile_status }} |
186
+ | 테스트 | ${{ steps.report.outputs.test_status }} |
187
+ | 빌드 | ${{ steps.report.outputs.build_status }} |
188
+
189
+ **전체 상태**: ${{ steps.report.outputs.overall_status }}
190
+
191
+ ---
192
+ *🤖 GitHub Actions에 의해 자동 생성됨 - ${new Date().toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' })}*`;
193
+
194
+ if (botComment) {
195
+ await github.rest.issues.updateComment({
196
+ owner: context.repo.owner,
197
+ repo: context.repo.repo,
198
+ comment_id: botComment.id,
199
+ body: successMessage
200
+ });
201
+ } else {
202
+ await github.rest.issues.createComment({
203
+ owner: context.repo.owner,
204
+ repo: context.repo.repo,
205
+ issue_number: context.issue.number,
206
+ body: successMessage
207
+ });
208
+ }
209
+
210
+ - name: Comment on PR (Failure)
211
+ if: github.event_name == 'pull_request' && steps.report.outputs.overall_status == '❌ 실패'
212
+ uses: actions/github-script@v7
213
+ with:
214
+ github-token: ${{ secrets.GITHUB_TOKEN }}
215
+ script: |
216
+ const { data: comments } = await github.rest.issues.listComments({
217
+ owner: context.repo.owner,
218
+ repo: context.repo.repo,
219
+ issue_number: context.issue.number,
220
+ });
221
+
222
+ // 기존 봇 댓글 찾기
223
+ const botComment = comments.find(comment =>
224
+ comment.user.type === 'Bot' &&
225
+ comment.body.includes('🔧 CI Build Check')
226
+ );
227
+
228
+ let errorDetails = '';
229
+
230
+ // 컴파일 에러 추가
231
+ if ('${{ steps.errors.outputs.compile_errors }}') {
232
+ errorDetails += '${{ steps.errors.outputs.compile_errors }}\n\n';
233
+ }
234
+
235
+ // 테스트 에러 추가
236
+ if ('${{ steps.errors.outputs.test_errors }}') {
237
+ errorDetails += '${{ steps.errors.outputs.test_errors }}\n\n';
238
+ }
239
+
240
+ // 빌드 에러 추가
241
+ if ('${{ steps.errors.outputs.build_errors }}') {
242
+ errorDetails += '${{ steps.errors.outputs.build_errors }}\n\n';
243
+ }
244
+
245
+ const failureMessage = `## 🔧 CI Build Check 결과
246
+
247
+ ### ❌ 빌드 실패!
248
+
249
+ | 단계 | 상태 |
250
+ |------|------|
251
+ | 컴파일 | ${{ steps.report.outputs.compile_status }} |
252
+ | 테스트 | ${{ steps.report.outputs.test_status }} |
253
+ | 빌드 | ${{ steps.report.outputs.build_status }} |
254
+
255
+ **전체 상태**: ${{ steps.report.outputs.overall_status }}
256
+
257
+ ### 📋 에러 상세 정보
258
+
259
+ ${errorDetails}
260
+
261
+ ### 🔧 해결 방법
262
+ - 로컬에서 \`./gradlew clean build\` 명령어로 빌드를 확인해보세요
263
+ - 에러 메시지를 참고하여 코드를 수정해주세요
264
+ - 테스트가 실패한 경우 \`./gradlew test\` 명령어로 테스트를 실행해보세요
265
+
266
+ ---
267
+ *🤖 GitHub Actions에 의해 자동 생성됨 - ${new Date().toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' })}*`;
268
+
269
+ if (botComment) {
270
+ await github.rest.issues.updateComment({
271
+ owner: context.repo.owner,
272
+ repo: context.repo.repo,
273
+ comment_id: botComment.id,
274
+ body: failureMessage
275
+ });
276
+ } else {
277
+ await github.rest.issues.createComment({
278
+ owner: context.repo.owner,
279
+ repo: context.repo.repo,
280
+ issue_number: context.issue.number,
281
+ body: failureMessage
282
+ });
283
+ }
284
+
285
+ - name: Create Check Run
286
+ if: always()
287
+ uses: actions/github-script@v7
288
+ with:
289
+ github-token: ${{ secrets.GITHUB_TOKEN }}
290
+ script: |
291
+ const conclusion = '${{ steps.report.outputs.overall_status }}' === '✅ 성공' ? 'success' : 'failure';
292
+ const summary = `빌드 검증이 ${conclusion === 'success' ? '성공' : '실패'}했습니다.`;
293
+
294
+ await github.rest.checks.create({
295
+ owner: context.repo.owner,
296
+ repo: context.repo.repo,
297
+ name: 'Build Verification',
298
+ head_sha: context.sha,
299
+ status: 'completed',
300
+ conclusion: conclusion,
301
+ output: {
302
+ title: '🔧 CI Build Check',
303
+ summary: summary,
304
+ text: `
305
+ 컴파일: ${{ steps.report.outputs.compile_status }}
306
+ 테스트: ${{ steps.report.outputs.test_status }}
307
+ 빌드: ${{ steps.report.outputs.build_status }}
308
+ `
309
+ }
310
+ });
311
+
312
+ - name: Fail Job on Build Failure
313
+ if: steps.report.outputs.overall_status == '❌ 실패'
314
+ run: |
315
+ echo "❌ 빌드가 실패했습니다. 위의 에러 메시지를 확인해주세요."
316
+ exit 1