大声道撒旦
This commit is contained in:
parent
914ad0d1a1
commit
5598468fab
@ -31,6 +31,12 @@ public class RepositoryBranch extends Entity<Long> {
|
|||||||
@Column(name = "commit_date")
|
@Column(name = "commit_date")
|
||||||
private LocalDateTime commitDate;
|
private LocalDateTime commitDate;
|
||||||
|
|
||||||
|
@Column(name = "last_update_time")
|
||||||
|
private LocalDateTime lastUpdateTime;
|
||||||
|
|
||||||
|
@Column(name = "last_commit_time")
|
||||||
|
private LocalDateTime lastCommitTime;
|
||||||
|
|
||||||
@Column(name = "is_protected")
|
@Column(name = "is_protected")
|
||||||
private Boolean isProtected = false;
|
private Boolean isProtected = false;
|
||||||
|
|
||||||
@ -54,5 +60,4 @@ public class RepositoryBranch extends Entity<Long> {
|
|||||||
|
|
||||||
@Column(name = "external_system_id")
|
@Column(name = "external_system_id")
|
||||||
private Long externalSystemId;
|
private Long externalSystemId;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -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.deploy.integration.response.GitProjectResponse;
|
||||||
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
|
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -11,10 +11,15 @@ import org.springframework.core.ParameterizedTypeReference;
|
|||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
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.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git服务集成实现
|
* Git服务集成实现
|
||||||
@ -25,6 +30,7 @@ import java.util.List;
|
|||||||
public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
||||||
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
private static final DateTimeFormatter GITLAB_DATE_FORMATTER = DateTimeFormatter.ISO_DATE_TIME;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testConnection(ExternalSystem system) {
|
public boolean testConnection(ExternalSystem system) {
|
||||||
@ -117,6 +123,16 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
HttpHeaders headers = createHeaders(system);
|
HttpHeaders headers = createHeaders(system);
|
||||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
// 先获取原始响应以便调试
|
||||||
|
ResponseEntity<String> rawResponse = restTemplate.exchange(
|
||||||
|
url,
|
||||||
|
HttpMethod.GET,
|
||||||
|
entity,
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
log.info("GitLab API raw response for project {}: {}", projectId, rawResponse.getBody());
|
||||||
|
|
||||||
|
// 然后解析为对象
|
||||||
ResponseEntity<List<GitBranchResponse>> response = restTemplate.exchange(
|
ResponseEntity<List<GitBranchResponse>> response = restTemplate.exchange(
|
||||||
url,
|
url,
|
||||||
HttpMethod.GET,
|
HttpMethod.GET,
|
||||||
@ -124,7 +140,12 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
new ParameterizedTypeReference<>() {}
|
new ParameterizedTypeReference<>() {}
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.getBody() != null ? response.getBody() : Collections.emptyList();
|
List<GitBranchResponse> 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) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to fetch git branches for system: {} and project: {}", system.getName(), projectId, e);
|
log.error("Failed to fetch git branches for system: {} and project: {}", system.getName(), projectId, e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -161,3 +182,89 @@ public class GitServiceIntegrationImpl implements IGitServiceIntegration {
|
|||||||
return headers;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,11 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.integration.response;
|
package com.qqchen.deploy.backend.deploy.integration.response;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git分支响应对象
|
* Git分支响应对象
|
||||||
@ -12,23 +15,62 @@ public class GitBranchResponse {
|
|||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@JsonProperty("default")
|
||||||
private Boolean isDefaultBranch;
|
private Boolean isDefaultBranch;
|
||||||
|
|
||||||
private Boolean isProtected;
|
private Boolean isProtected;
|
||||||
|
|
||||||
|
@JsonProperty("can_push")
|
||||||
private Boolean canPush;
|
private Boolean canPush;
|
||||||
|
|
||||||
|
@JsonProperty("developers_can_push")
|
||||||
private Boolean developersCanPush;
|
private Boolean developersCanPush;
|
||||||
|
|
||||||
|
@JsonProperty("developers_can_merge")
|
||||||
private Boolean developersCanMerge;
|
private Boolean developersCanMerge;
|
||||||
|
|
||||||
private String commitId;
|
@JsonProperty("commit")
|
||||||
|
private GitCommitResponse commit;
|
||||||
private String commitMessage;
|
|
||||||
|
|
||||||
private String commitAuthor;
|
|
||||||
|
|
||||||
private LocalDateTime commitDate;
|
|
||||||
|
|
||||||
|
@JsonProperty("web_url")
|
||||||
private String webUrl;
|
private String webUrl;
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +38,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git仓库分支服务实现
|
* Git仓库分支服务实现
|
||||||
*/
|
*/
|
||||||
@ -117,54 +119,41 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl<RepositoryBranc
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 获取上次成功同步的历史记录
|
|
||||||
RepositorySyncHistory lastSuccessSync = repositorySyncHistoryRepository
|
|
||||||
.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc(
|
|
||||||
externalSystemId, RepositorySyncType.BRANCH, ExternalSystemSyncStatus.SUCCESS);
|
|
||||||
|
|
||||||
// 5. 筛选需要同步的项目
|
|
||||||
List<RepositoryProject> 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);
|
AtomicInteger totalSyncedBranches = new AtomicInteger(0);
|
||||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||||
List<RepositoryBranch> branchesToSave = Collections.synchronizedList(new ArrayList<>());
|
List<RepositoryBranch> branchesToSave = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
// 6. 异步同步每个项目的分支
|
// 4. 异步处理每个项目
|
||||||
for (RepositoryProject project : projectsToSync) {
|
for (RepositoryProject project : projects) {
|
||||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// 6.1 获取远程分支信息
|
// 4.1 获取当前项目在GitLab上的所有分支
|
||||||
List<GitBranchResponse> remoteBranches = gitServiceIntegration.branches(externalSystem, project.getProjectId());
|
List<GitBranchResponse> remoteBranches = gitServiceIntegration.branches(externalSystem, project.getProjectId());
|
||||||
if (remoteBranches.isEmpty()) {
|
Set<String> remoteBranchNames = remoteBranches.stream()
|
||||||
log.info("No branches found for project: {}", project.getName());
|
.map(GitBranchResponse::getName)
|
||||||
return;
|
.collect(Collectors.toSet());
|
||||||
}
|
|
||||||
|
|
||||||
// 6.2 获取本地已存在的分支
|
// 4.2 获取数据库中的所有分支
|
||||||
Map<String, RepositoryBranch> existingBranchMap = repositoryBranchRepository
|
Map<String, RepositoryBranch> existingBranchMap = repositoryBranchRepository
|
||||||
.findByExternalSystemIdAndProjectIdAndDeletedFalse(externalSystemId, project.getId())
|
.findByExternalSystemIdAndProjectIdAndDeletedFalse(externalSystemId, project.getId())
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(RepositoryBranch::getName, Function.identity()));
|
.collect(Collectors.toMap(RepositoryBranch::getName, Function.identity()));
|
||||||
|
|
||||||
// 6.3 更新或创建分支
|
// 4.3 处理所有远程分支(新增或更新)
|
||||||
for (GitBranchResponse remoteBranch : remoteBranches) {
|
for (GitBranchResponse remoteBranch : remoteBranches) {
|
||||||
RepositoryBranch branch = updateOrCreateBranch(externalSystemId, project.getId(), remoteBranch, existingBranchMap);
|
RepositoryBranch branch = updateOrCreateBranch(externalSystemId, project.getId(), remoteBranch, existingBranchMap);
|
||||||
branchesToSave.add(branch);
|
branchesToSave.add(branch);
|
||||||
totalSyncedBranches.incrementAndGet();
|
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());
|
log.info("Processed {} branches for project: {}", remoteBranches.size(), project.getName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to sync branches for project: {}", project.getName(), e);
|
log.error("Failed to sync branches for project: {}", project.getName(), e);
|
||||||
@ -188,16 +177,15 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl<RepositoryBranc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 更新同步历史为成功
|
// 5. 更新同步历史为成功
|
||||||
repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null);
|
repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null);
|
||||||
|
|
||||||
log.info("Successfully synchronized total {} branches for external system: {}",
|
log.info("Successfully synchronized total {} branches for external system: {}",
|
||||||
totalSyncedBranches.get(), externalSystem.getName());
|
totalSyncedBranches.get(), externalSystem.getName());
|
||||||
return totalSyncedBranches.get();
|
return totalSyncedBranches.get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 8. 更新同步历史为失败
|
// 6. 更新同步历史为失败
|
||||||
repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage());
|
repositorySyncHistoryService.updateSyncHistory(syncHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage());
|
||||||
log.error("Failed to sync branches for external system: {}", externalSystemId, e);
|
|
||||||
throw new BusinessException(ResponseCode.REPOSITORY_BRANCH_SYNC_FAILED);
|
throw new BusinessException(ResponseCode.REPOSITORY_BRANCH_SYNC_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,6 +212,8 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl<RepositoryBranc
|
|||||||
branch.setCommitAuthor(remoteBranch.getCommitAuthor());
|
branch.setCommitAuthor(remoteBranch.getCommitAuthor());
|
||||||
branch.setCommitDate(remoteBranch.getCommitDate());
|
branch.setCommitDate(remoteBranch.getCommitDate());
|
||||||
branch.setWebUrl(remoteBranch.getWebUrl());
|
branch.setWebUrl(remoteBranch.getWebUrl());
|
||||||
|
branch.setLastUpdateTime(remoteBranch.getLastUpdateTime());
|
||||||
|
branch.setLastCommitTime(remoteBranch.getLastCommitTime());
|
||||||
|
|
||||||
return branch;
|
return branch;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -359,6 +359,8 @@ CREATE TABLE deploy_repo_branch
|
|||||||
commit_message TEXT NULL COMMENT '最新提交信息',
|
commit_message TEXT NULL COMMENT '最新提交信息',
|
||||||
commit_author VARCHAR(100) NULL COMMENT '最新提交作者',
|
commit_author VARCHAR(100) NULL COMMENT '最新提交作者',
|
||||||
commit_date DATETIME(6) NULL COMMENT '最新提交时间',
|
commit_date DATETIME(6) NULL COMMENT '最新提交时间',
|
||||||
|
last_update_time DATETIME(6) NULL COMMENT '分支最后更新时间',
|
||||||
|
last_commit_time DATETIME(6) NULL COMMENT '分支最后提交时间',
|
||||||
web_url VARCHAR(255) NULL COMMENT '网页URL'
|
web_url VARCHAR(255) NULL COMMENT '网页URL'
|
||||||
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='代码仓库分支表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='代码仓库分支表';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user