增加构建通知

This commit is contained in:
dengqichen 2025-11-27 16:07:38 +08:00
parent 1a5786502a
commit f6569fe020
2 changed files with 110 additions and 63 deletions

View File

@ -492,14 +492,20 @@ public class DeployServiceImpl implements IDeployService {
// 构建通知配置 - 使用MapStruct转换器 // 构建通知配置 - 使用MapStruct转换器
TeamEnvironmentNotificationConfig notificationConfig = notificationConfigMap.get(configKey); TeamEnvironmentNotificationConfig notificationConfig = notificationConfigMap.get(configKey);
UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO = UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO;
notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap); if (notificationConfig != null) {
notificationConfigDTO = notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap);
} else {
// 没有配置时返回默认值开关字段为false
notificationConfigDTO = createDefaultNotificationConfigDTO();
}
dto.setNotificationConfig(notificationConfigDTO); dto.setNotificationConfig(notificationConfigDTO);
} else { } else {
dto.setRequiresApproval(false); dto.setRequiresApproval(false);
dto.setRequireCodeReview(false); dto.setRequireCodeReview(false);
dto.setApprovers(Collections.emptyList()); dto.setApprovers(Collections.emptyList());
dto.setNotificationConfig(null); // 没有配置时返回默认值开关字段为false
dto.setNotificationConfig(createDefaultNotificationConfigDTO());
} }
// 构建应用列表 // 构建应用列表
@ -723,6 +729,17 @@ public class DeployServiceImpl implements IDeployService {
|| status == DeployRecordStatusEnums.CREATED; || status == DeployRecordStatusEnums.CREATED;
} }
/**
* 创建默认的通知配置DTO开关字段默认为false
*/
private UserTeamEnvironmentNotificationConfigDTO createDefaultNotificationConfigDTO() {
UserTeamEnvironmentNotificationConfigDTO dto = new UserTeamEnvironmentNotificationConfigDTO();
dto.setPreApprovalNotificationEnabled(false);
dto.setBuildNotificationEnabled(false);
dto.setBuildFailureFileEnabled(false);
return dto;
}
@Override @Override
@Transactional @Transactional
public DeployResultDTO executeDeploy(DeployExecuteRequest request) { public DeployResultDTO executeDeploy(DeployExecuteRequest request) {

View File

@ -16,8 +16,13 @@ import com.qqchen.deploy.backend.deploy.repository.*;
import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService; import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService;
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService; import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
import com.qqchen.deploy.backend.notification.entity.NotificationChannel; import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
import com.qqchen.deploy.backend.notification.entity.config.WeworkTemplateConfig;
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository; import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository;
import com.qqchen.deploy.backend.notification.service.INotificationService;
import com.qqchen.deploy.backend.notification.service.INotificationSendService; import com.qqchen.deploy.backend.notification.service.INotificationSendService;
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest; import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest; import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest;
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum; import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
@ -78,6 +83,12 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
@Resource @Resource
private INotificationChannelRepository notificationChannelRepository; private INotificationChannelRepository notificationChannelRepository;
@Resource
private INotificationTemplateRepository notificationTemplateRepository;
@Resource
private INotificationService notificationService;
@Resource @Resource
private INotificationSendService notificationSendService; private INotificationSendService notificationSendService;
@ -596,7 +607,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
} }
/** /**
* 发送通知 * 发送通知使用模板
*/ */
private void sendNotification( private void sendNotification(
TeamEnvironmentNotificationConfig config, TeamEnvironmentNotificationConfig config,
@ -607,88 +618,107 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
ExternalSystem externalSystem) { ExternalSystem externalSystem) {
try { try {
// 构建通知内容 // 1. 检查是否配置了构建通知模板
StringBuilder content = new StringBuilder(); if (config.getBuildNotificationTemplateId() == null) {
content.append("### 构建通知\n"); log.warn("未配置构建通知模板,跳过通知: teamId={}, envId={}",
content.append(String.format("> 任务: %s\n", job.getJobName())); config.getTeamId(), config.getEnvironmentId());
content.append(String.format("> 构建号: #%d\n", build.getBuildNumber())); return;
}
// 2. 查询模板
NotificationTemplate template = notificationTemplateRepository
.findById(config.getBuildNotificationTemplateId())
.orElse(null);
if (template == null) {
log.warn("构建通知模板不存在: templateId={}", config.getBuildNotificationTemplateId());
return;
}
// 3. 构建模板参数
Map<String, Object> templateParams = new HashMap<>();
templateParams.put("jobName", job.getJobName());
templateParams.put("buildNumber", build.getBuildNumber());
templateParams.put("buildUrl", build.getBuildUrl());
templateParams.put("status", status);
templateParams.put("startTime", build.getStarttime());
// 状态显示 // 状态显示
String statusDisplay; String statusDisplay = switch (status) {
switch (status) { case "SUCCESS" -> "✅ 成功";
case "SUCCESS": case "FAILURE" -> "❌ 失败";
statusDisplay = "✅ 成功"; case "BUILDING" -> "🔄 构建中";
break; default -> status;
case "FAILURE": };
statusDisplay = "❌ 失败"; templateParams.put("statusDisplay", statusDisplay);
break;
case "BUILDING":
statusDisplay = "🔄 构建中";
break;
default:
statusDisplay = status;
}
content.append(String.format("> 状态: %s\n", statusDisplay));
content.append(String.format("> 时间: %s\n", build.getStarttime()));
// 耗时仅结束状态 // 耗时
if (!"BUILDING".equals(status) && build.getDuration() != null) { if (build.getDuration() != null) {
long seconds = build.getDuration() / 1000; long seconds = build.getDuration() / 1000;
long minutes = seconds / 60; long minutes = seconds / 60;
long secs = seconds % 60; long secs = seconds % 60;
content.append(String.format("> 耗时: %d分%d秒\n", minutes, secs)); templateParams.put("duration", String.format("%d分%d秒", minutes, secs));
templateParams.put("durationMs", build.getDuration());
} }
// 构建失败时发送日志文件如果开启 // 4. 构建 SendNotificationRequest
if ("FAILURE".equals(status) && config.getBuildFailureFileEnabled() != null && config.getBuildFailureFileEnabled()) { SendNotificationRequest request = new SendNotificationRequest();
// 先发送文本通知 request.setNotificationTemplateId(config.getBuildNotificationTemplateId());
sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString()); request.setTemplateParams(templateParams);
request.setSendRequest(createSendRequestByChannel(channel, template));
// 然后发送日志文件
// 5. 发送通知
notificationService.send(request);
log.info("已发送构建通知: job={}, build={}, status={}, templateId={}",
job.getJobName(), build.getBuildNumber(), status, config.getBuildNotificationTemplateId());
// 6. 构建失败时发送日志文件如果开启
if ("FAILURE".equals(status) && Boolean.TRUE.equals(config.getBuildFailureFileEnabled())) {
sendBuildFailureLogFile(externalSystem, channel, job.getJobName(), build.getBuildNumber()); sendBuildFailureLogFile(externalSystem, channel, job.getJobName(), build.getBuildNumber());
return; // 已发送直接返回
} }
// 发送通知
sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString());
log.info("已发送构建通知: job={}, build={}, status={}",
job.getJobName(), build.getBuildNumber(), status);
} catch (Exception e) { } catch (Exception e) {
log.error("发送通知失败: job={}, build={}", job.getJobName(), build.getBuildNumber(), e); log.error("发送通知失败: job={}, build={}", job.getJobName(), build.getBuildNumber(), e);
} }
} }
/** /**
* 根据渠道类型发送通知 * 根据渠道类型创建对应的发送请求
*/ */
private void sendNotificationByChannelType(NotificationChannel channel, String title, String content) { private com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest createSendRequestByChannel(
NotificationChannel channel, NotificationTemplate template) {
switch (channel.getChannelType()) {
case WEWORK:
WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest();
weworkRequest.setChannelId(channel.getId());
weworkRequest.setMessageType(getWeworkMessageType(template));
return weworkRequest;
case EMAIL:
EmailSendNotificationRequest emailRequest = new EmailSendNotificationRequest();
emailRequest.setChannelId(channel.getId());
emailRequest.setToReceivers(Arrays.asList("admin@company.com"));
return emailRequest;
default:
throw new RuntimeException("不支持的渠道类型: " + channel.getChannelType());
}
}
/**
* 从模板配置中获取企业微信消息类型
*/
private WeworkMessageTypeEnum getWeworkMessageType(NotificationTemplate template) {
try { try {
switch (channel.getChannelType()) { if (template.getTemplateConfig() != null) {
case WEWORK -> { WeworkTemplateConfig weworkConfig = JsonUtils.fromMap(
WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest(); template.getTemplateConfig(), WeworkTemplateConfig.class);
weworkRequest.setChannelId(channel.getId()); if (weworkConfig != null && weworkConfig.getMessageType() != null) {
weworkRequest.setContent(title + "\n\n" + content); return weworkConfig.getMessageType();
weworkRequest.setMessageType(WeworkMessageTypeEnum.MARKDOWN); // 使用Markdown格式
notificationSendService.send(weworkRequest);
} }
case EMAIL -> {
EmailSendNotificationRequest emailRequest = new EmailSendNotificationRequest();
emailRequest.setChannelId(channel.getId());
emailRequest.setSubject(title);
emailRequest.setContent(content);
// 这里需要设置收件人但Jenkins构建通知中没有提供
// 实际应该从团队环境配置或其他地方获取
emailRequest.setToReceivers(java.util.Arrays.asList("admin@company.com"));
notificationSendService.send(emailRequest);
}
default -> throw new RuntimeException("不支持的渠道类型: " + channel.getChannelType());
} }
} catch (Exception e) { } catch (Exception e) {
log.error("发送通知失败: channelId={}, type={}", channel.getId(), channel.getChannelType(), e); log.warn("解析企业微信模板配置失败,使用默认消息类型: {}", e.getMessage());
throw e;
} }
return WeworkMessageTypeEnum.TEXT;
} }
/** /**