From 5598468fab277fb90e24c2a1cbd2c0134ef56ca0 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Thu, 9 Jan 2025 16:38:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E5=A3=B0=E9=81=93=E6=92=92=E6=97=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deploy/entity/RepositoryBranch.java | 7 +- .../integration/IGitServiceIntegration.java | 1 + .../impl/GitServiceIntegrationImpl.java | 109 +++++++++++++++++- .../response/GitBranchResponse.java | 58 ++++++++-- .../impl/RepositoryBranchServiceImpl.java | 54 ++++----- .../db/migration/V1.0.0__init_schema.sql | 2 + 6 files changed, 189 insertions(+), 42 deletions(-) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositoryBranch.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositoryBranch.java index 5e113e1e..5c68953d 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositoryBranch.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositoryBranch.java @@ -31,6 +31,12 @@ public class RepositoryBranch extends Entity { @Column(name = "commit_date") private LocalDateTime commitDate; + @Column(name = "last_update_time") + private LocalDateTime lastUpdateTime; + + @Column(name = "last_commit_time") + private LocalDateTime lastCommitTime; + @Column(name = "is_protected") private Boolean isProtected = false; @@ -54,5 +60,4 @@ public class RepositoryBranch extends Entity { @Column(name = "external_system_id") private Long externalSystemId; - } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IGitServiceIntegration.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IGitServiceIntegration.java index 731f36bc..6ed626bc 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IGitServiceIntegration.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IGitServiceIntegration.java @@ -6,6 +6,7 @@ import com.qqchen.deploy.backend.deploy.integration.response.GitGroupResponse; import com.qqchen.deploy.backend.deploy.integration.response.GitProjectResponse; import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum; +import java.time.LocalDateTime; import java.util.List; /** diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/GitServiceIntegrationImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/GitServiceIntegrationImpl.java index d3c8690d..ff95334c 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/GitServiceIntegrationImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/GitServiceIntegrationImpl.java @@ -11,10 +11,15 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Git服务集成实现 @@ -25,6 +30,7 @@ import java.util.List; public class GitServiceIntegrationImpl implements IGitServiceIntegration { private final RestTemplate restTemplate = new RestTemplate(); + private static final DateTimeFormatter GITLAB_DATE_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; @Override public boolean testConnection(ExternalSystem system) { @@ -117,6 +123,16 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration { HttpHeaders headers = createHeaders(system); HttpEntity entity = new HttpEntity<>(headers); + // 先获取原始响应以便调试 + ResponseEntity rawResponse = restTemplate.exchange( + url, + HttpMethod.GET, + entity, + String.class + ); + log.info("GitLab API raw response for project {}: {}", projectId, rawResponse.getBody()); + + // 然后解析为对象 ResponseEntity> response = restTemplate.exchange( url, HttpMethod.GET, @@ -124,7 +140,12 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration { new ParameterizedTypeReference<>() {} ); - return response.getBody() != null ? response.getBody() : Collections.emptyList(); + List branches = response.getBody(); + if (branches != null && !branches.isEmpty()) { + log.info("First branch details: {}", branches.get(0)); + } + + return branches != null ? branches : Collections.emptyList(); } catch (Exception e) { log.error("Failed to fetch git branches for system: {} and project: {}", system.getName(), projectId, e); return Collections.emptyList(); @@ -160,4 +181,90 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration { return headers; } +} + +/** + * GitLab事件响应对象 + */ +class GitlabEvent { + private String action; + private String targetType; + private String targetBranch; + private LocalDateTime createdAt; + + // Getters and setters + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getTargetType() { + return targetType; + } + + public void setTargetType(String targetType) { + this.targetType = targetType; + } + + public String getTargetBranch() { + return targetBranch; + } + + public void setTargetBranch(String targetBranch) { + this.targetBranch = targetBranch; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } +} + +/** + * GitLab仓库事件响应对象 + */ +class GitlabRepositoryEvent { + private String actionName; + private String refType; + private String ref; + private LocalDateTime createdAt; + + // Getters and setters + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public String getRefType() { + return refType; + } + + public void setRefType(String refType) { + this.refType = refType; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitBranchResponse.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitBranchResponse.java index 9518228c..38431e9e 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitBranchResponse.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitBranchResponse.java @@ -1,8 +1,11 @@ package com.qqchen.deploy.backend.deploy.integration.response; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; /** * Git分支响应对象 @@ -12,23 +15,62 @@ public class GitBranchResponse { private String name; + @JsonProperty("default") private Boolean isDefaultBranch; private Boolean isProtected; + @JsonProperty("can_push") private Boolean canPush; + @JsonProperty("developers_can_push") private Boolean developersCanPush; + @JsonProperty("developers_can_merge") private Boolean developersCanMerge; - private String commitId; - - private String commitMessage; - - private String commitAuthor; - - private LocalDateTime commitDate; + @JsonProperty("commit") + private GitCommitResponse commit; + @JsonProperty("web_url") private String webUrl; -} \ No newline at end of file + + @Data + public static class GitCommitResponse { + private String id; + private String message; + private String author_name; + + @JsonProperty("authored_date") + private OffsetDateTime authoredDate; + + @JsonProperty("committed_date") + private OffsetDateTime committedDate; + } + + public String getCommitId() { + return commit != null ? commit.id : null; + } + + public String getCommitMessage() { + return commit != null ? commit.message : null; + } + + public String getCommitAuthor() { + return commit != null ? commit.author_name : null; + } + + public LocalDateTime getCommitDate() { + return commit != null && commit.authoredDate != null ? + commit.authoredDate.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() : null; + } + + public LocalDateTime getLastUpdateTime() { + return commit != null && commit.committedDate != null ? + commit.committedDate.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() : null; + } + + public LocalDateTime getLastCommitTime() { + return getLastUpdateTime(); + } +} \ 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 965038e6..548c6657 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 @@ -38,6 +38,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; +import java.time.LocalDateTime; + /** * Git仓库分支服务实现 */ @@ -117,54 +119,41 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl projectsToSync = projects; - if (lastSuccessSync != null) { - projectsToSync = projects.stream() - .filter(project -> project.getLastActivityAt() == null || - project.getLastActivityAt().isAfter(lastSuccessSync.getEndTime())) - .collect(Collectors.toList()); - } - - if (projectsToSync.isEmpty()) { - log.info("No projects need to be synchronized for external system: {}", externalSystem.getName()); - repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); - return 0; - } - AtomicInteger totalSyncedBranches = new AtomicInteger(0); List> futures = new ArrayList<>(); List branchesToSave = Collections.synchronizedList(new ArrayList<>()); - // 6. 异步同步每个项目的分支 - for (RepositoryProject project : projectsToSync) { + // 4. 异步处理每个项目 + for (RepositoryProject project : projects) { CompletableFuture future = CompletableFuture.runAsync(() -> { try { - // 6.1 获取远程分支信息 + // 4.1 获取当前项目在GitLab上的所有分支 List remoteBranches = gitServiceIntegration.branches(externalSystem, project.getProjectId()); - if (remoteBranches.isEmpty()) { - log.info("No branches found for project: {}", project.getName()); - return; - } + Set remoteBranchNames = remoteBranches.stream() + .map(GitBranchResponse::getName) + .collect(Collectors.toSet()); - // 6.2 获取本地已存在的分支 + // 4.2 获取数据库中的所有分支 Map existingBranchMap = repositoryBranchRepository .findByExternalSystemIdAndProjectIdAndDeletedFalse(externalSystemId, project.getId()) .stream() .collect(Collectors.toMap(RepositoryBranch::getName, Function.identity())); - // 6.3 更新或创建分支 + // 4.3 处理所有远程分支(新增或更新) for (GitBranchResponse remoteBranch : remoteBranches) { RepositoryBranch branch = updateOrCreateBranch(externalSystemId, project.getId(), remoteBranch, existingBranchMap); branchesToSave.add(branch); totalSyncedBranches.incrementAndGet(); + existingBranchMap.remove(remoteBranch.getName()); } + // 4.4 处理已删除的分支 + existingBranchMap.forEach((branchName, branch) -> { + branch.setDeleted(true); + branchesToSave.add(branch); + totalSyncedBranches.incrementAndGet(); + }); + log.info("Processed {} branches for project: {}", remoteBranches.size(), project.getName()); } catch (Exception e) { log.error("Failed to sync branches for project: {}", project.getName(), e); @@ -188,16 +177,15 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl