Skip to content

Commit 2b8ad3e

Browse files
authored
feat(repository): RepositoryData 모든 데이터 적재 완료
feat(repository): RepositoryData 모든 데이터 적재 완료
2 parents e3d46f9 + ff7eb9e commit 2b8ad3e

21 files changed

+939
-56
lines changed

backend/src/main/java/com/backend/domain/analysis/service/AnalysisService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public void analyze(String githubUrl) {
2828
// Repository 데이터 수집
2929
RepositoryData repositoryData = repositoryService.fetchAndSaveRepository(owner, repo);
3030

31+
log.info("🫠 ResponseData: {}", repositoryData);
3132
// TODO: AI 평가
3233
// EvaluationResult evaluation = evaluationService.evaluate(repositoryData);
3334

backend/src/main/java/com/backend/domain/repository/dto/response/RepositoryData.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ public class RepositoryData {
5757
@Data
5858
public static class CommitInfo {
5959
private String message;
60-
private String author;
6160
private LocalDateTime committedDate;
61+
62+
@Override
63+
public String toString() {
64+
return "(message=" + message + ", committedDate=" + committedDate + ")";
65+
}
6266
}
6367

6468
@Data
@@ -67,6 +71,11 @@ public static class IssueInfo {
6771
private String state;
6872
private LocalDateTime createdAt;
6973
private LocalDateTime closedAt;
74+
75+
@Override
76+
public String toString() {
77+
return "(title=" + title + ", state=" + state + ", createdAt=" + createdAt + ", closedAt=" + closedAt + ")";
78+
}
7079
}
7180

7281
@Data
@@ -75,5 +84,9 @@ public static class PullRequestInfo {
7584
private String state;
7685
private LocalDateTime createdAt;
7786
private LocalDateTime mergedAt;
87+
88+
@Override
89+
public String toString() {
90+
return "(title=" + title + ", state=" + state + ", createdAt=" + createdAt + ", mergedAt=" + mergedAt + ")"; }
7891
}
7992
}
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
package com.backend.domain.repository.dto.response.github;
22

33
// commits 응답용 DTO
4-
public record CommitResponse() {
4+
public record CommitResponse(
5+
CommitDetails commit
6+
) {
7+
public record CommitDetails(
8+
String message,
9+
AuthorDetails author
10+
) {}
11+
12+
public record AuthorDetails(
13+
String date
14+
) {}
515
}
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
package com.backend.domain.repository.dto.response.github;
22

33
// issue 응답용 DTO
4-
public record IssueResponse() {
4+
public record IssueResponse(
5+
Long number,
6+
String title,
7+
String state,
8+
String created_at,
9+
String closed_at,
10+
PullRequest pull_request
11+
) {
12+
public record PullRequest(String url) {}
13+
14+
public boolean isPureIssue() {
15+
return pull_request == null;
16+
}
17+
18+
public boolean isClosed() {
19+
return "closed".equals(state);
20+
}
521
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.backend.domain.repository.dto.response.github;
22

33
// Pull Request 응답용 DTO
4-
public class PullRequestResponse {
4+
public record PullRequestResponse(
5+
Long number,
6+
String title,
7+
String state,
8+
String created_at,
9+
String merged_at
10+
) {
511
}
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package com.backend.domain.repository.dto.response.github;
22

3+
import java.util.List;
4+
35
// trees 응답용 DTO
4-
public record TreeResponse() {
6+
public record TreeResponse(
7+
List<TreeItem> tree,
8+
boolean truncated // 응답이 잘렸을 경우 true
9+
) {
10+
public record TreeItem(
11+
String path,
12+
String type
13+
) {}
514
}

backend/src/main/java/com/backend/domain/repository/entity/Repositories.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.backend.domain.repository.entity;
22

33
import com.backend.domain.analysis.entity.AnalysisResult;
4+
import com.backend.domain.repository.dto.response.github.RepoResponse;
5+
import com.backend.domain.repository.util.LanguageUtils;
46
import com.backend.domain.user.entity.User;
57
import com.backend.global.entity.BaseEntity;
68
import jakarta.persistence.*;
@@ -11,6 +13,9 @@
1113

1214
import java.util.ArrayList;
1315
import java.util.List;
16+
import java.util.Map;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
1419

1520
@Entity
1621
@Table(name = "repositories")
@@ -73,13 +78,40 @@ public void addLanguage(RepositoryLanguage language) {
7378
language.setRepositories(this);
7479
}
7580

76-
public void updateFrom(Repositories other) {
77-
this.name = other.name;
78-
this.description = other.description;
79-
this.mainBranch = other.mainBranch;
81+
public void updateFrom(RepoResponse repoInfo) {
82+
this.name = repoInfo.name();
83+
this.description = repoInfo.description();
84+
this.mainBranch = repoInfo.defaultBranch();
8085
}
8186

8287
public void updatePublicFrom(Repositories other) {
8388
this.publicRepository = other.publicRepository;
8489
}
90+
91+
public void updateLanguagesFrom(Map<String, Integer> newLanguagesData) {
92+
Set<Language> newLanguages = newLanguagesData.keySet().stream()
93+
.map(LanguageUtils::fromGitHubName)
94+
.collect(Collectors.toSet());
95+
96+
Set<Language> existingLanguages = this.languages.stream()
97+
.map(RepositoryLanguage::getLanguage)
98+
.collect(Collectors.toSet());
99+
100+
if (newLanguages.equals(existingLanguages)) {
101+
return;
102+
}
103+
104+
this.languages.removeIf(repoLang ->
105+
!newLanguages.contains(repoLang.getLanguage()));
106+
107+
newLanguages.stream()
108+
.filter(language -> !existingLanguages.contains(language))
109+
.forEach(language -> {
110+
RepositoryLanguage repositoryLanguage = RepositoryLanguage.builder()
111+
.repositories(this)
112+
.language(language)
113+
.build();
114+
this.addLanguage(repositoryLanguage);
115+
});
116+
}
85117
}

backend/src/main/java/com/backend/domain/repository/service/RepositoryService.java

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
11
package com.backend.domain.repository.service;
22

33
import com.backend.domain.repository.dto.response.RepositoryData;
4-
import com.backend.domain.repository.dto.response.github.RepoResponse;
4+
import com.backend.domain.repository.dto.response.github.*;
55
import com.backend.domain.repository.entity.Language;
66
import com.backend.domain.repository.entity.Repositories;
77
import com.backend.domain.repository.repository.RepositoryJpaRepository;
8-
import com.backend.global.exception.BusinessException;
9-
import com.backend.global.exception.ErrorCode;
108
import com.backend.domain.repository.service.fetcher.GitHubDataFetcher;
11-
import com.backend.domain.repository.service.mapper.ReadmeInfoMapper;
12-
import com.backend.domain.repository.service.mapper.RepositoriesMapper;
13-
import com.backend.domain.repository.service.mapper.RepositoryInfoMapper;
9+
import com.backend.domain.repository.service.mapper.*;
1410
import com.backend.domain.user.entity.User;
1511
import com.backend.domain.user.repository.UserRepository;
12+
import com.backend.global.exception.BusinessException;
13+
import com.backend.global.exception.ErrorCode;
1614
import lombok.RequiredArgsConstructor;
17-
import lombok.extern.slf4j.Slf4j;
1815
import org.springframework.stereotype.Service;
1916
import org.springframework.transaction.annotation.Transactional;
2017

18+
import java.time.ZoneOffset;
19+
import java.time.ZonedDateTime;
20+
import java.time.format.DateTimeFormatter;
21+
import java.time.temporal.ChronoUnit;
2122
import java.util.List;
23+
import java.util.Map;
2224
import java.util.Optional;
2325

24-
import static com.backend.global.exception.ErrorCode.GITHUB_REPO_NOT_FOUND;
25-
26-
@Slf4j
2726
@Service
2827
@RequiredArgsConstructor
2928
public class RepositoryService {
@@ -34,7 +33,13 @@ public class RepositoryService {
3433
private final GitHubDataFetcher gitHubDataFetcher;
3534
private final RepositoriesMapper repositoriesMapper;
3635
private final RepositoryInfoMapper repositoryInfoMapper;
36+
private final CommitInfoMapper commitInfoMapper;
3737
private final ReadmeInfoMapper readmeInfoMapper;
38+
private final SecurityInfoMapper securityInfoMapper;
39+
private final TestInfoMapper testInfoMapper;
40+
private final CicdInfoMapper cicdInfoMapper;
41+
private final IssueInfoMapper issueInfoMapper;
42+
private final PullRequestInfoMapper pullRequestInfoMapper;
3843
private final RepositoryJpaRepository repositoryJpaRepository;
3944

4045
@Transactional
@@ -43,12 +48,8 @@ public RepositoryData fetchAndSaveRepository(String owner, String repo) {
4348
return fetchCompleteRepositoryData(owner, repo);
4449
} catch (BusinessException e) {
4550
String errorCode = (e.getErrorCode() != null) ? e.getErrorCode().getCode() : "UNKNOWN";
46-
log.error("Repository analysis failed for {}/{}: {} - {}",
47-
owner, repo, errorCode, e.getMessage());
4851
throw e;
4952
} catch (Exception e) {
50-
log.error("Unexpected error during repository analysis for {}/{}: {}",
51-
owner, repo, e.getMessage(), e);
5253
throw new BusinessException(ErrorCode.INTERNAL_ERROR);
5354
}
5455
}
@@ -61,49 +62,60 @@ public RepositoryData fetchCompleteRepositoryData(String owner, String repo) {
6162
RepoResponse repoInfo = gitHubDataFetcher.fetchRepositoryInfo(owner, repo);
6263
repositoryInfoMapper.mapBasicInfo(data, repoInfo);
6364

64-
// TODO: 커밋 데이터 수집 및 매핑
65-
65+
// 2. 커밋 데이터 수집 및 매핑
66+
ZonedDateTime ninetyDaysAgoUtc = ZonedDateTime.now(ZoneOffset.UTC).minus(90, ChronoUnit.DAYS);
67+
String sinceParam = ninetyDaysAgoUtc.format(DateTimeFormatter.ISO_INSTANT);
68+
List<CommitResponse> commitInfo = gitHubDataFetcher.fetchCommitInfo(owner, repo, sinceParam);
69+
commitInfoMapper.mapCommitInfo(data, commitInfo);
6670

67-
// TODO: README 데이터 수집 및 매핑
71+
// 3. README 데이터 수집 및 매핑
6872
String readmeInfo = gitHubDataFetcher.fetchReadmeContent(owner, repo);
6973
readmeInfoMapper.mapReadmeInfo(data, readmeInfo);
7074

71-
// TODO: 보안 관리 데이터 수집 및 매핑
75+
// 4. 보안 관리 데이터 수집 및 매핑
76+
TreeResponse securityInfo = gitHubDataFetcher.fetchRepositoryTreeInfo(owner, repo, repoInfo.defaultBranch());
77+
securityInfoMapper.mapSecurityInfo(data, securityInfo);
7278

79+
// 5. 테스트 데이터 수집 및 매핑
80+
TreeResponse testInfo = gitHubDataFetcher.fetchRepositoryTreeInfo(owner, repo, repoInfo.defaultBranch());
81+
testInfoMapper.mapTestInfo(data, testInfo);
7382

74-
// TODO: 테스트 데이터 수집 및 매핑
83+
// 6. CI/CD 데이터 수집 및 매핑
84+
TreeResponse cicdInfo = gitHubDataFetcher.fetchRepositoryTreeInfo(owner, repo, repoInfo.defaultBranch());
85+
cicdInfoMapper.mapCicdInfo(data, cicdInfo);
7586

87+
// 7. 커뮤니티 활성도 데이터 수집 및 매핑
88+
List<IssueResponse> issueInfo = gitHubDataFetcher.fetchIssueInfo(owner, repo);
89+
issueInfoMapper.mapIssueInfo(data, issueInfo);
7690

77-
// TODO: CI/CD 데이터 수집 및 매핑
78-
79-
80-
// TODO: 커뮤니티 활성도 데이터 수집 및 매핑
91+
List<PullRequestResponse> pullRequestInfo = gitHubDataFetcher.fetchPullRequestInfo(owner, repo);
92+
pullRequestInfoMapper.mapPullRequestInfo(data, pullRequestInfo);
8193

8294
// Entity 저장 로직
83-
saveRepositoryEntity(repoInfo);
95+
Repositories savedRepository = saveOrUpdateRepository(repoInfo, owner, repo);
96+
8497

85-
log.info("✅ RepositoryData: {}", data);
8698
return data;
8799
}
88100

89-
private void saveRepositoryEntity(RepoResponse repoInfo) {
101+
private Repositories saveOrUpdateRepository(RepoResponse repoInfo, String owner, String repo) {
90102
User defaultUser = userRepository.findAll().stream()
91103
.findFirst()
92104
.orElseThrow(() -> new BusinessException(ErrorCode.INTERNAL_ERROR));
93105

94-
Repositories entity = repositoriesMapper.toEntity(repoInfo, defaultUser);
95-
repositoryJpaRepository
96-
.findByHtmlUrl(entity.getHtmlUrl())
106+
Map<String, Integer> languagesData = gitHubDataFetcher.fetchLanguages(owner, repo);
107+
108+
return repositoryJpaRepository.findByHtmlUrl(repoInfo.htmlUrl())
97109
.map(existing -> {
98-
existing.updateFrom(repositoriesMapper.toEntity(repoInfo, defaultUser));
110+
existing.updateFrom(repoInfo);
111+
existing.updateLanguagesFrom(languagesData);
99112
return existing;
100113
})
101114
.orElseGet(() -> {
102-
Repositories newEntity = repositoriesMapper.toEntity(repoInfo, defaultUser);
103-
return repositoryJpaRepository.save(newEntity);
115+
Repositories newRepo = repositoriesMapper.toEntity(repoInfo, defaultUser);
116+
newRepo.updateLanguagesFrom(languagesData);
117+
return repositoryJpaRepository.save(newRepo);
104118
});
105-
106-
log.info("✅ Repositories: {}", entity);
107119
}
108120

109121
// Repository에서 member로 리포지토리 찾기
@@ -116,7 +128,7 @@ public List<Language> findLanguagesByRepisotryId(Long gitRepositoryId){
116128
return repositoryJpaRepository.findLanguagesByRepositoryId(gitRepositoryId);
117129
}
118130

119-
// repostiroy 삭제
131+
// repository 삭제
120132
public void delete(Long repositoriesId){
121133
Optional<Repositories> optionalRepository = repositoryJpaRepository.findById(repositoriesId);
122134
if(optionalRepository.isPresent()){

0 commit comments

Comments
 (0)