大声道撒旦

This commit is contained in:
dengqichen 2025-01-07 17:41:01 +08:00
parent 1b3896b8bd
commit dea1e5d0c7
15 changed files with 465 additions and 72 deletions

View File

@ -1,28 +1,51 @@
package com.qqchen.deploy.backend.deploy.api;
import com.qqchen.deploy.backend.framework.controller.BaseController;
import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup;
import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO;
import com.qqchen.deploy.backend.deploy.query.RepositoryGroupQuery;
import com.qqchen.deploy.backend.deploy.service.IRepositoryGroupService;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
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分组 Controller
* Git仓库组Controller
*/
@Slf4j
@RestController
@RequestMapping("/api/v1/repo-group")
@Tag(name = "GIT分组管理", description = "GIT分组管理相关接口")
@Tag(name = "Git仓库组管理", description = "Git仓库组管理相关接口")
public class RepositoryGroupApiController extends BaseController<RepositoryGroup, RepositoryGroupDTO, Long, RepositoryGroupQuery> {
@Resource
private IRepositoryGroupService repositoryGroupService;
@Operation(summary = "同步仓库组")
@PostMapping("/{externalSystemId}/sync")
public Response<Integer> syncGroups(
@Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId
) {
return Response.success(repositoryGroupService.syncGroups(externalSystemId));
}
@Operation(summary = "获取仓库组数量")
@GetMapping("/{externalSystemId}/count")
public Response<Long> countGroups(
@Parameter(description = "外部系统ID", required = true) @PathVariable Long externalSystemId
) {
return Response.success(repositoryGroupService.countByExternalSystemId(externalSystemId));
}
@Override
protected void exportData(HttpServletResponse response, List<RepositoryGroupDTO> data) {
// TODO: 实现导出逻辑
log.info("导出GIT分组数据数据量{}", data.size());
}
}

View File

@ -1,4 +1,4 @@
package com.qqchen.deploy.backend.deploy.service.sync;
package com.qqchen.deploy.backend.deploy.dto.sync;
import com.qqchen.deploy.backend.deploy.dto.JenkinsSyncHistoryDTO;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;

View File

@ -42,4 +42,11 @@ public class RepositoryGroup extends Entity<Long> {
@Column(name = "external_system_id")
private Long externalSystemId;
@Column(name = "group_id", nullable = false)
private Long groupId;
private Integer sort;
private Boolean enabled = true;
}

View File

@ -0,0 +1,47 @@
package com.qqchen.deploy.backend.deploy.integration;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.integration.response.GitBranchResponse;
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.util.List;
/**
* Git服务集成接口
* 定义与外部Git系统交互的方法
*/
public interface IGitServiceIntegration extends IExternalSystemIntegration {
/**
* 获取所有Git组
*
* @param system 外部系统配置
* @return Git组列表
*/
List<GitGroupResponse> groups(ExternalSystem system);
/**
* 获取指定组下的所有项目
*
* @param system 外部系统配置
* @param groupId 组ID
* @return 项目列表
*/
List<GitProjectResponse> projects(ExternalSystem system, Long groupId);
/**
* 获取指定项目的所有分支
*
* @param system 外部系统配置
* @param projectId 项目ID
* @return 分支列表
*/
List<GitBranchResponse> branches(ExternalSystem system, Long projectId);
@Override
default ExternalSystemTypeEnum getSystemType() {
return ExternalSystemTypeEnum.GIT;
}
}

View File

@ -1,50 +0,0 @@
package com.qqchen.deploy.backend.deploy.integration.impl;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
import com.qqchen.deploy.backend.deploy.integration.IExternalSystemIntegration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpClientErrorException;
@Slf4j
@Service
public class GitIntegration implements IExternalSystemIntegration {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public boolean testConnection(ExternalSystem system) {
try {
String url = system.getUrl() + "/api/v4/version";
HttpHeaders headers = new HttpHeaders();
headers.set("PRIVATE-TOKEN", system.getToken());
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
String.class
);
return response.getStatusCode() == HttpStatus.OK;
} catch (HttpClientErrorException.Unauthorized e) {
log.error("GitLab token authentication failed: {}", system.getUrl());
return false;
} catch (HttpClientErrorException.NotFound e) {
log.error("GitLab API endpoint not found: {}", system.getUrl());
return false;
} catch (Exception e) {
log.error("Failed to connect to GitLab: {}", system.getUrl(), e);
return false;
}
}
@Override
public ExternalSystemTypeEnum getSystemType() {
return ExternalSystemTypeEnum.GIT;
}
}

View File

@ -0,0 +1,142 @@
package com.qqchen.deploy.backend.deploy.integration.impl;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.GitBranchResponse;
import com.qqchen.deploy.backend.deploy.integration.response.GitGroupResponse;
import com.qqchen.deploy.backend.deploy.integration.response.GitProjectResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
/**
* Git服务集成实现
* 主要负责与外部Git系统(如GitLab)的API交互
*/
@Slf4j
@Service
public class GitServiceIntegrationImpl implements IGitServiceIntegration {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public boolean testConnection(ExternalSystem system) {
try {
String url = system.getUrl() + "/api/v4/version";
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
String.class
);
return response.getStatusCode() == HttpStatus.OK;
} catch (Exception e) {
log.error("Git connection test failed for system: {}", system.getName(), e);
return false;
}
}
@Override
public List<GitGroupResponse> groups(ExternalSystem system) {
try {
String url = String.format("%s/api/v4/groups?per_page=100", system.getUrl());
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<List<GitGroupResponse>> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
new ParameterizedTypeReference<>() {}
);
return response.getBody() != null ? response.getBody() : Collections.emptyList();
} catch (Exception e) {
log.error("Failed to fetch git groups for system: {}", system.getName(), e);
return Collections.emptyList();
}
}
@Override
public List<GitProjectResponse> projects(ExternalSystem system, Long groupId) {
try {
String url = String.format("%s/api/v4/groups/%d/projects?per_page=100", system.getUrl(), groupId);
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<List<GitProjectResponse>> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
new ParameterizedTypeReference<>() {}
);
return response.getBody() != null ? response.getBody() : Collections.emptyList();
} catch (Exception e) {
log.error("Failed to fetch git projects for system: {} and group: {}", system.getName(), groupId, e);
return Collections.emptyList();
}
}
@Override
public List<GitBranchResponse> branches(ExternalSystem system, Long projectId) {
try {
String url = String.format("%s/api/v4/projects/%d/repository/branches", system.getUrl(), projectId);
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<List<GitBranchResponse>> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
new ParameterizedTypeReference<>() {}
);
return response.getBody() != null ? response.getBody() : Collections.emptyList();
} catch (Exception e) {
log.error("Failed to fetch git branches for system: {} and project: {}", system.getName(), projectId, e);
return Collections.emptyList();
}
}
/**
* 创建HTTP请求头
*/
private HttpHeaders createHeaders(ExternalSystem system) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 根据认证类型设置认证信息
switch (system.getAuthType()) {
case BASIC -> {
// Basic认证
String auth = system.getUsername() + ":" + system.getPassword();
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
String authHeader = "Basic " + new String(encodedAuth);
headers.set("Authorization", authHeader);
}
case TOKEN -> {
// Token认证 - GitLab使用Private Token
headers.set("PRIVATE-TOKEN", system.getToken());
}
case OAUTH -> {
// OAuth认证
headers.set("Authorization", "Bearer " + system.getToken());
}
default -> throw new RuntimeException("Unsupported authentication type: " + system.getAuthType());
}
return headers;
}
}

View File

@ -33,12 +33,10 @@ import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.stream.Collectors;
@Slf4j
@Service
public class JenkinsServiceIntegration implements IJenkinsServiceIntegration {
public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration {
@Resource
private IExternalSystemRepository systemRepository;

View File

@ -0,0 +1,37 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import lombok.Data;
import java.time.LocalDateTime;
/**
* Git分支响应对象
*/
@Data
public class GitBranchResponse {
private String name;
private Boolean merged;
private Boolean protected_;
private Boolean developersCanPush;
private Boolean developersCanMerge;
private Boolean canPush;
private Boolean isDefaultBranch;
private String webUrl;
// 提交信息
private String commitId;
private String commitMessage;
private String commitAuthor;
private LocalDateTime commitDate;
}

View File

@ -0,0 +1,26 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import lombok.Data;
/**
* Git组响应对象
*/
@Data
public class GitGroupResponse {
private Long id;
private String name;
private String path;
private String description;
private String visibility;
private Long parentId;
private String webUrl;
private String avatarUrl;
}

View File

@ -0,0 +1,34 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import lombok.Data;
import java.time.LocalDateTime;
/**
* Git项目响应对象
*/
@Data
public class GitProjectResponse {
private Long id;
private String name;
private String path;
private String description;
private String visibility;
private Long groupId;
private String defaultBranch;
private String webUrl;
private String sshUrl;
private String httpUrl;
private LocalDateTime lastActivityAt;
}

View File

@ -1,12 +1,39 @@
package com.qqchen.deploy.backend.deploy.repository;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* GIT分组 Repository
* Git仓库组Repository
*/
@Repository
public interface IRepositoryGroupRepository extends IBaseRepository<RepositoryGroup, Long> {
/**
* 根据外部系统ID查找仓库组
*
* @param externalSystemId 外部系统ID
* @return 仓库组列表
*/
List<RepositoryGroup> findByExternalSystemId(Long externalSystemId);
/**
* 统计外部系统的仓库组数量
*
* @param externalSystemId 外部系统ID
* @return 仓库组数量
*/
Long countByExternalSystemId(Long externalSystemId);
/**
* 根据外部系统ID和组ID查找仓库组
*
* @param externalSystemId 外部系统ID
* @param groupId 组ID
* @return 仓库组
*/
RepositoryGroup findByExternalSystemIdAndGroupId(Long externalSystemId, Long groupId);
}

View File

@ -1,12 +1,28 @@
package com.qqchen.deploy.backend.deploy.service;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup;
import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO;
import com.qqchen.deploy.backend.deploy.query.RepositoryGroupQuery;
import com.qqchen.deploy.backend.framework.service.IBaseService;
/**
* GIT分组 Service接口
* Git仓库组服务接口
*/
public interface IRepositoryGroupService extends IBaseService<RepositoryGroup, RepositoryGroupDTO, RepositoryGroupQuery, Long> {
/**
* 同步指定外部系统的所有仓库组
*
* @param externalSystemId 外部系统ID
* @return 同步的仓库组数量
*/
Integer syncGroups(Long externalSystemId);
/**
* 统计外部系统的仓库组数量
*
* @param externalSystemId 外部系统ID
* @return 仓库组数量
*/
Long countByExternalSystemId(Long externalSystemId);
}

View File

@ -13,7 +13,7 @@ import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.repository.*;
import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService;
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
import com.qqchen.deploy.backend.deploy.service.sync.JenkinsSyncContext;
import com.qqchen.deploy.backend.deploy.dto.sync.JenkinsSyncContext;
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;

View File

@ -1,18 +1,104 @@
package com.qqchen.deploy.backend.deploy.service.impl;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup;
import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO;
import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.GitGroupResponse;
import com.qqchen.deploy.backend.deploy.query.RepositoryGroupQuery;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IRepositoryGroupRepository;
import com.qqchen.deploy.backend.deploy.service.IRepositoryGroupService;
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分组 Service实现
* Git仓库组服务实现
*/
@Slf4j
@Service
public class RepositoryGroupServiceImpl extends BaseServiceImpl<RepositoryGroup, RepositoryGroupDTO, RepositoryGroupQuery, Long>
implements IRepositoryGroupService {
@Resource
private IExternalSystemRepository externalSystemRepository;
@Resource
private IRepositoryGroupRepository repositoryGroupRepository;
@Resource
private IGitServiceIntegration gitServiceIntegration;
@Override
@Transactional
public Integer syncGroups(Long externalSystemId) {
try {
// 1. 获取外部系统信息
ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId)
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));
// 2. 获取远程仓库组信息
List<GitGroupResponse> remoteGroups = gitServiceIntegration.groups(externalSystem);
if (remoteGroups.isEmpty()) {
log.info("No groups found in remote git system: {}", externalSystem.getName());
return 0;
}
// 3. 获取本地已存在的仓库组
List<RepositoryGroup> existingGroups = repositoryGroupRepository.findByExternalSystemId(externalSystemId);
Map<Long, RepositoryGroup> existingGroupMap = existingGroups.stream()
.collect(Collectors.toMap(RepositoryGroup::getGroupId, Function.identity()));
// 4. 更新或创建仓库组
List<RepositoryGroup> groupsToSave = remoteGroups.stream()
.map(remoteGroup -> updateOrCreateGroup(externalSystemId, remoteGroup, existingGroupMap))
.collect(Collectors.toList());
// 5. 保存仓库组
repositoryGroupRepository.saveAll(groupsToSave);
log.info("Successfully synchronized {} groups for external system: {}",
groupsToSave.size(), externalSystem.getName());
return groupsToSave.size();
} catch (Exception e) {
log.error("Failed to sync repository groups for external system: {}", externalSystemId, e);
throw new BusinessException(ResponseCode.REPOSITORY_SYNC_FAILED);
}
}
private RepositoryGroup updateOrCreateGroup(
Long externalSystemId,
GitGroupResponse remoteGroup,
Map<Long, RepositoryGroup> existingGroupMap) {
RepositoryGroup group = existingGroupMap.getOrDefault(remoteGroup.getId(), new RepositoryGroup());
// 更新基本信息
group.setExternalSystemId(externalSystemId);
group.setGroupId(remoteGroup.getId());
group.setName(remoteGroup.getName());
group.setPath(remoteGroup.getPath());
group.setDescription(remoteGroup.getDescription());
group.setVisibility(remoteGroup.getVisibility());
group.setParentId(remoteGroup.getParentId());
group.setWebUrl(remoteGroup.getWebUrl());
group.setAvatarUrl(remoteGroup.getAvatarUrl());
return group;
}
@Override
public Long countByExternalSystemId(Long externalSystemId) {
return repositoryGroupRepository.countByExternalSystemId(externalSystemId);
}
}

View File

@ -289,9 +289,9 @@ CREATE TABLE deploy_repo_group
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除0-未删除1-已删除',
-- 业务字段
group_id BIGINT NOT NULL COMMENT 'Git系统中的组ID',
name VARCHAR(100) NOT NULL COMMENT '仓库组名',
description VARCHAR(500) NULL COMMENT '仓库组描述',
group_id BIGINT NOT NULL COMMENT '外部系统中的组ID',
parent_id BIGINT NULL COMMENT '父级仓库组ID',
path VARCHAR(200) NOT NULL COMMENT '仓库组路径',
external_system_id BIGINT NOT NULL COMMENT '外部系统ID',