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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/bin/project-auto-wizard.js +19 -0
- package/package.json +36 -0
- package/payload/coderabbit.yaml +19 -0
- package/payload/config/breaking-changes.json +1 -0
- package/payload/config/wizard-prompts.yml +62 -0
- package/payload/scripts/changelog_manager.py +726 -0
- package/payload/scripts/version_manager.py +617 -0
- package/payload/version.yml.template +48 -0
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +303 -0
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +293 -0
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +289 -0
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +192 -0
- package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +209 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +591 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +700 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +308 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +992 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +689 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +987 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +471 -0
- package/payload/workflows/flutter/PROJECT-FLUTTER-SUH-LAB-APP-BUILD-TRIGGER.yaml +500 -0
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +185 -0
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +271 -0
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +81 -0
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +2191 -0
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +386 -0
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +194 -0
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +255 -0
- package/payload/workflows/spring/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +84 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-CI.yml +316 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +58 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +535 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +437 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +2277 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +425 -0
- package/src/cli/args.js +95 -0
- package/src/cli/help.js +27 -0
- package/src/commands/full.js +53 -0
- package/src/commands/interactive.js +276 -0
- package/src/commands/revert.js +60 -0
- package/src/commands/version.js +31 -0
- package/src/commands/workflows.js +49 -0
- package/src/context.js +26 -0
- package/src/core/assets.js +47 -0
- package/src/core/branches.js +60 -0
- package/src/core/branding.js +15 -0
- package/src/core/breaking-check.js +65 -0
- package/src/core/breaking.js +26 -0
- package/src/core/copy/coderabbit.js +26 -0
- package/src/core/copy/gitignore.js +55 -0
- package/src/core/copy/readme.js +30 -0
- package/src/core/copy/simple.js +23 -0
- package/src/core/copy/workflows.js +233 -0
- package/src/core/detect-fs.js +106 -0
- package/src/core/detect.js +62 -0
- package/src/core/fsutil.js +46 -0
- package/src/core/options-ask.js +99 -0
- package/src/core/paths-resolve.js +261 -0
- package/src/core/paths.js +16 -0
- package/src/core/version-yml.js +190 -0
- package/src/core/wizard-env.js +101 -0
- package/src/core/wizard-labels.js +107 -0
- package/src/index.js +162 -0
- package/src/ui/ansi.js +26 -0
- package/src/ui/banner.js +29 -0
- package/src/ui/env-plan.js +207 -0
- package/src/ui/prompts.js +99 -0
- package/src/ui/readline-engine.js +257 -0
- package/src/ui/status-cards.js +56 -0
- 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
|