Merge pull request #47 from Today-s-Sound/refactor/#41-test1 #34
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: TodaySound Server CI/CD | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| env: | |
| IMAGE_NAME: todaysound-server | |
| jobs: | |
| build-and-deploy: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout source code | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - name: Cache Gradle | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle- | |
| - name: Grant execute permission for gradlew | |
| run: chmod +x ./gradlew | |
| - name: Build Spring Boot app (skip tests) | |
| run: ./gradlew clean bootJar -x test | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Build and tag Docker image | |
| run: | | |
| GIT_SHA=${GITHUB_SHA::7} | |
| docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest -t ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${GIT_SHA} . | |
| - name: Push Docker image | |
| run: | | |
| GIT_SHA=${GITHUB_SHA::7} | |
| docker push ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest | |
| docker push ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${GIT_SHA} | |
| - name: Deploy to EC2 via SSH | |
| uses: appleboy/[email protected] | |
| env: | |
| DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} | |
| IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
| DB_URL: ${{ secrets.DB_URL }} | |
| DB_USERNAME: ${{ secrets.DB_USERNAME }} | |
| DB_PASSWORD: ${{ secrets.DB_PASSWORD }} | |
| FCM_JSON: ${{ secrets.FCM_JSON }} | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ${{ secrets.EC2_USERNAME }} | |
| key: ${{ secrets.EC2_PRIVATE_KEY }} | |
| script_stop: true | |
| envs: DOCKER_USERNAME,IMAGE_NAME,DB_URL,DB_USERNAME,DB_PASSWORD,FCM_JSON | |
| script: | | |
| set -e | |
| # Variables | |
| IMAGE="${DOCKER_USERNAME}/${IMAGE_NAME}:latest" | |
| APP_NAME="todaysound-server" | |
| NET_NAME="todaysound-net" | |
| PORT=8080 | |
| # Install Docker if not present | |
| if ! command -v docker &> /dev/null; then | |
| curl -fsSL https://get.docker.com -o get-docker.sh | |
| sudo sh get-docker.sh | |
| sudo usermod -aG docker $USER | |
| fi | |
| # Start Docker service | |
| sudo systemctl daemon-reload || true | |
| sudo systemctl start docker | |
| sudo systemctl enable docker | |
| # Docker setup | |
| sudo docker network inspect ${NET_NAME} >/dev/null 2>&1 || sudo docker network create ${NET_NAME} | |
| sudo docker pull ${IMAGE} | |
| # Run or replace container | |
| sudo docker rm -f ${APP_NAME} || true | |
| sudo docker run -d \ | |
| --name ${APP_NAME} \ | |
| --restart unless-stopped \ | |
| --network ${NET_NAME} \ | |
| -p 127.0.0.1:${PORT}:8080 \ | |
| -e SPRING_PROFILES_ACTIVE=prod \ | |
| -e DB_URL="${DB_URL}" \ | |
| -e DB_USERNAME="${DB_USERNAME}" \ | |
| -e DB_PASSWORD="${DB_PASSWORD}" \ | |
| -e FCM_JSON="${FCM_JSON}" \ | |
| ${IMAGE} | |
| # Health check (local) - try basic endpoint first | |
| echo "Waiting for app to start..." && sleep 45 | |
| # Show container status | |
| sudo docker ps -a | grep ${APP_NAME} || true | |
| # Try basic health check first (disable set -e for this section) | |
| set +e | |
| HEALTH_CHECK_PASSED=false | |
| for i in {1..15}; do | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${PORT}/actuator/health 2>/dev/null) | |
| if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "401" ] || [ "$HTTP_CODE" = "403" ]; then | |
| echo "Health check passed! HTTP code: $HTTP_CODE" | |
| HEALTH_CHECK_PASSED=true | |
| break | |
| else | |
| echo "Attempt $i failed, HTTP code: $HTTP_CODE, retrying in 5s..." | |
| sleep 5 | |
| fi | |
| done | |
| set -e | |
| if [ "$HEALTH_CHECK_PASSED" = "false" ]; then | |
| echo "Health check failed after 15 attempts" | |
| sudo docker logs ${APP_NAME} --tail 50 || true | |
| exit 1 | |
| fi | |
| # Optional domain health check (non-blocking) | |
| curl -f http://today-sound.com/ || echo "Domain check failed, but continuing..." |