Skip to content

๐ŸŽจ [BOT] Apply Spotless code style (#36) #73

๐ŸŽจ [BOT] Apply Spotless code style (#36)

๐ŸŽจ [BOT] Apply Spotless code style (#36) #73

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} ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋ฅผ ์น˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
API_TOKEN: ${{ secrets.REPLICATE_API_TOKEN }}
# ๋งŒ์•ฝ ํ…Œ์ŠคํŠธ DB ๋“ฑ ๋‹ค๋ฅธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# DB_URL: ${{ secrets.DB_URL_TEST }}
# DB_USERNAME: ${{ secrets.DB_USERNAME_TEST }}
# DB_PASSWORD: ${{ secrets.DB_PASSWORD_TEST }}
run: ./gradlew build
# 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