From 6b21e8730a8b9c325c988abc29284e7f3799a693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Thu, 25 Aug 2022 03:42:22 +0900 Subject: [PATCH 01/18] =?UTF-8?q?config:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A1=9C=EA=B7=B8=20=EC=A0=9C=EC=99=B8=20(#167)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-web/src/main/resources/web.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/module-web/src/main/resources/web.yml b/module-web/src/main/resources/web.yml index 90c4233..92b811a 100644 --- a/module-web/src/main/resources/web.yml +++ b/module-web/src/main/resources/web.yml @@ -18,4 +18,11 @@ management: endpoints: web: exposure: - include: "health,info" \ No newline at end of file + include: "health,info" + +logging: + level: + org: + apache: + catalina: + core: OFF From 96b02c69008df210652d528a2abfd3d9774da1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Fri, 26 Aug 2022 01:17:17 +0900 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20opengraph=20=EC=97=AC=EB=9F=AC?= =?UTF-8?q?=EA=B0=9C=20=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=EB=B3=91=EB=A0=AC=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20(#168)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspiration/InspirationService.java | 62 ++++++++++--------- .../YgtangOgMetaElementHtmlParser.java | 2 +- .../infrastructure/spring/ExecutorConfig.java | 19 ++++++ 3 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 module-domain/src/main/java/inspiration/infrastructure/spring/ExecutorConfig.java diff --git a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java index 1a31600..8f776b4 100644 --- a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java +++ b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java @@ -2,9 +2,6 @@ import inspiration.RestPage; import inspiration.aws.AwsS3Service; -import inspiration.exception.ConflictRequestException; -import inspiration.exception.NoAccessAuthorizationException; -import inspiration.exception.ResourceNotFoundException; import inspiration.domain.inspiration.opengraph.OpenGraphService; import inspiration.domain.inspiration.opengraph.OpenGraphVo; import inspiration.domain.inspiration.request.InspirationAddRequest; @@ -20,6 +17,9 @@ import inspiration.domain.tag.Tag; import inspiration.domain.tag.TagRepository; import inspiration.domain.tag.TagService; +import inspiration.exception.ConflictRequestException; +import inspiration.exception.NoAccessAuthorizationException; +import inspiration.exception.ResourceNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheEvict; @@ -27,6 +27,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +36,8 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Slf4j @@ -51,6 +54,7 @@ public class InspirationService { private final InspirationTagRepository inspirationTagRepository; private final TagRepository tagRepository; private final OpenGraphService openGraphService; + private final ThreadPoolTaskExecutor threadPoolTaskExecutor; @Transactional(readOnly = true) @Cacheable(value = "inspiration", key = "{#memberId, #pageable.pageNumber, #pageable.pageSize}") @@ -59,11 +63,7 @@ public RestPage findInspirations(Pageable pageable, Long me Member member = memberService.findById(memberId); Page inspirationPage = inspirationRepository.findAllByMember(member, pageable); - inspirationPage - .forEach( - inspiration -> - inspiration.setFilePath(getFilePath(inspiration.getType(), inspiration.getContent()))); - return new RestPage<>(inspirationPage.map(inspiration -> InspirationResponse.of(inspiration, getOpenGraphResponse(inspiration.getType(), inspiration.getContent())))); + return toRestPage(inspirationPage); } @Transactional(readOnly = true) @@ -72,7 +72,7 @@ public InspirationResponse findInspiration(Long id, Long memberId) { Member member = memberService.findById(memberId); Inspiration inspiration = inspirationRepository.findAllByMemberAndId(member, id) - .orElseThrow(ResourceNotFoundException::new); + .orElseThrow(ResourceNotFoundException::new); inspiration.setFilePath(getFilePath(inspiration.getType(), inspiration.getContent())); return InspirationResponse.of(inspiration, getOpenGraphResponse(inspiration.getType(), inspiration.getContent())); @@ -102,7 +102,7 @@ public OpenGraphResponse getOpenGraphResponse(String link) { } @CacheEvict(value = "inspiration", allEntries = true) - public Long addInspiration(InspirationAddRequest request, Long memberId) { + public Long addInspiration(InspirationAddRequest request, Long memberId) { Member member = memberService.findById(memberId); @@ -110,7 +110,7 @@ public Long addInspiration(InspirationAddRequest request, Long memberId) { tmpInspiration.writeBy(member); if (request.getType() == InspirationType.IMAGE) { - if(request.getFile() == null){ + if (request.getFile() == null) { throw new IllegalArgumentException("IMAGE 타입은 파일을 업로드 해야합니다."); } fileUpload(tmpInspiration, List.of(request.getFile())); @@ -119,8 +119,8 @@ public Long addInspiration(InspirationAddRequest request, Long memberId) { if (request.getTagIds() != null) { List tags = request.getTagIds().stream() - .map(tagService::getTag) - .collect(Collectors.toList()); + .map(tagService::getTag) + .collect(Collectors.toList()); tags.forEach(tag -> inspirationTagService.save(InspirationTag.of(inspiration, tag))); } return inspiration.getId(); @@ -133,18 +133,7 @@ public RestPage findInspirationsByTags(List tagIds, L Page inspirationPage = inspirationRepository.findDistinctByMemberIdAndTagIdInAndTypeAndCreatedDateTimeBetween(memberId, tagIds, types, createdDateTimeFrom, createdDateTimeTo, pageable); - inspirationPage - .forEach( - inspiration -> - inspiration.setFilePath(getFilePath(inspiration.getType(), inspiration.getContent())) - ); - - return new RestPage<>( - inspirationPage.map(inspiration -> InspirationResponse.of( - inspiration, - getOpenGraphResponse(inspiration.getType() ,inspiration.getContent())) - ) - ); + return toRestPage(inspirationPage); } @@ -252,7 +241,7 @@ public void unTagInspiration(Long id, Long tagId, Long memberId) { @CacheEvict(value = "inspiration", allEntries = true) public void unTagInspirationByInspiration(Long id, Long memberId) { - if(!getInspiration(id).getMember().isSameMember(memberId)) { + if (!getInspiration(id).getMember().isSameMember(memberId)) { throw new NoAccessAuthorizationException(); } @@ -266,7 +255,7 @@ public void unTagInspirationByTag(Long tagId, Long memberId) { Tag tag = tagService.getTag(tagId); - if(!tag.getMember().isSameMember(memberId)) { + if (!tag.getMember().isSameMember(memberId)) { throw new NoAccessAuthorizationException(); } @@ -276,13 +265,13 @@ public void unTagInspirationByTag(Long tagId, Long memberId) { private void fileUpload(Inspiration inspiration, List multipartFiles) { List fileNames = awsS3Service.uploadFile(multipartFiles); - if(!fileNames.isEmpty()){ + if (!fileNames.isEmpty()) { inspiration.setFilePath(fileNames.get(0)); } } private String getFilePath(InspirationType type, String content) { - if(type == InspirationType.IMAGE){ + if (type == InspirationType.IMAGE) { return awsS3Service.getFilePath(content); } return content; @@ -292,4 +281,19 @@ private Inspiration getInspiration(Long id) { return inspirationRepository.findById(id) .orElseThrow(ResourceNotFoundException::new); } + + private RestPage toRestPage(Page inspirationPage) { + return new RestPage<>( + inspirationPage.stream() + .parallel() + .peek(it -> it.setFilePath(getFilePath(it.getType(), it.getContent()))) + .map(it -> (Callable) () -> InspirationResponse.of(it, getOpenGraphResponse(it.getType(), it.getContent()))) + .map(it -> threadPoolTaskExecutor.submitListenable(it).completable()) + .map(CompletableFuture::join) + .collect(Collectors.toList()), + inspirationPage.getPageable().getPageNumber(), + inspirationPage.getPageable().getPageSize(), + inspirationPage.getTotalElements() + ); + } } diff --git a/module-api/src/main/java/inspiration/domain/inspiration/opengraph/YgtangOgMetaElementHtmlParser.java b/module-api/src/main/java/inspiration/domain/inspiration/opengraph/YgtangOgMetaElementHtmlParser.java index d3293f0..b472d2a 100644 --- a/module-api/src/main/java/inspiration/domain/inspiration/opengraph/YgtangOgMetaElementHtmlParser.java +++ b/module-api/src/main/java/inspiration/domain/inspiration/opengraph/YgtangOgMetaElementHtmlParser.java @@ -20,7 +20,7 @@ public class YgtangOgMetaElementHtmlParser implements OgMetaElementHtmlParser { public List getOgMetaElementsFrom(String url) { try { final Document document = Jsoup.connect(url) - .timeout(1000) + .timeout(2000) .get(); final Elements metaElements = document.select("meta"); List ogMetaElements = metaElements.stream() diff --git a/module-domain/src/main/java/inspiration/infrastructure/spring/ExecutorConfig.java b/module-domain/src/main/java/inspiration/infrastructure/spring/ExecutorConfig.java new file mode 100644 index 0000000..673660d --- /dev/null +++ b/module-domain/src/main/java/inspiration/infrastructure/spring/ExecutorConfig.java @@ -0,0 +1,19 @@ +package inspiration.infrastructure.spring; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +public class ExecutorConfig { + @Bean + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(10); + threadPoolTaskExecutor.setMaxPoolSize(10); + threadPoolTaskExecutor.setQueueCapacity(100); + threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); + threadPoolTaskExecutor.initialize(); + return threadPoolTaskExecutor; + } +} From 485dd468e4a0d0347de8931ac557d1cf25d9709d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Fri, 26 Aug 2022 01:17:57 +0900 Subject: [PATCH 03/18] =?UTF-8?q?config:=20aws=20s3=20client=20=ED=83=80?= =?UTF-8?q?=EC=9E=84=EC=95=84=EC=9B=83=20=EC=B6=94=EA=B0=80=20(#160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * config: aws s3 client 타임아웃 추가 * config: 타임아웃 값 외부에서 주입 * test: 테스트 실패 해결 --- .../src/main/java/inspiration/aws/AwsS3Config.java | 12 ++++++++++++ module-domain/src/main/resources/application.yml | 4 +++- module-domain/src/test/resources/application.yml | 4 ---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/module-api/src/main/java/inspiration/aws/AwsS3Config.java b/module-api/src/main/java/inspiration/aws/AwsS3Config.java index c2effef..19990bd 100644 --- a/module-api/src/main/java/inspiration/aws/AwsS3Config.java +++ b/module-api/src/main/java/inspiration/aws/AwsS3Config.java @@ -1,5 +1,6 @@ package inspiration.aws; +import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; @@ -11,6 +12,7 @@ @Configuration public class AwsS3Config { + @Value("${cloud.aws.credentials.access-key}") private String accessKey; @@ -20,12 +22,22 @@ public class AwsS3Config { @Value("${cloud.aws.region.static}") private String region; + @Value("${cloud.aws.s3.connection-timeout:1000}") + private int connectionTimeout; + + @Value("${cloud.aws.s3.request-timeout:3000}") + private int requestTimeout; + @Bean public AmazonS3 amazonS3() { AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + ClientConfiguration clientConfiguration = new ClientConfiguration(); + clientConfiguration.setConnectionTimeout(connectionTimeout); + clientConfiguration.setRequestTimeout(requestTimeout); return AmazonS3ClientBuilder.standard() .withRegion(region) .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .withClientConfiguration(clientConfiguration) .build(); } diff --git a/module-domain/src/main/resources/application.yml b/module-domain/src/main/resources/application.yml index 6734df8..1eeeabb 100644 --- a/module-domain/src/main/resources/application.yml +++ b/module-domain/src/main/resources/application.yml @@ -22,6 +22,8 @@ cloud: aws: region: static: ap-northeast-2 - + s3: + connection-timeout: 1000 + request-timeout: 3000 uri: webhook: diff --git a/module-domain/src/test/resources/application.yml b/module-domain/src/test/resources/application.yml index 79f3ac0..d7a6d1a 100644 --- a/module-domain/src/test/resources/application.yml +++ b/module-domain/src/test/resources/application.yml @@ -38,10 +38,6 @@ cloud: secret-key: region: static: - s3: - bucket: - stack: - auto: false logging: pattern: From 706409df0e04d7191bfd47525cd80d4071919735 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Sun, 28 Aug 2022 12:12:20 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20docker=20build=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20AWS=20CodeBuild=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20(#155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: docker build를 위한 AWS CodeBuild 환경 연동 * refactor: 사용되지 않는 스크립트 제거 --- .github/workflows/dev_deploy.yml | 28 ++++++------------------- appspec.yml | 7 ++----- docker-compose.yml | 36 ++++---------------------------- scripts/deploy.sh | 18 ++++++++++++++++ scripts/login_ecr.sh | 6 ++++++ 5 files changed, 36 insertions(+), 59 deletions(-) create mode 100644 scripts/deploy.sh create mode 100644 scripts/login_ecr.sh diff --git a/.github/workflows/dev_deploy.yml b/.github/workflows/dev_deploy.yml index c497fa7..baa1d6a 100644 --- a/.github/workflows/dev_deploy.yml +++ b/.github/workflows/dev_deploy.yml @@ -17,35 +17,17 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - shell: bash - - - name: Build with Gradle - run: ./gradlew build - shell: bash - name: Make Directory for deliver run: mkdir deploy - - name: Copy Jar - run: cp ./module-web/build/libs/*.jar ./deploy/ - # appspec.yml Copy - name: Copy appspec run: cp ./appspec.yml ./deploy/ # Dockerfile Copy - name: Copy Dockerfile - run: | - cp ./dockerfile ./deploy/ - cp ./docker-compose.yml ./deploy/ + run: cp ./docker-compose.yml ./deploy/ # script file Copy - name: Copy shell @@ -53,9 +35,6 @@ jobs: mkdir deploy/scripts cp ./scripts/* ./deploy/scripts/ - - name: Copy Jar - run: cp ./module-web/build/libs/*.jar ./deploy/ - - name: Make zip file run: zip -r ./$GITHUB_SHA.zip ./deploy/ shell: bash @@ -67,6 +46,11 @@ jobs: aws-secret-access-key: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.AWS_REGION }} + - name: Setup CodeBuild + uses: aws-actions/aws-codebuild-run-build@v1.0.3 + with: + project-name: ygtang-develop-build + - name: Upload to S3 run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_LOCATION/$PROJECT_NAME/$GITHUB_SHA.zip diff --git a/appspec.yml b/appspec.yml index 9d97e94..f7a9611 100644 --- a/appspec.yml +++ b/appspec.yml @@ -16,12 +16,9 @@ permissions: hooks: ApplicationStart: - - location: scripts/run_new_was.sh + - location: scripts/deploy.sh timeout: 200 runas: ubuntu - location: scripts/health_check.sh timeout: 200 - runas: ubuntu - #- location: scripts/switch.sh - # timeout: 180 - #cd bu runas: ubuntu + runas: ubuntu \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e6897cf..8e271ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,41 +1,13 @@ -version: "3" +version: "3.9" services: - spring1: - build: . - image: ${PROJECT_NAME}-${VERSION} + app: + image: "${IMAGE_REPO_NAME}:${IMAGE_TAG}" container_name: ${ACTIVE} ports: - "8080:8080" - "8081:8081" - "5005:5005" volumes: - - ./:/root/ + - "${YGTANG_LOG_DIR}:/logs" environment: - "JAVA_OPTS=${JAVA_OPTS}" - - "PROJECT_NAME=${PROJECT_NAME}" - - "VERSION=${VERSION}" - - "DEV_PORT=${DEV_PORT}" - - "ACTIVE=${ACTIVE}" - - "ERROR_LOG_POST_SLACK_URL=${ERROR_LOG_POST_SLACK_URL}" - - "DB_HOST=${DB_HOST}" - - "DB_PORT=${DB_PORT}" - - "DB_USER=${DB_USER}" - - "DB_PASSWORD=${DB_PASSWORD}" - - "REDIS_HOST=${REDIS_HOST}" - - "REDIS_PORT=${REDIS_PORT}" - - "MAIL_HOST=${MAIL_HOST}" - - "MAIL_PORT=${MAIL_PORT}" - - "MAIL_USERNAME=${MAIL_USERNAME}" - - "MAIL_PASSWORD=${MAIL_PASSWORD}" - - "SIGN_UP_EMAIL_SEND_MAIL=${SIGN_UP_EMAIL_SEND_MAIL}" - - "RESET_PASSWORD_FOR_AUTH_SEND_MAIL=${RESET_PASSWORD_FOR_AUTH_SEND_MAIL}" - - "AUTH_TOKEN=${AUTH_TOKEN}" - - "POLICY_URL=${POLICY_URL}" - - "SECRET_KEY=${SECRET_KEY}" - - "S3_ACCESS_KEY=${S3_ACCESS_KEY}" - - "S3_SECRET_KEY=${S3_SECRET_KEY}" - - "S3_REGION=${S3_REGION}" - - "S3_BUCKET=${S3_BUCKET}" - - "YGTANG_SERVER_HOST=${YGTANG_SERVER_HOST}" - - diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100644 index 0000000..be4ad76 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,18 @@ +#!/bin/bash +APP_PATH=/home/ubuntu/app/inspiration +SCRIPT_PATH=/home/ubuntu/app/inspiration/scripts + +cp ${APP_PATH}/deploy/.env ${APP_PATH}/source/.env +export $(cat ${APP_PATH}/source/.env | grep -v ^# | xargs) >/dev/null + +cd ${SCRIPT_PATH} + +$SCRIPT_PATH/login_ecr.sh ${AWS_CLI_REGION} ${AWS_CLI_ACCOUNT_ID} + +docker stop ${ACTIVE} +sleep 3 + +docker-compose -f ${APP_PATH}/source/docker-compose.yml pull +sleep 1 +docker-compose -f ${APP_PATH}/source/docker-compose.yml up -d +sleep 10 diff --git a/scripts/login_ecr.sh b/scripts/login_ecr.sh new file mode 100644 index 0000000..300f921 --- /dev/null +++ b/scripts/login_ecr.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +REGION=$1 +AWS_ACCOUNT_ID=$2 + +aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com From 9306421680d3648eb9d982ae38e4c2c870e85e18 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Sun, 28 Aug 2022 13:56:00 +0900 Subject: [PATCH 05/18] =?UTF-8?q?=EB=B9=8C=EB=93=9C=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=9C=20@SuppressWarning=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#174)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: docker build를 위한 AWS CodeBuild 환경 연동 * refactor: 사용되지 않는 스크립트 제거 * refactor: 빌드 자동화를 위한 @SuppressWarning 추가 --- .../src/main/java/inspiration/infrastructure/WebConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/module-web/src/main/java/inspiration/infrastructure/WebConfig.java b/module-web/src/main/java/inspiration/infrastructure/WebConfig.java index 23e7ff5..f07829f 100644 --- a/module-web/src/main/java/inspiration/infrastructure/WebConfig.java +++ b/module-web/src/main/java/inspiration/infrastructure/WebConfig.java @@ -91,6 +91,7 @@ protected void addResourceHandlers(ResourceHandlerRegistry registry) { } @Override + @SuppressWarnings("unchecked") protected void addArgumentResolvers(List argumentResolvers) { argumentResolvers.add(createAuthenticationPrincipalArgumentResolver()); argumentResolvers.add(new PageableHandlerMethodArgumentResolver()); From 850351f211dd78f4d9d5f5995a88b0c9aa6a8078 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Sun, 28 Aug 2022 14:38:35 +0900 Subject: [PATCH 06/18] Feature/120 codebuild deploy (#175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: docker build를 위한 AWS CodeBuild 환경 연동 * refactor: 사용되지 않는 스크립트 제거 * refactor: 빌드 자동화를 위한 @SuppressWarning 추가 * chore: gradle-git-properties apply 수정 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4c6bf51..eb3efba 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ buildscript { } plugins { - id "com.gorylenko.gradle-git-properties" version "$gradleGitPropertiesPluginVersion" apply false + id "com.gorylenko.gradle-git-properties" version "$gradleGitPropertiesPluginVersion" } subprojects { From af8f38319e23400f029fa82c109b115bb62082b2 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Sun, 28 Aug 2022 15:40:13 +0900 Subject: [PATCH 07/18] Feature/120 codebuild deploy (#176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: docker build를 위한 AWS CodeBuild 환경 연동 * refactor: 사용되지 않는 스크립트 제거 * refactor: 빌드 자동화를 위한 @SuppressWarning 추가 * chore: gradle-git-properties apply 수정 * chore: gradle-git-properties remove --- build.gradle | 3 --- module-web/build.gradle | 2 -- 2 files changed, 5 deletions(-) diff --git a/build.gradle b/build.gradle index eb3efba..dd38931 100644 --- a/build.gradle +++ b/build.gradle @@ -14,9 +14,6 @@ buildscript { } -plugins { - id "com.gorylenko.gradle-git-properties" version "$gradleGitPropertiesPluginVersion" -} subprojects { apply plugin: 'org.springframework.boot' diff --git a/module-web/build.gradle b/module-web/build.gradle index 9f1ed88..6c24ceb 100644 --- a/module-web/build.gradle +++ b/module-web/build.gradle @@ -1,5 +1,3 @@ -apply plugin: "com.gorylenko.gradle-git-properties" - dependencies { implementation project(':module-domain') implementation project(':module-api') From c3c0c6d0e34490c8924a998bb7cc79095b910278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Sun, 28 Aug 2022 18:02:14 +0900 Subject: [PATCH 08/18] =?UTF-8?q?config:=20=EC=BA=90=EC=8B=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20(#166)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/inspiration/InspirationService.java | 12 ------------ .../main/java/inspiration/domain/tag/TagService.java | 4 ---- 2 files changed, 16 deletions(-) diff --git a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java index 8f776b4..375acb0 100644 --- a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java +++ b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java @@ -22,8 +22,6 @@ import inspiration.exception.ResourceNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -57,7 +55,6 @@ public class InspirationService { private final ThreadPoolTaskExecutor threadPoolTaskExecutor; @Transactional(readOnly = true) - @Cacheable(value = "inspiration", key = "{#memberId, #pageable.pageNumber, #pageable.pageSize}") public RestPage findInspirations(Pageable pageable, Long memberId) { Member member = memberService.findById(memberId); @@ -67,7 +64,6 @@ public RestPage findInspirations(Pageable pageable, Long me } @Transactional(readOnly = true) - @Cacheable(value = "inspiration", key = "{#memberId, #id}") public InspirationResponse findInspiration(Long id, Long memberId) { Member member = memberService.findById(memberId); @@ -101,7 +97,6 @@ public OpenGraphResponse getOpenGraphResponse(String link) { return getOpenGraphResponse(InspirationType.LINK, link); } - @CacheEvict(value = "inspiration", allEntries = true) public Long addInspiration(InspirationAddRequest request, Long memberId) { Member member = memberService.findById(memberId); @@ -137,7 +132,6 @@ public RestPage findInspirationsByTags(List tagIds, L } - @CacheEvict(value = "inspiration", allEntries = true) public Long modifyMemo(InspirationModifyRequest request, Long memberId) { Inspiration inspiration = getInspiration(request.getId()); @@ -150,7 +144,6 @@ public Long modifyMemo(InspirationModifyRequest request, Long memberId) { } @Transactional - @CacheEvict(value = "inspiration", allEntries = true) public void removeInspiration(Long id, Long memberId) { Inspiration inspiration = getInspiration(id); @@ -171,7 +164,6 @@ public void removeInspiration(Long id, Long memberId) { } @Transactional - @CacheEvict(value = "inspiration", allEntries = true) public void removeAllInspiration(Long memberId) { Member member = memberService.findById(memberId); @@ -197,7 +189,6 @@ public void removeAllInspiration(Long memberId) { } @Transactional(isolation = Isolation.SERIALIZABLE) - @CacheEvict(value = "inspiration", allEntries = true) public Long tagInspiration(InspirationTagRequest request, Long memberId) { Inspiration inspiration = getInspiration(request.getId()); @@ -218,7 +209,6 @@ public Long tagInspiration(InspirationTagRequest request, Long memberId) { return inspiration.getId(); } - @CacheEvict(value = "inspiration", allEntries = true) public void unTagInspiration(Long id, Long tagId, Long memberId) { Inspiration inspiration = getInspiration(id); @@ -238,7 +228,6 @@ public void unTagInspiration(Long id, Long tagId, Long memberId) { } - @CacheEvict(value = "inspiration", allEntries = true) public void unTagInspirationByInspiration(Long id, Long memberId) { if (!getInspiration(id).getMember().isSameMember(memberId)) { @@ -250,7 +239,6 @@ public void unTagInspirationByInspiration(Long id, Long memberId) { inspirationTagService.deleteAllByInspiration(inspiration); } - @CacheEvict(value = "inspiration", allEntries = true) public void unTagInspirationByTag(Long tagId, Long memberId) { Tag tag = tagService.getTag(tagId); diff --git a/module-api/src/main/java/inspiration/domain/tag/TagService.java b/module-api/src/main/java/inspiration/domain/tag/TagService.java index 0018b1b..1f24b50 100644 --- a/module-api/src/main/java/inspiration/domain/tag/TagService.java +++ b/module-api/src/main/java/inspiration/domain/tag/TagService.java @@ -27,7 +27,6 @@ public class TagService { private final MemberService memberService; @Transactional(readOnly = true) - @Cacheable(value = "tag", key = "{#memberId, #pageable.pageNumber, #pageable.pageSize}") public RestPage findTags(Pageable pageable, Long memberId) { Member member = memberService.findById(memberId); @@ -54,7 +53,6 @@ public Page searchTags(Pageable pageable, String keyword, Long memb return new RestPage<>(tagPage.map(TagResponse::from)); } - @CacheEvict(value = "tag", allEntries = true) public TagResponse addTag(TagAddRequest request, Long memberId) { Member member = memberService.findById(memberId); @@ -74,7 +72,6 @@ public Tag getTag(Long id) { .orElseThrow(ResourceNotFoundException::new); } - @CacheEvict(value = "tag", allEntries = true) public void removeTag(Long id, Long memberId) { Tag tag = tagRepository.findById(id) .orElseThrow(ResourceNotFoundException::new); @@ -85,7 +82,6 @@ public void removeTag(Long id, Long memberId) { tagRepository.delete(tag); } - @CacheEvict(value = "tag", allEntries = true) public void removeAllTag(Long memberId) { Member member = memberService.findById(memberId); From 1e8c37f7720743db0966367a584ea326eb8a6521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=8F=84=EB=8B=A4?= Date: Sun, 28 Aug 2022 18:08:06 +0900 Subject: [PATCH 09/18] =?UTF-8?q?docs:=20readme=20owner=EC=97=90=20?= =?UTF-8?q?=ED=95=B4=EC=84=B1=EB=8B=98=20=EC=B6=94=EA=B0=80=20(#170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index b3a9c2c..96aa87a 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ 고은정 - + @@ -142,7 +142,7 @@ 오혜성 - + @@ -152,7 +152,7 @@ 정대윤 - + @@ -162,21 +162,9 @@ 정도현 - - - - -
- Design 🎨 -
- 김자영 -
- - - - - - + + + @@ -186,7 +174,7 @@ 김자연 - + @@ -196,7 +184,7 @@ 문인우 - + @@ -206,7 +194,30 @@ 정형일 - + + + +
+ BE 💾 +
+ 전해성 +
+ + + + + + + + + + +
+ Design 🎨 +
+ 김자영 +
+ @@ -216,7 +227,7 @@ 박수연 - + @@ -228,5 +239,5 @@ - + From 23b889bb49960945f73da75d002142f69d51fee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Tue, 30 Aug 2022 23:12:45 +0900 Subject: [PATCH 10/18] =?UTF-8?q?config:=20sonar=20cloud=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20(#159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * config: sonar cloud 연동 * config: jacoco plugin 추가 --- .github/workflows/gradle.yml | 27 ++++++++++++++++++--------- build.gradle | 25 +++++++++++++++++++++++++ gradle.properties | 4 +++- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 9804e68..0d5772f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,6 +9,7 @@ on: pull_request: branches: - 'develop' + types: [opened, synchronize, reopened] jobs: build: @@ -17,16 +18,24 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Set up JDK 17 uses: actions/setup-java@v1 with: java-version: 17 - - - name: Grant execute permission for gradlew - run: chmod +x ./gradlew - shell: bash - - - name: Build with Gradle - run: ./gradlew build - shell: bash + - name: Cache SonarCloud packages + uses: actions/cache@v1 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Cache Gradle packages + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: chmod +x ./gradlew && ./gradlew build sonarqube --info diff --git a/build.gradle b/build.gradle index dd38931..dece43f 100644 --- a/build.gradle +++ b/build.gradle @@ -14,12 +14,28 @@ buildscript { } +plugins { + id "org.sonarqube" version "$sonarqubeVersion" +} + +sonarqube { + properties { + property "sonar.projectKey", "ygtang-server" + property "sonar.organization", "yeonggamt" + property "sonar.host.url", "https://sonarcloud.io" + } +} subprojects { apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' apply plugin: 'java' apply plugin: 'java-library' + apply plugin: 'jacoco' + + jacoco { + toolVersion = "$jacocoVersion" + } group = 'com.depromeet.inspiration' version = '0.0.1' @@ -46,5 +62,14 @@ subprojects { } test { useJUnitPlatform() + finalizedBy jacocoTestReport + } + jacocoTestReport { + dependsOn test + reports { + xml.required = true + csv.required = false + html.required = false + } } } diff --git a/gradle.properties b/gradle.properties index 2a75f5e..ed3eb15 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,6 @@ apacheCommonsCsvVersion=1.9.0 slackSdkVersion=1.24.0 okhttpVersion=4.10.0 awsJavaSdkVersion=1.12.281 -jasyptVersion=3.0.4 \ No newline at end of file +jasyptVersion=3.0.4 +sonarqubeVersion=3.4.0.2513 +jacocoVersion=0.8.8 \ No newline at end of file From c844b332514d2c3a1d28f4eb00e18ff199969a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Tue, 30 Aug 2022 23:35:31 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20=EA=B5=AC=EA=B8=80=20=EC=8B=9C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20tag=20group=20=EC=A1=B0=ED=9A=8C=20(#172)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * config: google api key 추가 * feat: google sheet 로 tagGroup 조회 * feat: 비어있는 컬럼 제외 --- module-batch/build.gradle | 1 + .../inspiration/application/tag/TagGroup.java | 29 +++++++ .../application/tag/TagGroupService.java | 7 ++ .../application/tag/TagRankingConfig.java | 19 ++++- .../google/GoogleApiConfig.java | 44 +++++++++++ .../google/GoogleSheetTagGroupService.java | 79 +++++++++++++++++++ module-batch/src/main/resources/batch.yml | 6 +- 7 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 module-batch/src/main/java/inspiration/application/tag/TagGroup.java create mode 100644 module-batch/src/main/java/inspiration/application/tag/TagGroupService.java create mode 100644 module-batch/src/main/java/inspiration/infrastructure/google/GoogleApiConfig.java create mode 100644 module-batch/src/main/java/inspiration/infrastructure/google/GoogleSheetTagGroupService.java diff --git a/module-batch/build.gradle b/module-batch/build.gradle index ce2c6f1..b9694e2 100644 --- a/module-batch/build.gradle +++ b/module-batch/build.gradle @@ -3,6 +3,7 @@ dependencies { implementation project(':module-api') implementation 'org.springframework.boot:spring-boot-starter-batch' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework:spring-web' implementation "org.apache.commons:commons-csv:$apacheCommonsCsvVersion" implementation "com.slack.api:slack-api-client:$slackSdkVersion" implementation "com.squareup.okhttp3:okhttp:$okhttpVersion" diff --git a/module-batch/src/main/java/inspiration/application/tag/TagGroup.java b/module-batch/src/main/java/inspiration/application/tag/TagGroup.java new file mode 100644 index 0000000..b132f93 --- /dev/null +++ b/module-batch/src/main/java/inspiration/application/tag/TagGroup.java @@ -0,0 +1,29 @@ +package inspiration.application.tag; + +import org.springframework.util.Assert; + +import java.util.List; + +@SuppressWarnings("ClassCanBeRecord") +public class TagGroup { + private final String name; + private final List candidates; + + private TagGroup(String name, List candidates) { + this.name = name; + this.candidates = candidates; + } + + public static TagGroup from(List candidates) { + Assert.notEmpty(candidates, "'candidates' must not be null or empty"); + return new TagGroup(candidates.get(0), candidates); + } + + public String getName() { + return name; + } + + public boolean contains(String name) { + return candidates.stream().anyMatch(it -> it.equalsIgnoreCase(name)); + } +} diff --git a/module-batch/src/main/java/inspiration/application/tag/TagGroupService.java b/module-batch/src/main/java/inspiration/application/tag/TagGroupService.java new file mode 100644 index 0000000..7cd8ca0 --- /dev/null +++ b/module-batch/src/main/java/inspiration/application/tag/TagGroupService.java @@ -0,0 +1,7 @@ +package inspiration.application.tag; + +import java.util.List; + +public interface TagGroupService { + List getTagGroups(); +} diff --git a/module-batch/src/main/java/inspiration/application/tag/TagRankingConfig.java b/module-batch/src/main/java/inspiration/application/tag/TagRankingConfig.java index 16c5055..35f4739 100644 --- a/module-batch/src/main/java/inspiration/application/tag/TagRankingConfig.java +++ b/module-batch/src/main/java/inspiration/application/tag/TagRankingConfig.java @@ -51,6 +51,7 @@ public class TagRankingConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final InspirationTagRepository inspirationTagRepository; + private final TagGroupService googleSheetTagGroupService; @Value("${ygtang.slack.token.bot}") private String botToken; @@ -78,20 +79,21 @@ public Step tagRankingStep() { @StepScope public Tasklet tagRankingTasklet() { return (contribution, chunkContext) -> { - List tagRankingVoList = getTagRankingVoList(); + List tagGroups = googleSheetTagGroupService.getTagGroups(); + List tagRankingVoList = getTagRankingVoList(tagGroups); File csvFile = toCsvFile(tagRankingVoList); sendFileToSlack(csvFile); return RepeatStatus.FINISHED; }; } - private List getTagRankingVoList() { + private List getTagRankingVoList(List tagGroups) { List inspirationTags = inspirationTagRepository.findAll(); Map> contentTagIdSetMap = inspirationTags.stream() .collect(Collectors.toMap( - it -> it.getTag().getContent(), + it -> resolveTagName(it.getTag().getContent(), tagGroups), it -> Stream.of(it.getTag().getId()).collect(Collectors.toSet()), (a, b) -> { Set c = new HashSet<>(a); @@ -102,7 +104,7 @@ private List getTagRankingVoList() { Map> contentInspirationIdSetMap = inspirationTags.stream() .collect(Collectors.toMap( - it -> it.getTag().getContent(), + it -> resolveTagName(it.getTag().getContent(), tagGroups), it -> Stream.of(it.getInspiration().getId()).collect(Collectors.toSet()), (a, b) -> { Set c = new HashSet<>(a); @@ -124,6 +126,15 @@ private List getTagRankingVoList() { .collect(Collectors.toList()); } + private String resolveTagName(String tagName, List tagGroups) { + for (TagGroup tagGroup : tagGroups) { + if (tagGroup.contains(tagName)) { + return tagGroup.getName(); + } + } + return tagName; + } + private File toCsvFile(List tagRankingVoList) throws IOException { File file = File.createTempFile("tagRanking", "csv"); file.deleteOnExit(); diff --git a/module-batch/src/main/java/inspiration/infrastructure/google/GoogleApiConfig.java b/module-batch/src/main/java/inspiration/infrastructure/google/GoogleApiConfig.java new file mode 100644 index 0000000..5a28ef8 --- /dev/null +++ b/module-batch/src/main/java/inspiration/infrastructure/google/GoogleApiConfig.java @@ -0,0 +1,44 @@ +package inspiration.infrastructure.google; + +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.support.HttpRequestWrapper; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.time.Duration; + +@Configuration +public class GoogleApiConfig { + @Value("${ygtang.google.api-key}") + private String googleApiKey; + + @Bean + public RestTemplate googleApiRestTemplate() { + return new RestTemplateBuilder() + .additionalInterceptors( + (request, body, execution) -> { + URI uri = UriComponentsBuilder.fromHttpRequest(request) + .queryParam("key", googleApiKey) + .build().toUri(); + + HttpRequest modifiedRequest = new HttpRequestWrapper(request) { + @NotNull + @Override + public URI getURI() { + return uri; + } + }; + return execution.execute(modifiedRequest, body); + } + ) + .setConnectTimeout(Duration.ofSeconds(1L)) + .setReadTimeout(Duration.ofSeconds(3L)) + .build(); + } +} diff --git a/module-batch/src/main/java/inspiration/infrastructure/google/GoogleSheetTagGroupService.java b/module-batch/src/main/java/inspiration/infrastructure/google/GoogleSheetTagGroupService.java new file mode 100644 index 0000000..890048c --- /dev/null +++ b/module-batch/src/main/java/inspiration/infrastructure/google/GoogleSheetTagGroupService.java @@ -0,0 +1,79 @@ +package inspiration.infrastructure.google; + +import inspiration.application.tag.TagGroup; +import inspiration.application.tag.TagGroupService; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@SuppressWarnings("ClassCanBeRecord") +public class GoogleSheetTagGroupService implements TagGroupService { + private final RestTemplate googleApiRestTemplate; + + @Value("${ygtang.google.sheet-id.tag-group}") + private String tagGroupSheetId; + + @Override + public List getTagGroups() { + ResponseEntity responseEntity = googleApiRestTemplate.getForEntity( + UriComponentsBuilder.newInstance() + .scheme("https") + .host("sheets.googleapis.com") + .path("/v4/spreadsheets/{spreadsheetId}") + .queryParam("ranges", "A1:J1000") + .queryParam("includeGridData", "true") + .build(tagGroupSheetId), + GoogleSheetResponse.class + ); + if (responseEntity.getBody() == null) { + throw new IllegalStateException("Failed to get tag groups from Google Sheet Api"); + } + return responseEntity.getBody().getSheets().get(0).getData().get(0).getRowData() + .stream() + .map(it -> TagGroup.from( + it.getValues() + .stream() + .map(ValuesResponse::getFormattedValue) + .filter(StringUtils::hasText) + .collect(Collectors.toList()) + ) + ) + .collect(Collectors.toList()); + } + + @Data + static class GoogleSheetResponse { + List sheets; + } + + @Data + static class SheetsResponse { + List data; + } + + @Data + static class DataResponse { + List rowData; + } + + @Data + static class RowDataResponse { + List values; + } + + @Data + static class ValuesResponse { + String formattedValue; + } +} + diff --git a/module-batch/src/main/resources/batch.yml b/module-batch/src/main/resources/batch.yml index 23220dd..2285e87 100644 --- a/module-batch/src/main/resources/batch.yml +++ b/module-batch/src/main/resources/batch.yml @@ -6,4 +6,8 @@ spring: ygtang: slack: token: - bot: ENC(/vYHx8EfqXQ5Q+wUpBxmEkde8Nz0i32a1I1uFPzi7X5bOsfQ1/BU7/enM9DMzHt2VO7FwgOELpKfAkjc98kzHG4stHPZKF3mJ5Xqf0p9SeAEyMvv+Y6JPZojjQ755zAT) \ No newline at end of file + bot: ENC(tiq6tuKYXrEiqutBkfkXJxKFiHBO7JlCgPDH8zAiU/C72XsYPXZuDZ+ZWAkx871dBAKF+befdkDbQZ1SF2eHVPa2pemI38jqmszaycYcic0hnzY9EVcDNMOmPTLJauPT) + google: + api-key: ENC(eSD4S2QU5YycRNsFnwcVBXfcjyhZZZGt752BAZEORv5WgbT60yy1VGDiKrpq6NYBbN0wVKNXSc78/OVrc2sr7X4anCsUjRh81mykpr9PWTM=) + sheet-id: + tag-group: ENC(W5y38wS4Qp1HatcqmlZqTRVcylum+99xzcLyKbf+UC/H4sdhpv8V9du2KfevbClTQBChW2nxo/6BerOK4Kp4rZv4Jfr9W+woHlIWyhPze4M=) \ No newline at end of file From 307bbb0eea529b4a5ee256643ce8faa74cef2f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Tue, 30 Aug 2022 23:36:06 +0900 Subject: [PATCH 12/18] =?UTF-8?q?chore:=20local=20=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=83=9D=EA=B8=B0=EB=8A=94=20=ED=98=84?= =?UTF-8?q?=EC=83=81=20=ED=95=B4=EA=B2=B0=20(#179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-web/src/main/resources/logback-spring.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module-web/src/main/resources/logback-spring.xml b/module-web/src/main/resources/logback-spring.xml index 9971073..a1666ea 100644 --- a/module-web/src/main/resources/logback-spring.xml +++ b/module-web/src/main/resources/logback-spring.xml @@ -1,8 +1,6 @@ - - @@ -22,13 +20,14 @@ + - + @@ -36,6 +35,7 @@ + From 968773b60b36ec58e0a215d50e8621f6afbdcf44 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Sun, 4 Sep 2022 23:02:34 +0900 Subject: [PATCH 13/18] chore: build test --- module-web/src/main/resources/logback-spring.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module-web/src/main/resources/logback-spring.xml b/module-web/src/main/resources/logback-spring.xml index a1666ea..dbb4f77 100644 --- a/module-web/src/main/resources/logback-spring.xml +++ b/module-web/src/main/resources/logback-spring.xml @@ -21,14 +21,14 @@ - + - + From de96f27c3509c02dc738823ff03e71038d30725e Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Tue, 6 Sep 2022 13:25:37 +0900 Subject: [PATCH 14/18] chore: build test --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8e271ac..7e060cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,4 +10,4 @@ services: volumes: - "${YGTANG_LOG_DIR}:/logs" environment: - - "JAVA_OPTS=${JAVA_OPTS}" + - "JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Dspring.profiles.active=${ACTIVE} -Duser.timezone=Asia/Seoul -Djasypt.encryptor.password=${ENC_PASSWORD} -Dserver.tomcat.accesslog.enabled=true -Dserver.tomcat.basedir=/ -Dlogging.level.org.apache.catalina.core=OFF -Dlogging.file.name=/logs/spring.log" From 5b546556c452fa33c3d9905e4f0b6e9fb205eef7 Mon Sep 17 00:00:00 2001 From: IW-MOON Date: Tue, 6 Sep 2022 21:55:49 +0900 Subject: [PATCH 15/18] chore: build script (prod) --- .github/workflows/prod_deploy.yml | 41 +++++++------------ .../src/main/resources/logback-spring.xml | 4 +- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/.github/workflows/prod_deploy.yml b/.github/workflows/prod_deploy.yml index 6e8c5bf..ddff791 100644 --- a/.github/workflows/prod_deploy.yml +++ b/.github/workflows/prod_deploy.yml @@ -17,35 +17,17 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - shell: bash - - - name: Build with Gradle - run: ./gradlew build - shell: bash - name: Make Directory for deliver run: mkdir deploy - - name: Copy Jar - run: cp ./module-web/build/libs/*.jar ./deploy/ - # appspec.yml Copy - name: Copy appspec run: cp ./appspec.yml ./deploy/ # Dockerfile Copy - name: Copy Dockerfile - run: | - cp ./dockerfile ./deploy/ - cp ./docker-compose.yml ./deploy/ + run: cp ./docker-compose.yml ./deploy/ # script file Copy - name: Copy shell @@ -53,16 +35,21 @@ jobs: mkdir deploy/scripts cp ./scripts/* ./deploy/scripts/ - - name: Make zip file + - name: Make zip file run: zip -r ./$GITHUB_SHA.zip ./deploy/ - shell: bash + shell: bash - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ secrets.AWS_REGION }} + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Setup CodeBuild + uses: aws-actions/aws-codebuild-run-build@v1.0.3 + with: + project-name: ygtang-prod-build - name: Upload to S3 run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_LOCATION/$PROJECT_NAME/$GITHUB_SHA.zip diff --git a/module-web/src/main/resources/logback-spring.xml b/module-web/src/main/resources/logback-spring.xml index dbb4f77..a1666ea 100644 --- a/module-web/src/main/resources/logback-spring.xml +++ b/module-web/src/main/resources/logback-spring.xml @@ -21,14 +21,14 @@ - + - + From d7c88487392b7e2bd3dbdeeb18f19005f89f9ee9 Mon Sep 17 00:00:00 2001 From: nature1216 <63771579+nature1216@users.noreply.github.com> Date: Thu, 15 Sep 2022 05:10:50 -0700 Subject: [PATCH 16/18] add: Filtering (#181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 입력 단위 LocalDateTime에서 LocalDate로 변경 2. 비교범위 이상-이하로 변경 --- .../domain/inspiration/InspirationService.java | 4 ++-- .../inspiration/InspirationRepositoryCustom.java | 6 +++--- .../domain/inspiration/InspirationRepositoryImpl.java | 11 ++++++----- .../v1/inspiration/InspirationController.java | 6 +++--- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java index 375acb0..2edab22 100644 --- a/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java +++ b/module-api/src/main/java/inspiration/domain/inspiration/InspirationService.java @@ -31,7 +31,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import java.util.concurrent.Callable; @@ -123,7 +123,7 @@ public Long addInspiration(InspirationAddRequest request, Long memberId) { @Transactional(readOnly = true) public RestPage findInspirationsByTags(List tagIds, List types, - LocalDateTime createdDateTimeFrom, LocalDateTime createdDateTimeTo, + LocalDate createdDateTimeFrom, LocalDate createdDateTimeTo, Long memberId, Pageable pageable) { Page inspirationPage = inspirationRepository.findDistinctByMemberIdAndTagIdInAndTypeAndCreatedDateTimeBetween(memberId, tagIds, types, createdDateTimeFrom, createdDateTimeTo, pageable); diff --git a/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryCustom.java b/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryCustom.java index c2bf843..07b4dd1 100644 --- a/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryCustom.java +++ b/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryCustom.java @@ -3,7 +3,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.Collection; public interface InspirationRepositoryCustom { @@ -11,8 +11,8 @@ Page findDistinctByMemberIdAndTagIdInAndTypeAndCreatedDateTimeBetwe Long memberId, Collection tagIds, Collection inspirationTypes, - LocalDateTime createdDateTimeFrom, - LocalDateTime createdDateTimeTo, + LocalDate createdDateTimeFrom, + LocalDate createdDateTimeTo, Pageable pageable ); } diff --git a/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryImpl.java b/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryImpl.java index 8193bda..d92d798 100644 --- a/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryImpl.java +++ b/module-domain/src/main/java/inspiration/domain/inspiration/InspirationRepositoryImpl.java @@ -10,7 +10,8 @@ import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; import org.springframework.util.CollectionUtils; -import java.time.LocalDateTime; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.Collection; import java.util.Objects; @@ -27,8 +28,8 @@ public Page findDistinctByMemberIdAndTagIdInAndTypeAndCreatedDateTi Long memberId, Collection tagIds, Collection inspirationTypes, - LocalDateTime createdDateTimeFrom, - LocalDateTime createdDateTimeTo, + LocalDate createdDateTimeFrom, + LocalDate createdDateTimeTo, Pageable pageable ) { BooleanExpression expression = qInspiration.member.id.eq(memberId); @@ -39,10 +40,10 @@ public Page findDistinctByMemberIdAndTagIdInAndTypeAndCreatedDateTi expression = expression.and(qInspiration.type.in(inspirationTypes)); } if (createdDateTimeFrom != null) { - expression = expression.and(qInspiration.createdDateTime.goe(createdDateTimeFrom)); + expression = expression.and(qInspiration.createdDateTime.goe(createdDateTimeFrom.atStartOfDay())); } if (createdDateTimeTo != null) { - expression = expression.and(qInspiration.createdDateTime.lt(createdDateTimeTo)); + expression = expression.and(qInspiration.createdDateTime.loe(createdDateTimeTo.atTime(LocalTime.MAX))); } JPQLQuery query = from(qInspiration) diff --git a/module-web/src/main/java/inspiration/v1/inspiration/InspirationController.java b/module-web/src/main/java/inspiration/v1/inspiration/InspirationController.java index fd1a043..baab004 100644 --- a/module-web/src/main/java/inspiration/v1/inspiration/InspirationController.java +++ b/module-web/src/main/java/inspiration/v1/inspiration/InspirationController.java @@ -26,7 +26,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.net.URI; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; @RestController @@ -111,8 +111,8 @@ public ResponseEntity inspirationTagging(HttpServletRequest http }) public ResponseEntity findInspirationByTag(Pageable pageable, @RequestBody List tagIds, @RequestParam(required = false) List types, - @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime createdDateTimeFrom, - @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime createdDateTimeTo, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate createdDateTimeFrom, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate createdDateTimeTo, @ApiIgnore @AuthenticationPrincipal Long memberId) { Page inspirationResponsePage = inspirationService.findInspirationsByTags(tagIds, types, createdDateTimeFrom, createdDateTimeTo, memberId, pageable); From 938f8dbb9e2f37b5c855ef22771342d3ce982d58 Mon Sep 17 00:00:00 2001 From: Haeseong Jeon Date: Thu, 15 Sep 2022 21:25:28 +0900 Subject: [PATCH 17/18] =?UTF-8?q?config:=20codebuild=20project=20name=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/prod_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod_deploy.yml b/.github/workflows/prod_deploy.yml index ddff791..beaaddc 100644 --- a/.github/workflows/prod_deploy.yml +++ b/.github/workflows/prod_deploy.yml @@ -49,7 +49,7 @@ jobs: - name: Setup CodeBuild uses: aws-actions/aws-codebuild-run-build@v1.0.3 with: - project-name: ygtang-prod-build + project-name: ygtang-build-production - name: Upload to S3 run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_LOCATION/$PROJECT_NAME/$GITHUB_SHA.zip From 58ba2d1ad1925dd782e65acaa7079ec9fd8edeca Mon Sep 17 00:00:00 2001 From: Haeseong Jeon Date: Thu, 15 Sep 2022 22:28:10 +0900 Subject: [PATCH 18/18] =?UTF-8?q?config:=20.env=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/health_check.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/health_check.sh b/scripts/health_check.sh index fe850a7..f937e9e 100644 --- a/scripts/health_check.sh +++ b/scripts/health_check.sh @@ -4,10 +4,11 @@ TARGET_URL=localhost APP_PATH=/home/ubuntu/app/inspiration +export $(cat ${APP_PATH}/source/.env | grep -v ^# | xargs) >/dev/null + echo "> Start health check of WAS at '${TARGET_URL}:${PORT}' ..." -for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10 -do +for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10; do echo "> #${RETRY_COUNT} trying..." RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" ${TARGET_URL}:"${PORT}"/health)