chore : 워크플로우 수정, PR 및 커밋 템플릿 적용 #20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 워크플로우의 이름 | |
| 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 == '' | |
| run: ./gradlew build | |
| env: | |
| DB_URL: ${{ secrets.DB_URL }} | |
| DB_USERNAME: ${{ secrets.DB_USERNAME }} | |
| DB_PASSWORD: ${{ secrets.DB_PASSWORD }} | |
| R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }} | |
| R2_BUCKET: ${{ secrets.R2_BUCKET }} | |
| R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }} | |
| R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }} | |
| # 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: | | |
| ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}" | |
| ECR_REPOSITORY="cp_main_be" | |
| # AWS CLI 설정 및 docker login | |
| aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin $ECR_REGISTRY | |
| # 이미지 pull | |
| docker pull $ECR_REGISTRY/$ECR_REPOSITORY:latest | |
| # 기존 컨테이너 정리 | |
| if [ $(docker ps -a -q -f name=spring-app-container) ]; then | |
| docker stop spring-app-container | |
| docker rm spring-app-container | |
| fi | |
| # 환경변수 로드 및 새 컨테이너 실행 | |
| source /etc/environment | |
| docker run -d --name spring-app-container -p 8080:8080 \ | |
| -e DB_URL="$DB_URL" \ | |
| -e DB_USERNAME="$DB_USERNAME" \ | |
| -e DB_PASSWORD="$DB_PASSWORD" \ | |
| -e SPRING_PROFILES_ACTIVE=prod \ | |
| -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 }}" \ | |
| $ECR_REGISTRY/$ECR_REPOSITORY: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 |