增加GIT分支检测节点逻辑

This commit is contained in:
dengqichen 2025-12-04 17:40:01 +08:00
parent 6b83597d47
commit 485bf949b2
20 changed files with 1100 additions and 63 deletions

View File

@ -78,6 +78,30 @@ public class DeployExecuteRequest {
private String deployUser; private String deployUser;
@Schema(description = "源Git仓库配置")
@Valid
private GitRepositoryConfig sourceRepository;
@Schema(description = "目标Git仓库配置")
@Valid
private GitRepositoryConfig targetRepository;
/**
* Git仓库配置
*/
@Data
@Schema(description = "Git仓库配置")
public static class GitRepositoryConfig {
@Schema(description = "Git系统ID")
private Long systemId;
@Schema(description = "Git项目ID外部系统的项目ID")
private Long projectId;
@Schema(description = "分支名称")
private String branch;
}
/** /**
* Jenkins配置 * Jenkins配置
*/ */

View File

@ -27,20 +27,41 @@ public class TeamApplicationDTO extends BaseDTO {
@Schema(description = "构建类型", example = "JENKINS") @Schema(description = "构建类型", example = "JENKINS")
private BuildTypeEnum buildType; private BuildTypeEnum buildType;
@Schema(description = "分支名称", example = "develop") // ==================== 源Git配置公司内部Git ====================
private String branch;
@Schema(description = "代码源系统IDGit系统") @Schema(description = "Git系统ID公司Git")
private Long codeSourceSystemId; private Long sourceGitSystemId;
@Schema(description = "代码源系统名称") @Schema(description = "Git系统名称")
private String codeSourceSystemName; private String sourceGitSystemName;
@Schema(description = "代码源项目IDGit项目ID") @Schema(description = "Git项目ID公司Git项目ID")
private Long codeSourceProjectId; private Long sourceGitProjectId;
@Schema(description = "代码源项目名称") @Schema(description = "源Git项目名称")
private String codeSourceProjectName; private String sourceGitProjectName;
@Schema(description = "源分支名称公司Git分支", example = "develop")
private String sourceBranch;
// ==================== 目标Git配置客户环境Git ====================
@Schema(description = "目标Git系统ID客户环境Git")
private Long targetGitSystemId;
@Schema(description = "目标Git系统名称")
private String targetGitSystemName;
@Schema(description = "目标Git项目ID客户环境Git项目")
private Long targetGitProjectId;
@Schema(description = "目标Git项目名称")
private String targetGitProjectName;
@Schema(description = "目标分支名称(客户环境分支,为空时默认与源分支同名)")
private String targetBranch;
// ==================== 部署配置 ====================
@Schema(description = "部署系统IDJenkins系统") @Schema(description = "部署系统IDJenkins系统")
private Long deploySystemId; private Long deploySystemId;
@ -48,15 +69,17 @@ public class TeamApplicationDTO extends BaseDTO {
@Schema(description = "部署系统名称") @Schema(description = "部署系统名称")
private String deploySystemName; private String deploySystemName;
@Schema(description = "部署任务IDJenkins Job") @Schema(description = "部署任务名称Jenkins Job")
private String deployJob; private String deployJob;
@Schema(description = "工作流定义ID") @Schema(description = "工作流定义ID")
private Long workflowDefinitionId; private Long workflowDefinitionId;
@Schema(description = "工作流名称") @Schema(description = "工作流定义名称")
private String workflowDefinitionName; private String workflowDefinitionName;
// ==================== 关联信息 ====================
@Schema(description = "团队名称") @Schema(description = "团队名称")
private String teamName; private String teamName;

View File

@ -1,5 +1,6 @@
package com.qqchen.deploy.backend.deploy.dto; package com.qqchen.deploy.backend.deploy.dto;
import com.qqchen.deploy.backend.deploy.enums.DevelopmentModeEnum;
import com.qqchen.deploy.backend.framework.dto.BaseDTO; import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
@ -37,6 +38,14 @@ public class TeamDTO extends BaseDTO {
@NotNull(message = "排序号不能为空") @NotNull(message = "排序号不能为空")
private Integer sort; private Integer sort;
@Schema(description = "开发模式", example = "STANDARD")
@NotNull(message = "开发模式不能为空")
private DevelopmentModeEnum developmentMode;
@Schema(description = "是否启用Git同步检测仅SYNC_MODE模式有效")
@NotNull(message = "Git同步检测开关不能为空")
private Boolean enableGitSyncCheck;
@Schema(description = "成员数量") @Schema(description = "成员数量")
private Long memberCount; private Long memberCount;

View File

@ -38,8 +38,41 @@ public class UserDeployableTeamEnvironmentApplicationDTO {
@Schema(description = "构建类型JENKINS-Jenkins构建NATIVE-脚本部署)") @Schema(description = "构建类型JENKINS-Jenkins构建NATIVE-脚本部署)")
private BuildTypeEnum buildType; private BuildTypeEnum buildType;
@Schema(description = "分支名称") // ==================== 源Git配置公司内部Git ====================
private String branch;
@Schema(description = "源Git系统ID公司Git")
private Long sourceGitSystemId;
@Schema(description = "源Git系统名称")
private String sourceGitSystemName;
@Schema(description = "源Git项目ID公司Git项目ID")
private Long sourceGitProjectId;
@Schema(description = "源Git项目名称")
private String sourceGitProjectName;
@Schema(description = "源分支名称公司Git分支", example = "develop")
private String sourceBranch;
// ==================== 目标Git配置客户环境Git ====================
@Schema(description = "目标Git系统ID客户环境Git")
private Long targetGitSystemId;
@Schema(description = "目标Git系统名称")
private String targetGitSystemName;
@Schema(description = "目标Git项目ID客户环境Git项目")
private Long targetGitProjectId;
@Schema(description = "目标Git项目名称")
private String targetGitProjectName;
@Schema(description = "目标分支名称(客户环境分支)")
private String targetBranch;
// ==================== 部署配置 ====================
@Schema(description = "部署系统IDJenkins系统") @Schema(description = "部署系统IDJenkins系统")
private Long deploySystemId; private Long deploySystemId;
@ -47,11 +80,10 @@ public class UserDeployableTeamEnvironmentApplicationDTO {
@Schema(description = "部署系统名称") @Schema(description = "部署系统名称")
private String deploySystemName; private String deploySystemName;
@Schema(description = "部署任务IDJenkins Job") @Schema(description = "部署任务名称Jenkins Job")
private String deployJob; private String deployJob;
@Schema(description = "部署任务分支") // ==================== 工作流配置 ====================
private String deployBranch;
@Schema(description = "工作流定义ID") @Schema(description = "工作流定义ID")
private Long workflowDefinitionId; private Long workflowDefinitionId;

View File

@ -1,7 +1,10 @@
package com.qqchen.deploy.backend.deploy.entity; package com.qqchen.deploy.backend.deploy.entity;
import com.qqchen.deploy.backend.deploy.enums.DevelopmentModeEnum;
import com.qqchen.deploy.backend.framework.domain.Entity; import com.qqchen.deploy.backend.framework.domain.Entity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Enumerated;
import jakarta.persistence.EnumType;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -35,5 +38,18 @@ public class Team extends Entity<Long> {
@Column(name = "sort", nullable = false) @Column(name = "sort", nullable = false)
private Integer sort = 0; private Integer sort = 0;
/**
* 开发模式
*/
@Enumerated(EnumType.STRING)
@Column(name = "development_mode", length = 30, nullable = false)
private DevelopmentModeEnum developmentMode = DevelopmentModeEnum.STANDARD;
/**
* 是否启用Git同步检测仅SYNC_MODE模式有效
*/
@Column(name = "enable_git_sync_check", nullable = false)
private Boolean enableGitSyncCheck = false;
} }

View File

@ -45,23 +45,49 @@ public class TeamApplication extends Entity<Long> {
@Column(name = "build_type", length = 50) @Column(name = "build_type", length = 50)
private BuildTypeEnum buildType; private BuildTypeEnum buildType;
/** // ==================== 源Git配置公司内部Git ====================
* 分支名称
*/
@Column(name = "branch", length = 100)
private String branch;
/** /**
* 代码源系统ID关联sys_external_systemtype=GIT * 源Git系统ID公司Git关联sys_external_systemtype=GIT
*/ */
@Column(name = "code_source_system_id") @Column(name = "source_git_system_id")
private Long codeSourceSystemId; private Long sourceGitSystemId;
/** /**
* 代码源项目IDGit项目ID * Git项目ID公司Git项目ID
*/ */
@Column(name = "code_source_project_id") @Column(name = "source_git_project_id")
private Long codeSourceProjectId; private Long sourceGitProjectId;
/**
* 源分支名称公司Git分支
*/
@Column(name = "source_branch", length = 100)
private String sourceBranch;
// ==================== 目标Git配置客户环境Git ====================
/**
* 目标Git系统ID客户环境Git关联sys_external_system
* 仅在团队开发模式为SYNC_MODE时需要配置
*/
@Column(name = "target_git_system_id")
private Long targetGitSystemId;
/**
* 目标Git项目ID客户环境Git项目
*/
@Column(name = "target_git_project_id")
private Long targetGitProjectId;
/**
* 目标分支名称客户环境分支
* 为空时默认与源分支sourceBranch字段同名
*/
@Column(name = "target_branch", length = 255)
private String targetBranch;
// ==================== 部署配置 ====================
/** /**
* 部署系统ID关联sys_external_systemtype=JENKINS * 部署系统ID关联sys_external_systemtype=JENKINS

View File

@ -0,0 +1,107 @@
package com.qqchen.deploy.backend.deploy.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
/**
* 团队开发模式枚举
*
* @author qqchen
* @since 2025-12-04
*/
@Getter
public enum DevelopmentModeEnum {
/**
* 标准模式
* - 直接在客户环境/目标环境开发
* - 源码直接提交到客户Git
* - 无需内外网同步
*/
STANDARD(
"STANDARD",
"标准模式",
"单仓库直接开发部署",
false,
false
),
/**
* 同步模式
* - 内网Git开发
* - 源码定期同步到客户Git
* - 需要Git同步检测
*/
SYNC_MODE(
"SYNC_MODE",
"同步模式",
"源码内外网同步",
true,
true
),
/**
* 制品交付模式
* - 内网开发编译
* - 只交付JAR/WAR/镜像等制品
* - 客户无源码访问权限
* - 需要制品版本管理
*/
ARTIFACT_DELIVERY(
"ARTIFACT_DELIVERY",
"制品交付模式",
"仅交付编译制品,无源码",
true,
false
);
/**
* 编码
*/
@JsonValue
private final String code;
/**
* 显示名称
*/
private final String name;
/**
* 描述
*/
private final String description;
/**
* 是否内网开发
*/
private final boolean internalDevelopment;
/**
* 是否需要Git同步检测
*/
private final boolean requiresGitSyncCheck;
DevelopmentModeEnum(String code, String name, String description, boolean internalDevelopment, boolean requiresGitSyncCheck) {
this.code = code;
this.name = name;
this.description = description;
this.internalDevelopment = internalDevelopment;
this.requiresGitSyncCheck = requiresGitSyncCheck;
}
/**
* 根据编码查找对应的枚举
*
* @param code 开发模式编码
* @return 对应的枚举实例
* @throws IllegalArgumentException 当找不到对应的枚举值时抛出
*/
public static DevelopmentModeEnum fromValue(String code) {
for (DevelopmentModeEnum mode : values()) {
if (mode.code.equals(code)) {
return mode;
}
}
throw new IllegalArgumentException("Unknown DevelopmentMode code: " + code);
}
}

View File

@ -49,6 +49,32 @@ public interface IGitServiceIntegration extends IExternalSystemIntegration {
*/ */
List<GitBranchResponse> branches(ExternalSystem system, Long projectId); List<GitBranchResponse> branches(ExternalSystem system, Long projectId);
/**
* 获取指定分支信息
*
* @param system 外部系统配置
* @param projectId 项目ID
* @param branchName 分支名称
* @return 分支信息如果分支不存在返回null
*/
GitBranchResponse getBranch(ExternalSystem system, Long projectId, String branchName);
/**
* 获取分支的提交记录
*
* @param system 外部系统配置
* @param projectId 项目ID
* @param branchName 分支名称
* @param limit 获取的提交数量限制
* @return 提交记录列表
*/
List<com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse> getCommits(
ExternalSystem system,
Long projectId,
String branchName,
int limit
);
@Override @Override
default ExternalSystemTypeEnum getSystemType() { default ExternalSystemTypeEnum getSystemType() {
return ExternalSystemTypeEnum.GIT; return ExternalSystemTypeEnum.GIT;

View File

@ -15,11 +15,7 @@ import org.springframework.web.util.UriComponentsBuilder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Base64; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -238,4 +234,63 @@ public class GitServiceIntegrationImpl extends BaseExternalSystemIntegration imp
return headers; return headers;
} }
@Override
public GitBranchResponse getBranch(ExternalSystem system, Long projectId, String branchName) {
try {
// GitLab API: GET /projects/:id/repository/branches/:branch
String url = String.format("%s/api/v4/projects/%d/repository/branches/%s",
system.getUrl(), projectId, branchName);
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<GitBranchResponse> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
GitBranchResponse.class
);
return response.getBody();
} catch (Exception e) {
log.warn("Failed to get branch {} for project {}: {}", branchName, projectId, e.getMessage());
return null;
}
}
@Override
public List<com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse> getCommits(
ExternalSystem system,
Long projectId,
String branchName,
int limit) {
try {
// GitLab API: GET /projects/:id/repository/commits?ref_name=:branch&per_page=:limit
String url = String.format("%s/api/v4/projects/%d/repository/commits?ref_name=%s&per_page=%d",
system.getUrl(), projectId, branchName, limit);
HttpHeaders headers = createHeaders(system);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<List<com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse>> response =
restTemplate.exchange(
url,
HttpMethod.GET,
entity,
new ParameterizedTypeReference<>() {}
);
List<com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse> commits = response.getBody();
log.info("获取到{}个提交记录 - 项目: {}, 分支: {}",
commits != null ? commits.size() : 0, projectId, branchName);
return commits != null ? commits : Collections.emptyList();
} catch (Exception e) {
log.error("获取提交记录失败 - 项目: {}, 分支: {}", projectId, branchName, e);
return Collections.emptyList();
}
}
} }

View File

@ -0,0 +1,97 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
/**
* Git提交响应对象
*
* @author qqchen
* @since 2025-12-04
*/
@Data
public class GitCommitResponse {
/**
* 提交SHA
*/
private String id;
/**
* 短SHA前8位
*/
@JsonProperty("short_id")
private String shortId;
/**
* 提交标题
*/
private String title;
/**
* 提交信息
*/
private String message;
/**
* 作者名称
*/
@JsonProperty("author_name")
private String authorName;
/**
* 作者邮箱
*/
@JsonProperty("author_email")
private String authorEmail;
/**
* 提交者名称
*/
@JsonProperty("committer_name")
private String committerName;
/**
* 提交者邮箱
*/
@JsonProperty("committer_email")
private String committerEmail;
/**
* 创建时间
*/
@JsonProperty("created_at")
private OffsetDateTime createdAt;
/**
* 提交时间
*/
@JsonProperty("committed_date")
private OffsetDateTime committedDate;
/**
* Web URL
*/
@JsonProperty("web_url")
private String webUrl;
/**
* 获取提交时间LocalDateTime
*/
public LocalDateTime getCommittedDateTime() {
return committedDate != null ?
committedDate.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() : null;
}
/**
* 获取创建时间LocalDateTime
*/
public LocalDateTime getCreatedDateTime() {
return createdAt != null ?
createdAt.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() : null;
}
}

View File

@ -76,4 +76,13 @@ public interface IRepositoryProjectRepository extends IBaseRepository<Repository
"WHERE p.repoGroupId IN :repoGroupIds AND p.deleted = false " + "WHERE p.repoGroupId IN :repoGroupIds AND p.deleted = false " +
"GROUP BY p.repoGroupId") "GROUP BY p.repoGroupId")
List<Object[]> countByRepoGroupIds(@Param("repoGroupIds") Collection<Long> repoGroupIds); List<Object[]> countByRepoGroupIds(@Param("repoGroupIds") Collection<Long> repoGroupIds);
/**
* 根据外部系统ID和项目ID集合查询项目列表避免跨系统混淆
*
* @param externalSystemId 外部系统ID
* @param ids 项目ID集合
* @return 项目列表
*/
List<RepositoryProject> findByExternalSystemIdAndIdIn(Long externalSystemId, Collection<Long> ids);
} }

View File

@ -124,6 +124,8 @@ public class DeployServiceImpl implements IDeployService {
@Resource @Resource
private TeamEnvironmentNotificationConfigConverter notificationConfigConverter; private TeamEnvironmentNotificationConfigConverter notificationConfigConverter;
@Resource
private IRepositoryProjectRepository repositoryProjectRepository;
@Override @Override
public List<UserTeamDeployableDTO> getDeployableEnvironments() { public List<UserTeamDeployableDTO> getDeployableEnvironments() {
@ -200,6 +202,10 @@ public class DeployServiceImpl implements IDeployService {
Set<Long> workflowIds = new HashSet<>(); Set<Long> workflowIds = new HashSet<>();
List<Long> teamApplicationIds = new ArrayList<>(); List<Long> teamApplicationIds = new ArrayList<>();
// 收集源和目标Git项目查询条件
record GitProjectKey(Long systemId, Long repoProjectId) {}
Set<GitProjectKey> gitProjectKeys = new HashSet<>();
for (TeamApplication ta : allTeamApps) { for (TeamApplication ta : allTeamApps) {
teamApplicationIds.add(ta.getId()); teamApplicationIds.add(ta.getId());
allEnvIds.add(ta.getEnvironmentId()); allEnvIds.add(ta.getEnvironmentId());
@ -210,6 +216,20 @@ public class DeployServiceImpl implements IDeployService {
if (ta.getWorkflowDefinitionId() != null) { if (ta.getWorkflowDefinitionId() != null) {
workflowIds.add(ta.getWorkflowDefinitionId()); workflowIds.add(ta.getWorkflowDefinitionId());
} }
// 收集源Git系统和项目
if (ta.getSourceGitSystemId() != null) {
systemIds.add(ta.getSourceGitSystemId());
if (ta.getSourceGitProjectId() != null) {
gitProjectKeys.add(new GitProjectKey(ta.getSourceGitSystemId(), ta.getSourceGitProjectId()));
}
}
// 收集目标Git系统和项目
if (ta.getTargetGitSystemId() != null) {
systemIds.add(ta.getTargetGitSystemId());
if (ta.getTargetGitProjectId() != null) {
gitProjectKeys.add(new GitProjectKey(ta.getTargetGitSystemId(), ta.getTargetGitProjectId()));
}
}
} }
// 9. 应用配置按团队分组 // 9. 应用配置按团队分组
@ -238,11 +258,21 @@ public class DeployServiceImpl implements IDeployService {
? applicationRepository.findAllById(appIds).stream().collect(toMap(Application::getId, a -> a)) ? applicationRepository.findAllById(appIds).stream().collect(toMap(Application::getId, a -> a))
: Collections.emptyMap(); : Collections.emptyMap();
// 12. 批量查询部署系统 // 12. 批量查询部署系统包含源/目标Git系统
Map<Long, ExternalSystem> systemMap = !systemIds.isEmpty() Map<Long, ExternalSystem> systemMap = !systemIds.isEmpty()
? externalSystemRepository.findAllById(systemIds).stream().collect(toMap(ExternalSystem::getId, s -> s)) ? externalSystemRepository.findAllById(systemIds).stream().collect(toMap(ExternalSystem::getId, s -> s))
: Collections.emptyMap(); : Collections.emptyMap();
// 12.5. 批量查询Git项目信息 systemId + repoProjectId
Map<String, RepositoryProject> gitProjectMap = new HashMap<>();
for (GitProjectKey key : gitProjectKeys) {
repositoryProjectRepository.findByRepoProjectIdAndExternalSystemIdAndDeletedFalse(
key.repoProjectId(), key.systemId()
).ifPresent(project ->
gitProjectMap.put(key.systemId() + "_" + key.repoProjectId(), project)
);
}
// 13. 批量查询工作流定义 // 13. 批量查询工作流定义
Map<Long, WorkflowDefinition> workflowMap = !workflowIds.isEmpty() Map<Long, WorkflowDefinition> workflowMap = !workflowIds.isEmpty()
? workflowDefinitionRepository.findAllById(workflowIds).stream().collect(toMap(WorkflowDefinition::getId, w -> w)) ? workflowDefinitionRepository.findAllById(workflowIds).stream().collect(toMap(WorkflowDefinition::getId, w -> w))
@ -308,7 +338,7 @@ public class DeployServiceImpl implements IDeployService {
for (Long teamId : teamIds) { for (Long teamId : teamIds) {
UserTeamDeployableDTO teamDTO = buildUserTeamDeployableDTO( UserTeamDeployableDTO teamDTO = buildUserTeamDeployableDTO(
currentUserId, teamId, teamMap, ownerMap, membersByTeam, memberUserMap, currentUserId, teamId, teamMap, ownerMap, membersByTeam, memberUserMap,
teamAppsMap, envMap, appMap, systemMap, workflowMap, teamAppsMap, envMap, appMap, systemMap, gitProjectMap, workflowMap,
teamEnvConfigMap, approverMap, teamEnvConfigMap, approverMap,
notificationConfigMap, channelMap, templateMap, notificationConfigMap, channelMap, templateMap,
statisticsMap, latestRecordMap, recentRecordsMap statisticsMap, latestRecordMap, recentRecordsMap
@ -336,6 +366,7 @@ public class DeployServiceImpl implements IDeployService {
Map<Long, Environment> envMap, Map<Long, Environment> envMap,
Map<Long, Application> appMap, Map<Long, Application> appMap,
Map<Long, ExternalSystem> systemMap, Map<Long, ExternalSystem> systemMap,
Map<String, RepositoryProject> gitProjectMap,
Map<Long, WorkflowDefinition> workflowMap, Map<Long, WorkflowDefinition> workflowMap,
Map<String, TeamEnvironmentConfig> teamEnvConfigMap, Map<String, TeamEnvironmentConfig> teamEnvConfigMap,
Map<Long, User> approverMap, Map<Long, User> approverMap,
@ -417,7 +448,7 @@ public class DeployServiceImpl implements IDeployService {
UserDeployableTeamEnvironmentDTO envDTO = buildUserDeployableTeamEnvironmentDTO( UserDeployableTeamEnvironmentDTO envDTO = buildUserDeployableTeamEnvironmentDTO(
currentUserId, team.getOwnerId(), currentUserId, team.getOwnerId(),
teamId, env, envApps, teamId, env, envApps,
appMap, systemMap, workflowMap, appMap, systemMap, gitProjectMap, workflowMap,
teamEnvConfigMap, approverMap, teamEnvConfigMap, approverMap,
notificationConfigMap, channelMap, templateMap, notificationConfigMap, channelMap, templateMap,
statisticsMap, latestRecordMap, recentRecordsMap statisticsMap, latestRecordMap, recentRecordsMap
@ -443,6 +474,7 @@ public class DeployServiceImpl implements IDeployService {
List<TeamApplication> teamApps, List<TeamApplication> teamApps,
Map<Long, Application> appMap, Map<Long, Application> appMap,
Map<Long, ExternalSystem> systemMap, Map<Long, ExternalSystem> systemMap,
Map<String, RepositoryProject> gitProjectMap,
Map<Long, WorkflowDefinition> workflowMap, Map<Long, WorkflowDefinition> workflowMap,
Map<String, TeamEnvironmentConfig> teamEnvConfigMap, Map<String, TeamEnvironmentConfig> teamEnvConfigMap,
Map<Long, User> approverMap, Map<Long, User> approverMap,
@ -512,7 +544,7 @@ public class DeployServiceImpl implements IDeployService {
// 构建应用列表 // 构建应用列表
List<UserDeployableTeamEnvironmentApplicationDTO> applications = teamApps.stream() List<UserDeployableTeamEnvironmentApplicationDTO> applications = teamApps.stream()
.map(teamApp -> buildUserDeployableTeamEnvironmentApplicationDTO( .map(teamApp -> buildUserDeployableTeamEnvironmentApplicationDTO(
teamApp, appMap, systemMap, workflowMap, teamApp, appMap, systemMap, gitProjectMap, workflowMap,
statisticsMap, latestRecordMap, recentRecordsMap statisticsMap, latestRecordMap, recentRecordsMap
)) ))
.filter(app -> app != null) .filter(app -> app != null)
@ -541,6 +573,7 @@ public class DeployServiceImpl implements IDeployService {
TeamApplication teamApp, TeamApplication teamApp,
Map<Long, Application> appMap, Map<Long, Application> appMap,
Map<Long, ExternalSystem> systemMap, Map<Long, ExternalSystem> systemMap,
Map<String, RepositoryProject> gitProjectMap,
Map<Long, WorkflowDefinition> workflowMap, Map<Long, WorkflowDefinition> workflowMap,
Map<Long, DeployStatisticsDTO> statisticsMap, Map<Long, DeployStatisticsDTO> statisticsMap,
Map<Long, DeployRecord> latestRecordMap, Map<Long, DeployRecord> latestRecordMap,
@ -559,7 +592,44 @@ public class DeployServiceImpl implements IDeployService {
dto.setApplicationDesc(app.getAppDesc()); dto.setApplicationDesc(app.getAppDesc());
dto.setLanguage(app.getLanguage()); dto.setLanguage(app.getLanguage());
dto.setBuildType(teamApp.getBuildType()); dto.setBuildType(teamApp.getBuildType());
dto.setBranch(teamApp.getBranch());
// 设置源Git配置
dto.setSourceGitSystemId(teamApp.getSourceGitSystemId());
dto.setSourceGitProjectId(teamApp.getSourceGitProjectId());
dto.setSourceBranch(teamApp.getSourceBranch());
if (teamApp.getSourceGitSystemId() != null) {
ExternalSystem sourceGitSystem = systemMap.get(teamApp.getSourceGitSystemId());
if (sourceGitSystem != null) {
dto.setSourceGitSystemName(sourceGitSystem.getName());
}
// 填充源Git项目名称
if (teamApp.getSourceGitProjectId() != null) {
String key = teamApp.getSourceGitSystemId() + "_" + teamApp.getSourceGitProjectId();
RepositoryProject project = gitProjectMap.get(key);
if (project != null) {
dto.setSourceGitProjectName(project.getName());
}
}
}
// 设置目标Git配置
dto.setTargetGitSystemId(teamApp.getTargetGitSystemId());
dto.setTargetGitProjectId(teamApp.getTargetGitProjectId());
dto.setTargetBranch(teamApp.getTargetBranch());
if (teamApp.getTargetGitSystemId() != null) {
ExternalSystem targetGitSystem = systemMap.get(teamApp.getTargetGitSystemId());
if (targetGitSystem != null) {
dto.setTargetGitSystemName(targetGitSystem.getName());
}
// 填充目标Git项目名称
if (teamApp.getTargetGitProjectId() != null) {
String key = teamApp.getTargetGitSystemId() + "_" + teamApp.getTargetGitProjectId();
RepositoryProject project = gitProjectMap.get(key);
if (project != null) {
dto.setTargetGitProjectName(project.getName());
}
}
}
// 设置部署系统信息 // 设置部署系统信息
if (teamApp.getDeploySystemId() != null) { if (teamApp.getDeploySystemId() != null) {
@ -569,7 +639,6 @@ public class DeployServiceImpl implements IDeployService {
dto.setDeploySystemName(system.getName()); dto.setDeploySystemName(system.getName());
} }
dto.setDeployJob(teamApp.getDeployJob()); dto.setDeployJob(teamApp.getDeployJob());
dto.setDeployBranch(teamApp.getBranch());
} }
// 设置工作流定义信息 // 设置工作流定义信息

View File

@ -126,12 +126,26 @@ public class TeamApplicationServiceImpl extends BaseServiceImpl<TeamApplication,
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Set<Long> codeSourceSystemIds = teamApps.stream() Set<Long> codeSourceSystemIds = teamApps.stream()
.map(TeamApplicationDTO::getCodeSourceSystemId) .map(TeamApplicationDTO::getSourceGitSystemId)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Set<Long> codeSourceProjectIds = teamApps.stream() // 收集源Git项目查询条件systemId + repoProjectId
.map(TeamApplicationDTO::getCodeSourceProjectId) record SourceProjectKey(Long systemId, Long repoProjectId) {}
Set<SourceProjectKey> sourceProjectKeys = teamApps.stream()
.filter(app -> app.getSourceGitSystemId() != null && app.getSourceGitProjectId() != null)
.map(app -> new SourceProjectKey(app.getSourceGitSystemId(), app.getSourceGitProjectId()))
.collect(Collectors.toSet());
// 收集目标Git项目查询条件systemId + repoProjectId
record TargetProjectKey(Long systemId, Long repoProjectId) {}
Set<TargetProjectKey> targetProjectKeys = teamApps.stream()
.filter(app -> app.getTargetGitSystemId() != null && app.getTargetGitProjectId() != null)
.map(app -> new TargetProjectKey(app.getTargetGitSystemId(), app.getTargetGitProjectId()))
.collect(Collectors.toSet());
Set<Long> targetGitSystemIds = teamApps.stream()
.map(TeamApplicationDTO::getTargetGitSystemId)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@ -183,15 +197,35 @@ public class TeamApplicationServiceImpl extends BaseServiceImpl<TeamApplication,
); );
} }
// 8. 批量查询代码源项目信息 // 8. 批量查询源Git项目信息 systemId + repoProjectId
Map<Long, RepositoryProject> codeSourceProjectMap = new HashMap<>(); Map<String, RepositoryProject> codeSourceProjectMap = new HashMap<>();
if (!codeSourceProjectIds.isEmpty()) { for (SourceProjectKey key : sourceProjectKeys) {
repositoryProjectRepository.findAllById(codeSourceProjectIds).forEach(project -> repositoryProjectRepository.findByRepoProjectIdAndExternalSystemIdAndDeletedFalse(
codeSourceProjectMap.put(project.getId(), project) key.repoProjectId(), key.systemId()
).ifPresent(project ->
codeSourceProjectMap.put(key.systemId() + "_" + key.repoProjectId(), project)
); );
} }
// 9. 填充扩展字段 // 9. 批量查询目标Git系统信息
Map<Long, ExternalSystem> targetGitSystemMap = new HashMap<>();
if (!targetGitSystemIds.isEmpty()) {
externalSystemRepository.findAllById(targetGitSystemIds).forEach(system ->
targetGitSystemMap.put(system.getId(), system)
);
}
// 10. 批量查询目标Git项目信息 systemId + repoProjectId
Map<String, RepositoryProject> targetGitProjectMap = new HashMap<>();
for (TargetProjectKey key : targetProjectKeys) {
repositoryProjectRepository.findByRepoProjectIdAndExternalSystemIdAndDeletedFalse(
key.repoProjectId(), key.systemId()
).ifPresent(project ->
targetGitProjectMap.put(key.systemId() + "_" + key.repoProjectId(), project)
);
}
// 11. 填充扩展字段
teamApps.forEach(teamApp -> { teamApps.forEach(teamApp -> {
// 填充团队名称 // 填充团队名称
if (teamApp.getTeamId() != null) { if (teamApp.getTeamId() != null) {
@ -234,19 +268,37 @@ public class TeamApplicationServiceImpl extends BaseServiceImpl<TeamApplication,
} }
} }
// 填充代码源系统名称 // 填充Git系统名称
if (teamApp.getCodeSourceSystemId() != null) { if (teamApp.getSourceGitSystemId() != null) {
ExternalSystem system = codeSourceSystemMap.get(teamApp.getCodeSourceSystemId()); ExternalSystem system = codeSourceSystemMap.get(teamApp.getSourceGitSystemId());
if (system != null) { if (system != null) {
teamApp.setCodeSourceSystemName(system.getName()); teamApp.setSourceGitSystemName(system.getName());
} }
} }
// 填充代码源项目名称 // 填充源Git项目名称
if (teamApp.getCodeSourceProjectId() != null) { if (teamApp.getSourceGitSystemId() != null && teamApp.getSourceGitProjectId() != null) {
RepositoryProject project = codeSourceProjectMap.get(teamApp.getCodeSourceProjectId()); String key = teamApp.getSourceGitSystemId() + "_" + teamApp.getSourceGitProjectId();
RepositoryProject project = codeSourceProjectMap.get(key);
if (project != null) { if (project != null) {
teamApp.setCodeSourceProjectName(project.getName()); teamApp.setSourceGitProjectName(project.getName());
}
}
// 填充目标Git系统名称
if (teamApp.getTargetGitSystemId() != null) {
ExternalSystem system = targetGitSystemMap.get(teamApp.getTargetGitSystemId());
if (system != null) {
teamApp.setTargetGitSystemName(system.getName());
}
}
// 填充目标Git项目名称
if (teamApp.getTargetGitSystemId() != null && teamApp.getTargetGitProjectId() != null) {
String key = teamApp.getTargetGitSystemId() + "_" + teamApp.getTargetGitProjectId();
RepositoryProject project = targetGitProjectMap.get(key);
if (project != null) {
teamApp.setTargetGitProjectName(project.getName());
} }
} }
}); });

View File

@ -0,0 +1,308 @@
package com.qqchen.deploy.backend.workflow.delegate;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.workflow.dto.CommitDifferenceInfo;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.GitSyncCheckInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.GitSyncCheckOutputs;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* Git同步检测节点委派
*
* @author qqchen
* @since 2025-12-04
*/
@Slf4j
@Component("gitSyncCheckDelegate")
public class GitSyncCheckDelegate extends BaseNodeDelegate<GitSyncCheckInputMapping, GitSyncCheckOutputs> {
@Resource
private IGitServiceIntegration gitServiceIntegration;
@Resource
private IExternalSystemRepository externalSystemRepository;
/**
* 获取commits的数量限制
*/
private static final int COMMITS_LIMIT = 10;
@Override
protected void executeInternal(DelegateExecution execution,
Map<String, Object> configs,
GitSyncCheckInputMapping input) {
log.info("开始Git同步检测 - 源分支: {}/{}/{}, 目标分支: {}/{}/{}",
input.getSourceGitSystemId(), input.getSourceGitProjectId(), input.getSourceBranch(),
input.getTargetGitSystemId(), input.getTargetGitProjectId(), input.getTargetBranch());
try {
// 0. 检查是否配置了目标Git信息非强制如果未配置则跳过检测
if (input.getTargetGitSystemId() == null ||
input.getTargetGitProjectId() == null ||
input.getTargetBranch() == null ||
input.getTargetBranch().trim().isEmpty()) {
String skipReason = "目标Git系统未配置跳过Git同步检测团队可能未启用同步模式";
log.info("⏭️ {}", skipReason);
output.setStatus(NodeExecutionStatusEnum.SUCCESS);
output.setMessage(skipReason);
output.setCheckDetail(skipReason);
output.setHasDifference(false);
output.setCommitsAhead(0);
output.setCommitsBehind(0);
logInfo(skipReason);
return; // 直接返回成功不影响流程
}
// 1. 查询Git系统配置技术异常 - 强制失败
ExternalSystem sourceSystem = externalSystemRepository.findById(input.getSourceGitSystemId())
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND,
new Object[]{"源Git系统不存在: " + input.getSourceGitSystemId()}));
ExternalSystem targetSystem = externalSystemRepository.findById(input.getTargetGitSystemId())
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND,
new Object[]{"目标Git系统不存在: " + input.getTargetGitSystemId()}));
// 2. 获取源分支最近10个commits
List<GitCommitResponse> sourceCommits = gitServiceIntegration.getCommits(
sourceSystem,
input.getSourceGitProjectId(),
input.getSourceBranch(),
COMMITS_LIMIT
);
// 业务失败源分支不存在或无法获取提交记录
if (sourceCommits.isEmpty()) {
String errorMsg = String.format("无法获取源分支提交记录: %s (分支可能不存在)", input.getSourceBranch());
log.warn(errorMsg);
output.setStatus(NodeExecutionStatusEnum.FAILURE);
output.setMessage(errorMsg);
output.setCheckDetail(errorMsg);
logWarn(errorMsg);
return; // 正常返回由基类根据 continueOnFailure 决定是否抛 BpmnError
}
// 3. 获取目标分支最近10个commits
List<GitCommitResponse> targetCommits = gitServiceIntegration.getCommits(
targetSystem,
input.getTargetGitProjectId(),
input.getTargetBranch(),
COMMITS_LIMIT
);
// 业务失败目标分支不存在或无法获取提交记录
if (targetCommits.isEmpty()) {
String errorMsg = String.format("无法获取目标分支提交记录: %s (分支可能不存在)", input.getTargetBranch());
log.warn(errorMsg);
output.setStatus(NodeExecutionStatusEnum.FAILURE);
output.setMessage(errorMsg);
output.setCheckDetail(errorMsg);
logWarn(errorMsg);
return; // 正常返回由基类根据 continueOnFailure 决定是否抛 BpmnError
}
// 4. 比较commits找出差异
CompareResult compareResult = compareCommits(sourceCommits, targetCommits);
// 5. 填充输出结果
output.setSourceLatestCommit(sourceCommits.get(0).getId());
output.setTargetLatestCommit(targetCommits.get(0).getId());
output.setHasDifference(compareResult.hasDifference);
output.setCommitsAhead(compareResult.commitsAhead);
output.setCommitsBehind(compareResult.commitsBehind);
output.setDifferenceCommits(compareResult.differenceCommits);
// 6. 判断检测结果
if (!compareResult.hasDifference) {
// 合规目标分支的所有commits都在源分支中
String detail = String.format(
"✅ Git同步检测通过目标分支 [%s] 的所有代码已回归到源分支 [%s]",
input.getTargetBranch(),
input.getSourceBranch()
);
output.setStatus(NodeExecutionStatusEnum.SUCCESS);
output.setMessage(detail);
output.setCheckDetail(detail);
logInfo(detail);
} else {
// 不合规目标分支有源分支没有的commits
StringBuilder detailBuilder = new StringBuilder();
detailBuilder.append(String.format(
"❌ Git同步检测不合规目标分支 [%s] 存在 %d 个未回归到源分支 [%s] 的提交\n\n",
input.getTargetBranch(),
compareResult.commitsBehind,
input.getSourceBranch()
));
// 详细列出不合规的commits
detailBuilder.append("不合规提交列表:\n");
for (int i = 0; i < compareResult.differenceCommits.size(); i++) {
CommitDifferenceInfo commit = compareResult.differenceCommits.get(i);
detailBuilder.append(String.format(
"%d. [%s] %s\n 作者: %s <%s>\n 时间: %s\n",
i + 1,
commit.getCommitId().substring(0, 8),
commit.getShortMessage(),
commit.getAuthor(),
commit.getAuthorEmail(),
commit.getCommittedDate()
));
}
String detail = detailBuilder.toString();
output.setStatus(NodeExecutionStatusEnum.FAILURE);
output.setCheckDetail(detail);
output.setMessage(String.format(
"目标分支存在%d个未回归的提交请检查",
compareResult.commitsBehind
));
logWarn(detail);
// 正常返回基类会根据 output.status + continueOnFailure 决定是否抛 BpmnError
}
} catch (BusinessException e) {
// 技术异常Git系统不存在等- 直接抛出强制失败
log.error("Git同步检测技术异常", e);
throw e;
} catch (Exception e) {
// 未预期的异常 - 标记为失败友好处理
log.error("Git同步检测发生异常", e);
output.setStatus(NodeExecutionStatusEnum.FAILURE);
output.setMessage("Git同步检测异常: " + e.getMessage());
output.setCheckDetail("系统异常: " + e.getMessage());
logError("Git同步检测异常: " + e.getMessage());
// 正常返回基类会根据 output.status + continueOnFailure 决定是否抛 BpmnError
}
}
/**
* 比较两个分支的commits基于源分支为基准的规则
*
* <p><b>核心规则</b>源分支公司Git是基准所有代码都应该回归到源分支
* <ul>
* <li>如果目标分支中有任何commit不在源分支中 <b>不合规</b></li>
* <li>需要将目标分支独有的commits列出来放到checkDetail中供通知使用</li>
* </ul>
*
* @param sourceCommits 源分支的最近N个commits公司Git基准
* @param targetCommits 目标分支的最近N个commits客户Git
* @return 比较结果
*/
private CompareResult compareCommits(List<GitCommitResponse> sourceCommits, List<GitCommitResponse> targetCommits) {
CompareResult result = new CompareResult();
// 构建源分支commit ID集合基准
Set<String> sourceCommitIds = sourceCommits.stream()
.map(GitCommitResponse::getId)
.collect(Collectors.toSet());
// 找出目标分支中有但源分支中没有的commits不合规的commits
List<GitCommitResponse> nonCompliantCommits = targetCommits.stream()
.filter(commit -> !sourceCommitIds.contains(commit.getId()))
.collect(Collectors.toList());
if (nonCompliantCommits.isEmpty()) {
// 目标分支的所有commits都在源分支中 合规
result.hasDifference = false;
result.commitsAhead = 0;
result.commitsBehind = 0;
result.differenceCommits = Collections.emptyList();
log.info("✅ Git同步检测通过 - 目标分支的所有提交都已回归到源分支");
return result;
}
// 存在不合规的commits
result.hasDifference = true;
result.commitsAhead = 0; // 不关心源分支领先多少
result.commitsBehind = nonCompliantCommits.size(); // 目标分支独有的commit数量
result.differenceCommits = buildDifferenceList(nonCompliantCommits, "target");
log.warn("⚠️ Git同步检测不合规 - 目标分支存在{}个未回归到源分支的提交",
nonCompliantCommits.size());
// 打印不合规的commits用于调试
nonCompliantCommits.forEach(commit ->
log.warn(" - 不合规commit: {} by {} at {}",
commit.getId().substring(0, 8),
commit.getAuthorName(),
commit.getCommittedDateTime())
);
return result;
}
/**
* 构建差异提交信息列表
*/
private List<CommitDifferenceInfo> buildDifferenceList(List<GitCommitResponse> commits, String branchLabel) {
return commits.stream()
.map(commit -> {
CommitDifferenceInfo info = new CommitDifferenceInfo();
info.setCommitId(commit.getId());
info.setAuthor(commit.getAuthorName());
info.setAuthorEmail(commit.getAuthorEmail());
info.setCommittedDate(commit.getCommittedDateTime());
info.setMessage(commit.getMessage());
info.setShortMessage(truncateMessage(commit.getTitle(), 100));
info.setBranch(branchLabel);
return info;
})
.collect(Collectors.toList());
}
/**
* 截断消息
*/
private String truncateMessage(String message, int maxLength) {
if (message == null) {
return null;
}
if (message.length() <= maxLength) {
return message;
}
return message.substring(0, maxLength) + "...";
}
/**
* 比较结果内部类
*/
private static class CompareResult {
/**
* 是否存在差异目标分支是否有未回归的commits
*/
boolean hasDifference;
/**
* 源分支领先数量本规则下不使用始终为0
*/
int commitsAhead;
/**
* 目标分支独有的commit数量未回归到源分支的commits
*/
int commitsBehind;
/**
* 不合规的commits列表目标分支独有的
*/
List<CommitDifferenceInfo> differenceCommits;
}
}

View File

@ -0,0 +1,50 @@
package com.qqchen.deploy.backend.workflow.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* Git提交差异信息
*
* @author qqchen
* @since 2025-12-04
*/
@Data
public class CommitDifferenceInfo {
/**
* 提交SHA
*/
private String commitId;
/**
* 提交作者
*/
private String author;
/**
* 提交邮箱
*/
private String authorEmail;
/**
* 提交时间
*/
private LocalDateTime committedDate;
/**
* 提交信息
*/
private String message;
/**
* 提交信息缩略最多100字符
*/
private String shortMessage;
/**
* 所在分支source/target
*/
private String branch;
}

View File

@ -0,0 +1,59 @@
package com.qqchen.deploy.backend.workflow.dto.inputmapping;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* Git同步检测节点输入映射
*
* @author qqchen
* @since 2025-12-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class GitSyncCheckInputMapping extends BaseNodeInputMapping {
/**
* 源Git系统ID内网Git
*/
@NotNull(message = "源Git系统ID不能为空")
private Long sourceGitSystemId;
/**
* 源Git项目ID
*/
@NotNull(message = "源Git项目ID不能为空")
private Long sourceGitProjectId;
/**
* 源分支名称
*/
@NotBlank(message = "源分支不能为空")
private String sourceBranch;
/**
* 目标Git系统ID客户Git
* 可选字段如果未配置则跳过Git同步检测
*/
private Long targetGitSystemId;
/**
* 目标Git项目ID
* 可选字段如果未配置则跳过Git同步检测
*/
private Long targetGitProjectId;
/**
* 目标分支名称
* 可选字段如果未配置则跳过Git同步检测
*/
private String targetBranch;
// 继承自 BaseNodeInputMapping.continueOnFailure
// - true: 发现差异时标记为FAILURE但继续执行不阻断
// - false: 发现差异时抛出BpmnError终止流程阻断
}

View File

@ -0,0 +1,53 @@
package com.qqchen.deploy.backend.workflow.dto.outputs;
import com.qqchen.deploy.backend.workflow.dto.CommitDifferenceInfo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* Git同步检测节点输出
*
* @author qqchen
* @since 2025-12-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GitSyncCheckOutputs extends BaseNodeOutputs {
/**
* 是否存在差异
*/
private Boolean hasDifference;
/**
* 源分支领先的提交数
*/
private Integer commitsAhead;
/**
* 目标分支领先的提交数
*/
private Integer commitsBehind;
/**
* 差异提交列表最多显示20条
*/
private List<CommitDifferenceInfo> differenceCommits;
/**
* 源分支最新提交SHA
*/
private String sourceLatestCommit;
/**
* 目标分支最新提交SHA
*/
private String targetLatestCommit;
/**
* 检查结果详情用于通知模板
*/
private String checkDetail;
}

View File

@ -87,6 +87,13 @@ public enum NodeTypeEnums {
BpmnNodeTypeEnums.USER_TASK, BpmnNodeTypeEnums.USER_TASK,
NodeCategoryEnums.TASK, NodeCategoryEnums.TASK,
"人工审批节点,支持多种审批模式" "人工审批节点,支持多种审批模式"
),
GIT_SYNC_CHECK(
"GIT_SYNC_CHECK",
"Git同步检测",
BpmnNodeTypeEnums.SERVICE_TASK,
NodeCategoryEnums.TASK,
"检测源分支与目标分支的同步状态"
); );
@JsonValue @JsonValue

View File

@ -1349,7 +1349,7 @@ INSERT INTO sys_notification_template (id, create_by, create_time, update_by, up
</#if> </#if>
--- ---
*Deploy Ease Platform *', 1, '{"messageType": "MARKDOWN"}'), *Deploy Ease Platform *', 1, '{"channelType": "WEWORK", "messageType": "MARKDOWN"}'),
(2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0, (2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
'Jenkins构建通知-邮件', 'jenkins_build_email', 'Jenkins构建结果通知模板邮件', 'EMAIL', 'Jenkins构建通知-邮件', 'jenkins_build_email', 'Jenkins构建结果通知模板邮件', 'EMAIL',
@ -1394,7 +1394,7 @@ INSERT INTO sys_notification_template (id, create_by, create_time, update_by, up
</#if> </#if>
<hr> <hr>
<p style="color: #666; font-size: 12px;">Deploy Ease Platform </p>', 1, '{"contentType": "HTML", "priority": "NORMAL"}'), <p style="color: #666; font-size: 12px;">Deploy Ease Platform </p>', 1, '{"channelType": "EMAIL", "contentType": "HTML", "priority": "NORMAL"}'),
-- 部署通知模板 -- 部署通知模板
(3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0, (3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
@ -1418,7 +1418,7 @@ INSERT INTO sys_notification_template (id, create_by, create_time, update_by, up
</#if> </#if>
--- ---
*Deploy Ease Platform *', 1, '{"messageType": "MARKDOWN"}'), *Deploy Ease Platform *', 1, '{"channelType": "WEWORK", "messageType": "MARKDOWN"}'),
(4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0, (4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
'部署通知-邮件', 'deploy_notification_email', '应用部署结果通知模板(邮件)', 'EMAIL', '部署通知-邮件', 'deploy_notification_email', '应用部署结果通知模板(邮件)', 'EMAIL',
@ -1465,4 +1465,4 @@ INSERT INTO sys_notification_template (id, create_by, create_time, update_by, up
</#if> </#if>
<hr> <hr>
<p style="color: #666; font-size: 12px;">Deploy Ease Platform </p>', 1, '{"contentType": "HTML", "priority": "NORMAL"}'); <p style="color: #666; font-size: 12px;">Deploy Ease Platform </p>', 1, '{"channelType": "EMAIL", "contentType": "HTML", "priority": "NORMAL"}');

View File

@ -765,6 +765,10 @@ CREATE TABLE deploy_team
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用', enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用',
sort INT NOT NULL DEFAULT 0 COMMENT '排序号', sort INT NOT NULL DEFAULT 0 COMMENT '排序号',
-- Git同步相关配置
development_mode VARCHAR(30) NOT NULL DEFAULT 'STANDARD' COMMENT '开发模式: STANDARD-标准模式, SYNC_MODE-同步模式, ARTIFACT_DELIVERY-制品交付模式',
enable_git_sync_check BIT NOT NULL DEFAULT 0 COMMENT '是否启用Git同步检测仅SYNC_MODE模式有效',
UNIQUE INDEX uk_team_code (team_code), UNIQUE INDEX uk_team_code (team_code),
INDEX idx_owner (owner_id), INDEX idx_owner (owner_id),
CONSTRAINT fk_team_owner FOREIGN KEY (owner_id) REFERENCES sys_user (id) CONSTRAINT fk_team_owner FOREIGN KEY (owner_id) REFERENCES sys_user (id)
@ -808,9 +812,18 @@ CREATE TABLE deploy_team_application
application_id BIGINT NOT NULL COMMENT '应用ID', application_id BIGINT NOT NULL COMMENT '应用ID',
environment_id BIGINT NOT NULL COMMENT '环境ID', environment_id BIGINT NOT NULL COMMENT '环境ID',
build_type VARCHAR(50) NULL COMMENT '构建类型JENKINS-Jenkins构建NATIVE-脚本部署)', build_type VARCHAR(50) NULL COMMENT '构建类型JENKINS-Jenkins构建NATIVE-脚本部署)',
branch VARCHAR(100) NULL COMMENT '分支名称',
code_source_system_id BIGINT NULL COMMENT '代码源系统ID关联sys_external_systemtype=GIT', -- 源Git配置公司内部Git
code_source_project_id BIGINT NULL COMMENT '代码源项目IDGit项目ID', source_git_system_id BIGINT NULL COMMENT '源Git系统ID公司Git关联sys_external_systemtype=GIT',
source_git_project_id BIGINT NULL COMMENT '源Git项目ID公司Git项目',
source_branch VARCHAR(100) NULL COMMENT '源分支名称公司Git分支',
-- 目标Git配置客户环境Git用于同步检测仅SYNC_MODE模式需要
target_git_system_id BIGINT NULL COMMENT '目标Git系统ID客户环境Git关联sys_external_system',
target_git_project_id BIGINT NULL COMMENT '目标Git项目ID客户环境Git项目',
target_branch VARCHAR(255) NULL COMMENT '目标分支名称(客户环境分支)',
-- 部署配置
deploy_system_id BIGINT NULL COMMENT '部署系统ID关联sys_external_systemtype=JENKINS仅当build_type=JENKINS时使用', deploy_system_id BIGINT NULL COMMENT '部署系统ID关联sys_external_systemtype=JENKINS仅当build_type=JENKINS时使用',
deploy_job VARCHAR(100) NULL COMMENT '部署任务名称Jenkins Job名称仅当build_type=JENKINS时使用', deploy_job VARCHAR(100) NULL COMMENT '部署任务名称Jenkins Job名称仅当build_type=JENKINS时使用',
workflow_definition_id BIGINT NULL COMMENT '工作流定义ID关联workflow_definition', workflow_definition_id BIGINT NULL COMMENT '工作流定义ID关联workflow_definition',
@ -820,12 +833,14 @@ CREATE TABLE deploy_team_application
INDEX idx_application (application_id), INDEX idx_application (application_id),
INDEX idx_environment (environment_id), INDEX idx_environment (environment_id),
INDEX idx_build_type (build_type), INDEX idx_build_type (build_type),
INDEX idx_code_source_system (code_source_system_id), INDEX idx_source_git_system (source_git_system_id),
INDEX idx_deploy_system (deploy_system_id), INDEX idx_deploy_system (deploy_system_id),
INDEX idx_deploy_job (deploy_job), INDEX idx_deploy_job (deploy_job),
INDEX idx_workflow_definition (workflow_definition_id), INDEX idx_workflow_definition (workflow_definition_id),
INDEX idx_target_git_system (target_git_system_id),
CONSTRAINT fk_team_app_team FOREIGN KEY (team_id) REFERENCES deploy_team (id), CONSTRAINT fk_team_app_team FOREIGN KEY (team_id) REFERENCES deploy_team (id),
CONSTRAINT fk_team_app_application FOREIGN KEY (application_id) REFERENCES deploy_application (id) CONSTRAINT fk_team_app_application FOREIGN KEY (application_id) REFERENCES deploy_application (id),
CONSTRAINT fk_team_app_target_git_system FOREIGN KEY (target_git_system_id) REFERENCES sys_external_system (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队应用关联表(包含代码源和部署配置)'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='团队应用关联表(包含代码源和部署配置)';
-- 团队配置表 -- 团队配置表