大声道撒旦

This commit is contained in:
dengqichen 2025-01-14 14:57:21 +08:00
parent a23e7237a2
commit ec79cfa018
7 changed files with 257 additions and 19 deletions

View File

@ -66,7 +66,6 @@ public class JenkinsBaseBuildVariables {
private String jobId;
@SchemaProperty(
title = "Pipeline script",
description = "流水线脚本",
@ -84,8 +83,59 @@ public class JenkinsBaseBuildVariables {
autoComplete = true,
folding = true
),
order = 6
order = 5
)
private String script;
//
// @SchemaProperty(
// title = "绑定三方Git系统",
// description = "请选择三方Git系统",
// required = true,
// dataSource = @SchemaPropertyDataSource(
// type = "api",
// url = "/api/v1/external-system/list?type=GIT",
// valueField = "id",
// labelField = "name"
// ),
// order = 6
// )
// private String gitExternalSystemId;
//
// @SchemaProperty(
// title = "绑定Git项目",
// description = "绑定Git项目",
// required = true,
// dataSource = @SchemaPropertyDataSource(
// type = "api",
// url = "/api/v1/repository-project/list",
// valueField = "repoProjectId",
// labelField = "name",
// dependsOn = {"gitExternalSystemId"},
// params = {
// @SchemaPropertyDataSourceParam(name = "externalSystemId", value = "${gitExternalSystemId}")
// }
// ),
// order = 7
// )
// private String repoProjectId;
//
// @SchemaProperty(
// title = "绑定代码分支",
// description = "请选择代码分支",
// required = true,
// dataSource = @SchemaPropertyDataSource(
// type = "api",
// url = "/api/v1/repository-branch/list",
// valueField = "name",
// labelField = "name",
// dependsOn = {"gitExternalSystemId", "repoProjectId"},
// params = {
// @SchemaPropertyDataSourceParam(name = "externalSystemId", value = "${gitExternalSystemId}"),
// @SchemaPropertyDataSourceParam(name = "repoProjectId", value = "${repoProjectId}")
// }
// ),
// order = 8
// )
// private String branch;
}

View File

@ -21,8 +21,8 @@ import org.hibernate.annotations.Type;
@Table(name = "deploy_app_config")
public class DeployAppConfig extends Entity<Long> {
@Column(name = "branch", nullable = false)
private String branch;
// @Column(name = "branch", nullable = false)
// private String branch;
@Column(name = "build_type", nullable = false)
@Enumerated(EnumType.STRING)

View File

@ -28,6 +28,19 @@ 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.util.Base64;
import java.util.Collections;
@ -103,10 +116,6 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
return new HttpEntity<>(headers);
}
@Override
public ExternalSystemTypeEnum getSystemType() {
return ExternalSystemTypeEnum.JENKINS;
}
@Override
public JenkinsCrumbIssuerResponse getJenkinsCrumbIssue() {
@ -120,6 +129,11 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
@Override
public String buildWithParameters(ExternalSystem externalSystem, String jobName, Map<String, String> parameters) {
try {
// 如果参数中包含PIPELINE_SCRIPT确保Job配置中有该参数
if (parameters.containsKey("PIPELINE_SCRIPT")) {
ensurePipelineScriptParameter(externalSystem, jobName);
}
// 1. 获取Crumb
JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue();
@ -162,6 +176,177 @@ public class JenkinsServiceIntegrationImpl implements IJenkinsServiceIntegration
}
}
/**
* 确保Jenkins Job配置中包含PIPELINE_SCRIPT参数
*/
private void ensurePipelineScriptParameter(ExternalSystem externalSystem, String jobName) {
try {
// 获取 Crumb
JenkinsCrumbIssuerResponse jenkinsCrumbIssue = getJenkinsCrumbIssue();
// 获取Job配置
String configUrl = String.format("%s/job/%s/config.xml", externalSystem.getUrl(), jobName);
HttpHeaders headers = createHeaders(externalSystem);
headers.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
headers.set("Jenkins-Crumb", jenkinsCrumbIssue.getCrumb());
headers.set("Cookie", jenkinsCrumbIssue.getCookie());
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
configUrl,
HttpMethod.GET,
entity,
String.class
);
if (response.getBody() == null) {
throw new RuntimeException("无法获取Jenkins Job配置");
}
// 解析XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
DocumentBuilder builder = factory.newDocumentBuilder();
// 使用UTF-8编码解析XML
InputSource is = new InputSource(new StringReader(response.getBody()));
is.setEncoding("UTF-8");
Document doc = builder.parse(is);
// 检查是否已存在PIPELINE_SCRIPT参数
NodeList parameterDefinitions = doc.getElementsByTagName("parameterDefinitions");
if (parameterDefinitions.getLength() > 0) {
NodeList parameters = parameterDefinitions.item(0).getChildNodes();
for (int i = 0; i < parameters.getLength(); i++) {
Node parameter = parameters.item(i);
if (parameter.getNodeType() == Node.ELEMENT_NODE) {
NodeList parameterChildren = parameter.getChildNodes();
for (int j = 0; j < parameterChildren.getLength(); j++) {
Node child = parameterChildren.item(j);
if ("name".equals(child.getNodeName()) && "PIPELINE_SCRIPT".equals(child.getTextContent())) {
// 参数已存在无需添加
return;
}
}
}
}
}
// 需要添加PIPELINE_SCRIPT参数
Element root = doc.getDocumentElement();
// 获取或创建properties元素
NodeList propertiesList = doc.getElementsByTagName("properties");
Element properties;
if (propertiesList.getLength() == 0) {
properties = doc.createElement("properties");
root.appendChild(properties);
} else {
properties = (Element) propertiesList.item(0);
}
// 获取或创建ParametersDefinitionProperty元素
NodeList paramDefProps = properties.getElementsByTagName("hudson.model.ParametersDefinitionProperty");
Element paramDefProp;
if (paramDefProps.getLength() == 0) {
paramDefProp = doc.createElement("hudson.model.ParametersDefinitionProperty");
properties.appendChild(paramDefProp);
} else {
paramDefProp = (Element) paramDefProps.item(0);
}
// 获取或创建parameterDefinitions元素
NodeList paramDefs = paramDefProp.getElementsByTagName("parameterDefinitions");
Element parameterDefs;
if (paramDefs.getLength() == 0) {
parameterDefs = doc.createElement("parameterDefinitions");
paramDefProp.appendChild(parameterDefs);
} else {
parameterDefs = (Element) paramDefs.item(0);
}
// 创建PIPELINE_SCRIPT参数定义
Element stringParam = doc.createElement("hudson.model.StringParameterDefinition");
Element name = doc.createElement("name");
name.setTextContent("PIPELINE_SCRIPT");
stringParam.appendChild(name);
Element description = doc.createElement("description");
description.setTextContent("Pipeline脚本内容");
stringParam.appendChild(description);
Element defaultValue = doc.createElement("defaultValue");
defaultValue.setTextContent("");
stringParam.appendChild(defaultValue);
Element trim = doc.createElement("trim");
trim.setTextContent("false");
stringParam.appendChild(trim);
parameterDefs.appendChild(stringParam);
// 更新Job配置时设置正确的编码
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(javax.xml.transform.OutputKeys.VERSION, "1.1");
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
transformer.setOutputProperty(javax.xml.transform.OutputKeys.STANDALONE, "no");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
String updatedConfig = writer.toString();
// 更新Job配置
HttpHeaders updateHeaders = createHeaders(externalSystem);
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,
HttpMethod.POST,
updateEntity,
String.class
);
log.info("Successfully added PIPELINE_SCRIPT parameter to Jenkins job: {}", jobName);
} catch (Exception e) {
log.error("Failed to ensure PIPELINE_SCRIPT parameter for Jenkins job: {}, error: {}", jobName, e.getMessage(), e);
throw new RuntimeException("确保Jenkins Job PIPELINE_SCRIPT参数失败", e);
}
}
/**
* 清理XML内容移除无效字符
*/
private String cleanXmlContent(String xml) {
if (xml == null) {
return "";
}
// 移除XML中的无效字符
StringBuilder cleanXml = new StringBuilder();
for (int i = 0; i < xml.length(); i++) {
char c = xml.charAt(i);
// XML 1.1规范允许的字符范围比1.0更宽松
if ((c == 0x9) ||
(c == 0xA) ||
(c == 0xD) ||
((c >= 0x20) && (c <= 0xD7FF)) ||
((c >= 0xE000) && (c <= 0xFFFD)) ||
((c >= 0x10000) && (c <= 0x10FFFF)) ||
// 允许一些常见的控制字符
(c >= 0x1) && (c <= 0x1F)) {
cleanXml.append(c);
}
}
return cleanXml.toString();
}
@Override
public JenkinsQueueBuildInfoResponse getQueuedBuildInfo(String queueId) {
ExternalSystem externalSystem = systemRepository.findById(1L).orElseThrow(() -> new RuntimeException("没有找到三方系统"));

View File

@ -16,12 +16,6 @@ public class RepositoryBranchQuery extends BaseQuery {
@QueryField(field = "name", type = QueryType.LIKE)
private String name;
@QueryField(field = "project_id")
private Long projectId;
@QueryField(field = "external_system_id")
private Long externalSystemId;
@QueryField(field = "is_default_branch")
private Boolean isDefaultBranch;
@ -30,4 +24,13 @@ public class RepositoryBranchQuery extends BaseQuery {
@QueryField(field = "commit_author", type = QueryType.LIKE)
private String commitAuthor;
@QueryField(field = "externalSystemId", type = QueryType.EQUAL)
private Long externalSystemId;
@QueryField(field = "projectId", type = QueryType.EQUAL)
private Long projectId;
@QueryField(field = "repoProjectId", type = QueryType.EQUAL)
private Long repoProjectId;
}

View File

@ -22,15 +22,15 @@ public class RepositoryProjectQuery extends BaseQuery {
@QueryField(field = "visibility")
private String visibility;
@QueryField(field = "externalSystemId")
@QueryField(field = "externalSystemId", type = QueryType.EQUAL)
private Long externalSystemId;
@QueryField(field = "projectId")
@QueryField(field = "projectId", type = QueryType.EQUAL)
private Long projectId;
@QueryField(field = "repoGroupId")
@QueryField(field = "repoGroupId", type = QueryType.EQUAL)
private Long repoGroupId;
@QueryField(field = "repoProjectId")
@QueryField(field = "repoProjectId", type = QueryType.EQUAL)
private Long repoProjectId;
}

View File

@ -62,6 +62,7 @@ public class DeployNodeDelegate extends BaseNodeDelegate<DeployNodePanelVariable
protected void executeInternal(DelegateExecution execution, DeployNodePanelVariables panelVariables, DeployNodeLocalVariables localVariables) {
ExternalSystem externalSystem = externalSystemRepository.findById(localVariables.getExternalSystemId()).orElseThrow(() -> new RuntimeException("ExternalSystem not found!!!"));
JenkinsJob jenkinsJob = jenkinsJobRepository.findById(localVariables.getJobId()).orElseThrow(() -> new RuntimeException("Jenkins job not found!!!"));
// Pipeline脚本模板
Map<String, String> parameters = new HashMap<>();
parameters.put("PIPELINE_SCRIPT", localVariables.getScript());
String queueId = jenkinsServiceIntegration.buildWithParameters(externalSystem, jenkinsJob.getJobName(), parameters);

View File

@ -652,7 +652,6 @@ CREATE TABLE deploy_app_config
form_variables_schema TEXT NULL,
language_type VARCHAR(50) NOT NULL,
workflow_definition_id BIGINT NOT NULL,
branch VARCHAR(50) NOT NULL,
environment_id BIGINT NOT NULL,
application_id BIGINT NOT NULL,