增加构建通知
This commit is contained in:
parent
123b9054da
commit
3645d8d062
@ -21,13 +21,6 @@ public interface IJenkinsServiceIntegration extends IExternalSystemIntegration {
|
||||
*/
|
||||
boolean testConnection(ExternalSystem system);
|
||||
|
||||
/**
|
||||
* 获取Jenkins Crumb(用于CSRF保护)
|
||||
*
|
||||
* @param externalSystem Jenkins系统配置
|
||||
* @return Crumb响应信息
|
||||
*/
|
||||
JenkinsCrumbIssuerResponse getJenkinsCrumbIssue(ExternalSystem externalSystem);
|
||||
|
||||
/**
|
||||
* 使用参数触发构建
|
||||
|
||||
@ -7,6 +7,7 @@ import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
|
||||
import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus;
|
||||
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
|
||||
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse;
|
||||
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse;
|
||||
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsJobResponse;
|
||||
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsQueueBuildInfoResponse;
|
||||
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsCrumbIssuerResponse;
|
||||
@ -29,18 +30,22 @@ import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
@ -48,6 +53,7 @@ import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -58,14 +64,78 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// Jenkins Crumb缓存 - 线程安全
|
||||
private static final Map<Long, JenkinsCrumbCache> CRUMB_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private static final long CRUMB_EXPIRE_TIME = 25 * 60 * 1000; // 25分钟过期
|
||||
|
||||
/**
|
||||
* Jenkins Crumb缓存内部类
|
||||
*/
|
||||
private static class JenkinsCrumbCache {
|
||||
final JenkinsCrumbIssuerResponse crumb;
|
||||
|
||||
final ExternalSystem decryptedSystem;
|
||||
|
||||
final long expireTime;
|
||||
|
||||
JenkinsCrumbCache(JenkinsCrumbIssuerResponse crumb, ExternalSystem system) {
|
||||
this.crumb = crumb;
|
||||
this.decryptedSystem = system;
|
||||
this.expireTime = System.currentTimeMillis() + CRUMB_EXPIRE_TIME;
|
||||
}
|
||||
|
||||
boolean isExpired() {
|
||||
return System.currentTimeMillis() > expireTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 线程安全地获取Jenkins Crumb缓存
|
||||
* 如果缓存不存在或已过期,会重新获取和解密
|
||||
*/
|
||||
private synchronized JenkinsCrumbCache getCrumbCache(ExternalSystem system) {
|
||||
Long systemId = system.getId();
|
||||
JenkinsCrumbCache cache = CRUMB_CACHE.get(systemId);
|
||||
|
||||
if (cache == null || cache.isExpired()) {
|
||||
log.debug("Jenkins Crumb缓存失效,重新获取: systemId={}", systemId);
|
||||
|
||||
// 解密系统信息(只在这里解密一次)
|
||||
ExternalSystem decryptedSystem = decryptSystem(system);
|
||||
|
||||
// 获取新的crumb
|
||||
JenkinsCrumbIssuerResponse crumb = fetchCrumbFromJenkins(decryptedSystem);
|
||||
|
||||
// 创建新缓存
|
||||
cache = new JenkinsCrumbCache(crumb, decryptedSystem);
|
||||
CRUMB_CACHE.put(systemId, cache);
|
||||
|
||||
log.debug("Jenkins Crumb缓存已更新: systemId={}, expireTime={}", systemId, cache.expireTime);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接从Jenkins服务器获取Crumb(不经过缓存)
|
||||
*/
|
||||
private JenkinsCrumbIssuerResponse fetchCrumbFromJenkins(ExternalSystem decryptedSystem) {
|
||||
String url = decryptedSystem.getUrl() + "/crumbIssuer/api/json";
|
||||
HttpHeaders headers = createBasicHeaders(decryptedSystem);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
return convertResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection(ExternalSystem system) {
|
||||
// 解密系统信息
|
||||
system = decryptSystem(system);
|
||||
|
||||
try {
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String url = system.getUrl() + "/api/json";
|
||||
|
||||
// 创建请求头(内部自动处理解密和crumb)
|
||||
HttpHeaders headers = createHeaders(system);
|
||||
|
||||
// 打印实际发送的请求头
|
||||
@ -88,71 +158,67 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建包含认证信息和Jenkins Crumb的完整请求头
|
||||
* 内部自动处理缓存获取和解密
|
||||
*/
|
||||
private HttpHeaders createHeaders(ExternalSystem system) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
switch (system.getAuthType()) {
|
||||
case BASIC -> {
|
||||
String auth = system.getUsername() + ":" + system.getPassword();
|
||||
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
|
||||
headers.set("Authorization", "Basic " + new String(encodedAuth));
|
||||
// 获取缓存的解密系统和crumb
|
||||
JenkinsCrumbCache cache = getCrumbCache(system);
|
||||
ExternalSystem decryptedSystem = cache.decryptedSystem;
|
||||
JenkinsCrumbIssuerResponse crumb = cache.crumb;
|
||||
|
||||
// 创建基础认证头
|
||||
HttpHeaders headers = createBasicHeaders(decryptedSystem);
|
||||
|
||||
// 自动添加Jenkins Crumb和Cookie(如果存在)
|
||||
if (crumb != null) {
|
||||
if (crumb.getCrumb() != null) {
|
||||
headers.set("Jenkins-Crumb", crumb.getCrumb());
|
||||
}
|
||||
case TOKEN -> headers.set("Authorization", "Bearer " + system.getToken());
|
||||
case OAUTH -> headers.set("Authorization", "Bearer " + system.getToken());
|
||||
if (crumb.getCookie() != null) {
|
||||
headers.set("Cookie", crumb.getCookie());
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
private HttpEntity<String> createHttpEntity(ExternalSystem jenkins) {
|
||||
/**
|
||||
* 创建基础认证头(不包含crumb),用于获取crumb时避免循环依赖
|
||||
*/
|
||||
private HttpHeaders createBasicHeaders(ExternalSystem decryptedSystem) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
// 根据认证类型设置认证信息
|
||||
switch (jenkins.getAuthType()) {
|
||||
switch (decryptedSystem.getAuthType()) {
|
||||
case BASIC -> {
|
||||
// Basic认证
|
||||
String auth = jenkins.getUsername() + ":" + jenkins.getPassword();
|
||||
String auth = decryptedSystem.getUsername() + ":" + decryptedSystem.getPassword();
|
||||
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
|
||||
String authHeader = "Basic " + new String(encodedAuth);
|
||||
headers.set("Authorization", authHeader);
|
||||
headers.set("Authorization", "Basic " + new String(encodedAuth));
|
||||
}
|
||||
case TOKEN -> {
|
||||
// Jenkins API Token认证也使用Basic Auth格式:username:apiToken
|
||||
String auth = jenkins.getUsername() + ":" + jenkins.getToken();
|
||||
String auth = decryptedSystem.getUsername() + ":" + decryptedSystem.getToken();
|
||||
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
|
||||
String authHeader = "Basic " + new String(encodedAuth);
|
||||
headers.set("Authorization", authHeader);
|
||||
headers.set("Authorization", "Basic " + new String(encodedAuth));
|
||||
}
|
||||
default -> throw new RuntimeException("Unsupported authentication type: " + jenkins.getAuthType());
|
||||
default -> throw new RuntimeException("Unsupported authentication type: " + decryptedSystem.getAuthType());
|
||||
}
|
||||
|
||||
// 设置接受JSON响应
|
||||
headers.set("Accept", "application/json");
|
||||
|
||||
return new HttpEntity<>(headers);
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JenkinsCrumbIssuerResponse getJenkinsCrumbIssue(ExternalSystem externalSystem) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
String url = externalSystem.getUrl() + "/crumbIssuer/api/json";
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
return convertResponse(restTemplate.exchange(url, HttpMethod.GET, entity, String.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildWithParameters(ExternalSystem externalSystem, String jobName, Map<String, String> parameters) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
try {
|
||||
// 如果参数中包含PIPELINE_SCRIPT,确保Job配置中有该参数
|
||||
if (parameters.containsKey("PIPELINE_SCRIPT")) {
|
||||
ensurePipelineScriptParameter(externalSystem, jobName);
|
||||
}
|
||||
|
||||
// 1. 获取Crumb
|
||||
JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue(externalSystem);
|
||||
|
||||
// 2. 构建URL
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
||||
.path("/job/")
|
||||
.path(jobName)
|
||||
@ -160,11 +226,9 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
// 3. 构建请求头
|
||||
// 创建请求头(自动包含认证和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
|
||||
headers.set("Cookie", jenkinsCrumbIssue.getCookie());
|
||||
|
||||
// 4. 构建请求体
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
@ -196,20 +260,15 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
*/
|
||||
private void ensurePipelineScriptParameter(ExternalSystem externalSystem, String jobName) {
|
||||
try {
|
||||
// 获取 Crumb
|
||||
JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue(externalSystem);
|
||||
|
||||
// 获取Job配置
|
||||
// 直接使用原始系统信息构建Job配置URL(URL不需要解密)
|
||||
String configUrl = String.format("%s/job/%s/config.xml", externalSystem.getUrl(), jobName);
|
||||
|
||||
// 创建请求头(自动包含认证和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
// 设置请求和响应的字符编码
|
||||
headers.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
|
||||
headers.set(HttpHeaders.CONTENT_TYPE, "application/xml;charset=UTF-8");
|
||||
headers.setAcceptCharset(Collections.singletonList(Charset.forName("UTF-8")));
|
||||
|
||||
headers.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
|
||||
headers.set("Cookie", jenkinsCrumbIssue.getCookie());
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
// 配置RestTemplate,确保使用UTF-8编码
|
||||
@ -327,8 +386,6 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
updateHeaders.setContentType(MediaType.APPLICATION_XML);
|
||||
updateHeaders.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
|
||||
updateHeaders.set("Content-Type", "application/xml; charset=utf-8");
|
||||
updateHeaders.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
|
||||
updateHeaders.set("Cookie", jenkinsCrumbIssue.getCookie());
|
||||
HttpEntity<String> updateEntity = new HttpEntity<>(updatedConfig, updateHeaders);
|
||||
restTemplate.exchange(
|
||||
configUrl,
|
||||
@ -373,9 +430,14 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
|
||||
@Override
|
||||
public JenkinsQueueBuildInfoResponse getQueuedBuildInfo(ExternalSystem externalSystem, String queueId) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String queueUrl = String.format("%s/queue/item/%s/api/json", externalSystem.getUrl().trim(), queueId);
|
||||
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(queueUrl, HttpMethod.GET, createHttpEntity(externalSystem), new ParameterizedTypeReference<>() {
|
||||
|
||||
// 创建请求头(内部自动处理解密和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(queueUrl, HttpMethod.GET, entity, new ParameterizedTypeReference<>() {
|
||||
});
|
||||
|
||||
Map<String, Object> queueInfo = response.getBody();
|
||||
@ -404,13 +466,18 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
|
||||
@Override
|
||||
public JenkinsBuildStatus getBuildStatus(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
try {
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String url = String.format("%s/job/%s/%d/api/json", externalSystem.getUrl().trim(), jobName, buildNumber);
|
||||
|
||||
// 创建请求头(内部自动处理解密和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
createHttpEntity(externalSystem),
|
||||
entity,
|
||||
new ParameterizedTypeReference<>() {
|
||||
}
|
||||
);
|
||||
@ -435,13 +502,13 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
|
||||
@Override
|
||||
public JenkinsBuildResponse getBuildDetails(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
try {
|
||||
// 构建 tree 参数,只获取我们需要的字段
|
||||
String treeQuery = "number,url,result,duration,timestamp,building," +
|
||||
"changeSets[items[commitId,author,message]]," +
|
||||
"artifacts[fileName,relativePath,displayPath]";
|
||||
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
||||
.path("/job/")
|
||||
.path(jobName)
|
||||
@ -452,7 +519,9 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>(createHeaders(externalSystem));
|
||||
// 创建请求头(自动包含认证和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
@ -563,10 +632,9 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
* @return 视图列表
|
||||
*/
|
||||
public List<JenkinsViewResponse> listViews(ExternalSystem externalSystem) {
|
||||
final ExternalSystem decryptedSystem = decryptSystem(externalSystem);
|
||||
String treeQuery = "views[name,url,description,_class]";
|
||||
List<JenkinsViewResponse> views = callJenkinsApi(
|
||||
decryptedSystem,
|
||||
externalSystem,
|
||||
"/api/json",
|
||||
treeQuery,
|
||||
"views",
|
||||
@ -574,7 +642,7 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
);
|
||||
|
||||
// 过滤和清洗数据
|
||||
final String baseUrl = StringUtils.removeEnd(decryptedSystem.getUrl(), "/");
|
||||
final String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/");
|
||||
return views.stream()
|
||||
.filter(view -> !"all".equalsIgnoreCase(view.getName()))
|
||||
.peek(view -> {
|
||||
@ -598,7 +666,6 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
* @return 任务列表
|
||||
*/
|
||||
public List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
// 只查询必要的字段,确保包含lastBuild的timestamp字段
|
||||
String treeQuery = "jobs[name,url,description,buildable,nextBuildNumber," +
|
||||
"lastBuild[number,timestamp,result],color]";
|
||||
@ -632,9 +699,8 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
|
||||
@Override
|
||||
public JenkinsJobResponse job(ExternalSystem externalSystem, String jobName) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
try {
|
||||
// 1. 构建请求URL
|
||||
// 直接使用原始系统信息构建URL(URL不需要解密)
|
||||
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
||||
.path("/job/")
|
||||
.path(jobName)
|
||||
@ -681,7 +747,6 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
* @return 构建信息列表
|
||||
*/
|
||||
public List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName) {
|
||||
externalSystem = decryptSystem(externalSystem);
|
||||
// Jenkins API 默认只返回最近的若干个构建,通过 {from,to} 可以指定范围
|
||||
String treeQuery = "builds[number,url,result,timestamp,duration,building,actions[_class,parameters[_class,name,value]]]";
|
||||
List<JenkinsBuildResponse> builds = callJenkinsApi(
|
||||
@ -703,18 +768,13 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse getConsoleOutput(
|
||||
ExternalSystem externalSystem,
|
||||
String jobName,
|
||||
Integer buildNumber,
|
||||
Long startOffset) {
|
||||
public JenkinsConsoleOutputResponse getConsoleOutput(ExternalSystem externalSystem, String jobName, Integer buildNumber, Long startOffset) {
|
||||
try {
|
||||
if (startOffset == null) {
|
||||
startOffset = 0L;
|
||||
}
|
||||
|
||||
// 构建 Jenkins Progressive Text API URL
|
||||
// Jenkins API: /job/{jobName}/{buildNumber}/logText/progressiveText?start={offset}
|
||||
// 直接使用原始系统信息构建 Jenkins Progressive Text API URL(URL不需要解密)
|
||||
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
|
||||
.path("/job/")
|
||||
.path(jobName)
|
||||
@ -725,7 +785,7 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
// 发送请求
|
||||
// 创建请求头(自动包含认证和crumb)
|
||||
HttpHeaders headers = createHeaders(externalSystem);
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
@ -738,8 +798,7 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
);
|
||||
|
||||
// 解析响应
|
||||
com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse result =
|
||||
new com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse();
|
||||
JenkinsConsoleOutputResponse result = new JenkinsConsoleOutputResponse();
|
||||
|
||||
// 从响应体获取日志内容(按行分割)
|
||||
String logContent = response.getBody();
|
||||
@ -767,12 +826,10 @@ public class JenkinsServiceIntegrationImpl extends BaseExternalSystemIntegration
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to get Jenkins console output: job={}, build={}, offset={}, error={}",
|
||||
jobName, buildNumber, startOffset, e.getMessage(), e);
|
||||
log.error("Failed to get Jenkins console output: job={}, build={}, offset={}, error={}", jobName, buildNumber, startOffset, e.getMessage(), e);
|
||||
|
||||
// 返回空结果而不是抛异常,避免中断轮询
|
||||
com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse emptyResult =
|
||||
new com.qqchen.deploy.backend.deploy.integration.response.JenkinsConsoleOutputResponse();
|
||||
JenkinsConsoleOutputResponse emptyResult = new JenkinsConsoleOutputResponse();
|
||||
emptyResult.setLines(Collections.emptyList());
|
||||
emptyResult.setNextOffset(startOffset);
|
||||
emptyResult.setHasMoreData(false);
|
||||
|
||||
@ -43,8 +43,6 @@ public class JenkinsBuildDelegate extends BaseNodeDelegate<JenkinsBuildInputMapp
|
||||
@Resource
|
||||
private IExternalSystemRepository externalSystemRepository;
|
||||
|
||||
@Resource
|
||||
private IJenkinsJobRepository jenkinsJobRepository;
|
||||
|
||||
@Resource
|
||||
private IWorkflowNodeLogService workflowNodeLogService;
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
package com.qqchen.deploy.backend.workflow.delegate;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
|
||||
import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
|
||||
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.enums.WeworkMessageTypeEnum;
|
||||
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.workflow.dto.inputmapping.NotificationInputMapping;
|
||||
import com.qqchen.deploy.backend.workflow.dto.outputs.NotificationOutputs;
|
||||
@ -34,6 +38,9 @@ public class NotificationNodeDelegate extends BaseNodeDelegate<NotificationInput
|
||||
@Resource
|
||||
private INotificationChannelRepository notificationChannelRepository;
|
||||
|
||||
@Resource
|
||||
private INotificationTemplateRepository notificationTemplateRepository;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(DelegateExecution execution, Map<String, Object> configs, NotificationInputMapping input) {
|
||||
// 1. 参数校验
|
||||
@ -42,21 +49,22 @@ public class NotificationNodeDelegate extends BaseNodeDelegate<NotificationInput
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 2. 查询渠道信息(仅用于确定渠道类型)
|
||||
NotificationChannel channel = notificationChannelRepository.findById(input.getChannelId())
|
||||
.orElseThrow(() -> new RuntimeException("通知渠道不存在: " + input.getChannelId()));
|
||||
// 2. 查询渠道和模板信息
|
||||
NotificationChannel channel = notificationChannelRepository.findById(input.getChannelId()).orElseThrow(() -> new RuntimeException("通知渠道不存在: " + input.getChannelId()));
|
||||
NotificationTemplate template = notificationTemplateRepository.findById(input.getNotificationTemplateId()).orElseThrow(() -> new RuntimeException("通知模板不存在: " + input.getNotificationTemplateId()));
|
||||
|
||||
// 3. 构建SendNotificationRequest
|
||||
SendNotificationRequest request = new SendNotificationRequest();
|
||||
request.setNotificationTemplateId(input.getNotificationTemplateId());
|
||||
request.setTemplateParams(execution.getVariables());
|
||||
|
||||
// 4. 根据渠道类型创建基础的sendRequest(具体配置由NotificationService处理)
|
||||
// 4. 根据渠道类型创建sendRequest,并从模板配置中获取参数
|
||||
switch (channel.getChannelType()) {
|
||||
case WEWORK -> {
|
||||
WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest();
|
||||
weworkRequest.setChannelId(input.getChannelId());
|
||||
// 其他配置(消息类型等)由NotificationService根据模板配置自动设置
|
||||
// 从模板配置中获取消息类型
|
||||
weworkRequest.setMessageType(getWeworkMessageType(template));
|
||||
request.setSendRequest(weworkRequest);
|
||||
}
|
||||
case EMAIL -> {
|
||||
@ -81,6 +89,24 @@ public class NotificationNodeDelegate extends BaseNodeDelegate<NotificationInput
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从模板配置中获取企业微信消息类型
|
||||
*/
|
||||
private WeworkMessageTypeEnum getWeworkMessageType(NotificationTemplate template) {
|
||||
try {
|
||||
if (template.getTemplateConfig() != null) {
|
||||
WeworkTemplateConfig weworkConfig = JsonUtils.fromMap(template.getTemplateConfig(), WeworkTemplateConfig.class);
|
||||
if (weworkConfig != null && weworkConfig.getMessageType() != null) {
|
||||
return weworkConfig.getMessageType();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析企业微信模板配置失败,使用默认消息类型: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 默认使用TEXT类型
|
||||
return WeworkMessageTypeEnum.TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件收件人列表
|
||||
|
||||
Loading…
Reference in New Issue
Block a user