增加构建通知

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转换器
TeamEnvironmentNotificationConfig notificationConfig = notificationConfigMap.get(configKey);
UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO =
notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap);
UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO;
if (notificationConfig != null) {
notificationConfigDTO = notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap);
} else {
// 没有配置时返回默认值开关字段为false
notificationConfigDTO = createDefaultNotificationConfigDTO();
}
dto.setNotificationConfig(notificationConfigDTO);
} else {
dto.setRequiresApproval(false);
dto.setRequireCodeReview(false);
dto.setApprovers(Collections.emptyList());
dto.setNotificationConfig(null);
// 没有配置时返回默认值开关字段为false
dto.setNotificationConfig(createDefaultNotificationConfigDTO());
}
// 构建应用列表
@ -723,6 +729,17 @@ public class DeployServiceImpl implements IDeployService {
|| status == DeployRecordStatusEnums.CREATED;
}
/**
* 创建默认的通知配置DTO开关字段默认为false
*/
private UserTeamEnvironmentNotificationConfigDTO createDefaultNotificationConfigDTO() {
UserTeamEnvironmentNotificationConfigDTO dto = new UserTeamEnvironmentNotificationConfigDTO();
dto.setPreApprovalNotificationEnabled(false);
dto.setBuildNotificationEnabled(false);
dto.setBuildFailureFileEnabled(false);
return dto;
}
@Override
@Transactional
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.IJenkinsSyncHistoryService;
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.INotificationTemplateRepository;
import com.qqchen.deploy.backend.notification.service.INotificationService;
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.EmailSendNotificationRequest;
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
@ -78,6 +83,12 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
@Resource
private INotificationChannelRepository notificationChannelRepository;
@Resource
private INotificationTemplateRepository notificationTemplateRepository;
@Resource
private INotificationService notificationService;
@Resource
private INotificationSendService notificationSendService;
@ -596,7 +607,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
}
/**
* 发送通知
* 发送通知使用模板
*/
private void sendNotification(
TeamEnvironmentNotificationConfig config,
@ -607,88 +618,107 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
ExternalSystem externalSystem) {
try {
// 构建通知内容
StringBuilder content = new StringBuilder();
content.append("### 构建通知\n");
content.append(String.format("> 任务: %s\n", job.getJobName()));
content.append(String.format("> 构建号: #%d\n", build.getBuildNumber()));
// 1. 检查是否配置了构建通知模板
if (config.getBuildNotificationTemplateId() == null) {
log.warn("未配置构建通知模板,跳过通知: teamId={}, envId={}",
config.getTeamId(), config.getEnvironmentId());
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;
switch (status) {
case "SUCCESS":
statusDisplay = "✅ 成功";
break;
case "FAILURE":
statusDisplay = "❌ 失败";
break;
case "BUILDING":
statusDisplay = "🔄 构建中";
break;
default:
statusDisplay = status;
}
content.append(String.format("> 状态: %s\n", statusDisplay));
content.append(String.format("> 时间: %s\n", build.getStarttime()));
String statusDisplay = switch (status) {
case "SUCCESS" -> "✅ 成功";
case "FAILURE" -> "❌ 失败";
case "BUILDING" -> "🔄 构建中";
default -> status;
};
templateParams.put("statusDisplay", statusDisplay);
// 耗时仅结束状态
if (!"BUILDING".equals(status) && build.getDuration() != null) {
// 耗时
if (build.getDuration() != null) {
long seconds = build.getDuration() / 1000;
long minutes = 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());
}
// 构建失败时发送日志文件如果开启
if ("FAILURE".equals(status) && config.getBuildFailureFileEnabled() != null && config.getBuildFailureFileEnabled()) {
// 先发送文本通知
sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString());
// 然后发送日志文件
// 4. 构建 SendNotificationRequest
SendNotificationRequest request = new SendNotificationRequest();
request.setNotificationTemplateId(config.getBuildNotificationTemplateId());
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());
return; // 已发送直接返回
}
// 发送通知
sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString());
log.info("已发送构建通知: job={}, build={}, status={}",
job.getJobName(), build.getBuildNumber(), status);
} catch (Exception 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 {
switch (channel.getChannelType()) {
case WEWORK -> {
WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest();
weworkRequest.setChannelId(channel.getId());
weworkRequest.setContent(title + "\n\n" + content);
weworkRequest.setMessageType(WeworkMessageTypeEnum.MARKDOWN); // 使用Markdown格式
notificationSendService.send(weworkRequest);
if (template.getTemplateConfig() != null) {
WeworkTemplateConfig weworkConfig = JsonUtils.fromMap(
template.getTemplateConfig(), WeworkTemplateConfig.class);
if (weworkConfig != null && weworkConfig.getMessageType() != null) {
return weworkConfig.getMessageType();
}
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) {
log.error("发送通知失败: channelId={}, type={}", channel.getId(), channel.getChannelType(), e);
throw e;
log.warn("解析企业微信模板配置失败,使用默认消息类型: {}", e.getMessage());
}
return WeworkMessageTypeEnum.TEXT;
}
/**