diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryBranchRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryBranchRepository.java index 926d6dbe..5ec29efd 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryBranchRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryBranchRepository.java @@ -35,4 +35,6 @@ public interface IRepositoryBranchRepository extends IBaseRepository findByExternalSystemIdAndProjectIdAndDeletedFalse(Long externalSystemId, Long id); + + List findByExternalSystemIdAndDeletedFalse(Long externalSystemId); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java index 7cf138a7..a24c91ea 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java @@ -27,6 +27,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.ArrayList; @@ -70,7 +72,9 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl> futures = new ArrayList<>(); - List branchesToSave = Collections.synchronizedList(new ArrayList<>()); + // 4. 一次性获取所有现有分支 + List existingBranches = repositoryBranchRepository.findByExternalSystemIdAndDeletedFalse(externalSystemId); + Map> existingBranchMap = existingBranches.stream() + .collect(Collectors.groupingBy( + RepositoryBranch::getName, + Collectors.toMap( + RepositoryBranch::getProjectId, + Function.identity(), + (existing, replacement) -> existing + ) + )); + log.info("Found {} existing branches in database", existingBranches.size()); - // 4. 异步处理每个项目 + AtomicInteger totalSyncedBranches = new AtomicInteger(0); + List>> futures = new ArrayList<>(); + + // 5. 并行处理每个项目 for (RepositoryProject project : projects) { - CompletableFuture future = CompletableFuture.runAsync(() -> { + CompletableFuture> future = CompletableFuture.supplyAsync(() -> { try { - log.info("Syncing branches for project: {} (ID: {}, GitLab ID: {})", - project.getName(), project.getId(), project.getProjectId()); - - // 4.1 获取当前项目在GitLab上的所有分支,使用GitLab的真实project_id + log.info("Syncing branches for project: {} (ID: {}, GitLab ID: {})", project.getName(), project.getId(), project.getProjectId()); + + // 5.1 获取当前项目在GitLab上的所有分支 List remoteBranches = gitServiceIntegration.branches(externalSystem, project.getProjectId()); log.info("Found {} remote branches for project: {}", remoteBranches.size(), project.getName()); - - Set remoteBranchNames = remoteBranches.stream() - .map(GitBranchResponse::getName) - .collect(Collectors.toSet()); - log.info("Remote branch names: {}", remoteBranchNames); - // 4.2 获取数据库中的所有分支 - Map existingBranchMap = repositoryBranchRepository - .findByExternalSystemIdAndProjectIdAndDeletedFalse(externalSystemId, project.getId()) - .stream() - .collect(Collectors.toMap(RepositoryBranch::getName, Function.identity())); - log.info("Found {} existing branches in database for project: {}", existingBranchMap.size(), project.getName()); - log.info("Existing branch names: {}", existingBranchMap.keySet()); + List branchesToUpdate = new ArrayList<>(); + Set processedBranches = new HashSet<>(); - // 4.3 处理所有远程分支(新增或更新) + // 5.2 处理远程分支 for (GitBranchResponse remoteBranch : remoteBranches) { - RepositoryBranch branch = updateOrCreateBranch(externalSystemId, project.getId(), remoteBranch, existingBranchMap); - branchesToSave.add(branch); + Map projectBranches = existingBranchMap.getOrDefault(remoteBranch.getName(), new HashMap<>()); + RepositoryBranch branch = projectBranches.getOrDefault(project.getId(), new RepositoryBranch()); + + // 更新分支信息 + updateBranchInfo(branch, externalSystemId, project.getId(), project.getProjectId(), remoteBranch); + branchesToUpdate.add(branch); + processedBranches.add(remoteBranch.getName()); totalSyncedBranches.incrementAndGet(); - existingBranchMap.remove(remoteBranch.getName()); - log.info("Processed remote branch: {}", remoteBranch.getName()); } - // 4.4 处理已删除的分支 - existingBranchMap.forEach((branchName, branch) -> { - branch.setDeleted(true); - branchesToSave.add(branch); - totalSyncedBranches.incrementAndGet(); - log.info("Marked branch as deleted: {}", branchName); - }); + // 5.3 处理已删除的分支 + Map projectBranches = existingBranchMap.values().stream() + .flatMap(map -> map.values().stream()) + .filter(b -> b.getProjectId().equals(project.getId())) + .collect(Collectors.toMap(RepositoryBranch::getName, Function.identity())); + + for (RepositoryBranch branch : projectBranches.values()) { + if (!processedBranches.contains(branch.getName())) { + branch.setDeleted(true); + branchesToUpdate.add(branch); + totalSyncedBranches.incrementAndGet(); + } + } - log.info("Completed processing {} branches for project: {}", remoteBranches.size(), project.getName()); + log.info("Processed {} branches for project: {}", branchesToUpdate.size(), project.getName()); + return branchesToUpdate; } catch (Exception e) { - log.error("Failed to sync branches for project: {} (ID: {}, GitLab ID: {})", + log.error("Failed to sync branches for project: {} (ID: {}, GitLab ID: {})", project.getName(), project.getId(), project.getProjectId(), e); throw new RuntimeException(e); } @@ -177,50 +192,49 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl allBranchesToSave = futures.stream() + .map(CompletableFuture::join) + .flatMap(List::stream) + .collect(Collectors.toList()); - // 批量保存分支 - if (!branchesToSave.isEmpty()) { + // 7. 批量保存所有分支 + if (!allBranchesToSave.isEmpty()) { try { - log.info("Saving {} branches to database", branchesToSave.size()); - saveBatch(branchesToSave); + log.info("Saving {} branches to database in batch", allBranchesToSave.size()); + saveBatch(allBranchesToSave); } catch (Exception e) { log.error("Error saving branches in batch", e); throw e; } } - // 5. 更新同步历史为成功 + // 8. 更新同步历史为成功 repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); - log.info("Successfully synchronized {} branches for external system: {}", + log.info("Successfully synchronized {} branches for external system: {}", totalSyncedBranches.get(), externalSystem.getName()); return totalSyncedBranches.get(); } catch (Exception e) { - // 6. 更新同步历史为失败 + // 9. 更新同步历史为失败 log.error("Failed to sync branches", e); repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage()); throw new BusinessException(ResponseCode.REPOSITORY_BRANCH_SYNC_FAILED); } } - private RepositoryBranch updateOrCreateBranch( - Long externalSystemId, - Long projectId, - GitBranchResponse remoteBranch, - Map existingBranchMap) { - - RepositoryBranch branch = existingBranchMap.getOrDefault(remoteBranch.getName(), new RepositoryBranch()); - - // 获取对应的RepositoryProject以获取GitLab的真实project_id - RepositoryProject project = repositoryProjectRepository.findById(projectId) - .orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_PROJECT_NOT_FOUND)); - - // 更新基本信息 + /** + * 更新分支信息 + */ + private void updateBranchInfo( + RepositoryBranch branch, + Long externalSystemId, + Long projectId, + Long gitProjectId, + GitBranchResponse remoteBranch) { branch.setExternalSystemId(externalSystemId); - branch.setProjectId(projectId); // 设置我们数据库的project ID - branch.setGitProjectId(project.getProjectId()); // 设置GitLab的真实project ID + branch.setProjectId(projectId); + branch.setGitProjectId(gitProjectId); branch.setName(remoteBranch.getName()); branch.setIsDefaultBranch(remoteBranch.getIsDefaultBranch()); branch.setCanPush(remoteBranch.getCanPush()); @@ -233,8 +247,6 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl