Skip to content

Merge pull request #118 from hamlsy/feat/117 #114

Merge pull request #118 from hamlsy/feat/117

Merge pull request #118 from hamlsy/feat/117 #114

Workflow file for this run

name: Deploy to S3
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
AWS_REGION: ap-northeast-2
NODE_VERSION: '18'
jobs:
# 빌드 및 테스트
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GIT_PERSONAL_ACCESS_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
# cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Setup environment
run: |
# 환경 결정 (개발/프로덕션만)
#if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
ENV="production"
#else
# ENV="development"
#fi
# 환경변수 설정
node scripts/setup-env.js $ENV setup
echo "ENVIRONMENT=$ENV" >> $GITHUB_ENV
- name: Validate environment
run: npm run env:validate
- name: Lint code
run: npm run lint
- name: Clean build artifacts and cache
run: |
echo "🧹 Cleaning dist folder..."
rm -rf dist
echo "🧹 Cleaning node_modules cache..."
rm -rf node_modules/.cache
echo "🧹 Cleaning npm cache..."
npm cache clean --force
echo "✅ Cleanup completed!"
- name: Build application
run: |
#if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
# npm run build:prod
npm run build:prod
#else
# npm run build:dev
#fi
# 빌드된 index.html 확인
echo "📋 Checking built index.html..."
echo "JS files referenced:"
grep -o 'src="[^"]*\.js"' dist/index.html || echo "No JS references found"
# 실제 생성된 JS 파일 확인
echo "📋 Actual JS files in dist:"
ls -lh dist/js/*.js || echo "No JS files found"
# 참조와 실제 파일이 일치하는지 검증
JS_REF=$(grep -o 'src="/js/app\.[^"]*\.js"' dist/index.html | sed 's|src="/js/||;s|"||' | head -1)
if [ -n "$JS_REF" ]; then
echo "Checking if referenced file exists: $JS_REF"
if [ -f "dist/js/$JS_REF" ]; then
echo "✅ Referenced file exists: $JS_REF"
else
echo "❌ ERROR: Referenced file NOT found: $JS_REF"
echo "Available files:"
ls -lh dist/js/
exit 1
fi
fi
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1
# S3 배포
deploy:
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GIT_PERSONAL_ACCESS_TOKEN }}
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Deploy to S3
run: |
# 환경 결정
#if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
ENV="production"
# DEPLOY_PATH="/"
#else
# ENV="development"
# DEPLOY_PATH="/dev/"
#fi
DEPLOY_PATH=""
BUCKET="${{ secrets.S3_BUCKET }}"
echo "Deploying to $ENV environment..."
echo "S3 Bucket: $BUCKET"
echo "Deploy Path: $DEPLOY_PATH"
# S3에 파일 업로드 (경로별 배포)
# 정적 파일들 업로드 (캐시 설정, HTML/JSON 제외)
aws s3 sync dist/ s3://$BUCKET$DEPLOY_PATH \
--cache-control "public, max-age=31536000, immutable" \
--exclude "*.html" --exclude "*.json"
# HTML 파일은 캐시하지 않음
aws s3 cp dist/index.html s3://$BUCKET$DEPLOY_PATH/index.html \
--cache-control "no-cache, no-store, must-revalidate"
# manifest.json 파일이 있으면 업로드
if [ -f "dist/manifest.json" ]; then
aws s3 cp dist/manifest.json s3://$BUCKET$DEPLOY_PATH/manifest.json \
--cache-control "no-cache, no-store, must-revalidate"
fi
# Welcome 페이지 업로드
if [ -f "dist/welcome/index.html" ]; then
aws s3 cp dist/welcome/index.html s3://$BUCKET$DEPLOY_PATH/welcome/index.html \
--cache-control "no-cache, no-store, must-revalidate"
echo "✅ Welcome page uploaded"
else
echo "⚠️ Welcome page not found in dist/welcome/index.html"
fi
echo "Deployment completed successfully!"
echo "Application URL: https://$BUCKET.s3-website.ap-northeast-2.amazonaws.com$DEPLOY_PATH"
- name: CloudFront Invalidation
env:
CLOUD_FRONT_ID: ${{ secrets.AWS_CLOUDFRONT_ID}}
run: |
if [ -n "$CLOUD_FRONT_ID" ]; then
echo "Invalidating CloudFront cache..."
# 무효화 요청 생성
INVALIDATION_OUTPUT=$(aws cloudfront create-invalidation \
--distribution-id $CLOUD_FRONT_ID \
--paths "/*")
if [ $? -eq 0 ]; then
# 무효화 ID 추출
INVALIDATION_ID=$(echo "$INVALIDATION_OUTPUT" | grep -oP '"Id"\s*:\s*"\K[^"]+' | head -1)
if [ -n "$INVALIDATION_ID" ]; then
echo "✅ CloudFront cache invalidation initiated: $INVALIDATION_ID"
# 무효화 완료까지 대기 (최대 15분)
echo "Waiting for invalidation to complete (this may take up to 15 minutes)..."
MAX_WAIT_TIME=900 # 15분 (초)
WAIT_INTERVAL=10 # 10초마다 확인
ELAPSED_TIME=0
while [ $ELAPSED_TIME -lt $MAX_WAIT_TIME ]; do
sleep $WAIT_INTERVAL
ELAPSED_TIME=$((ELAPSED_TIME + WAIT_INTERVAL))
STATUS_OUTPUT=$(aws cloudfront get-invalidation \
--distribution-id $CLOUD_FRONT_ID \
--id $INVALIDATION_ID 2>&1)
if [ $? -eq 0 ]; then
STATUS=$(echo "$STATUS_OUTPUT" | grep -oP '"Status"\s*:\s*"\K[^"]+' | head -1)
if [ "$STATUS" == "Completed" ]; then
echo "✅ CloudFront cache invalidation completed!"
break
elif [ "$STATUS" == "InProgress" ]; then
PROGRESS=$((ELAPSED_TIME * 100 / MAX_WAIT_TIME))
echo "Invalidation in progress... (${PROGRESS}% of max wait time elapsed)"
fi
fi
done
if [ $ELAPSED_TIME -ge $MAX_WAIT_TIME ]; then
echo "⚠️ Invalidation is still in progress after maximum wait time. It will continue in the background."
fi
else
echo "⚠️ Failed to extract invalidation ID from response"
fi
else
echo "⚠️ Failed to invalidate CloudFront cache"
fi
else
echo "⚠️ CloudFront ID not configured, skipping invalidation"
fi
- name: Notify deployment
if: always()
run: |
if [[ "${{ job.status }}" == "success" ]]; then
echo "✅ Deployment successful!"
else
echo "❌ Deployment failed!"
fi