Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/prod-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Spring CD (Production)

# main 브랜치 PR에서만 실행 (이미 빌드된 Docker 이미지 사용)
on:
pull_request:
push:
branches:
- main
paths:
Expand All @@ -18,7 +18,7 @@ jobs:
# ==================================
# CD: Deploy to Production Environment
# ==================================
cd-test:
cd-prod:
runs-on: ubuntu-latest

steps:
Expand Down Expand Up @@ -60,7 +60,6 @@ jobs:
echo "📋 Checking current NPM configuration... 📋"
CURRENT_CONFIG=$(curl -s -H "Authorization: Bearer $TOKEN" \
"http://${NPM_HOST}/api/nginx/proxy-hosts/${PROXY_HOST_ID}")
echo "Current Config: $CURRENT_CONFIG"

CURRENT_TARGET=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_host // .forward_host')
CURRENT_PORT=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_port // .forward_port')
Expand Down
116 changes: 116 additions & 0 deletions .github/workflows/test-server-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Spring CD (Test Server)

on:
push:
branches:
- develop

jobs:
cd-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Deploy to Test Environment
uses: appleboy/[email protected]
with:
host: ${{ secrets.TEST_SERVER_HOST }}
username: ec2-user
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# GHCR 로그인
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.repository_owner }}" --password-stdin
docker pull ghcr.io/${{ github.repository }}/zoopzoop:latest

NPM_HOST="localhost:81"
NPM_EMAIL="${{ secrets.NPM_ADMIN_EMAIL }}"
NPM_PASSWORD="${{ secrets.NPM_ADMIN_PASSWORD }}"
PROXY_HOST_ID="${{ secrets.NPM_PROXY_HOST_ID }}"

# NPM 토큰
TOKEN=$(curl -s -X POST "http://${NPM_HOST}/api/tokens" \
-H "Content-Type: application/json" \
-d "{\"identity\":\"${NPM_EMAIL}\",\"secret\":\"${NPM_PASSWORD}\"}" | jq -r '.token')
if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then
echo "❌ Failed to get NPM API token"
exit 1
fi

CURRENT_CONFIG=$(curl -s -H "Authorization: Bearer $TOKEN" \
"http://${NPM_HOST}/api/nginx/proxy-hosts/${PROXY_HOST_ID}")

CURRENT_TARGET=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_host // .forward_host')
CURRENT_PORT=$(echo $CURRENT_CONFIG | jq -r '.[0].forward_port // .forward_port')
echo "Current NPM target: $CURRENT_TARGET:$CURRENT_PORT"

if [ "$(docker ps -q -f name=zoopzoop-blue)" ]; then
NEW_CONTAINER=zoopzoop-green
OLD_CONTAINER=zoopzoop-blue
NEW_PORT=8082
else
NEW_CONTAINER=zoopzoop-blue
OLD_CONTAINER=zoopzoop-green
NEW_PORT=8081
fi

docker run -d --restart unless-stopped \
-p $NEW_PORT:8080 \
--name $NEW_CONTAINER \
--network common \
-e SPRING_DATASOURCE_URL="${{secrets.TEST_DB_URL}}" \
-e SPRING_DATASOURCE_USERNAME="${{secrets.TEST_DB_USERNAME}}" \
-e SPRING_DATASOURCE_PASSWORD="${{secrets.TEST_DB_PASSWORD}}" \
Copy link

Copilot AI Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent spacing in GitHub Actions expressions. Use consistent spacing like ${{ secrets.TEST_DB_URL }} with spaces around the expression.

Suggested change
-e SPRING_DATASOURCE_PASSWORD="${{secrets.TEST_DB_PASSWORD}}" \
-e SPRING_DATASOURCE_PASSWORD="${{ secrets.TEST_DB_PASSWORD }}" \

Copilot uses AI. Check for mistakes.
ghcr.io/${{ github.repository }}/zoopzoop:latest

# 헬스체크
for i in {1..30}; do
if curl -s http://localhost:$NEW_PORT/actuator/health | grep -q '"status":"UP"'; then
echo "✅ New container is healthy!"
break
else
echo "Waiting for new container to be healthy..."
sleep 5
fi
if [ $i -eq 30 ]; then
echo "❌ Health check failed. Rolling back..."
docker stop $NEW_CONTAINER || true
docker rm $NEW_CONTAINER || true
exit 1
fi
done
Comment on lines +76 to +82
Copy link

Copilot AI Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The health check logic is incorrect. This condition will never be reached because the loop ends at i=30, but this check is inside the loop. Move this check outside the loop or restructure the logic.

Suggested change
if [ $i -eq 30 ]; then
echo "❌ Health check failed. Rolling back..."
docker stop $NEW_CONTAINER || true
docker rm $NEW_CONTAINER || true
exit 1
fi
done
done
# If the loop did not break, health check failed
if ! curl -s http://localhost:$NEW_PORT/actuator/health | grep -q '"status":"UP"'; then
echo "❌ Health check failed. Rolling back..."
docker stop $NEW_CONTAINER || true
docker rm $NEW_CONTAINER || true
exit 1

Copilot uses AI. Check for mistakes.

# NPM 트래픽 스위칭
DOMAIN_NAME=$(echo $CURRENT_CONFIG | jq -r '.domain_names[0]')
CERT_ID=$(echo "$CURRENT_CONFIG" | jq -r '.certificate_id')

SWITCH_RESPONSE=$(curl -s -w "%{http_code}" -X PUT "http://${NPM_HOST}/api/nginx/proxy-hosts/${PROXY_HOST_ID}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"domain_names\": [\"$DOMAIN_NAME\"],
\"forward_scheme\": \"http\",
\"forward_host\": \"$NEW_CONTAINER\",
\"forward_port\": 8080,
\"caching_enabled\": false,
\"block_exploits\": true,
\"advanced_config\": \"\",
\"locations\": [],
\"certificate_id\": $CERT_ID,
\"ssl_forced\": 1,
\"hsts_enabled\": 1,
\"hsts_subdomains\": 1
}")

HTTP_CODE=${SWITCH_RESPONSE: -3}
if [ "$HTTP_CODE" -ne 200 ] && [ "$HTTP_CODE" -ne 201 ]; then
echo "❌ Traffic switching failed! HTTP Code: $HTTP_CODE"
echo "Response: ${SWITCH_RESPONSE%???}"
docker stop $NEW_CONTAINER || true
docker rm $NEW_CONTAINER || true
exit 1
fi

docker stop $OLD_CONTAINER || true
docker rm $OLD_CONTAINER || true
108 changes: 108 additions & 0 deletions .github/workflows/test-server-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# 워크플로우 이름
name: Spring CI/CD Pipeline (Develop)

# develop 브랜치 PR에서만 실행
on:
pull_request:
branches:
- develop
paths:
- 'src/**'
- 'build.gradle*'
- 'settings.gradle*'
- 'gradle/**'
- 'Dockerfile'
- '.github/workflows/**'

jobs:
# ==================================
# CI: Test and Build and Push Docker Image
# ==================================
ci:
runs-on: ubuntu-latest

steps:
# 1. 소스 코드 체크아웃
- name: Checkout source code
uses: actions/checkout@v4

# 2. JDK 21 설치
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'

# 3. Gradle 캐시 설정
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

# 4. gradlew 실행 권한 부여
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew

# 5. application-secrets.yml 생성
- name: Generate application-secrets.yml
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_SECRET_YML }}" > src/main/resources/application-secrets.yml
echo "OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}" >> src/main/resources/application-secrets.yml

# 6. application-secrets-server.yml 생성
- name: Generate application-secrets-server.yml
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_SECRET_SERVER_YML }}" > src/main/resources/application-secrets-server.yml
echo "OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}" >> src/main/resources/application-secrets-server.yml

# 7. Gradle 테스트 실행
- name: Test with Gradle
run: ./gradlew test

# 8. 테스트 결과 요약 출력
- name: Show test results
run: |
echo "==== Test Results ===="
if compgen -G "build/test-results/test/TEST-*.xml" > /dev/null; then
total=$(grep '<testcase ' build/test-results/test/TEST-*.xml | wc -l)
failed=$(grep -h '<failure' build/test-results/test/TEST-*.xml | wc -l)
error=$(grep -h '<error' build/test-results/test/TEST-*.xml | wc -l)
passed=$((total - failed - error))
echo "Total tests: $total"
echo "Passed tests: $passed"
echo "Failed tests: $failed"
echo "Errored tests: $error"
else
echo "No test results found."
fi

# 9. Gradle 빌드 실행 (테스트 성공 시)
- name: Build with Gradle
run: ./gradlew build

# 10. GHCR 로그인
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

# 11. Docker 이미지 빌드 & 푸시
- name: Build & Push Docker Image
run: |
IMAGE_NAME=ghcr.io/${{ github.repository }}/zoopzoop

docker build -t $IMAGE_NAME:${GITHUB_SHA} .
docker tag $IMAGE_NAME:${GITHUB_SHA} $IMAGE_NAME:latest

docker push $IMAGE_NAME:${GITHUB_SHA}
docker push $IMAGE_NAME:latest

Loading