Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3d47caa
refactor: 중복 조회 로직 수정
coli-geonwoo Aug 11, 2025
6045f1f
refactor: 같은 레포 대상 등록이 가능하도록 변경
coli-geonwoo Aug 11, 2025
844c70b
chore: 패키지 이동
coli-geonwoo Aug 11, 2025
73e9126
refactor: 심는 웹훅 아이디가 구분되도록 변경
coli-geonwoo Aug 11, 2025
ac7999a
refactor: 단일 url로 웹훅 관리
coli-geonwoo Aug 11, 2025
a3c0686
refactor: 트래킹 중일 때만 pr 및 질문을 생성하도록 변경
coli-geonwoo Aug 11, 2025
21922b7
feat: 등록 정보를 관리하도록 변경
coli-geonwoo Aug 11, 2025
cba5cec
chore: 로컬 테스트 환경 변경
coli-geonwoo Aug 11, 2025
360f853
chore: 불필요한 컨트롤러 제거
coli-geonwoo Aug 11, 2025
9d6bbae
chore: registrycount 정보 관리
coli-geonwoo Aug 11, 2025
8cfa396
chore: 웹훅 하나로 동일 레포를 관리하도록 변경
coli-geonwoo Aug 11, 2025
0de277e
chore: exists로 로직 변경
coli-geonwoo Aug 11, 2025
6566958
refactor: 불필요한 메서드 제거
coli-geonwoo Aug 11, 2025
57bf2cc
test: 테스트 코드 작성
coli-geonwoo Aug 11, 2025
f2f9f34
chore: 패키지 이동
coli-geonwoo Aug 11, 2025
dde44db
test: 실패하는 테스트 변경
coli-geonwoo Aug 11, 2025
0d72cf6
feat: 웹훅 서비스에 트랜잭션 반영
coli-geonwoo Aug 14, 2025
3659c1e
refactor: 구체적인 에러 타입으로 변경
coli-geonwoo Aug 14, 2025
5aeca5d
fix: 사용하지 않는 path variable 수정
coli-geonwoo Aug 14, 2025
326ba96
refactor: 원자적 쿼리를 통해 동시성 이슈 대응
coli-geonwoo Aug 14, 2025
f1fd798
refactor: updatedRow 검증
coli-geonwoo Aug 14, 2025
5b83e10
refactor: 동시성 이슈를 예방하고자 updatedRow를 원자성 쿼리로 대체
coli-geonwoo Aug 18, 2025
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package com.devoops.controller.docs;

import com.devoops.controller.auth.AuthUser;
import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.PullRequests;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.RepositorySaveRequest;
import com.devoops.dto.response.AnswerUpdateResponse;
import com.devoops.dto.response.MyRepositoriesResponse;
import com.devoops.dto.response.RepositoryPullRequestResponses;
import com.devoops.dto.response.RepositorySaveResponse;
Expand All @@ -17,10 +13,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "Repository API")
@SecurityRequirement(name = "Authorization")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.devoops.controller.auth.AuthUser;
import com.devoops.controller.docs.PullRequestControllerSwagger;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.pr.RecordStatus;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.response.PullRequestDetailReadResponse;
import com.devoops.dto.response.PullRequestRankingResponses;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.devoops.controller.auth.AuthUser;
import com.devoops.controller.docs.QuestionControllerSwagger;
import com.devoops.domain.entity.github.Answer;
import com.devoops.domain.entity.github.Answers;
import com.devoops.domain.entity.github.answer.Answer;
import com.devoops.domain.entity.github.answer.Answers;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.AnswerPutRequests;
import com.devoops.dto.request.AnswerUpdateRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.devoops.controller.auth.AuthUser;
import com.devoops.controller.docs.RepositoryControllerSwagger;
import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.PullRequests;
import com.devoops.domain.entity.github.repo.GithubRepository;
import com.devoops.domain.entity.github.pr.PullRequests;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.RepositorySaveRequest;
import com.devoops.dto.response.MyRepositoriesResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.Answer;
import com.devoops.domain.entity.github.answer.Answer;

public record AnswerPutResponse(
long answerId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.Answers;
import com.devoops.domain.entity.github.answer.Answers;
import java.util.List;
import java.util.stream.Collectors;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.Answer;
import com.devoops.domain.entity.github.answer.Answer;
import io.swagger.v3.oas.annotations.media.Schema;

public record AnswerSaveResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.Answer;
import com.devoops.domain.entity.github.answer.Answer;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.repo.GithubRepository;

import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.PullRequest;
import com.devoops.domain.entity.github.pr.PullRequest;
import com.devoops.domain.entity.github.QuestionAnswer;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.pr.RecordStatus;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.AnswerRanking;
import com.devoops.domain.entity.github.answer.AnswerRanking;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.AnswerRankings;
import com.devoops.dto.request.AnswerPutRequest;
import com.devoops.domain.entity.github.answer.AnswerRankings;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.PullRequest;
import com.devoops.domain.entity.github.pr.PullRequest;
import com.devoops.domain.entity.github.QuestionAnswer;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.pr.RecordStatus;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.PullRequest;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.pr.PullRequest;
import com.devoops.domain.entity.github.pr.RecordStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.PullRequests;
import com.devoops.dto.request.AnswerPutRequest;
import com.devoops.domain.entity.github.pr.PullRequests;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.dto.response;

import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.repo.GithubRepository;
import io.swagger.v3.oas.annotations.media.Schema;

public record RepositorySaveResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
package com.devoops.service;

import com.devoops.client.GitHubClient;
import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.GithubToken;
import com.devoops.domain.entity.github.GithubWebhook;
import com.devoops.domain.entity.github.token.GithubToken;
import com.devoops.domain.entity.user.User;
import com.devoops.domain.repository.github.GithubRepoDomainRepository;
import com.devoops.domain.repository.github.GithubTokenDomainRepository;
import com.devoops.domain.repository.github.GithubWebhookDomainRepository;
import com.devoops.dto.request.GitHubWebhookRequest;
import com.devoops.dto.request.GithubRepoUrl;
import com.devoops.dto.response.GithubPrResponse;
import com.devoops.dto.response.GithubRepoInfoResponse;
import com.devoops.dto.response.WebHookCreateResponse;
import com.devoops.exception.GithubNotFoundException;
import com.devoops.exception.custom.GssException;
import com.devoops.exception.errorcode.ErrorCode;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
Expand All @@ -33,32 +21,7 @@ public class GitHubService {
private static final int MAX_PER_PAGE_PULL_REQUEST = 10;
private static final String REQUEST_PULL_REQUEST_STATUS = "closed";

@Value("${dev-oops.mcp.webhook-url}")
private String mcpWebhookUrl;

private final GitHubClient gitHubClient;
private final GithubRepoDomainRepository githubRepoDomainRepository;
private final GithubTokenDomainRepository githubTokenDomainRepository;
private final GithubWebhookDomainRepository githubWebhookDomainRepository;

public void registerWebhook(User user, long repositoryId) {

GithubRepository githubRepository = githubRepoDomainRepository.findByIdAndUserId(repositoryId, user.getId());
GithubToken githubToken = githubTokenDomainRepository.findByUserId(user)
.orElseThrow(() -> new GssException(ErrorCode.NO_RESOURCE_FOUND));
createWebHook(githubToken, githubRepository);
}

private GithubWebhook createWebHook(GithubToken token, GithubRepository repo) {
WebHookCreateResponse webHookCreateResponse = gitHubClient.createWebhook(
BEARER_PREFIX + token.getToken(),
repo.getOwner(),
repo.getName(),
GitHubWebhookRequest.ofPullRequestEvent(mcpWebhookUrl)
);
GithubWebhook webhook = new GithubWebhook(webHookCreateResponse.id(), repo.getId());
return githubWebhookDomainRepository.save(webhook);
}

public List<GithubPrResponse> getUserPullRequests(
GithubRepoUrl repoUrl,
Expand Down Expand Up @@ -86,27 +49,4 @@ public GithubRepoInfoResponse getRepositoryInfo(GithubRepoUrl repoUrl, GithubTok
repoUrl.getRepoName()
);
}

@Transactional
public void deleteWebhook(User user, long repositoryId) {
GithubRepository repo = githubRepoDomainRepository.findByIdAndUserId(repositoryId, user.getId());
GithubToken githubToken = githubTokenDomainRepository.findByUserId(user)
.orElseThrow(() -> new GssException(ErrorCode.NO_RESOURCE_FOUND));
GithubWebhook webhook = githubWebhookDomainRepository.findByRepositoryId(repo.getId());
tryDeleteWebhook(githubToken, webhook, repo);
githubWebhookDomainRepository.deleteById(webhook.getId());
}

private void tryDeleteWebhook(GithubToken githubToken, GithubWebhook webhook, GithubRepository repo) {
try {
gitHubClient.deleteWebhook(
BEARER_PREFIX + githubToken.getToken(),
repo.getOwner(),
repo.getName(),
webhook.getExternalId()
);
} catch (GithubNotFoundException githubNotFoundException) {
log.error("깃허브 레포에서 웹훅을 찾을 수 없습니다 : {}, repo : {} ", githubNotFoundException, repo.getName());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.devoops.service.facade;

import com.devoops.domain.entity.github.GithubToken;
import com.devoops.domain.entity.github.token.GithubToken;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.UserSaveRequest;
import com.devoops.dto.response.AuthResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.devoops.service.facade;

import com.devoops.domain.entity.github.AnswerRankings;
import com.devoops.domain.entity.github.PullRequest;
import com.devoops.domain.entity.github.answer.AnswerRankings;
import com.devoops.domain.entity.github.pr.PullRequest;
import com.devoops.domain.entity.github.QuestionAnswer;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.pr.RecordStatus;
import com.devoops.dto.response.PullRequestDetailReadResponse;
import com.devoops.dto.response.PullRequestRankingResponses;
import com.devoops.dto.response.PullRequestReadResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.devoops.service.facade;

import com.devoops.command.request.AnswerUpdateCommand;
import com.devoops.domain.entity.github.Answer;
import com.devoops.domain.entity.github.Answers;
import com.devoops.domain.entity.github.PullRequest;
import com.devoops.domain.entity.github.RecordStatus;
import com.devoops.domain.entity.github.answer.Answer;
import com.devoops.domain.entity.github.answer.Answers;
import com.devoops.domain.entity.github.pr.PullRequest;
import com.devoops.domain.entity.github.pr.RecordStatus;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.AnswerPutRequests;
import com.devoops.service.answer.AnswerService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import static com.devoops.Constants.INITIAL_PULL_REQUEST_COUNT;

import com.devoops.command.request.RepositoryCreateCommand;
import com.devoops.domain.entity.github.GithubRepository;
import com.devoops.domain.entity.github.PullRequests;
import com.devoops.domain.entity.github.repo.GithubRepository;
import com.devoops.domain.entity.github.pr.PullRequests;
import com.devoops.domain.entity.user.User;
import com.devoops.dto.request.GithubRepoUrl;
import com.devoops.dto.request.RepositorySaveRequest;
import com.devoops.dto.response.GithubRepoInfoResponse;
import com.devoops.event.AnalyzeMyPrEvent;
import com.devoops.service.GitHubService;
import com.devoops.service.github.WebHookService;
import com.devoops.service.repository.RepositoryService;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,13 +25,14 @@ public class RepositoryFacadeService {

private final RepositoryService repositoryService;
private final GitHubService gitHubService;
private final WebHookService webHookService;
private final ApplicationEventPublisher eventPublisher;

@Transactional
public GithubRepository save(RepositorySaveRequest request, User user) {
GithubRepoUrl repoUrl = new GithubRepoUrl(request.url());
GithubRepository savedRepository = saveRepository(repoUrl, user);
gitHubService.registerWebhook(user, savedRepository.getId());
webHookService.registerWebhook(user, savedRepository.getId());
eventPublisher.publishEvent(new AnalyzeMyPrEvent(repoUrl, user, this));
return savedRepository;
}
Expand Down Expand Up @@ -62,7 +64,8 @@ public List<GithubRepository> findMyRepositories(User user) {

@Transactional
public void deleteRepository(User user, long repositoryId) {
gitHubService.deleteWebhook(user, repositoryId);
//TODO 다른 유저로부터 등록된 상황 고려
repositoryService.stopTrackingRepository(user, repositoryId);
webHookService.deleteWebhook(user, repositoryId);
}
}
Loading
Loading