Skip to content

Refactor: 점수,알림,신고 기능 추가 및 기존 로직 리팩토링 #99

Refactor: 점수,알림,신고 기능 추가 및 기존 로직 리팩토링

Refactor: 점수,알림,신고 기능 추가 및 기존 로직 리팩토링 #99

Workflow file for this run

# 워크플로우의 이름
name: Spring Boot CI/CD with AWS
# 워크플로우가 실행될 조건 정의
on:
push:
branches: [ develop ]
pull_request:
types: [ opened, edited ] # PR 생성/수정 시에만 동작하도록 타입 명시
branches: [ develop ]
# PR 생성, 코드 수정, AWS OIDC 토큰 요청을 위한 권한 설정
permissions:
id-token: write
contents: write
pull-requests: write
checks: write
jobs:
# 코드 포맷팅, 빌드, 테스트를 처리하는 Job
build:
runs-on: ubuntu-latest
outputs:
build-success: ${{ steps.build-status.outputs.success }}
steps:
# 1. 소스 코드 체크아웃
- name: Checkout Source Code
uses: actions/checkout@v4
# 2. JDK 17 설치
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'corretto'
# === [추가된 부분] PR 템플릿 검사기 ===
- name: Check PR Template
if: github.event_name == 'pull_request' && github.event.pull_request.body == ''
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// 템플릿 파일이 있는 경로를 정확히 지정해야 합니다.
// 예: .github/pr_templates/for_develop.md
const template = fs.readFileSync('.github/pr_templates/for_develop.md', 'utf8');
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `🚨 **PR 본문이 비어있습니다!**\n\n아래 템플릿을 복사하여 PR 내용을 작성해주세요.\n\n---\n\n${template}`
});
core.setFailed('PR 본문을 템플릿에 맞게 작성해주세요.');
# =======================================
# 3. Gradle 캐시 설정
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# 4. Gradle 실행 권한 부여
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
# 5. 코드 포맷팅 검사 또는 적용
- name: Check code formatting (PR)
if: github.event_name == 'pull_request'
run: ./gradlew spotlessCheck
- name: Apply code formatting (Push)
if: github.event_name == 'push'
run: ./gradlew spotlessApply
# 6. 포맷팅 변경사항으로 PR 생성 (전략 2)
- name: Create Pull Request with formatting changes
if: github.event_name == 'push'
id: create_pr # step의 id를 지정하여 output을 참조할 수 있도록 함
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "🎨 [BOT] Apply Spotless code style"
title: "🎨 [BOT] Apply Spotless code style"
body: |
Spotless 봇이 코드 스타일을 자동으로 수정했습니다.
변경 사항을 확인하고 병합해 주세요.
*This PR was auto-generated by a GitHub Action.*
branch: "spotless-patches/${{ github.ref_name }}"
delete-branch: true
labels: bot, chore
# 7. Gradle로 빌드 및 단위 테스트 실행
# 중요: PR이 생성되지 않았을 때만(코드 포맷이 완벽할 때만) 빌드/테스트를 진행합니다.
- name: Build with Gradle
if: steps.create_pr.outputs.pull-request-number == ''
env:
# Spring Boot는 이 환경 변수(API_TOKEN)를 인식하여
# application.properties의 ${API_TOKEN} 플레이스홀더를 치환합니다.
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
FASTAPI_URL: ${{ secrets.FASTAPI_URL }}
API_TOKEN: ${{ secrets.API_TOKEN }}
# 만약 테스트 DB 등 다른 환경 변수가 필요하다면 아래와 같이 추가할 수 있습니다.
# DB_URL: ${{ secrets.DB_URL_TEST }}
# DB_USERNAME: ${{ secrets.DB_USERNAME_TEST }}
# DB_PASSWORD: ${{ secrets.DB_PASSWORD_TEST }}
run: ./gradlew build --stacktrace --info
# 8. 테스트 결과 업로드
- name: Publish Test Results
if: (success() || failure()) && steps.create_pr.outputs.pull-request-number == ''
uses: dorny/test-reporter@v1
with:
name: Gradle Tests
path: build/test-results/test/*.xml
reporter: java-junit
# 9. 빌드 성공 상태 설정
- name: Set build success status
id: build-status
if: success() && steps.create_pr.outputs.pull-request-number == ''
run: echo "success=true" >> $GITHUB_OUTPUT
# ====================================================================
# 이하 배포 관련 Job들은 'build' Job의 최종 성공 여부에 따라 실행됩니다.
# ====================================================================
# EC2 상태 확인 작업
check-ec2:
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && needs.build.outputs.build-success == 'true'
outputs:
ec2-available: ${{ steps.check-ec2-status.outputs.available }}
steps:
- name: Check EC2 instance status
id: check-ec2-status
run: |
if timeout 10 nc -z ${{ secrets.EC2_HOST }} 22 2>/dev/null; then
echo "EC2 instance is reachable"
echo "available=true" >> $GITHUB_OUTPUT
else
echo "EC2 instance is not reachable or stopped"
echo "available=false" >> $GITHUB_OUTPUT
fi
continue-on-error: true
# Docker 이미지 빌드 및 ECR 푸시
build-and-push-image:
runs-on: ubuntu-latest
needs: [build, check-ec2]
if: github.event_name == 'push' && needs.build.outputs.build-success == 'true' && needs.check-ec2.outputs.ec2-available == 'true'
outputs:
image-pushed: ${{ steps.push-status.outputs.success }}
steps:
- name: Checkout Source Code
uses: actions/checkout@v4
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: cp_main_be
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
docker push --all-tags $ECR_REGISTRY/$ECR_REPOSITORY
- name: Set push success status
id: push-status
if: success()
run: echo "success=true" >> $GITHUB_OUTPUT
# EC2 배포 작업
deploy:
runs-on: ubuntu-latest
needs: [build, check-ec2, build-and-push-image]
if: github.event_name == 'push' && needs.build-and-push-image.outputs.image-pushed == 'true'
steps:
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Deploy to EC2 instance
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
# AWS ECR 로그인
aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin ${{ steps.login-ecr.outputs.registry }}
# 최신 이미지 pull
docker pull ${{ steps.login-ecr.outputs.registry }}/cp_main_be:latest
# 기존 컨테이너 중지 및 삭제
if [ $(docker ps -a -q -f name=spring-app-container) ]; then
docker stop spring-app-container
docker rm spring-app-container
fi
# 1. GitHub Secret에서 Firebase 키 파일 생성
echo "${{ secrets.FIREBASE_KEY_JSON }}" > /home/${{ secrets.EC2_USER }}/serviceAccountKey.json
# 2. 모든 환경 변수를 포함하여 새 컨테이너 실행
docker run -d --name spring-app-container -p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL="${{ secrets.DB_URL }}" \
-e DB_USERNAME="${{ secrets.DB_USERNAME }}" \
-e DB_PASSWORD="${{ secrets.DB_PASSWORD }}" \
-e R2_ENDPOINT="${{ secrets.R2_ENDPOINT }}" \
-e R2_BUCKET="${{ secrets.R2_BUCKET }}" \
-e R2_ACCESS_KEY="${{ secrets.R2_ACCESS_KEY }}" \
-e R2_SECRET_KEY="${{ secrets.R2_SECRET_KEY }}" \
-e JWT_SECRET="${{ secrets.JWT_SECRET }}" \
-e FASTAPI_URL="${{ secrets.FASTAPI_URL }}" \
-e API_TOKEN="${{ secrets.API_TOKEN }}" \
-e GOOGLE_APPLICATION_CREDENTIALS=/app/serviceAccountKey.json \
-v /home/${{ secrets.EC2_USER }}/serviceAccountKey.json:/app/serviceAccountKey.json \
${{ steps.login-ecr.outputs.registry }}/cp_main_be:latest
# 워크플로우 실행 결과 요약
summary:
runs-on: ubuntu-latest
needs: [build, check-ec2, build-and-push-image, deploy]
if: always()
steps:
- name: Workflow Summary
run: |
echo "## 워크플로우 실행 결과" >> $GITHUB_STEP_SUMMARY
echo "| 단계 | 상태 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 빌드 및 테스트 | ${{ needs.build.result == 'success' && '✅ 성공' || '❌ 실패/건너뜀' }} |" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "| EC2 상태 확인 | ${{ needs.check-ec2.result == 'success' && '✅ 성공' || (needs.check-ec2.result == 'skipped' && '⏭️ 건너뜀' || '❌ 실패') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Docker 이미지 빌드/푸시 | ${{ needs.build-and-push-image.result == 'success' && '✅ 성공' || (needs.build-and-push-image.result == 'skipped' && '⏭️ 건너뜀' || '❌ 실패') }} |" >> $GITHUB_STEP_SUMMARY
echo "| EC2 배포 | ${{ needs.deploy.result == 'success' && '✅ 성공' || (needs.deploy.result == 'skipped' && '⏭️ 건너뜀' || '❌ 실패') }} |" >> $GITHUB_STEP_SUMMARY
else
echo "| 배포 관련 작업 | ⏭️ 건너뜀 (PR 이벤트) |" >> $GITHUB_STEP_SUMMARY
fi