Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1차 배포 이후 Slack 적용 및 이슈 해결 #201

Merged
merged 21 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d100714
무중단배포 테스트
kimdozzi Apr 23, 2024
e1ed74f
무중단 배포 테스트
kimdozzi Apr 23, 2024
8e647f0
[FEAT] AWS S3 파일 저장 이슈 해결 (#181)
kimdozzi May 24, 2024
f167233
chore: main yml 수정 (#182)
kimdozzi May 24, 2024
9c99f5d
[FEAT] nginx & docker-compose 무중단 배포 (#184)
kimdozzi May 28, 2024
0c720f8
chore: yml conflict 해결
kimdozzi May 28, 2024
2e1a2d3
chore: yml conflict 해결
kimdozzi May 28, 2024
9372bd4
[REFACTOR] 파일이 저장소에 존재하지 않을 때에 대한 응답 데이터 리팩토링 및 추가 예외 처리 (#183)
SSung023 May 28, 2024
915987d
Merge branch 'main' of https://github.com/TeamTheGenius/TeamTheGenius…
kimdozzi May 28, 2024
65e8739
[FEAT] Slack Webhook 적용 (#186)
kimdozzi May 29, 2024
66a6f76
[FIX] 추천 챌린지가 제대로 전달되지 않는 버그 픽스 (#187)
SSung023 May 29, 2024
b6c895f
[FIX] FE에서 Item을 식별하는 코드가 제대로 설정되지 않는 버그 픽스 (#189)
SSung023 May 30, 2024
0beb306
refactor: topic과 관련된 파일 조작 코드 삭제 (#199)
SSung023 Jun 7, 2024
eef0b99
[FIX] 당일에 시작하는 챌린지에 참여할 수 있는 버그 픽스 (#198)
SSung023 Jun 7, 2024
8f12f07
[FEAT] 프로필 프레임 아이템 추가 (#196)
SSung023 Jun 7, 2024
55df2e3
[FEAT] 배포 자동화 적용 (#195)
SSung023 Jun 7, 2024
9a807b6
fix: 인스턴스 상세 조회 시 좋아요 개수 버그 픽스 (#200)
SSung023 Jun 7, 2024
da4b6be
chore: 사용하지 않는 파일 삭제
SSung023 Jun 7, 2024
4a7d0b8
Merge branch 'production' into main
SSung023 Jun 7, 2024
f1c9e87
fix: 누락된 Slack webhook 설정 코드 추가
SSung023 Jun 7, 2024
fcab3b5
fix: slack webhook 위치 조정
SSung023 Jun 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ on:

env:
AWS_REGION: ap-northeast-2
AWS_S3_BUCKET: gitget-bucket-hey
AWS_CODE_DEPLOY_APPLICATION: GitGet-Application-HEY
AWS_CODE_DEPLOY_GROUP: GitGet-CICD-group-hey
AWS_S3_BUCKET: gitget-deploy-bucket
AWS_CODE_DEPLOY_APPLICATION: GitGet-Application-CD
AWS_CODE_DEPLOY_GROUP: GitGet-Deployment-Group

jobs:
deploy:
Expand All @@ -19,25 +19,21 @@ jobs:
contents: read
packages: write
steps:
# Actions
- name: Checkout
uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

# 프로젝트 내 yml 파일 실행
- name: make application.yml
run: |
mkdir -p ./src/main/resources
cd ./src/main/resources
touch ./application.yml
touch ./application-common.yml
touch ./application-prod.yml

echo "${{ secrets.APPLICATION }}" > ./application.yml
echo "${{ secrets.COMMON }}" > ./application-common.yml
echo "${{ secrets.PROD }}" > ./application-prod.yml
Expand All @@ -51,32 +47,39 @@ jobs:
echo "${{ secrets.APPLICATION_TEST }}" > ./application.yml
echo "${{ secrets.TEST }}" > ./application-test.yml


- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash


- name: Build with Gradle and Test
run: ./gradlew build test


- name: Make zip file
run: zip -r ./$GITHUB_SHA.zip .
shell: bash


- name: Deliver to AWS S3 (AWS credential 설정)
- name: AWS credential 설정
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.CICD_ACCESS_KEY_HEY }}
aws-secret-access-key: ${{ secrets.CICD_SECRET_KEY_HEY }}
aws-access-key-id: ${{ secrets.CICD_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.CICD_SECRET_KEY }}


- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip

- name: EC2에 배포
run: aws deploy create-deployment --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} --s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip

- name: Code Deploy (EC2에 배포)
run: aws deploy create-deployment --application-name GitGet-Application-HEY --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name GitGet-CICD-group-hey --s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip
- name: action-slack (Slack notification after deploy)
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
author_name: Backend
fields: repo,commit,message,author
mention: here
if_mention: failure,cancelled
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: always()
25 changes: 7 additions & 18 deletions appspec.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
version: 0.0 # CodeDeploy Version.

os: linux # 배포할 서버의 운영체제
version: 0.0
os: linux

files:
- source: / # CodeDeploy에서 전달해 준 파일 중 destination으로 이동시킬 대상을 지정 (루트 경로 : 전체 파일)
destination: /home/ubuntu/app # source에서 지정된 파일을 받을 위치
overwrite: yes # 기존 파일들을 덮어 쓰기
- source: /
destination: /home/ubuntu/app
overwrite: yes

# CodeDeploy에서 EC2로 넘겨준 파일들을 모두 ec2-user 권한 부여.
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu

# CodeDeploy 배포 단계에서 실행할 명령어를 지정 (차례대로 스크립트들이 실행)
hooks:
ApplicationStart:
- location: scripts/run_new_was.sh
timeout: 180
runas: ubuntu
- location: scripts/health.sh
timeout: 180
runas: ubuntu
- location: scripts/switch.sh
timeout: 180
runas: ubuntu
- location: scripts/deploy.sh
timeout: 60
1 change: 0 additions & 1 deletion scripts/health.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ else
exit 1
fi


echo "> Start health check of WAS at http://localhost:${TARGET_PORT}/api/auth/health-check ..."

for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.genius.gitget.challenge.instance.controller;

import static com.genius.gitget.global.util.exception.SuccessCode.JOIN_SUCCESS;
import static com.genius.gitget.global.util.exception.SuccessCode.QUIT_SUCCESS;
import static com.genius.gitget.global.util.exception.SuccessCode.SUCCESS;

import com.genius.gitget.challenge.instance.dto.detail.InstanceResponse;
Expand All @@ -9,6 +10,7 @@
import com.genius.gitget.challenge.instance.service.InstanceDetailService;
import com.genius.gitget.global.security.domain.UserPrincipal;
import com.genius.gitget.global.util.response.dto.SingleResponse;
import java.time.LocalDate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -51,6 +53,7 @@ public ResponseEntity<SingleResponse<JoinResponse>> joinChallenge(
JoinRequest joinRequest = JoinRequest.builder()
.instanceId(instanceId)
.repository(repo)
.todayDate(LocalDate.now())
.build();
JoinResponse joinResponse = instanceDetailService.joinNewChallenge(userPrincipal.getUser(), joinRequest);

Expand All @@ -67,7 +70,7 @@ public ResponseEntity<SingleResponse<JoinResponse>> quitChallenge(
JoinResponse joinResponse = instanceDetailService.quitChallenge(userPrincipal.getUser(), instanceId);

return ResponseEntity.ok().body(
new SingleResponse<>(JOIN_SUCCESS.getStatus(), JOIN_SUCCESS.getMessage(), joinResponse)
new SingleResponse<>(QUIT_SUCCESS.getStatus(), QUIT_SUCCESS.getMessage(), joinResponse)
);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.genius.gitget.challenge.instance.dto.detail;

import java.time.LocalDate;
import lombok.Builder;

@Builder
public record JoinRequest(
Long instanceId,
String repository
String repository,
LocalDate todayDate
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ public static LikesInfo createExist(Long likesId, int likesCount) {
.build();
}

public static LikesInfo createNotExist() {
public static LikesInfo createNotExist(int likesCount) {
return LikesInfo.builder()
.likesId(0L)
.isLiked(false)
.likesCount(0)
.likesCount(likesCount)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public interface InstanceRepository extends JpaRepository<Instance, Long> {
@Query("select i from Instance i where i.topic.id = :topicId")
Page<Instance> findInstancesByTopicId(Pageable pageable, Long topicId);

@Query("select i from Instance i where i.progress = :progress and i.tags in :userTags")
Slice<Instance> findRecommendations(@Param("userTags") List<String> userTags, Progress progress, Pageable pageable);
@Query("select i from Instance i where i.progress = :progress and i.tags like %:userTag%")
List<Instance> findRecommendations(@Param("userTag") String userTag, Progress progress);

@Query("select i from Instance i where i.progress = :progress")
Slice<Instance> findPagesByProgress(@Param("progress") Progress progress, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.genius.gitget.global.file.dto.FileResponse;
import com.genius.gitget.global.file.service.FilesService;
import com.genius.gitget.global.util.exception.BusinessException;
import java.time.LocalDate;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -59,7 +60,7 @@ private LikesInfo getLikesInfo(Long userId, Instance instance) {
return LikesInfo.createExist(likes.getId(), instance.getLikesCount());
}

return LikesInfo.createNotExist();
return LikesInfo.createNotExist(instance.getLikesCount());
}

@Transactional
Expand All @@ -69,27 +70,37 @@ public JoinResponse joinNewChallenge(User user, JoinRequest joinRequest) {

String repository = joinRequest.repository();

if (!verifyGithub(persistUser, repository) || !canJoinChallenge(persistUser, instance)) {
throw new BusinessException(CAN_NOT_JOIN_INSTANCE);
}
validateJoinDate(instance, joinRequest.todayDate());
validateInstanceCondition(persistUser, instance);
validateGithub(persistUser, repository);

instance.updateParticipantCount(1);
Participant participant = Participant.createDefaultParticipant(repository);
participant.setUserAndInstance(persistUser, instance);
return JoinResponse.createJoinResponse(participantProvider.save(participant));
}

private boolean canJoinChallenge(User user, Instance instance) {
boolean b = !participantProvider.hasParticipant(user.getId(), instance.getId());
return (instance.getProgress() == Progress.PREACTIVITY) &&
!participantProvider.hasParticipant(user.getId(), instance.getId());
private void validateJoinDate(Instance instance, LocalDate todayDate) {
LocalDate startedDate = instance.getStartedDate().toLocalDate();

if (todayDate.isBefore(startedDate)) {
return;
}
throw new BusinessException(CAN_NOT_JOIN_INSTANCE);
}

private void validateInstanceCondition(User user, Instance instance) {
boolean isParticipated = participantProvider.hasParticipant(user.getId(), instance.getId());
if ((instance.getProgress() == Progress.PREACTIVITY) && !isParticipated) {
return;
}
throw new BusinessException(CAN_NOT_JOIN_INSTANCE);
}

private boolean verifyGithub(User user, String repository) {
private void validateGithub(User user, String repository) {
GitHub gitHub = githubProvider.getGithubConnection(user);
String repositoryFullName = githubProvider.getRepoFullName(gitHub, repository);
githubProvider.validateGithubRepository(gitHub, repositoryFullName);
return true;
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import com.genius.gitget.challenge.user.domain.User;
import com.genius.gitget.global.file.dto.FileResponse;
import com.genius.gitget.global.file.service.FilesService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
Expand All @@ -26,12 +28,20 @@ public class InstanceHomeService {
private final InstanceRepository instanceRepository;

public Slice<HomeInstanceResponse> getRecommendations(User user, Pageable pageable) {
List<Instance> instances = new ArrayList<>();
List<String> userTags = Arrays.stream(user.getTags().split(",")).toList();

Slice<Instance> recommendations = instanceRepository.findRecommendations(userTags, PREACTIVITY,
pageable);

return recommendations.map(this::mapToHomeInstanceResponse);
for (String userTag : userTags) {
instances.addAll(instanceRepository.findRecommendations(userTag, PREACTIVITY));
}

List<HomeInstanceResponse> recommendations = instances.stream()
.distinct()
.map(this::mapToHomeInstanceResponse)
.toList();

int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), recommendations.size());
return new PageImpl<>(recommendations.subList(start, end), pageable, recommendations.size());
}

public Slice<HomeInstanceResponse> getInstancesByCondition(Pageable pageable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -23,6 +24,7 @@
@RestController
@RequestMapping("/api/challenges")
@RequiredArgsConstructor
@CrossOrigin
public class MyChallengeController {
private final MyChallengeService myChallengeService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ public ResponseEntity<SingleResponse<FileResponse>> uploadFile(
FileHolder fileHolder = finder.findByInfo(id, fileType);
Files files;

if (multipartFile == null && fileType == FileType.INSTANCE) {
files = filesService.copyTopicToInstance(fileHolder);
} else {
files = filesService.uploadFile(fileHolder, multipartFile, fileType);
}

files = filesService.uploadFile(fileHolder, multipartFile, fileType);
FileResponse fileResponse = filesService.convertToFileResponse(Optional.ofNullable(files));

return ResponseEntity.ok().body(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public static FileResponse createExistFile(Long filesId, String encodedFile) {
}

public static FileResponse createNotExistFile() {
return new FileResponse(0L, "none");
return new FileResponse(0L, "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public interface FileManager {
* Files 내에 저장된 값들을 통해 UrlResource 등으로 다운받은 후, base64로 인코딩한 결과 반환
*
* @param files 얻기 원하는 파일의 정보를 담고 있는 Files 객체
* @return base64로 encode한 결과 값(문자열)
* @return base64로 encode한 결과 값(문자열) 반환
* 파일을 받아오지 못한 경우에는 빈 문자열("") 반환
*/
String getEncodedImage(Files files);

Expand All @@ -32,10 +33,12 @@ public interface FileManager {

/**
* 기존에 저장소에 저장되어 있던 파일을 특정 타입에 복사 후, Files 객체 생성에 필요한 정보들을 반환
* NOTE!! 복사 이전에 원본이 되는 파일이 저장소에 존재하는지 `validateFileExist()`를 통해 확인 필요
*
* @param files 복사하고자하는 파일의 정보를 담고 있는 Files 객체
* @param fileType 복사해서 적용하고 싶은 대상의 파일 타입(TOPIC/INSTANCE/PROFILE 중 택 1)
* @return Files 객체 생성에 필요한 정보(UploadDTO) 반환
* @throws BusinessException 원본이 되는 파일이 저장소에 존재하지 않는 경우 FILE_NOT_EXIST 발생
*/
FileDTO copy(Files files, FileType fileType);

Expand All @@ -55,4 +58,14 @@ public interface FileManager {
* @throws BusinessException 삭제에 실패했을 때 발생
*/
void deleteInStorage(Files files);

/**
* Files 객체 내의 정보를 활용하여 저장소에 파일이 저장이 되어 있는지 확인 후 boolean 반환
* 각 저장소의 특성에 맞춰 Files 내의 메타데이터를 통해 저장소 내에 파일이 제대로 저장되어 있는지 확인
* 파일이 존재하지 않는 경우 FILE_NOT_EXIST 예외 발생 시킬 것
*
* @param files 저장소에 저장되어 있는지 확인하고자하는 Files 객체
* @throws FILE_NOT_EXIST 저장소에서 파일(이미지)을 찾을 수 없을 때 발생
*/
void validateFileExist(Files files);
}
Loading
Loading