From 68fe2fedef3e71406c2e898039fc406114677645 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 8 Jan 2025 10:28:35 +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/api/GitManagerApiController.java | 70 ++++++ .../api/RepositoryBranchApiController.java | 60 ++++++ .../api/RepositoryProjectApiController.java | 52 +++++ .../converter/RepositoryBranchConverter.java | 13 ++ .../converter/RepositoryProjectConverter.java | 13 ++ .../RepositorySyncHistoryConverter.java | 13 ++ .../backend/deploy/dto/GitInstanceDTO.java | 32 +++ .../deploy/dto/RepositoryBranchDTO.java | 41 ++++ .../deploy/dto/RepositoryProjectDTO.java | 39 ++++ .../deploy/dto/RepositorySyncHistoryDTO.java | 31 +++ .../deploy/entity/RepositorySyncHistory.java | 52 ++--- .../deploy/enums/RepositorySyncType.java | 10 + .../response/GitBranchResponse.java | 15 +- .../response/GitProjectResponse.java | 2 - .../deploy/query/RepositoryBranchQuery.java | 33 +++ .../deploy/query/RepositoryProjectQuery.java | 33 +++ .../query/RepositorySyncHistoryQuery.java | 29 +++ .../IRepositoryBranchRepository.java | 27 ++- .../IRepositoryProjectRepository.java | 24 ++- .../IRepositorySyncHistoryRepository.java | 24 ++- .../deploy/service/IGitManagerService.java | 47 ++++ .../service/IRepositoryBranchService.java | 37 ++++ .../service/IRepositoryGroupService.java | 10 + .../service/IRepositoryProjectService.java | 33 +++ .../IRepositorySyncHistoryService.java | 32 +++ .../service/impl/GitManagerServiceImpl.java | 203 ++++++++++++++++++ .../impl/RepositoryBranchServiceImpl.java | 123 +++++++++++ .../impl/RepositoryGroupServiceImpl.java | 26 ++- .../impl/RepositoryProjectServiceImpl.java | 126 +++++++++++ .../RepositorySyncHistoryServiceImpl.java | 58 +++++ .../backend/framework/enums/ResponseCode.java | 6 +- .../db/migration/V1.0.1__init_data.sql | 4 +- 32 files changed, 1254 insertions(+), 64 deletions(-) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/api/GitManagerApiController.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryBranchApiController.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryProjectApiController.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryBranchConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryProjectConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositorySyncHistoryConverter.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/GitInstanceDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryBranchDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryProjectDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositorySyncHistoryDTO.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/RepositorySyncType.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryBranchQuery.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryProjectQuery.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositorySyncHistoryQuery.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IGitManagerService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryBranchService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryProjectService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositorySyncHistoryService.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/GitManagerServiceImpl.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryProjectServiceImpl.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositorySyncHistoryServiceImpl.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/GitManagerApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/GitManagerApiController.java new file mode 100644 index 00000000..960f2473 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/GitManagerApiController.java @@ -0,0 +1,70 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.dto.GitInstanceDTO; +import com.qqchen.deploy.backend.deploy.service.IGitManagerService; +import com.qqchen.deploy.backend.framework.api.Response; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/** + * Git仓库管理API控制器 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/git-manager") +@Tag(name = "Git仓库管理", description = "Git仓库管理相关接口") +public class GitManagerApiController { + + @Resource + private IGitManagerService gitManagerService; + + @Operation(summary = "同步所有Git数据", description = "同步指定外部系统的所有Git数据,包括仓库组、项目和分支") + @PostMapping("/{externalSystemId}/sync-all") + public Response syncAll( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId + ) { + gitManagerService.syncAll(externalSystemId); + return Response.success(); + } + + @Operation(summary = "同步Git仓库组", description = "同步指定外部系统的所有仓库组") + @PostMapping("/{externalSystemId}/sync-groups") + public Response syncGroups( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId + ) { + gitManagerService.syncGroups(externalSystemId); + return Response.success(); + } + + @Operation(summary = "同步Git项目", description = "同步指定外部系统下指定仓库组的所有项目") + @PostMapping("/{externalSystemId}/groups/{groupId}/sync-projects") + public Response syncProjects( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId, + @Parameter(description = "仓库组ID", required = true) @PathVariable Long groupId + ) { + gitManagerService.syncProjects(externalSystemId, groupId); + return Response.success(); + } + + @Operation(summary = "同步Git分支", description = "同步指定外部系统下指定项目的所有分支") + @PostMapping("/{externalSystemId}/projects/{projectId}/sync-branches") + public Response syncBranches( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId, + @Parameter(description = "项目ID", required = true) @PathVariable Long projectId + ) { + gitManagerService.syncBranches(externalSystemId, projectId); + return Response.success(); + } + + @Operation(summary = "获取Git实例信息", description = "获取指定外部系统的Git实例信息,包括仓库组、项目和分支的数量及最后同步时间") + @GetMapping("/{externalSystemId}/instance") + public Response instance( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId + ) { + return Response.success(gitManagerService.instance(externalSystemId)); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryBranchApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryBranchApiController.java new file mode 100644 index 00000000..abdaf75c --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryBranchApiController.java @@ -0,0 +1,60 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.entity.RepositoryBranch; +import com.qqchen.deploy.backend.deploy.dto.RepositoryBranchDTO; +import com.qqchen.deploy.backend.deploy.query.RepositoryBranchQuery; +import com.qqchen.deploy.backend.deploy.service.IRepositoryBranchService; +import com.qqchen.deploy.backend.framework.api.Response; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Git仓库分支管理接口 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/repository-branch") +@Tag(name = "Git仓库分支管理", description = "Git仓库分支管理相关接口") +public class RepositoryBranchApiController extends BaseController { + + @Resource + private IRepositoryBranchService repositoryBranchService; + + @Operation(summary = "同步指定外部系统下指定项目的分支") + @PostMapping("/{externalSystemId}/projects/{projectId}/sync") + public Response syncBranches( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId, + @Parameter(description = "项目ID", required = true) @PathVariable Long projectId + ) { + return Response.success(repositoryBranchService.syncBranches(externalSystemId, projectId)); + } + + @Operation(summary = "统计指定外部系统下的分支数量") + @GetMapping("/{externalSystemId}/count") + public Response countByExternalSystemId( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId + ) { + return Response.success(repositoryBranchService.countByExternalSystemId(externalSystemId)); + } + + @Operation(summary = "统计指定项目下的分支数量") + @GetMapping("/projects/{projectId}/count") + public Response countByProjectId( + @Parameter(description = "项目ID", required = true) @PathVariable Long projectId + ) { + return Response.success(repositoryBranchService.countByProjectId(projectId)); + } + + @Override + protected void exportData(HttpServletResponse response, List data) { + + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryProjectApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryProjectApiController.java new file mode 100644 index 00000000..10ddf32e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/api/RepositoryProjectApiController.java @@ -0,0 +1,52 @@ +package com.qqchen.deploy.backend.deploy.api; + +import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; +import com.qqchen.deploy.backend.deploy.query.RepositoryProjectQuery; +import com.qqchen.deploy.backend.deploy.service.IRepositoryProjectService; +import com.qqchen.deploy.backend.framework.api.Response; +import com.qqchen.deploy.backend.framework.controller.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Git仓库项目管理接口 + */ +@Slf4j +@RestController +@RequestMapping("/api/v1/repository-project") +@Tag(name = "Git仓库项目管理", description = "Git仓库项目管理相关接口") +public class RepositoryProjectApiController extends BaseController { + + @Resource + private IRepositoryProjectService repositoryProjectService; + + @Operation(summary = "同步指定外部系统下指定仓库组的项目") + @PostMapping("/{externalSystemId}/groups/{groupId}/sync") + public Response syncProjects( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId, + @Parameter(description = "仓库组ID", required = true) @PathVariable Long groupId + ) { + return Response.success(repositoryProjectService.syncProjects(externalSystemId, groupId)); + } + + @Operation(summary = "统计指定外部系统下的项目数量") + @GetMapping("/{externalSystemId}/count") + public Response countByExternalSystemId( + @Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId + ) { + return Response.success(repositoryProjectService.countByExternalSystemId(externalSystemId)); + } + + @Override + protected void exportData(HttpServletResponse response, List data) { + + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryBranchConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryBranchConverter.java new file mode 100644 index 00000000..adf8f63d --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryBranchConverter.java @@ -0,0 +1,13 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.deploy.entity.RepositoryBranch; +import com.qqchen.deploy.backend.deploy.dto.RepositoryBranchDTO; +import org.mapstruct.Mapper; + +/** + * Git仓库分支转换器 + */ +@Mapper(config = BaseConverter.class) +public interface RepositoryBranchConverter extends BaseConverter { +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryProjectConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryProjectConverter.java new file mode 100644 index 00000000..cf6264af --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositoryProjectConverter.java @@ -0,0 +1,13 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; +import org.mapstruct.Mapper; + +/** + * Git仓库项目转换器 + */ +@Mapper(config = BaseConverter.class) +public interface RepositoryProjectConverter extends BaseConverter { +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositorySyncHistoryConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositorySyncHistoryConverter.java new file mode 100644 index 00000000..a90252eb --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/RepositorySyncHistoryConverter.java @@ -0,0 +1,13 @@ +package com.qqchen.deploy.backend.deploy.converter; + +import com.qqchen.deploy.backend.deploy.entity.RepositorySyncHistory; +import com.qqchen.deploy.backend.deploy.dto.RepositorySyncHistoryDTO; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import org.mapstruct.Mapper; + +/** + * Git同步历史记录 Converter + */ +@Mapper(config = BaseConverter.class) +public interface RepositorySyncHistoryConverter extends BaseConverter { +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/GitInstanceDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/GitInstanceDTO.java new file mode 100644 index 00000000..76703bba --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/GitInstanceDTO.java @@ -0,0 +1,32 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * Git实例信息 DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GitInstanceDTO extends BaseDTO { + + private int totalGroups; + + private LocalDateTime lastSyncGroupsTime; + + private int totalProjects; + + private LocalDateTime lastSyncProjectsTime; + + private int totalBranches; + + private LocalDateTime lastSyncBranchesTime; + + private List repositoryGroupList; + + private List repositoryProjectList; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryBranchDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryBranchDTO.java new file mode 100644 index 00000000..24638b5f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryBranchDTO.java @@ -0,0 +1,41 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * Git仓库分支DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositoryBranchDTO extends BaseDTO { + + private String name; + + private Long projectId; + + private Long externalSystemId; + + private Boolean isDefaultBranch; + + private Boolean isProtected; + + private Boolean canPush; + + private Boolean developersCanPush; + + private Boolean developersCanMerge; + + private String commitId; + + private String commitMessage; + + private String commitAuthor; + + private LocalDateTime commitDate; + + private String webUrl; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryProjectDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryProjectDTO.java new file mode 100644 index 00000000..5be20f4c --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositoryProjectDTO.java @@ -0,0 +1,39 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * Git仓库项目DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositoryProjectDTO extends BaseDTO { + + private String name; + + private String path; + + private String description; + + private String visibility; + + private Long groupId; + + private String isDefaultBranch; + + private String webUrl; + + private String sshUrl; + + private String httpUrl; + + private LocalDateTime lastActivityAt; + + private Long externalSystemId; + + private Long projectId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositorySyncHistoryDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositorySyncHistoryDTO.java new file mode 100644 index 00000000..8608d38e --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/RepositorySyncHistoryDTO.java @@ -0,0 +1,31 @@ +package com.qqchen.deploy.backend.deploy.dto; + +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * Git同步历史记录 DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositorySyncHistoryDTO extends BaseDTO { + + private String number; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + private String errorMessage; + + private ExternalSystemSyncStatus status; + + private RepositorySyncType syncType; + + private Long externalSystemId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositorySyncHistory.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositorySyncHistory.java index 06d2e5ff..a4fc05de 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositorySyncHistory.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/RepositorySyncHistory.java @@ -1,48 +1,42 @@ package com.qqchen.deploy.backend.deploy.entity; -import com.qqchen.deploy.backend.framework.annotation.LogicDelete; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; import com.qqchen.deploy.backend.framework.domain.Entity; import jakarta.persistence.Column; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.Table; import lombok.Data; import lombok.EqualsAndHashCode; import java.time.LocalDateTime; +/** + * Git同步历史记录 + */ @Data @EqualsAndHashCode(callSuper = true) @jakarta.persistence.Entity @Table(name = "deploy_repo_sync_history") -@LogicDelete public class RepositorySyncHistory extends Entity { - - @Column(name = "repository_id", nullable = false) - private Long repositoryId; - - @Column(name = "sync_type", nullable = false) - @Enumerated(EnumType.STRING) - private SyncType syncType; - + + @Column(nullable = false) + private String number; + @Column(nullable = false) - @Enumerated(EnumType.STRING) - private SyncStatus status; - - @Column(name = "error_message", columnDefinition = "TEXT") - private String errorMessage; - - @Column(name = "start_time", nullable = false) private LocalDateTime startTime; - - @Column(name = "end_time") + + @Column private LocalDateTime endTime; - - public enum SyncType { - GROUP, PROJECT, BRANCH - } - - public enum SyncStatus { - SUCCESS, FAILED, RUNNING - } + + @Column + private String errorMessage; + + @Column(nullable = false) + private ExternalSystemSyncStatus status; + + @Column(nullable = false) + private RepositorySyncType syncType; + + @Column(nullable = false) + private Long externalSystemId; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/RepositorySyncType.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/RepositorySyncType.java new file mode 100644 index 00000000..4619df81 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/enums/RepositorySyncType.java @@ -0,0 +1,10 @@ +package com.qqchen.deploy.backend.deploy.enums; + +/** + * Git同步类型枚举 + */ +public enum RepositorySyncType { + GROUP, + PROJECT, + BRANCH +} \ 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 0c5f99d1..9518228c 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 @@ -12,21 +12,16 @@ public class GitBranchResponse { private String name; - private Boolean merged; + private Boolean isDefaultBranch; - private Boolean protected_; + private Boolean isProtected; + + private Boolean canPush; private Boolean developersCanPush; private Boolean developersCanMerge; - private Boolean canPush; - - private Boolean isDefaultBranch; - - private String webUrl; - - // 提交信息 private String commitId; private String commitMessage; @@ -34,4 +29,6 @@ public class GitBranchResponse { private String commitAuthor; private LocalDateTime commitDate; + + private String webUrl; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitProjectResponse.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitProjectResponse.java index d1078252..dd7beb9f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitProjectResponse.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/GitProjectResponse.java @@ -20,8 +20,6 @@ public class GitProjectResponse { private String visibility; - private Long groupId; - private String defaultBranch; private String webUrl; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryBranchQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryBranchQuery.java new file mode 100644 index 00000000..baeb510f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryBranchQuery.java @@ -0,0 +1,33 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Git仓库分支查询对象 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositoryBranchQuery extends BaseQuery { + + @QueryField(field = "name", type = QueryType.LIKE) + private String name; + + @QueryField(field = "project_id") + private Long projectId; + + @QueryField(field = "external_system_id") + private Long externalSystemId; + + @QueryField(field = "is_default_branch") + private Boolean isDefaultBranch; + + @QueryField(field = "is_protected") + private Boolean isProtected; + + @QueryField(field = "commit_author", type = QueryType.LIKE) + private String commitAuthor; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryProjectQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryProjectQuery.java new file mode 100644 index 00000000..5daf57d1 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositoryProjectQuery.java @@ -0,0 +1,33 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Git仓库项目查询对象 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositoryProjectQuery extends BaseQuery { + + @QueryField(field = "name", type = QueryType.LIKE) + private String name; + + @QueryField(field = "path", type = QueryType.LIKE) + private String path; + + @QueryField(field = "visibility") + private String visibility; + + @QueryField(field = "group_id") + private Long groupId; + + @QueryField(field = "external_system_id") + private Long externalSystemId; + + @QueryField(field = "project_id") + private Long projectId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositorySyncHistoryQuery.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositorySyncHistoryQuery.java new file mode 100644 index 00000000..bf407813 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/query/RepositorySyncHistoryQuery.java @@ -0,0 +1,29 @@ +package com.qqchen.deploy.backend.deploy.query; + +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.framework.annotation.QueryField; +import com.qqchen.deploy.backend.framework.enums.QueryType; +import com.qqchen.deploy.backend.framework.query.BaseQuery; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Git同步历史记录查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RepositorySyncHistoryQuery extends BaseQuery { + + @QueryField(field = "number", type = QueryType.LIKE) + private String number; + + @QueryField(field = "status") + private ExternalSystemSyncStatus status; + + @QueryField(field = "syncType") + private RepositorySyncType syncType; + + @QueryField(field = "externalSystemId") + private Long externalSystemId; +} \ No newline at end of file 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 cb6cde54..eabd6e66 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 @@ -2,14 +2,35 @@ package com.qqchen.deploy.backend.deploy.repository; import com.qqchen.deploy.backend.framework.repository.IBaseRepository; import com.qqchen.deploy.backend.deploy.entity.RepositoryBranch; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Optional; @Repository public interface IRepositoryBranchRepository extends IBaseRepository { + /** + * 根据外部系统ID和项目ID查找分支列表 + * + * @param externalSystemId 外部系统ID + * @param projectId 项目ID + * @return 分支列表 + */ + List findByExternalSystemIdAndProjectId(Long externalSystemId, Long projectId); + + /** + * 统计指定外部系统下的分支数量 + * + * @param externalSystemId 外部系统ID + * @return 分支数量 + */ + Long countByExternalSystemId(Long externalSystemId); + + /** + * 统计指定项目下的分支数量 + * + * @param projectId 项目ID + * @return 分支数量 + */ + Long countByProjectId(Long projectId); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryProjectRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryProjectRepository.java index a664a4e1..84f8f2d5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryProjectRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositoryProjectRepository.java @@ -1,15 +1,31 @@ package com.qqchen.deploy.backend.deploy.repository; +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; import com.qqchen.deploy.backend.framework.repository.IBaseRepository; import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Optional; @Repository public interface IRepositoryProjectRepository extends IBaseRepository { - + + /** + * 根据外部系统ID和仓库组ID查找项目列表 + * + * @param externalSystemId 外部系统ID + * @param groupId 仓库组ID + * @return 项目列表 + */ + List findByExternalSystemIdAndGroupId(Long externalSystemId, Long groupId); + + /** + * 统计指定外部系统下的项目数量 + * + * @param externalSystemId 外部系统ID + * @return 项目数量 + */ + Long countByExternalSystemId(Long externalSystemId); + + List findByExternalSystemId(Long externalSystemId); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositorySyncHistoryRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositorySyncHistoryRepository.java index 54c3e75f..a69bf0c4 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositorySyncHistoryRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IRepositorySyncHistoryRepository.java @@ -1,12 +1,28 @@ package com.qqchen.deploy.backend.deploy.repository; - -import com.qqchen.deploy.backend.framework.repository.IBaseRepository; import com.qqchen.deploy.backend.deploy.entity.RepositorySyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; import org.springframework.stereotype.Repository; -import java.util.List; - +/** + * Git同步历史记录 Repository + */ @Repository public interface IRepositorySyncHistoryRepository extends IBaseRepository { + + /** + * 查询最后一次同步记录 + * + * @param externalSystemId 外部系统ID + * @param syncType 同步类型 + * @param status 同步状态 + * @return 同步历史记录 + */ + RepositorySyncHistory findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + Long externalSystemId, + RepositorySyncType syncType, + ExternalSystemSyncStatus status + ); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IGitManagerService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IGitManagerService.java new file mode 100644 index 00000000..b52eaec6 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IGitManagerService.java @@ -0,0 +1,47 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.GitInstanceDTO; + +/** + * Git管理服务接口 + */ +public interface IGitManagerService { + + /** + * 同步Git所有数据(组、项目、分支) + * + * @param externalSystemId 外部系统ID + */ + void syncAll(Long externalSystemId); + + /** + * 同步Git组 + * + * @param externalSystemId 外部系统ID + */ + void syncGroups(Long externalSystemId); + + /** + * 同步Git项目 + * + * @param externalSystemId 外部系统ID + * @param groupId 组ID + */ + void syncProjects(Long externalSystemId, Long groupId); + + /** + * 同步Git分支 + * + * @param externalSystemId 外部系统ID + * @param projectId 项目ID + */ + void syncBranches(Long externalSystemId, Long projectId); + + /** + * 获取Git实例信息 + * + * @param externalSystemId 外部系统ID + * @return Git实例信息 + */ + GitInstanceDTO instance(Long externalSystemId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryBranchService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryBranchService.java new file mode 100644 index 00000000..422de524 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryBranchService.java @@ -0,0 +1,37 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.RepositoryBranchDTO; +import com.qqchen.deploy.backend.deploy.entity.RepositoryBranch; +import com.qqchen.deploy.backend.deploy.query.RepositoryBranchQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +/** + * Git仓库分支服务接口 + */ +public interface IRepositoryBranchService extends IBaseService { + + /** + * 同步指定外部系统下指定项目的分支 + * + * @param externalSystemId 外部系统ID + * @param projectId 项目ID + * @return 同步的分支数量 + */ + Integer syncBranches(Long externalSystemId, Long projectId); + + /** + * 统计指定外部系统下的分支数量 + * + * @param externalSystemId 外部系统ID + * @return 分支数量 + */ + Long countByExternalSystemId(Long externalSystemId); + + /** + * 统计指定项目下的分支数量 + * + * @param projectId 项目ID + * @return 分支数量 + */ + Long countByProjectId(Long projectId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryGroupService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryGroupService.java index 3a511261..82db5cca 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryGroupService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryGroupService.java @@ -5,6 +5,8 @@ import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO; import com.qqchen.deploy.backend.deploy.query.RepositoryGroupQuery; import com.qqchen.deploy.backend.framework.service.IBaseService; +import java.util.List; + /** * Git仓库组服务接口 */ @@ -25,4 +27,12 @@ public interface IRepositoryGroupService extends IBaseService findByExternalSystemId(Long externalSystemId); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryProjectService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryProjectService.java new file mode 100644 index 00000000..b3f07fb0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositoryProjectService.java @@ -0,0 +1,33 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; +import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; +import com.qqchen.deploy.backend.deploy.query.RepositoryProjectQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +import java.util.List; + +/** + * Git仓库项目服务接口 + */ +public interface IRepositoryProjectService extends IBaseService { + + /** + * 同步指定外部系统下指定仓库组的项目 + * + * @param externalSystemId 外部系统ID + * @param groupId 仓库组ID + * @return 同步的项目数量 + */ + Integer syncProjects(Long externalSystemId, Long groupId); + + /** + * 统计指定外部系统下的项目数量 + * + * @param externalSystemId 外部系统ID + * @return 项目数量 + */ + Long countByExternalSystemId(Long externalSystemId); + + List findByExternalSystemId(Long externalSystemId); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositorySyncHistoryService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositorySyncHistoryService.java new file mode 100644 index 00000000..f066e699 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IRepositorySyncHistoryService.java @@ -0,0 +1,32 @@ +package com.qqchen.deploy.backend.deploy.service; + +import com.qqchen.deploy.backend.deploy.dto.RepositorySyncHistoryDTO; +import com.qqchen.deploy.backend.deploy.entity.RepositorySyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.deploy.query.RepositorySyncHistoryQuery; +import com.qqchen.deploy.backend.framework.service.IBaseService; + +/** + * Git同步历史记录 Service + */ +public interface IRepositorySyncHistoryService extends IBaseService { + + /** + * 创建同步历史记录 + * + * @param externalSystemId 外部系统ID + * @param syncType 同步类型 + * @return 同步历史记录 + */ + RepositorySyncHistoryDTO createSyncHistory(Long externalSystemId, RepositorySyncType syncType); + + /** + * 更新同步历史记录 + * + * @param id 同步历史记录ID + * @param status 同步状态 + * @param errorMessage 错误信息 + */ + void updateSyncHistory(Long id, ExternalSystemSyncStatus status, String errorMessage); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/GitManagerServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/GitManagerServiceImpl.java new file mode 100644 index 00000000..dcfab9e5 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/GitManagerServiceImpl.java @@ -0,0 +1,203 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.dto.GitInstanceDTO; +import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO; +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; +import com.qqchen.deploy.backend.deploy.dto.RepositorySyncHistoryDTO; +import com.qqchen.deploy.backend.deploy.entity.RepositorySyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.deploy.repository.IRepositorySyncHistoryRepository; +import com.qqchen.deploy.backend.deploy.service.*; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static com.qqchen.deploy.backend.framework.enums.ResponseCode.REPOSITORY_BRANCH_SYNC_FAILED; +import static com.qqchen.deploy.backend.framework.enums.ResponseCode.REPOSITORY_PROJECT_SYNC_FAILED; +import static com.qqchen.deploy.backend.framework.enums.ResponseCode.REPOSITORY_SYNC_FAILED; + +/** + * Git管理服务实现 + */ +@Slf4j +@Service +public class GitManagerServiceImpl implements IGitManagerService { + + @Resource + private IRepositoryGroupService repositoryGroupService; + + @Resource + private IRepositoryProjectService repositoryProjectService; + + @Resource + private IRepositoryBranchService repositoryBranchService; + + @Resource + private IRepositorySyncHistoryService repositorySyncHistoryService; + + @Resource + private IRepositorySyncHistoryRepository repositorySyncHistoryRepository; + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncAll(Long externalSystemId) { + try { + // 1. 创建同步历史记录 + RepositorySyncHistoryDTO allHistory = repositorySyncHistoryService.createSyncHistory(externalSystemId, RepositorySyncType.GROUP); + + try { + // 2. 同步组 + syncGroups(externalSystemId); + + // 3. 获取所有组,同步每个组的项目 + List groups = repositoryGroupService.findByExternalSystemId(externalSystemId); + for (RepositoryGroupDTO group : groups) { + syncProjects(externalSystemId, group.getId()); + } + + // 4. 获取所有项目,同步每个项目的分支 + List projects = repositoryProjectService.findByExternalSystemId(externalSystemId); + for (RepositoryProjectDTO project : projects) { + syncBranches(externalSystemId, project.getId()); + } + + // 5. 更新同步历史记录为成功 + repositorySyncHistoryService.updateSyncHistory(allHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); + log.info("Successfully synchronized all Git data for external system: {}", externalSystemId); + } catch (Exception e) { + // 6. 更新同步历史记录为失败 + repositorySyncHistoryService.updateSyncHistory(allHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage()); + log.error("Failed to synchronize Git data for external system: {}", externalSystemId, e); + throw e; + } + } catch (Exception e) { + log.error("Failed to create sync history for external system: {}", externalSystemId, e); + throw new BusinessException(REPOSITORY_SYNC_FAILED); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncGroups(Long externalSystemId) { + try { + // 1. 创建同步历史记录 + RepositorySyncHistoryDTO groupHistory = repositorySyncHistoryService.createSyncHistory(externalSystemId, RepositorySyncType.GROUP); + + try { + // 2. 同步组 + Integer groupCount = repositoryGroupService.syncGroups(externalSystemId); + + // 3. 更新同步历史记录为成功 + repositorySyncHistoryService.updateSyncHistory(groupHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); + log.info("Successfully synchronized {} groups for external system: {}", groupCount, externalSystemId); + } catch (Exception e) { + // 4. 更新同步历史记录为失败 + repositorySyncHistoryService.updateSyncHistory(groupHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage()); + log.error("Failed to synchronize groups for external system: {}", externalSystemId, e); + throw e; + } + } catch (Exception e) { + log.error("Failed to create sync history for external system: {}", externalSystemId, e); + throw new BusinessException(ResponseCode.REPOSITORY_GROUP_SYNC_FAILED); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncProjects(Long externalSystemId, Long groupId) { + try { + // 1. 创建同步历史记录 + RepositorySyncHistoryDTO projectHistory = repositorySyncHistoryService.createSyncHistory(externalSystemId, RepositorySyncType.PROJECT); + + try { + // 2. 同步项目 + Integer projectCount = repositoryProjectService.syncProjects(externalSystemId, groupId); + + // 3. 更新同步历史记录为成功 + repositorySyncHistoryService.updateSyncHistory(projectHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); + log.info("Successfully synchronized {} projects for group {} in external system: {}", projectCount, groupId, externalSystemId); + } catch (Exception e) { + // 4. 更新同步历史记录为失败 + repositorySyncHistoryService.updateSyncHistory(projectHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage()); + log.error("Failed to synchronize projects for group {} in external system: {}", groupId, externalSystemId, e); + throw e; + } + } catch (Exception e) { + log.error("Failed to create sync history for external system: {}", externalSystemId, e); + throw new BusinessException(REPOSITORY_PROJECT_SYNC_FAILED); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncBranches(Long externalSystemId, Long projectId) { + try { + // 1. 创建同步历史记录 + RepositorySyncHistoryDTO branchHistory = repositorySyncHistoryService.createSyncHistory(externalSystemId, RepositorySyncType.BRANCH); + + try { + // 2. 同步分支 + Integer branchCount = repositoryBranchService.syncBranches(externalSystemId, projectId); + + // 3. 更新同步历史记录为成功 + repositorySyncHistoryService.updateSyncHistory(branchHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null); + log.info("Successfully synchronized {} branches for project {} in external system: {}", branchCount, projectId, externalSystemId); + } catch (Exception e) { + // 4. 更新同步历史记录为失败 + repositorySyncHistoryService.updateSyncHistory(branchHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage()); + log.error("Failed to synchronize branches for project {} in external system: {}", projectId, externalSystemId, e); + throw e; + } + } catch (Exception e) { + log.error("Failed to create sync history for external system: {}", externalSystemId, e); + throw new BusinessException(REPOSITORY_BRANCH_SYNC_FAILED); + } + } + + @Override + public GitInstanceDTO instance(Long externalSystemId) { + // 1. 创建返回对象 + GitInstanceDTO instanceDTO = new GitInstanceDTO(); + + // 2. 获取组列表 + List groups = repositoryGroupService.findByExternalSystemId(externalSystemId); + instanceDTO.setRepositoryGroupList(groups); + instanceDTO.setTotalGroups(groups.size()); + + // 3. 获取项目列表 + List projects = repositoryProjectService.findByExternalSystemId(externalSystemId); + instanceDTO.setRepositoryProjectList(projects); + instanceDTO.setTotalProjects(projects.size()); + + // 4. 获取分支总数 + Long totalBranches = repositoryBranchService.countByExternalSystemId(externalSystemId); + instanceDTO.setTotalBranches(totalBranches.intValue()); + + // 5. 获取最后同步时间 + RepositorySyncHistory lastGroupSync = repositorySyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, RepositorySyncType.GROUP, ExternalSystemSyncStatus.SUCCESS); + if (lastGroupSync != null) { + instanceDTO.setLastSyncGroupsTime(lastGroupSync.getEndTime()); + } + + RepositorySyncHistory lastProjectSync = repositorySyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, RepositorySyncType.PROJECT, ExternalSystemSyncStatus.SUCCESS); + if (lastProjectSync != null) { + instanceDTO.setLastSyncProjectsTime(lastProjectSync.getEndTime()); + } + + RepositorySyncHistory lastBranchSync = repositorySyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, RepositorySyncType.BRANCH, ExternalSystemSyncStatus.SUCCESS); + if (lastBranchSync != null) { + instanceDTO.setLastSyncBranchesTime(lastBranchSync.getEndTime()); + } + + return instanceDTO; + } +} \ 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 new file mode 100644 index 00000000..c09dede5 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryBranchServiceImpl.java @@ -0,0 +1,123 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.entity.ExternalSystem; +import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; +import com.qqchen.deploy.backend.deploy.entity.RepositoryBranch; +import com.qqchen.deploy.backend.deploy.dto.RepositoryBranchDTO; +import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration; +import com.qqchen.deploy.backend.deploy.integration.response.GitBranchResponse; +import com.qqchen.deploy.backend.deploy.query.RepositoryBranchQuery; +import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository; +import com.qqchen.deploy.backend.deploy.repository.IRepositoryProjectRepository; +import com.qqchen.deploy.backend.deploy.repository.IRepositoryBranchRepository; +import com.qqchen.deploy.backend.deploy.service.IRepositoryBranchService; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Git仓库分支服务实现 + */ +@Slf4j +@Service +public class RepositoryBranchServiceImpl extends BaseServiceImpl + implements IRepositoryBranchService { + + @Resource + private IExternalSystemRepository externalSystemRepository; + + @Resource + private IRepositoryProjectRepository repositoryProjectRepository; + + @Resource + private IRepositoryBranchRepository repositoryBranchRepository; + + @Resource + private IGitServiceIntegration gitServiceIntegration; + + @Override + @Transactional + public Integer syncBranches(Long externalSystemId, Long projectId) { + try { + // 1. 获取外部系统信息 + ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId) + .orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND)); + + // 2. 获取项目信息 + RepositoryProject project = repositoryProjectRepository.findById(projectId) + .orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_PROJECT_NOT_FOUND)); + + // 3. 获取远程仓库分支信息 + List remoteBranches = gitServiceIntegration.branches(externalSystem, project.getProjectId()); + if (remoteBranches.isEmpty()) { + log.info("No branches found in remote git system: {}, project: {}", externalSystem.getName(), project.getName()); + return 0; + } + + // 4. 获取本地已存在的仓库分支 + List existingBranches = repositoryBranchRepository.findByExternalSystemIdAndProjectId(externalSystemId, projectId); + Map existingBranchMap = existingBranches.stream() + .collect(Collectors.toMap(RepositoryBranch::getName, Function.identity())); + + // 5. 更新或创建仓库分支 + List branchesToSave = remoteBranches.stream() + .map(remoteBranch -> updateOrCreateBranch(externalSystemId, projectId, remoteBranch, existingBranchMap)) + .collect(Collectors.toList()); + + // 6. 保存仓库分支 + repositoryBranchRepository.saveAll(branchesToSave); + + log.info("Successfully synchronized {} branches for external system: {}, project: {}", + branchesToSave.size(), externalSystem.getName(), project.getName()); + return branchesToSave.size(); + } catch (Exception e) { + log.error("Failed to sync repository branches for external system: {}, project: {}", externalSystemId, projectId, e); + throw new BusinessException(ResponseCode.REPOSITORY_SYNC_FAILED); + } + } + + private RepositoryBranch updateOrCreateBranch( + Long externalSystemId, + Long projectId, + GitBranchResponse remoteBranch, + Map existingBranchMap) { + + RepositoryBranch branch = existingBranchMap.getOrDefault(remoteBranch.getName(), new RepositoryBranch()); + + // 更新基本信息 + branch.setExternalSystemId(externalSystemId); + branch.setProjectId(projectId); + branch.setName(remoteBranch.getName()); + branch.setIsDefaultBranch(remoteBranch.getIsDefaultBranch()); + branch.setIsProtected(remoteBranch.getIsProtected()); + branch.setCanPush(remoteBranch.getCanPush()); + branch.setDevelopersCanPush(remoteBranch.getDevelopersCanPush()); + branch.setDevelopersCanMerge(remoteBranch.getDevelopersCanMerge()); + branch.setCommitId(remoteBranch.getCommitId()); + branch.setCommitMessage(remoteBranch.getCommitMessage()); + branch.setCommitAuthor(remoteBranch.getCommitAuthor()); + branch.setCommitDate(remoteBranch.getCommitDate()); + branch.setWebUrl(remoteBranch.getWebUrl()); + + return branch; + } + + @Override + public Long countByExternalSystemId(Long externalSystemId) { + return repositoryBranchRepository.countByExternalSystemId(externalSystemId); + } + + @Override + public Long countByProjectId(Long projectId) { + return repositoryBranchRepository.countByProjectId(projectId); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryGroupServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryGroupServiceImpl.java index 6acb6eb9..a3c64c02 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryGroupServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryGroupServiceImpl.java @@ -1,5 +1,6 @@ package com.qqchen.deploy.backend.deploy.service.impl; +import com.qqchen.deploy.backend.deploy.converter.RepositoryGroupConverter; import com.qqchen.deploy.backend.deploy.entity.ExternalSystem; import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup; import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO; @@ -27,8 +28,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class RepositoryGroupServiceImpl extends BaseServiceImpl - implements IRepositoryGroupService { +public class RepositoryGroupServiceImpl extends BaseServiceImpl implements IRepositoryGroupService { @Resource private IExternalSystemRepository externalSystemRepository; @@ -39,6 +39,9 @@ public class RepositoryGroupServiceImpl extends BaseServiceImpl existingGroupMap) { - + Long externalSystemId, + GitGroupResponse remoteGroup, + Map existingGroupMap) { + RepositoryGroup group = existingGroupMap.getOrDefault(remoteGroup.getId(), new RepositoryGroup()); - + // 更新基本信息 group.setExternalSystemId(externalSystemId); group.setGroupId(remoteGroup.getId()); @@ -93,7 +96,7 @@ public class RepositoryGroupServiceImpl extends BaseServiceImpl findByExternalSystemId(Long externalSystemId) { + return repositoryGroupConverter.toDtoList(repositoryGroupRepository.findByExternalSystemId(externalSystemId)); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryProjectServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryProjectServiceImpl.java new file mode 100644 index 00000000..8c204aa4 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositoryProjectServiceImpl.java @@ -0,0 +1,126 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.converter.RepositoryProjectConverter; +import com.qqchen.deploy.backend.deploy.entity.ExternalSystem; +import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup; +import com.qqchen.deploy.backend.deploy.entity.RepositoryProject; +import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO; +import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration; +import com.qqchen.deploy.backend.deploy.integration.response.GitProjectResponse; +import com.qqchen.deploy.backend.deploy.query.RepositoryProjectQuery; +import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository; +import com.qqchen.deploy.backend.deploy.repository.IRepositoryGroupRepository; +import com.qqchen.deploy.backend.deploy.repository.IRepositoryProjectRepository; +import com.qqchen.deploy.backend.deploy.service.IRepositoryProjectService; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Git仓库项目服务实现 + */ +@Slf4j +@Service +public class RepositoryProjectServiceImpl extends BaseServiceImpl implements IRepositoryProjectService { + + @Resource + private IExternalSystemRepository externalSystemRepository; + + @Resource + private IRepositoryGroupRepository repositoryGroupRepository; + + @Resource + private IRepositoryProjectRepository repositoryProjectRepository; + + @Resource + private IGitServiceIntegration gitServiceIntegration; + + @Resource + private RepositoryProjectConverter repositoryProjectConverter; + + @Override + @Transactional + public Integer syncProjects(Long externalSystemId, Long groupId) { + try { + // 1. 获取外部系统信息 + ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId) + .orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND)); + + // 2. 获取仓库组信息 + RepositoryGroup group = repositoryGroupRepository.findById(groupId) + .orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_GROUP_NOT_FOUND)); + + // 3. 获取远程仓库项目信息 + List remoteProjects = gitServiceIntegration.projects(externalSystem, group.getGroupId()); + if (remoteProjects.isEmpty()) { + log.info("No projects found in remote git system: {}, group: {}", externalSystem.getName(), group.getName()); + return 0; + } + + // 4. 获取本地已存在的仓库项目 + List existingProjects = repositoryProjectRepository.findByExternalSystemIdAndGroupId(externalSystemId, groupId); + Map existingProjectMap = existingProjects.stream() + .collect(Collectors.toMap(RepositoryProject::getProjectId, Function.identity())); + + // 5. 更新或创建仓库项目 + List projectsToSave = remoteProjects.stream() + .map(remoteProject -> updateOrCreateProject(externalSystemId, groupId, remoteProject, existingProjectMap)) + .collect(Collectors.toList()); + + // 6. 保存仓库项目 + repositoryProjectRepository.saveAll(projectsToSave); + + log.info("Successfully synchronized {} projects for external system: {}, group: {}", + projectsToSave.size(), externalSystem.getName(), group.getName()); + return projectsToSave.size(); + } catch (Exception e) { + log.error("Failed to sync repository projects for external system: {}, group: {}", externalSystemId, groupId, e); + throw new BusinessException(ResponseCode.REPOSITORY_SYNC_FAILED); + } + } + + private RepositoryProject updateOrCreateProject( + Long externalSystemId, + Long groupId, + GitProjectResponse remoteProject, + Map existingProjectMap) { + + RepositoryProject project = existingProjectMap.getOrDefault(remoteProject.getId(), new RepositoryProject()); + + // 更新基本信息 + project.setExternalSystemId(externalSystemId); + project.setGroupId(groupId); + project.setProjectId(remoteProject.getId()); + project.setName(remoteProject.getName()); + project.setPath(remoteProject.getPath()); + project.setDescription(remoteProject.getDescription()); + project.setVisibility(remoteProject.getVisibility()); + project.setIsDefaultBranch(remoteProject.getDefaultBranch()); + project.setWebUrl(remoteProject.getWebUrl()); + project.setSshUrl(remoteProject.getSshUrl()); + project.setHttpUrl(remoteProject.getHttpUrl()); + project.setLastActivityAt(remoteProject.getLastActivityAt()); + + return project; + } + + @Override + public Long countByExternalSystemId(Long externalSystemId) { + return repositoryProjectRepository.countByExternalSystemId(externalSystemId); + } + + @Override + public List findByExternalSystemId(Long externalSystemId) { + return repositoryProjectConverter.toDtoList(repositoryProjectRepository.findByExternalSystemId(externalSystemId)); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositorySyncHistoryServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositorySyncHistoryServiceImpl.java new file mode 100644 index 00000000..1b306c94 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/RepositorySyncHistoryServiceImpl.java @@ -0,0 +1,58 @@ +package com.qqchen.deploy.backend.deploy.service.impl; + +import com.qqchen.deploy.backend.deploy.dto.RepositorySyncHistoryDTO; +import com.qqchen.deploy.backend.deploy.entity.RepositorySyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType; +import com.qqchen.deploy.backend.deploy.query.RepositorySyncHistoryQuery; +import com.qqchen.deploy.backend.deploy.repository.IRepositorySyncHistoryRepository; +import com.qqchen.deploy.backend.deploy.service.IRepositorySyncHistoryService; +import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; +import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * Git同步历史记录 Service实现 + */ +@Slf4j +@Service +public class RepositorySyncHistoryServiceImpl extends BaseServiceImpl + implements IRepositorySyncHistoryService { + + @Resource + private IRepositorySyncHistoryRepository repositorySyncHistoryRepository; + + @Override + @Transactional(rollbackFor = Exception.class) + public RepositorySyncHistoryDTO createSyncHistory(Long externalSystemId, RepositorySyncType syncType) { + RepositorySyncHistory history = new RepositorySyncHistory(); + history.setNumber(UUID.randomUUID().toString()); + history.setStartTime(LocalDateTime.now()); + history.setStatus(ExternalSystemSyncStatus.RUNNING); + history.setSyncType(syncType); + history.setExternalSystemId(externalSystemId); + + history = repositorySyncHistoryRepository.save(history); + return converter.toDto(history); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSyncHistory(Long id, ExternalSystemSyncStatus status, String errorMessage) { + RepositorySyncHistory history = repositorySyncHistoryRepository.findById(id) + .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND)); + + history.setEndTime(LocalDateTime.now()); + history.setStatus(status); + history.setErrorMessage(errorMessage); + + repositorySyncHistoryRepository.save(history); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index 64888d17..19d12afd 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -79,13 +79,13 @@ public enum ResponseCode { // 仓库相关错误码 (2600-2699) REPOSITORY_GROUP_NOT_FOUND(2600, "repository.group.not.found"), - REPOSITORY_GROUP_NAME_EXISTS(2601, "repository.group.name.exists"), + REPOSITORY_GROUP_SYNC_FAILED(2601, "repository.group.sync.failed"), REPOSITORY_GROUP_PATH_EXISTS(2602, "repository.group.path.exists"), REPOSITORY_PROJECT_NOT_FOUND(2610, "repository.project.not.found"), - REPOSITORY_PROJECT_NAME_EXISTS(2611, "repository.project.name.exists"), + REPOSITORY_PROJECT_SYNC_FAILED(2611, "repository.project.sync.failed"), REPOSITORY_PROJECT_PATH_EXISTS(2612, "repository.project.path.exists"), REPOSITORY_BRANCH_NOT_FOUND(2620, "repository.branch.not.found"), - REPOSITORY_BRANCH_NAME_EXISTS(2621, "repository.branch.name.exists"), + REPOSITORY_BRANCH_SYNC_FAILED(2621, "repository.branch.sync.failed"), REPOSITORY_SYNC_IN_PROGRESS(2630, "repository.sync.in.progress"), REPOSITORY_SYNC_FAILED(2631, "repository.sync.failed"), REPOSITORY_SYNC_HISTORY_NOT_FOUND(2632, "repository.sync.history.not.found"), diff --git a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql index 3f08024c..293096be 100644 --- a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql +++ b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql @@ -82,8 +82,10 @@ VALUES (204, '部署配置管理', '/deploy/deployment', '/src/pages/Deploy/Deployment/List/index', 'CloudOutlined', 2, 200, 4, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), (205, 'Jenkins管理', '/deploy/jenkins-manager', '/src/pages/Deploy/JenkinsManager/List', 'CloudOutlined', 2, 200, 5, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), + +(206, 'Git管理', '/deploy/git-manager', '/src/pages/Deploy/GitManager/List', 'CloudOutlined', 2, 200, 6, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE), -- 三方系统 -(206, '三方系统管理', '/deploy/external', '/src/pages/Deploy/external/index', 'ApiOutlined', 2, 200, 6, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE); +(207, '三方系统管理', '/deploy/external', '/src/pages/Deploy/external/index', 'ApiOutlined', 2, 200, 7, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE); -- 初始化角色数据 INSERT INTO sys_role (id, create_time, code, name, type, description, sort)