增加生成后端服务代码。

This commit is contained in:
asp_ly 2024-12-28 22:13:37 +08:00
parent 7c8b7dfe2f
commit 7bc5f66967
5 changed files with 530 additions and 4 deletions

View File

@ -1,19 +1,89 @@
package com.qqchen.deploy.backend.deploy.integration; package com.qqchen.deploy.backend.deploy.integration;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus; import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildInfoResponse; import com.qqchen.deploy.backend.deploy.integration.response.*;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsQueueBuildInfoResponse; import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsCrumbIssuerResponse;
import java.util.List;
/**
* Jenkins集成服务接口
*/
public interface IJenkinsServiceIntegration extends IExternalSystemIntegration { public interface IJenkinsServiceIntegration extends IExternalSystemIntegration {
/**
* 测试Jenkins连接
*
* @param system Jenkins系统配置
* @return 连接是否成功
*/
boolean testConnection(ExternalSystem system);
/**
* 获取Jenkins Crumb用于CSRF保护
*
* @return Crumb响应信息
*/
JenkinsCrumbIssuerResponse getJenkinsCrumbIssue(); JenkinsCrumbIssuerResponse getJenkinsCrumbIssue();
/**
* 使用参数触发构建
*
* @return 构建队列ID
*/
String buildWithParameters(); String buildWithParameters();
/**
* 获取队列中的构建信息
*
* @param queueId 队列ID
* @return 队列构建信息
*/
JenkinsQueueBuildInfoResponse getQueuedBuildInfo(String queueId); JenkinsQueueBuildInfoResponse getQueuedBuildInfo(String queueId);
/**
* 获取构建状态
*
* @param jobName 任务名称
* @param buildNumber 构建编号
* @return 构建状态
*/
JenkinsBuildStatus getBuildStatus(String jobName, Integer buildNumber); JenkinsBuildStatus getBuildStatus(String jobName, Integer buildNumber);
/**
* 查询所有视图
*
* @param externalSystem Jenkins系统配置
* @return 视图列表
*/
List<JenkinsViewResponse> listViews(ExternalSystem externalSystem);
/**
* 查询视图下的所有任务
*
* @param externalSystem Jenkins系统配置
* @param viewName 视图名称
* @return 任务列表
*/
List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName);
/**
* 查询任务的构建信息
*
* @param externalSystem Jenkins系统配置
* @param jobName 任务名称
* @return 构建信息列表
*/
List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName);
/**
* 获取系统类型
*
* @return Jenkins系统类型
*/
@Override
default ExternalSystemTypeEnum getSystemType() {
return ExternalSystemTypeEnum.JENKINS;
}
} }

View File

@ -1,14 +1,18 @@
package com.qqchen.deploy.backend.deploy.integration.impl; package com.qqchen.deploy.backend.deploy.integration.impl;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem; import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus; import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus;
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration; import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildInfoResponse; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildInfoResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse;
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.JenkinsQueueBuildInfoResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsCrumbIssuerResponse; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsCrumbIssuerResponse;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsViewResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository; import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum; import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -21,11 +25,14 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Base64; import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j @Slf4j
@ -199,7 +206,7 @@ public class JenkinsServiceIntegration implements IJenkinsServiceIntegration {
} }
public JenkinsCrumbIssuerResponse convertResponse(ResponseEntity<String> response) { public JenkinsCrumbIssuerResponse convertResponse(ResponseEntity<String> response) {
// 1. 应体中解析JSON // 1. <EFBFBD><EFBFBD><EFBFBD>应体中解析JSON
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode; JsonNode jsonNode;
try { try {
@ -218,4 +225,109 @@ public class JenkinsServiceIntegration implements IJenkinsServiceIntegration {
return result; return result;
} }
/**
* 通用的Jenkins API调用方法
*
* @param externalSystem Jenkins系统配置
* @param path API路径
* @param treeQuery tree查询参数
* @param responseClass 响应类型
* @param <T> 响应类型泛型
* @return API响应结果
*/
private <T> List<T> callJenkinsApi(ExternalSystem externalSystem,
String path,
String treeQuery,
String jsonArrayKey,
Class<T> responseClass) {
try {
String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl())
.path(path)
.queryParam("tree", treeQuery)
.build()
.toUriString();
HttpEntity<String> entity = new HttpEntity<>(createHeaders(externalSystem));
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
String.class
);
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
return mapper.convertValue(root.get(jsonArrayKey),
new TypeReference<List<T>>() {
});
}
return Collections.emptyList();
} catch (Exception e) {
log.error("Failed to call Jenkins API: path={}, error={}", path, e.getMessage(), e);
throw new RuntimeException("调用Jenkins API失败: " + path, e);
}
}
/**
* 查询所有视图
*
* @param externalSystem Jenkins系统配置
* @return 视图列表
*/
public List<JenkinsViewResponse> listViews(ExternalSystem externalSystem) {
String treeQuery = "views[name,url,description,_class,primaryView," +
"properties[owner,configurationStatus,filter]," +
"jobs[*,lastBuild[*],lastCompletedBuild[*]]]";
return callJenkinsApi(
externalSystem,
"/api/json",
treeQuery,
"views",
JenkinsViewResponse.class
);
}
/**
* 查询视图下的所有任务
*
* @param externalSystem Jenkins系统配置
* @param viewName 视图名称
* @return 任务列表
*/
public List<JenkinsJobResponse> listJobs(ExternalSystem externalSystem, String viewName) {
String treeQuery = "jobs[name,url,description,_class,buildable,inQueue," +
"keepDependencies,nextBuildNumber,concurrentBuild,disabled," +
"displayName,fullName,color,lastBuild[*],lastCompletedBuild[*]," +
"lastFailedBuild[*],lastSuccessfulBuild[*],lastUnstableBuild[*]," +
"lastUnsuccessfulBuild[*],property[parameterDefinitions[*]]]";
return callJenkinsApi(
externalSystem,
"/view/" + viewName + "/api/json",
treeQuery,
"jobs",
JenkinsJobResponse.class
);
}
/**
* 查询任务的构建信息
*
* @param externalSystem Jenkins系统配置
* @param jobName 任务名称
* @return 构建信息列表
*/
public List<JenkinsBuildResponse> listBuilds(ExternalSystem externalSystem, String jobName) {
String treeQuery = "builds[number,url,result,timestamp,duration,building," +
"description,displayName,fullDisplayName,id,keepLog,queueId," +
"actions[*],changeSets[*],artifacts[*]]";
return callJenkinsApi(
externalSystem,
"/job/" + jobName + "/api/json",
treeQuery,
"builds",
JenkinsBuildResponse.class
);
}
} }

View File

@ -0,0 +1,138 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* Jenkins构建响应对象
*/
@Data
public class JenkinsBuildResponse {
/**
* 构建编号
*/
private Integer number;
/**
* 构建URL
*/
private String url;
/**
* 构建类型
*/
@JsonProperty("_class")
private String buildClass;
/**
* 构建结果
*/
private String result;
/**
* 构建时间戳
*/
private Long timestamp;
/**
* 构建开始时间
*/
private Long startTimeMillis;
/**
* 构建持续时间毫秒
*/
private Long duration;
/**
* 预计持续时间
*/
private Long estimatedDuration;
/**
* 是否正在构建
*/
private Boolean building;
/**
* 构建描述
*/
private String description;
/**
* 显示名称
*/
private String displayName;
/**
* 完整显示名称
*/
private String fullDisplayName;
/**
* 构建ID
*/
private String id;
/**
* 保持永久
*/
private Boolean keepLog;
/**
* 构建队列ID
*/
private Long queueId;
/**
* 构建参数
*/
private List<BuildParameter> actions;
/**
* 构建变更集
*/
private List<ChangeSet> changeSets;
/**
* 构建制品
*/
private List<Artifact> artifacts;
/**
* 构建控制台输出
*/
private String consoleLog;
@Data
public static class BuildParameter {
@JsonProperty("_class")
private String type;
private Map<String, String> parameters;
private Map<String, Object> causes;
}
@Data
public static class ChangeSet {
private String kind;
private List<ChangeSetItem> items;
}
@Data
public static class ChangeSetItem {
private String commitId;
private String author;
private String message;
private Long timestamp;
private List<String> affectedPaths;
}
@Data
public static class Artifact {
private String displayPath;
private String fileName;
private String relativePath;
}
}

View File

@ -0,0 +1,141 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* Jenkins任务响应对象
*/
@Data
public class JenkinsJobResponse {
/**
* 任务名称
*/
private String name;
/**
* 任务URL
*/
private String url;
/**
* 任务描述
*/
private String description;
/**
* 任务类型
*/
@JsonProperty("_class")
private String jobClass;
/**
* 是否可构建
*/
private Boolean buildable;
/**
* 是否在队列中
*/
private Boolean inQueue;
/**
* 是否保持构建
*/
private Boolean keepDependencies;
/**
* 下一个构建号
*/
private Integer nextBuildNumber;
/**
* 并发构建
*/
private Boolean concurrentBuild;
/**
* 禁用原因
*/
private String disabledReason;
/**
* 显示名称
*/
private String displayName;
/**
* 全名
*/
private String fullName;
/**
* 颜色状态
*/
private String color;
/**
* 最后一次构建
*/
@JsonProperty("lastBuild")
private BuildInfo lastBuild;
/**
* 最后一次完成的构建
*/
@JsonProperty("lastCompletedBuild")
private BuildInfo lastCompletedBuild;
/**
* 最后一次失败的构建
*/
@JsonProperty("lastFailedBuild")
private BuildInfo lastFailedBuild;
/**
* 最后一次成功的构建
*/
@JsonProperty("lastSuccessfulBuild")
private BuildInfo lastSuccessfulBuild;
/**
* 最后一次不稳定的构建
*/
@JsonProperty("lastUnstableBuild")
private BuildInfo lastUnstableBuild;
/**
* 最后一次不成功的构建
*/
@JsonProperty("lastUnsuccessfulBuild")
private BuildInfo lastUnsuccessfulBuild;
/**
* 构建参数定义
*/
private List<ParameterDefinition> parameterDefinitions;
@Data
public static class BuildInfo {
private Integer number;
private String url;
}
@Data
public static class ParameterDefinition {
@JsonProperty("_class")
private String type;
private String name;
private String description;
private String defaultValue;
private List<Choice> choices;
}
@Data
public static class Choice {
private String value;
private String name;
}
}

View File

@ -0,0 +1,65 @@
package com.qqchen.deploy.backend.deploy.integration.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* Jenkins视图响应对象
*/
@Data
public class JenkinsViewResponse {
/**
* 视图名称
*/
private String name;
/**
* 视图URL
*/
private String url;
/**
* 视图描述
*/
private String description;
/**
* 视图类型
*/
@JsonProperty("_class")
private String viewClass;
/**
* 是否为主视图
*/
private Boolean isPrimary;
/**
* 视图属性
*/
private Properties properties;
/**
* 视图下的任务
*/
private List<JenkinsJobResponse> jobs;
@Data
public static class Properties {
/**
* 视图所有者
*/
private String owner;
/**
* 视图配置状态
*/
private String configurationStatus;
/**
* 视图过滤器
*/
private String filter;
}
}