diff --git a/.github/workflows/cd-api-dev.yml b/.github/workflows/cd-api-dev.yml new file mode 100644 index 0000000..17ce669 --- /dev/null +++ b/.github/workflows/cd-api-dev.yml @@ -0,0 +1,97 @@ +name: CD API DEV + +on: + push: + branches: [ develop ] + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + api_changed: ${{ steps.filter.outputs.api }} + steps: + - uses: actions/checkout@v4 + - id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + api: + - 'api/**' + + build-api: + needs: detect-changes + if: needs.detect-changes.outputs.api_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'corretto' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Grant execute permission for run-test-mysql-redis.sh + run: chmod +x run-test-mysql-redis.sh + working-directory: ./domain + + - name: Run test mysql redis script + run: ./run-test-mysql-redis.sh + working-directory: ./domain + + - name: Test & Build api only + run: ./gradlew :api:build + + - name: Sign in Dockerhub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build the Docker image + run: docker build -f ./Dockerfile --platform linux/amd64 --no-cache -t samhap/kokomen-notification-api:dev . + working-directory: ./api + + - name: Push the Docker Image to Dockerhub + run: docker push samhap/kokomen-notification-api:dev + working-directory: ./api + + deploy-api: + needs: build-api + runs-on: [ self-hosted, dev-notification ] + steps: + - name: Stop existing container + run: sudo docker rm -f kokomen-notification-dev-api || true + + - name: Remove old API Docker image + run: | + if sudo docker images samhap/kokomen-notification-api:dev -q | grep -q .; then + sudo docker rmi -f samhap/kokomen-notification-api:dev || true + fi + + - name: pull docker compose yaml files + working-directory: /home/ubuntu + run: | + [ -d kokomen-notification ] || git clone --filter=blob:none --no-checkout https://github.com/samhap-soft/kokomen-notification.git + cd kokomen-notification + git sparse-checkout init --cone + git fetch origin develop + git checkout develop + git sparse-checkout set docker/dev + git pull origin develop + + - name: Docker Image pull + run: sudo docker pull samhap/kokomen-notification-api:dev + + - name: Docker run + working-directory: /home/ubuntu + env: + MYSQL_ROOT_PASSWORD_DEV: ${{ secrets.MYSQL_ROOT_PASSWORD_DEV }} + SPRING_DATASOURCE_USERNAME_DEV: ${{ secrets.SPRING_DATASOURCE_USERNAME_DEV }} + SPRING_DATASOURCE_PASSWORD_DEV: ${{ secrets.SPRING_DATASOURCE_PASSWORD_DEV }} + run: | + export HOSTNAME=$(hostname) + cd kokomen-notification/docker/dev + sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-api diff --git a/.github/workflows/cd-internal-dev.yml b/.github/workflows/cd-internal-dev.yml new file mode 100644 index 0000000..5ce5ec8 --- /dev/null +++ b/.github/workflows/cd-internal-dev.yml @@ -0,0 +1,97 @@ +name: CD INTERNAL DEV + +on: + push: + branches: [ develop ] + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + internal_changed: ${{ steps.filter.outputs.internal }} + steps: + - uses: actions/checkout@v4 + - id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + internal: + - 'internal/**' + + build-internal: + needs: detect-changes + if: needs.detect-changes.outputs.internal_changed == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'corretto' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Grant execute permission for run-test-mysql-redis.sh + run: chmod +x run-test-mysql-redis.sh + working-directory: ./domain + + - name: Run test mysql redis script + run: ./run-test-mysql-redis.sh + working-directory: ./domain + + - name: Test & Build internal only + run: ./gradlew :internal:build + + - name: Sign in Dockerhub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build the Docker image + run: docker build -f ./Dockerfile --platform linux/amd64 --no-cache -t samhap/kokomen-notification-internal:dev . + working-directory: ./internal + + - name: Push the Docker Image to Dockerhub + run: docker push samhap/kokomen-notification-internal:dev + working-directory: ./internal + + deploy-internal: + needs: build-internal + runs-on: [ self-hosted, dev-notification ] + steps: + - name: Stop existing container + run: sudo docker rm -f kokomen-notification-dev-internal || true + + - name: Remove old INTERNAL Docker image + run: | + if sudo docker images samhap/kokomen-notification-internal:dev -q | grep -q .; then + sudo docker rmi -f samhap/kokomen-notification-internal:dev || true + fi + + - name: pull docker compose yaml files + working-directory: /home/ubuntu + run: | + [ -d kokomen-notification ] || git clone --filter=blob:none --no-checkout https://github.com/samhap-soft/kokomen-notification.git + cd kokomen-notification + git sparse-checkout init --cone + git fetch origin develop + git checkout develop + git sparse-checkout set docker/dev + git pull origin develop + + - name: Docker Image pull + run: sudo docker pull samhap/kokomen-notification-internal:dev + + - name: Docker run + working-directory: /home/ubuntu + env: + MYSQL_ROOT_PASSWORD_DEV: ${{ secrets.MYSQL_ROOT_PASSWORD_DEV }} + SPRING_DATASOURCE_USERNAME_DEV: ${{ secrets.SPRING_DATASOURCE_USERNAME_DEV }} + SPRING_DATASOURCE_PASSWORD_DEV: ${{ secrets.SPRING_DATASOURCE_PASSWORD_DEV }} + run: | + export HOSTNAME=$(hostname) + cd kokomen-notification/docker/dev + sudo -E docker compose -f docker-compose-dev.yml up -d kokomen-notification-dev-internal diff --git a/.github/workflows/ci-api-test.yml b/.github/workflows/ci-api-test.yml new file mode 100644 index 0000000..fcaded1 --- /dev/null +++ b/.github/workflows/ci-api-test.yml @@ -0,0 +1,65 @@ +name: CI API TEST + +on: + pull_request: + branches: [ main, develop ] + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + api_changed: ${{ steps.filter.outputs.api }} + steps: + - uses: actions/checkout@v4 + - id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + api: + - 'api/**' + + build: + needs: detect-changes + if: needs.detect-changes.outputs.api_changed == 'true' + runs-on: ubuntu-latest + permissions: + checks: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'corretto' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Grant execute permission for run-test-mysql-redis.sh + run: chmod +x run-test-mysql-redis.sh + working-directory: ./domain + + - name: Run test mysql redis script + run: ./run-test-mysql-redis.sh + working-directory: ./domain + + - name: Test & Build api only + run: ./gradlew :api:build + + - name: Publish Unit Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: ${{ always() }} + with: + files: ${{ github.workspace }}/api/build/test-results/**/*.xml + seconds_between_github_reads: 1.0 + seconds_between_github_writes: 3.0 + secondary_rate_limit_wait_seconds: 90.0 + + - name: When test fail, comment on that code + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: ${{ github.workspace }}/api/build/test-results/**/*.xml + token: ${{ github.token }} diff --git a/.github/workflows/ci-internal-test.yml b/.github/workflows/ci-internal-test.yml new file mode 100644 index 0000000..f0707e8 --- /dev/null +++ b/.github/workflows/ci-internal-test.yml @@ -0,0 +1,65 @@ +name: CI INTERNAL TEST + +on: + pull_request: + branches: [ main, develop ] + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + internal_changed: ${{ steps.filter.outputs.internal }} + steps: + - uses: actions/checkout@v4 + - id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + internal: + - 'internal/**' + + build: + needs: detect-changes + if: needs.detect-changes.outputs.internal_changed == 'true' + runs-on: ubuntu-latest + permissions: + checks: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'corretto' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Grant execute permission for run-test-mysql-redis.sh + run: chmod +x run-test-mysql-redis.sh + working-directory: ./domain + + - name: Run test mysql redis script + run: ./run-test-mysql-redis.sh + working-directory: ./domain + + - name: Test & Build internal only + run: ./gradlew :internal:build + + - name: Publish Unit Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: ${{ always() }} + with: + files: ${{ github.workspace }}/internal/build/test-results/**/*.xml + seconds_between_github_reads: 1.0 + seconds_between_github_writes: 3.0 + secondary_rate_limit_wait_seconds: 90.0 + + - name: When test fail, comment on that code + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: ${{ github.workspace }}/internal/build/test-results/**/*.xml + token: ${{ github.token }} diff --git a/docker/dev/docker-compose-dev.yml b/docker/dev/docker-compose-dev.yml new file mode 100644 index 0000000..1e00031 --- /dev/null +++ b/docker/dev/docker-compose-dev.yml @@ -0,0 +1,86 @@ +services: + # ✅ Notification Internal Spring Application + kokomen-notification-dev-internal: + image: samhap/kokomen-notification-internal:dev + container_name: kokomen-notification-dev-internal + restart: on-failure:3 + expose: + - 8080 + volumes: + - ./notification/internal/app/logs:/logs + environment: + TZ: Asia/Seoul + JAVA_TOOL_OPTIONS: -Duser.timezone=Asia/Seoul + HOSTNAME: ${HOSTNAME} + SPRING_PROFILES_ACTIVE: dev + SPRING_DATASOURCE_USERNAME_DEV: ${SPRING_DATASOURCE_USERNAME_DEV} + SPRING_DATASOURCE_PASSWORD_DEV: ${SPRING_DATASOURCE_PASSWORD_DEV} + networks: + - dev-kokomen-net + + kokomen-notification-dev-api: + image: samhap/kokomen-notification-api:dev + container_name: kokomen-notification-dev-api + restart: on-failure:3 + expose: + - 8080 + volumes: + - ./notification/api/app/logs:/logs + environment: + TZ: Asia/Seoul + JAVA_TOOL_OPTIONS: -Duser.timezone=Asia/Seoul + HOSTNAME: ${HOSTNAME} + SPRING_PROFILES_ACTIVE: dev + SPRING_DATASOURCE_USERNAME_DEV: ${SPRING_DATASOURCE_USERNAME_DEV} + SPRING_DATASOURCE_PASSWORD_DEV: ${SPRING_DATASOURCE_PASSWORD_DEV} + networks: + - dev-kokomen-net + + kokomen-notification-mysql-dev: + image: mysql:8.4.5 + container_name: kokomen-notification-mysql-dev + command: + [ + "mysqld", + "--character-set-server=utf8mb4", + "--collation-server=utf8mb4_general_ci" + ] + volumes: + - notification-mysql-data:/var/lib/mysql + - notification-mysql-init:/docker-entrypoint-initdb.d + expose: + - 3306 + restart: always + environment: + TZ: Asia/Seoul + MYSQL_USER: ${SPRING_DATASOURCE_USERNAME_DEV} + MYSQL_PASSWORD: ${SPRING_DATASOURCE_PASSWORD_DEV} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD_DEV} + MYSQL_DATABASE: kokomen-notification-dev + LANG: C.UTF-8 + MYSQL_INIT_CONNECT: "SET NAMES utf8mb4" + networks: + - dev-kokomen-net + + notification-mysql-dev-exporter: + image: prom/mysqld-exporter + container_name: notification-mysql-dev-exporter + restart: unless-stopped + environment: + DATA_SOURCE_NAME: "root:${MYSQL_ROOT_PASSWORD_DEV}@tcp(kokomen-notification-mysql-dev:3306)/" + TZ: Asia/Seoul + expose: + - 9104 + volumes: + - ./my.cnf:/.my.cnf + networks: + - dev-kokomen-net + +volumes: + notification-mysql-data: + notification-mysql-init: + +networks: + dev-kokomen-net: + external: true + driver: bridge diff --git a/docker/dev/my.cnf b/docker/dev/my.cnf new file mode 100644 index 0000000..8672866 --- /dev/null +++ b/docker/dev/my.cnf @@ -0,0 +1,4 @@ +[client] +user=root +password=root +host=kokomen-notification-mysql-dev diff --git a/domain/local-docker-compose.yml b/domain/local-docker-compose.yml index d3e4d49..3a7e277 100644 --- a/domain/local-docker-compose.yml +++ b/domain/local-docker-compose.yml @@ -41,4 +41,5 @@ services: networks: kokomen-notification-network: + external: true driver: bridge diff --git a/domain/src/main/java/com/samhap/kokomen/notification/domain/Notification.java b/domain/src/main/java/com/samhap/kokomen/notification/domain/Notification.java index 7fe0350..42b63f7 100644 --- a/domain/src/main/java/com/samhap/kokomen/notification/domain/Notification.java +++ b/domain/src/main/java/com/samhap/kokomen/notification/domain/Notification.java @@ -35,5 +35,6 @@ public class Notification extends BaseEntity { public Notification(Long receiverMemberId, String content) { this.receiverMemberId = receiverMemberId; this.content = content; + this.notificationState = NotificationState.UNREAD; } } diff --git a/domain/src/main/resources/application-domain.yml b/domain/src/main/resources/application-domain.yml index b443166..1e73ec2 100644 --- a/domain/src/main/resources/application-domain.yml +++ b/domain/src/main/resources/application-domain.yml @@ -26,3 +26,19 @@ spring: hibernate: ddl-auto: validate +--- +# dev profile +spring: + config: + activate: + on-profile: dev + datasource: + url: jdbc:mysql://kokomen-notification-mysql-dev:3306/kokomen-notification-dev + username: ${SPRING_DATASOURCE_USERNAME_DEV} + password: ${SPRING_DATASOURCE_PASSWORD_DEV} + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + database: mysql + show-sql: false + hibernate: + ddl-auto: validate diff --git a/internal/local-internal-docker-compose.yml b/internal/local-internal-docker-compose.yml index 6e0a706..9715dd3 100644 --- a/internal/local-internal-docker-compose.yml +++ b/internal/local-internal-docker-compose.yml @@ -14,4 +14,5 @@ services: networks: kokomen-notification-network: + external: true driver: bridge diff --git a/internal/run-local-internal.sh b/internal/run-local-internal.sh index 80feb78..a8d0e21 100755 --- a/internal/run-local-internal.sh +++ b/internal/run-local-internal.sh @@ -23,11 +23,10 @@ fi # 도메인 도커 컴포즈 실행 docker compose -f ../domain/local-docker-compose.yml up -d -../gradlew clean build +../gradlew clean :internal:build # 로컬 도커 컴포즈 실행 # 실행 전에 헬스 체크 필요 cd ../internal docker rm -f kokomen-notification-local-internal docker compose -f local-internal-docker-compose.yml up --build -d - diff --git a/internal/src/main/java/com/samhap/kokomen/KokomenNotificationInternalApplication.java b/internal/src/main/java/com/samhap/kokomen/KokomenNotificationInternalApplication.java index 0cf578b..12333e7 100644 --- a/internal/src/main/java/com/samhap/kokomen/KokomenNotificationInternalApplication.java +++ b/internal/src/main/java/com/samhap/kokomen/KokomenNotificationInternalApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class KokomenNotificationInternalApplication { diff --git a/internal/src/main/java/com/samhap/kokomen/notification/controller/NotificationInternalController.java b/internal/src/main/java/com/samhap/kokomen/notification/controller/NotificationInternalController.java index b8b1c1a..7caea12 100644 --- a/internal/src/main/java/com/samhap/kokomen/notification/controller/NotificationInternalController.java +++ b/internal/src/main/java/com/samhap/kokomen/notification/controller/NotificationInternalController.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,7 +17,7 @@ public class NotificationInternalController { private final NotificationInternalService notificationInternalService; @PostMapping - public ResponseEntity saveNotification(NotificationRequest notificationRequest) { + public ResponseEntity saveNotification(@RequestBody NotificationRequest notificationRequest) { notificationInternalService.saveNotification(notificationRequest); return ResponseEntity.noContent().build(); }