diff --git a/.github/workflows/dev-CI.yml b/.github/workflows/dev-CI.yml index b1b933aa..bf2da314 100644 --- a/.github/workflows/dev-CI.yml +++ b/.github/workflows/dev-CI.yml @@ -2,14 +2,11 @@ name: dev-CI on: pull_request: - branches: - - develop - types: - - opened - - synchronize - - reopened + branches: [ "develop" ] + jobs: dev-ci: + # Using Environment - dev 환경 environment: dev # Operating system - ubuntu-22.04 @@ -31,14 +28,43 @@ jobs: # gradle caching - 빌드 시간 향상 - name: Gradle Caching - uses: gradle/actions/setup-gradle@v4 + uses: actions/cache@v3 with: - gradle-home-cache-cleanup: true + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- - # Inject environment variables - application-secret.properties 생성 - - name: Inject application-secret.properties + # Inject environment variables - 환경 변수를 yml 파일에 주입 + - name: Inject environment variables into application-dev.yml + env: + DEV_DB_URL: ${{ secrets.DEV_DB_URL }} + DEV_DB_USERNAME: ${{ secrets.DEV_DB_USERNAME }} + DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }} + DEV_JWT_SECRET: ${{ secrets.DEV_JWT_SECRET }} + DEV_KAKAO_CLIENT_ID: ${{ secrets.DEV_KAKAO_CLIENT_ID }} + DEV_KAKAO_CLIENT_SECRET: ${{ secrets.DEV_KAKAO_CLIENT_SECRET }} + DEV_KAKAO_REDIRECT_URI: ${{ secrets.DEV_KAKAO_REDIRECT_URI }} + DEV_REDIS_HOST: ${{ secrets.DEV_REDIS_HOST }} + DEV_REDIS_PORT: ${{ secrets.DEV_REDIS_PORT }} + DEV_REDIS_PASSWORD: ${{ secrets.DEV_REDIS_PASSWORD }} + DEV_S3_ACCESS_KEY: ${{ secrets.DEV_S3_ACCESS_KEY }} + DEV_S3_SECRET_KEY: ${{ secrets.DEV_S3_SECRET_KEY }} + DEV_COOLSMS_KEY: ${{ secrets.DEV_COOLSMS_KEY }} + DEV_COOLSMS_NUMBER: ${{ secrets.DEV_COOLSMS_NUMBER }} + DEV_COOLSMS_SECRET: ${{ secrets.DEV_COOLSMS_SECRET }} + DEV_ACCESS_TOKEN_EXPIRE_TIME: ${{ secrets.DEV_ACCESS_TOKEN_EXPIRE_TIME }} + DEV_REFRESH_TOKEN_EXPIRE_TIME: ${{ secrets.DEV_REFRESH_TOKEN_EXPIRE_TIME }} + DEV_ALLOWED_ORIGINS: ${{ secrets.DEV_ALLOWED_ORIGINS }} + DEV_SERVER_URL: ${{ secrets.DEV_SERVER_URL }} + DEV_ACTUATOR_PORT: ${{ secrets.DEV_ACTUATOR_PORT }} + DEV_ACTUATOR_PATH: ${{ secrets.DEV_ACTUATOR_PATH }} + DEV_SLACK_WEBHOOK_URL: ${{ secrets.DEV_SLACK_WEBHOOK_URL }} run: | - echo "${{ secrets.APPLICATION_SECRET_SPRING }}" > src/main/resources/application-secret.properties + cd ./src/main/resources + envsubst < application-dev.yml > application-dev.tmp.yml && mv application-dev.tmp.yml application-dev.yml # gradle build - 테스트 없이 gradle 빌드 - name: Build with Gradle diff --git a/.gitignore b/.gitignore index e3eae835..4b05952c 100644 --- a/.gitignore +++ b/.gitignore @@ -179,9 +179,8 @@ Temporary Items # End of https://www.toptal.com/developers/gitignore/api/intellij,java,macos.gradle/ .idea/ -# Ignore application profile +# Ignore application-local.yml src/main/resources/application-local.yml -src/main/resources/application-secret.properties ## Ignore Qclass src/main/generated/querydsl diff --git a/Jenkinsfile b/Jenkinsfile index 1e7f999b..7baadcf8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,9 +2,9 @@ pipeline { agent any environment { - // PORT - EXTERNAL_PORT_BLUE = credentials('EXTERNAL_PORT_BLUE') - EXTERNAL_PORT_GREEN = credentials('EXTERNAL_PORT_GREEN') + // PORT + EXTERNAL_PORT_BLUE = credentials('EXTERNAL_PORT_BLUE') + EXTERNAL_PORT_GREEN = credentials('EXTERNAL_PORT_GREEN') } stages { @@ -23,7 +23,6 @@ pipeline { // DOCKER DOCKER_HUB_DEV_CREDENTIAL_ID = 'DOCKER_HUB_DEV_CREDENTIALS' DOCKER_HUB_PROD_CREDENTIAL_ID = 'DOCKER_HUB_PROD_CREDENTIALS' - DOCKER_HUB_CREDENTIAL_ID = BRANCH_NAME.equals(PROD_BRANCH) ? DOCKER_HUB_PROD_CREDENTIAL_ID : DOCKER_HUB_DEV_CREDENTIAL_ID // SSH SSH_CREDENTIAL_ID = OPERATION_ENV.toUpperCase() + '_SSH' @@ -32,20 +31,10 @@ pipeline { // ENVIRONMENT CONFIG FILE ENVIRONMENT_CONFIG_FILE = 'application-' + OPERATION_ENV + '.yml' - - echo "Branch: ${BRANCH_NAME}, Environment: ${OPERATION_ENV}" } } } - stage('Git Checkout') { - steps { - echo 'Checkout Remote Repository' - git branch: "${env.BRANCH_NAME}", - url: REPOSITORY_URL - } - } - stage('Parse Internal Port') { steps { script { @@ -55,10 +44,19 @@ pipeline { } } + stage('Git Checkout') { + steps { + echo 'Checkout Remote Repository' + git branch: "${env.BRANCH_NAME}", + url: REPOSITORY_URL + } + } + stage('Deploy to Server') { steps { echo 'Deploy to Server' script { + def DOCKER_HUB_CREDENTIAL_ID = BRANCH_NAME.equals(PROD_BRANCH) ? DOCKER_HUB_PROD_CREDENTIAL_ID : DOCKER_HUB_DEV_CREDENTIAL_ID withCredentials([ usernamePassword(credentialsId: DOCKER_HUB_CREDENTIAL_ID, usernameVariable: 'DOCKER_HUB_ID', diff --git a/src/main/java/com/beat/domain/booking/dao/BookingRepository.java b/src/main/java/com/beat/domain/booking/dao/BookingRepository.java index 6f5a59c0..cd12d617 100644 --- a/src/main/java/com/beat/domain/booking/dao/BookingRepository.java +++ b/src/main/java/com/beat/domain/booking/dao/BookingRepository.java @@ -8,7 +8,6 @@ import org.springframework.data.repository.query.Param; import com.beat.domain.booking.domain.Booking; -import com.beat.domain.booking.domain.BookingStatus; public interface BookingRepository extends JpaRepository { @Query("SELECT b FROM Booking b " + @@ -34,9 +33,6 @@ Optional findFirstByBookerNameAndBookerPhoneNumberAndBirthDateAndPasswo List findByUsersId(Long userId); - @Query("SELECT COUNT(b) > 0 FROM Booking b WHERE b.schedule.id IN :scheduleIds AND b.bookingStatus NOT IN :excludedStatuses") - boolean existsActiveBookingByScheduleIds( - @Param("scheduleIds") List scheduleIds, - @Param("excludedStatuses") List excludedStatuses - ); -} + @Query("SELECT COUNT(b) > 0 FROM Booking b WHERE b.schedule.id IN :scheduleIds AND b.bookingStatus != 'BOOKING_CANCELLED'") + boolean existsByScheduleIdIn(@Param("scheduleIds") List scheduleIds); +} \ No newline at end of file diff --git a/src/main/java/com/beat/domain/performance/application/PerformanceManagementService.java b/src/main/java/com/beat/domain/performance/application/PerformanceManagementService.java index 543ad059..47da088c 100644 --- a/src/main/java/com/beat/domain/performance/application/PerformanceManagementService.java +++ b/src/main/java/com/beat/domain/performance/application/PerformanceManagementService.java @@ -4,12 +4,12 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.List; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.beat.domain.booking.dao.BookingRepository; -import com.beat.domain.booking.domain.BookingStatus; import com.beat.domain.cast.dao.CastRepository; import com.beat.domain.cast.domain.Cast; import com.beat.domain.member.dao.MemberRepository; @@ -96,7 +96,7 @@ public PerformanceResponse createPerformance(Long memberId, PerformanceRequest r performance ); }) - .toList(); + .collect(Collectors.toList()); performance.assignScheduleNumbers(schedules); scheduleRepository.saveAll(schedules); @@ -105,7 +105,7 @@ public PerformanceResponse createPerformance(Long memberId, PerformanceRequest r List performanceDates = schedules.stream() .map(Schedule::getPerformanceDate) - .toList(); + .collect(Collectors.toList()); performance.updatePerformancePeriod(performanceDates); performanceRepository.save(performance); @@ -116,7 +116,7 @@ public PerformanceResponse createPerformance(Long memberId, PerformanceRequest r castRequest.castPhoto(), performance )) - .toList(); + .collect(Collectors.toList()); castRepository.saveAll(casts); List staffs = request.staffList().stream() @@ -126,7 +126,7 @@ public PerformanceResponse createPerformance(Long memberId, PerformanceRequest r staffRequest.staffPhoto(), performance )) - .toList(); + .collect(Collectors.toList()); staffRepository.saveAll(staffs); List performanceImageList = request.performanceImageList().stream() @@ -134,7 +134,7 @@ public PerformanceResponse createPerformance(Long memberId, PerformanceRequest r performanceImageRequest.performanceImage(), performance )) - .toList(); + .collect(Collectors.toList()); performanceImageRepository.saveAll(performanceImageList); return mapToPerformanceResponse(performance, schedules, casts, staffs, performanceImageList); @@ -150,7 +150,7 @@ private PerformanceResponse mapToPerformanceResponse(Performance performance, Li calculateDueDate(schedule.getPerformanceDate().toLocalDate()), schedule.getScheduleNumber() )) - .toList(); + .collect(Collectors.toList()); List castResponses = casts.stream() .map(cast -> CastResponse.of( @@ -159,7 +159,7 @@ private PerformanceResponse mapToPerformanceResponse(Performance performance, Li cast.getCastRole(), cast.getCastPhoto() )) - .toList(); + .collect(Collectors.toList()); List staffResponses = staffs.stream() .map(staff -> StaffResponse.of( @@ -168,14 +168,14 @@ private PerformanceResponse mapToPerformanceResponse(Performance performance, Li staff.getStaffRole(), staff.getStaffPhoto() )) - .toList(); + .collect(Collectors.toList()); List performanceImageResponses = performanceImages.stream() .map(image -> PerformanceImageResponse.of( image.getId(), image.getPerformanceImageUrl() )) - .toList(); + .collect(Collectors.toList()); return PerformanceResponse.of( performance.getUsers().getId(), @@ -226,10 +226,9 @@ public void deletePerformance(Long memberId, Long performanceId) { List scheduleIds = scheduleRepository.findIdsByPerformanceId(performanceId); - List statusesToExclude = List.of(BookingStatus.BOOKING_CANCELLED, BookingStatus.BOOKING_DELETED); - boolean isBookerExist = bookingRepository.existsActiveBookingByScheduleIds(scheduleIds, statusesToExclude); + boolean hasBookings = bookingRepository.existsByScheduleIdIn(scheduleIds); - if (isBookerExist) { + if (hasBookings) { throw new ForbiddenException(PerformanceErrorCode.PERFORMANCE_DELETE_FAILED); } diff --git a/src/main/java/com/beat/domain/performance/application/PerformanceModifyService.java b/src/main/java/com/beat/domain/performance/application/PerformanceModifyService.java index 90da2118..e705f4ed 100644 --- a/src/main/java/com/beat/domain/performance/application/PerformanceModifyService.java +++ b/src/main/java/com/beat/domain/performance/application/PerformanceModifyService.java @@ -5,12 +5,12 @@ import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.beat.domain.booking.dao.BookingRepository; -import com.beat.domain.booking.domain.BookingStatus; import com.beat.domain.cast.dao.CastRepository; import com.beat.domain.cast.domain.Cast; import com.beat.domain.cast.exception.CastErrorCode; @@ -73,9 +73,7 @@ public PerformanceModifyResponse modifyPerformance(Long memberId, PerformanceMod validateOwnership(userId, performance); List scheduleIds = scheduleRepository.findIdsByPerformanceId(request.performanceId()); - - List statusesToExclude = List.of(BookingStatus.BOOKING_CANCELLED, BookingStatus.BOOKING_DELETED); - boolean isBookerExist = bookingRepository.existsActiveBookingByScheduleIds(scheduleIds, statusesToExclude); + boolean isBookerExist = bookingRepository.existsByScheduleIdIn(scheduleIds); if (isBookerExist && request.ticketPrice() != performance.getTicketPrice()) { log.error("Ticket price update failed due to existing bookings for performanceId: {}", performance.getId()); @@ -150,7 +148,7 @@ private void updatePerformanceDetails(Performance performance, PerformanceModify List performanceDates = request.scheduleModifyRequests().stream() .map(ScheduleModifyRequest::performanceDate) - .toList(); + .collect(Collectors.toList()); performance.updatePerformancePeriod(performanceDates); if (!isBookerExist) { @@ -169,11 +167,11 @@ private List processSchedules(List requestScheduleIds = scheduleRequests.stream() .map(ScheduleModifyRequest::scheduleId) .filter(Objects::nonNull) - .toList(); + .collect(Collectors.toList()); List schedulesToDelete = existingScheduleIds.stream() .filter(id -> !requestScheduleIds.contains(id)) - .toList(); + .collect(Collectors.toList()); deleteRemainingSchedules(schedulesToDelete); @@ -193,7 +191,7 @@ private List processSchedules(List processSchedules(List processStaffs(List staffRe return updateStaff(request, performance); } }) - .toList(); + .collect(Collectors.toList()); deleteRemainingStaffs(existingStaffIds); diff --git a/src/main/java/com/beat/domain/performance/application/PerformanceService.java b/src/main/java/com/beat/domain/performance/application/PerformanceService.java index 9b06cbb8..06943d44 100644 --- a/src/main/java/com/beat/domain/performance/application/PerformanceService.java +++ b/src/main/java/com/beat/domain/performance/application/PerformanceService.java @@ -5,12 +5,12 @@ import java.time.temporal.ChronoUnit; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.beat.domain.booking.dao.BookingRepository; -import com.beat.domain.booking.domain.BookingStatus; import com.beat.domain.cast.dao.CastRepository; import com.beat.domain.cast.domain.Cast; import com.beat.domain.member.dao.MemberRepository; @@ -76,7 +76,7 @@ public PerformanceDetailResponse getPerformanceDetail(Long performanceId) { return PerformanceDetailScheduleResponse.of(schedule.getId(), schedule.getPerformanceDate(), schedule.getScheduleNumber().name(), dueDate, schedule.isBooking()); }) - .toList(); + .collect(Collectors.toList()); int minDueDate = scheduleService.getMinDueDate(scheduleRepository.findAllByPerformanceId(performanceId)); @@ -84,19 +84,19 @@ public PerformanceDetailResponse getPerformanceDetail(Long performanceId) { .stream() .map(cast -> PerformanceDetailCastResponse.of(cast.getId(), cast.getCastName(), cast.getCastRole(), cast.getCastPhoto())) - .toList(); + .collect(Collectors.toList()); List staffList = staffRepository.findByPerformanceId(performanceId) .stream() .map(staff -> PerformanceDetailStaffResponse.of(staff.getId(), staff.getStaffName(), staff.getStaffRole(), staff.getStaffPhoto())) - .toList(); + .collect(Collectors.toList()); List performanceImageList = performanceImageRepository.findAllByPerformanceId( performanceId) .stream() .map(image -> PerformanceDetailImageResponse.of(image.getId(), image.getPerformanceImageUrl())) - .toList(); + .collect(Collectors.toList()); log.info("Successfully completed getPerformanceDetail for performanceId: {}", performanceId); return PerformanceDetailResponse.of(performance.getId(), performance.getPerformanceTitle(), @@ -119,7 +119,7 @@ public BookingPerformanceDetailResponse getBookingPerformanceDetail(Long perform return BookingPerformanceDetailScheduleResponse.of(schedule.getId(), schedule.getPerformanceDate(), schedule.getScheduleNumber().name(), scheduleService.getAvailableTicketCount(schedule), schedule.isBooking(), dueDate); - }).toList(); + }).collect(Collectors.toList()); return BookingPerformanceDetailResponse.of(performance.getId(), performance.getPerformanceTitle(), performance.getPerformancePeriod(), scheduleList, performance.getTicketPrice(), @@ -146,17 +146,17 @@ public MakerPerformanceResponse getMemberPerformances(Long memberId) { return MakerPerformanceDetailResponse.of(performance.getId(), performance.getGenre().name(), performance.getPerformanceTitle(), performance.getPosterImage(), performance.getPerformancePeriod(), minDueDate); - }).toList(); + }).collect(Collectors.toList()); List positiveDueDates = performanceDetails.stream() .filter(detail -> detail.minDueDate() >= 0) .sorted(Comparator.comparingInt(MakerPerformanceDetailResponse::minDueDate)) - .toList(); + .collect(Collectors.toList()); List negativeDueDates = performanceDetails.stream() .filter(detail -> detail.minDueDate() < 0) .sorted(Comparator.comparingInt(MakerPerformanceDetailResponse::minDueDate).reversed()) - .toList(); + .collect(Collectors.toList()); positiveDueDates.addAll(negativeDueDates); @@ -186,8 +186,7 @@ public PerformanceModifyDetailResponse getPerformanceEdit(Long memberId, Long pe List scheduleIds = scheduleRepository.findIdsByPerformanceId(performanceId); - List statusesToExclude = List.of(BookingStatus.BOOKING_CANCELLED, BookingStatus.BOOKING_DELETED); - boolean isBookerExist = bookingRepository.existsActiveBookingByScheduleIds(scheduleIds, statusesToExclude); + boolean isBookerExist = bookingRepository.existsByScheduleIdIn(scheduleIds); List schedules = scheduleRepository.findAllByPerformanceId(performanceId); List casts = castRepository.findAllByPerformanceId(performanceId); @@ -204,21 +203,21 @@ private PerformanceModifyDetailResponse mapToPerformanceEditResponse(Performance .map(schedule -> ScheduleResponse.of(schedule.getId(), schedule.getPerformanceDate(), schedule.getTotalTicketCount(), calculateDueDate(schedule.getPerformanceDate()), schedule.getScheduleNumber())) - .toList(); + .collect(Collectors.toList()); List castResponses = casts.stream() .map(cast -> CastResponse.of(cast.getId(), cast.getCastName(), cast.getCastRole(), cast.getCastPhoto())) - .toList(); + .collect(Collectors.toList()); List staffResponses = staffs.stream() .map(staff -> StaffResponse.of(staff.getId(), staff.getStaffName(), staff.getStaffRole(), staff.getStaffPhoto())) - .toList(); + .collect(Collectors.toList()); List performanceImageResponses = performanceImages.stream() .map(performanceImage -> PerformanceImageResponse.of(performanceImage.getId(), performanceImage.getPerformanceImageUrl())) - .toList(); + .collect(Collectors.toList()); return PerformanceModifyDetailResponse.of(performance.getUsers().getId(), performance.getId(), performance.getPerformanceTitle(), performance.getGenre(), performance.getRunningTime(), diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 710fd8ab..afcf2920 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,6 +1,33 @@ +server: + port: 8080 + +management: + server: + port: ${DEV_ACTUATOR_PORT} + endpoint: + health: + show-details: always + enabled: true + info: + enabled: true + prometheus: + enabled: true + endpoints: + enabled-by-default: false + jmx: + exposure: + exclude: "*" + web: + exposure: + include: info, health, prometheus + base-path: ${DEV_ACTUATOR_PATH} + prometheus: + metrics: + export: + enabled: true + spring: config: - import: optional:classpath:application-secret.properties activate: on-profile: dev @@ -49,34 +76,6 @@ spring: secret: ${DEV_COOLSMS_SECRET} number: ${DEV_COOLSMS_NUMBER} -server: - port: 8080 - -management: - server: - port: ${DEV_ACTUATOR_PORT} - endpoint: - health: - show-details: always - enabled: true - info: - enabled: true - prometheus: - enabled: true - endpoints: - enabled-by-default: false - jmx: - exposure: - exclude: "*" - web: - exposure: - include: info, health, prometheus - base-path: ${DEV_ACTUATOR_PATH} - prometheus: - metrics: - export: - enabled: true - jwt: secret: ${DEV_JWT_SECRET} access-token-expire-time: ${DEV_ACCESS_TOKEN_EXPIRE_TIME} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f75c712..66f574ea 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - default: dev + default: local \ No newline at end of file