Merge remote-tracking branch 'origin/master'

This commit is contained in:
HopeLi 2025-07-11 17:52:03 +08:00
commit 8a4854554c
75 changed files with 3127 additions and 419 deletions

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cd.casic.boot</groupId>
<artifactId>modules</artifactId>
<version>${revision}</version>
</parent>
<artifactId>module-ci-machine</artifactId>
<packaging>jar</packaging>
<version>${revision}</version>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>cd.casic.boot</groupId>
<artifactId>commons</artifactId>
</dependency>
<dependency>
<groupId>cd.casic.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.antherd</groupId>
<artifactId>sm-crypto</artifactId>
<version>0.3.2.1-RELEASE</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,37 @@
package cd.casic.module.machine.contants;
import cd.casic.framework.commons.exception.ErrorCode;
/**
* 机器报错
*/
public interface MachineErrorCodeConstants {
// ========== 机器基础信息模块 1-003-000-000 ==========
ErrorCode MACHINE_INFO_NULL = new ErrorCode(1_003_000_000, "机器信息为空");
ErrorCode MACHINE_INFO_HOST_IP_NULL = new ErrorCode(1_003_000_001, "机器主机IP为空");
ErrorCode MACHINE_INFO_USER_NAME_NULL = new ErrorCode(1_003_000_002, "机器用户名为空");
ErrorCode MACHINE_INFO_TYPE_NULL = new ErrorCode(1_003_000_003, "机器类型为空");
ErrorCode MACHINE_INFO_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_004, "机器类型不存在");
ErrorCode MACHINE_INFO_TAG_NULL = new ErrorCode(1_003_000_005, "机器唯一标识为空");
ErrorCode MACHINE_INFO_TAG_EXISTS = new ErrorCode(1_003_000_006, "机器唯一标识已存在");
ErrorCode MACHINE_INFO_AUTHENTICATION_TYPE_NULL = new ErrorCode(1_003_000_007, "机器认证类型为空");
ErrorCode MACHINE_INFO_AUTHENTICATION_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_008, "机器认证类型不存在");
ErrorCode MACHINE_ENABLE = new ErrorCode(1_003_000_009, "机器启用中");
// ========== 机器环境变量模块 1-003-002-000 ==========
ErrorCode MACHINE_ENV_NULL = new ErrorCode(1_003_002_000, "机器环境变量为空");
ErrorCode MACHINE_ENV_NOT_EXISTS = new ErrorCode(1_003_002_001, "机器不存在");
ErrorCode MACHINE_ENV_KEY_ILLEGAL = new ErrorCode(1_003_002_002, "机器环境变量键不合法");
// ========== 机器代理模块 1-003-003-000 ==========
ErrorCode MACHINE_PROXY_HOST_IP_NULL = new ErrorCode(1_003_003_000, "机器代理主机地址为空");
ErrorCode MACHINE_PROXY_USER_NAME_NULL = new ErrorCode(1_003_003_001, "机器代理用户名为空");
ErrorCode MACHINE_PROXY_NOT_EXISTS = new ErrorCode(1_003_003_002, "机器代理不存在");
ErrorCode MACHINE_PROXY_TYPE_NOT_EXISTS = new ErrorCode(1_003_003_003, "机器代理类型不存在");
ErrorCode MACHINE_PROXY_IS_ONLINE = new ErrorCode(1_003_003_004, "机器代理在线,不能删除");
// ========== 密钥模块 1-003-004-000 ==========
ErrorCode SECRET_KEY_NULL = new ErrorCode(1_003_004_000, "密钥为空");
ErrorCode SECRET_KEY_NOT_EXISTS = new ErrorCode(1_003_004_001, "密钥不存在");
ErrorCode ENCRYPT_OR_DECRYPT_FAIL = new ErrorCode(1_003_004_002, "加密/解密失败");
}

View File

@ -0,0 +1,84 @@
package cd.casic.module.machine.controller;
import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.module.machine.dal.dataobject.MachineEnvDO;
import cd.casic.module.machine.service.MachineEnvService;
import cd.casic.module.machine.controller.vo.MachineEnvVO;
import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import static cd.casic.framework.commons.pojo.CommonResult.success;
/**
* 环境变量控制器
*/
@Tag(name = "环境变量管理")
@RestController
@RequestMapping("/ci/machineEnv")
@Validated
public class MachineEnvController {
@Resource
private MachineEnvService machineEnvService;
@PostMapping("/create")
@Operation(summary = "新增环境变量")
@PreAuthorize("@ss.hasPermission('ci:machineEnv:create')")
public CommonResult<Long> createEnv(@Valid @RequestBody MachineEnvVO machineEnvVO) {
Long id = machineEnvService.createEnv(machineEnvVO);
return success(id);
}
@PutMapping("/update")
@Operation(summary = "修改环境变量")
@PreAuthorize("@ss.hasPermission('ci:machineEnv:update')")
public CommonResult<Boolean> updateEnv(@Valid @RequestBody MachineEnvVO machineEnvVO) {
machineEnvService.updateEnv(machineEnvVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除机器的环境变量")
@PreAuthorize("@ss.hasPermission('ci:machineEnv:delete')")
public CommonResult<Boolean> deleteEnv(@RequestParam("id") Long id) {
machineEnvService.deleteEnv(id);
return success(true);
}
@DeleteMapping("/deleteList")
@Operation(summary = "批量删除机器环境变量")
@PreAuthorize("@ss.hasPermission('ci:machineEnv:delete')")
public CommonResult<Boolean> deleteEnvList(@RequestParam("ids") String ids) {
machineEnvService.deleteEnvList(ids);
return success(true);
}
@GetMapping("/getEnv")
@Operation(summary = "获取机器的环境变量")
public CommonResult<MachineEnvVO> getEnv(@RequestParam("id") Long id) {
MachineEnvVO machineEnvVO = machineEnvService.getEnv(id);
return success(machineEnvVO);
}
@PostMapping("/list")
@Operation(summary = "获取环境变量列表")
public CommonResult<PageResult<MachineEnvVO>> getEnvPage(@Valid @RequestBody MachineEnvVO machineEnvVO) {
PageResult<MachineEnvDO> pageResult = machineEnvService.getEnvPage(machineEnvVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal()));
}
return success(BeanUtils.toBean(pageResult, MachineEnvVO.class));
}
}

View File

@ -0,0 +1,83 @@
package cd.casic.module.machine.controller;
import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.service.MachineInfoService;
import cd.casic.module.machine.controller.vo.MachineInfoVO;
import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static cd.casic.framework.commons.pojo.CommonResult.success;
@RestController
@Tag(name = "机器信息管理")
@RequestMapping("/ci/machineInfo")
@Validated
public class MachineInfoController {
@Resource
private MachineInfoService machineInfoService;
@PostMapping("/create")
@Operation(summary = "新增机器信息")
// @PreAuthorize("@ss.hasPermission('ci:machineInfo:create')")
public CommonResult<Long> createMachine(@Valid @RequestBody MachineInfoVO machineInfoVO) {
Long id = machineInfoService.createMachine(machineInfoVO);
return success(id);
}
@PutMapping("/update")
@Operation(summary = "编辑机器信息")
// @PreAuthorize("@ss.hasPermission('ci:machineInfo:update')")
public CommonResult<Boolean> updateMachineInfo(@Valid @RequestBody MachineInfoVO machineInfoVO) {
machineInfoService.updateMachineInfo(machineInfoVO);
return success(true);
}
@PutMapping("/updateStatus")
@Operation(summary = "机器启用/停用")
// @PreAuthorize("@ss.hasPermission('ci:machineInfo:status')")
public CommonResult<Integer> updateStatus(@Valid @RequestBody MachineInfoVO machineInfoVO) {
Integer newStatus = machineInfoService.updateStatus(machineInfoVO);
return success(newStatus);
}
@PostMapping("/list")
@Operation(summary = "获取机器信息列表")
public CommonResult<PageResult<MachineInfoVO>> list(@Valid @RequestBody MachineInfoVO machineInfoVO) {
PageResult<MachineInfoDO> pageResult = machineInfoService.listMachineInfo(machineInfoVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal()));
}
return success(BeanUtils.toBean(pageResult, MachineInfoVO.class));
}
@DeleteMapping("/delete")
@Operation(summary = "机器信息删除")
// @PreAuthorize("@ss.hasPermission('ci:machineInfo:delete')")
public CommonResult<Boolean> deleteMachineInfo(@RequestParam("machineInfoId") Long machineInfoId) {
machineInfoService.deleteMachineInfo(machineInfoId);
return success(true);
}
@DeleteMapping("/deleteList")
@Operation(summary = "批量删除机器信息")
// @PreAuthorize("@ss.hasPermission('ci:machineInfo:delete')")
public CommonResult<Boolean> deleteMachineInfoList(@RequestParam("machineInfoIds") String ids) {
machineInfoService.deleteMachineInfoList(ids);
return success(true);
}
@PutMapping("/bindingSecretKey")
@Operation(summary = "绑定/解绑密钥")
public void bindingSecretKey(@RequestBody SecretKeyVO secretKeyVO) {
machineInfoService.bindingSecretKey(secretKeyVO);
}
}

View File

@ -0,0 +1,81 @@
package cd.casic.module.machine.controller;
import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.module.machine.controller.vo.MachineProxyVO;
import cd.casic.module.machine.dal.dataobject.MachineProxyDO;
import cd.casic.module.machine.service.MachineProxyService;
import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import static cd.casic.framework.commons.pojo.CommonResult.success;
/**
* 机器代理控制器
*/
@RestController
@RequestMapping("/ci/machineProxy")
@Tag(name = "机器代理管理")
@Validated
public class MachineProxyController {
@Resource
private MachineProxyService machineProxyService;
@PostMapping("/create")
@Operation(summary = "注册新的机器代理")
// @PreAuthorize("@ss.hasPermission('ci:machineProxy:create')")
public CommonResult<Long> createProxy(@Valid @RequestBody MachineProxyVO machineProxyVO) {
Long id = machineProxyService.createProxy(machineProxyVO);
return success(id);
}
@PutMapping("/update")
@Operation(summary = "修改代理")
// @PreAuthorize("@ss.hasPermission('ci:machineProxy:update')")
public CommonResult<Boolean> updateProxy(@Valid @RequestBody MachineProxyVO machineProxyVO) {
machineProxyService.updateProxy(machineProxyVO);
return success(true);
}
@PostMapping("/list")
@Operation(summary = "获取代理列表")
public CommonResult<PageResult<MachineProxyVO>> getProxyPage(@Valid @RequestBody MachineProxyVO machineProxyVO) {
PageResult<MachineProxyDO> pageResult = machineProxyService.getProxyPage(machineProxyVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal()));
}
return success(BeanUtils.toBean(pageResult, MachineProxyVO.class));
}
@GetMapping("/allStatus")
@Operation(summary = "获取所有代理的状态统计")
public CommonResult<Map<Integer, Long>> getStatusStatistics() {
return success(machineProxyService.getAllProxyStatus());
}
@DeleteMapping("delete")
@Operation(summary = "删除代理")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
machineProxyService.delete(id);
return success(true);
}
@DeleteMapping("/deleteList")
@Operation(summary = "批量删除代理")
// @PreAuthorize("@ss.hasPermission('ci:machineProxy:delete')")
public CommonResult<Boolean> deleteProxyList(@RequestParam String ids) {
machineProxyService.deleteProxyList(ids);
return success(true);
}
}

View File

@ -0,0 +1,76 @@
package cd.casic.module.machine.controller;
import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
import cd.casic.module.machine.service.SecretKeyService;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static cd.casic.framework.commons.pojo.CommonResult.success;
@RestController
@RequestMapping("/ci/secretKey")
@Tag(name = "密钥管理")
@Validated
public class SecretKeyController {
@Resource
private SecretKeyService secretKeyService;
@PostMapping(value = "/create")
@Operation(summary = "新增密钥")
// @PreAuthorize("@ss.hasPermission('ci:secretKey:create')")
public CommonResult<Long> createSecretKey(@Valid @RequestBody SecretKeyVO secretKeyVO) {
Long secretKeyId = secretKeyService.createSecretKey(secretKeyVO);
return success(secretKeyId);
}
@PutMapping("/update")
@Operation(summary = "编辑密钥信息")
// @PreAuthorize("@ss.hasPermission('ci:secretKey:update')")
public CommonResult<Boolean> updateSecretKey(@Valid @RequestBody SecretKeyVO secretKeyVO) {
secretKeyService.updateSecretKey(secretKeyVO);
return success(true);
}
@GetMapping("/getBindMachine")
@Operation(summary = "获取密钥绑定的机器列表")
public CommonResult<List<MachineInfoDO>> getBindMachine(@RequestParam Long secretKeyId) {
return success(secretKeyService.getBindMachine(secretKeyId));
}
@GetMapping("/getSecretKey")
@Operation(summary = "获取机器的密钥")
public CommonResult<SecretKeyVO> getSecretKey(@RequestParam("id") Long id) {
SecretKeyVO secretKeyVO = secretKeyService.getSecretKey(id);
return success(secretKeyVO);
}
@DeleteMapping("/deleteList")
@Operation(summary = "批量删除密钥")
// @PreAuthorize("@ss.hasPermission('ci:secretKey:delete')")
public CommonResult<Boolean> deleteSecretKeyList(@RequestParam("ids") List<Long> ids) {
secretKeyService.deleteSecretKeyList(ids);
return success(true);
}
@PostMapping("/list")
@Operation(summary = "获取密钥信息列表")
public CommonResult<PageResult<SecretKeyVO>> getSecretKeyPage(@Valid @RequestBody SecretKeyVO secretKeyVO) {
PageResult<SecretKeyDO> pageResult = secretKeyService.getSecretKeyPage(secretKeyVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal()));
}
return success(BeanUtils.toBean(pageResult, SecretKeyVO.class));
}
}

View File

@ -0,0 +1,38 @@
package cd.casic.module.machine.controller.vo;
import cd.casic.framework.commons.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
@EqualsAndHashCode(callSuper = true)
@Schema(description = "管理后台 - 机器环境变量信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true) // 添加链式调用支持
public class MachineEnvVO extends PageParam {
@Schema(description = "环境变量ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "环境变量键", requiredMode = Schema.RequiredMode.REQUIRED, example = "JAVA_HOME")
private String envKey;
@Schema(description = "环境变量值", requiredMode = Schema.RequiredMode.REQUIRED, example = "/usr/java/jdk1.8.0_271")
private String envValue;
@Schema(description = "环境变量描述", example = "Java运行环境路径")
private String description;
@Schema(description = "关联的机器ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long machineId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-15T10:30:00")
private LocalDateTime createTime;
@Schema(description = "更新时间", example = "2023-06-15T10:30:00")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,64 @@
package cd.casic.module.machine.controller.vo;
import cd.casic.framework.commons.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Schema(description = "管理后台 - 机器信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class MachineInfoVO extends PageParam {
@Schema(description = "机器ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-15T10:30:00")
private Date createTime;
@Schema(description = "更新时间", example = "2023-06-15T10:30:00")
private Date updateTime;
@Schema(description = "机器名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "server-01")
private String name;
@Schema(description = "机器标签,唯一标识", example = "production,web-server")
private String tag;
@Schema(description = "主机IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.100")
private String hostIp;
@Schema(description = "机器描述", example = "生产环境Web服务器")
private String description;
@Schema(description = "登录用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
private String username;
@Schema(description = "机器状态", example = "online,offline,maintenance")
private Integer status = -1;
@Schema(description = "SSH端口", example = "22")
private Integer sshPort;
@Schema(description = "登录密码", example = "******")
private String password;
@Schema(description = "密钥ID", example = "5")
private Long secretKeyId;
@Schema(description = "代理ID", example = "101")
private Long machineProxyId;
@Schema(description = "认证类型", example = "password,key")
private Integer authenticationType ;
@Schema(description = "机器信息类型", example = "Linux,Windows")
private Integer machineInfoType;
}

View File

@ -0,0 +1,52 @@
package cd.casic.module.machine.controller.vo;
import cd.casic.framework.commons.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 机器代理信息 Response VO")
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class MachineProxyVO extends PageParam {
@Schema(description = "代理ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
private String username;
@Schema(description = "代理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "HTTP")
private Integer proxyType = -1;
@Schema(description = "版本号", example = "1.0.0")
private String version;
@Schema(description = "状态ONLINE:在线OFFLINE:离线)", requiredMode = Schema.RequiredMode.REQUIRED, example = "ONLINE")
private int status = -1;
@Schema(description = "描述信息", example = "用于生产环境的代理服务器")
private String description;
@Schema(description = "主机IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.100")
private String hostIp;
@Schema(description = "SSH端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "22")
private String sshPort;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-15T10:30:00")
private LocalDateTime createTime;
@Schema(description = "更新时间", example = "2023-06-15T10:30:00")
private LocalDateTime updateTime;
@Schema(description = "密码", example = "******")
private String password;
}

View File

@ -0,0 +1,48 @@
package cd.casic.module.machine.controller.vo;
import cd.casic.framework.commons.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Schema(description = "管理后台 - 密钥信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true) // 添加链式调用支持
public class SecretKeyVO extends PageParam {
@Schema(description = "密钥ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "密钥名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "生产环境密钥")
private String name;
@Schema(description = "密钥描述", example = "用于加密敏感数据的密钥")
private String description;
@Schema(description = "密钥密码", example = "******")
private String password;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-15T10:30:00")
private LocalDateTime createTime;
@Schema(description = "更新时间", example = "2023-06-15T10:30:00")
private LocalDateTime updateTime;
@Schema(description = "关联的机器ID列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024, 2048]")
private List<Long> machineInfoIds;
@Schema(description = "私钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "******")
private String privateKey;
@Schema(description = "公钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "******")
private String publicKey;
@Schema(description = "绑定/解绑密钥",example = "true")
private Boolean enableBind;
}

View File

@ -0,0 +1,57 @@
package cd.casic.module.machine.dal.dataobject;
import cd.casic.framework.commons.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.*;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 环境变量实体类
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("machine_env")
public class MachineEnvDO extends BaseDO {
/**
* 环境变量id
*/
@TableId
private Long id;
/**
* 机器ID唯一关联
*/
private Long machineId;
/**
* 环境变量键
*/
private String envKey;
/**
* 环境变量值
*/
private String envValue;
/**
* 描述信息
*/
private String description;
}

View File

@ -0,0 +1,71 @@
package cd.casic.module.machine.dal.dataobject;
import cd.casic.framework.commons.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "machine_info")
public class MachineInfoDO extends BaseDO {
/**
* 机器id
*/
@TableId
private Long id;
@TableField(value = "name")
private String name;
/**
* 机器唯一标识
*/
@TableField(value = "tag")
private String tag;
@TableField(value = "host_ip")
private String hostIp;
@TableField(value = "description")
private String description;
//1Linux 2Windows
@TableField(value = "machine_info_type")
private Integer machineInfoType;
// 1启用 0停用
@TableField(value = "status")
private Integer status;
//用户名
@TableField(value = "username")
private String username;
//SSH端口号
@TableField(value = "ssh_port")
private Integer sshPort;
@TableField(value = "password")
private String password;
@TableField(value = "secret_key_id")
private Long secretKeyId;
@TableField(value = "machine_proxy_id")
private Long machineProxyId;
//1密码认证 2密钥认证
@TableField(value = "authentication_type")
private Integer authenticationType;
}

View File

@ -0,0 +1,56 @@
package cd.casic.module.machine.dal.dataobject;
import cd.casic.framework.commons.dataobject.BaseDO;
import cd.casic.module.machine.enums.MachineProxyStatus;
import com.baomidou.mybatisplus.annotation.*;
import cd.casic.module.machine.enums.MachineProxyType;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 机器代理实体类
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("machine_proxy")
public class MachineProxyDO extends BaseDO {
/**
* 代理id
*/
@TableId
private Long id;
@TableField(value = "host_ip")
private String hostIp;
@TableField(value = "ssh_port")
private String sshPort;
@TableField(value = "proxy_type")
private int proxyType;
@TableField(value = "version")
private String version;
@TableField(value = "status")
private int status;
@TableField(value = "username")
private String username;
@TableField(value = "password")
private String password;
@TableField(value = "description")
private String description;
}

View File

@ -0,0 +1,44 @@
package cd.casic.module.machine.dal.dataobject;
import cd.casic.framework.commons.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "machine_secret_key")
public class SecretKeyDO extends BaseDO {
/**
* 密钥id
*/
@TableId
private Long id;
@TableField(value = "name")
private String name;
@TableField(value = "description")
private String description;
//密钥密码
@TableField(value = "password")
private String password;
// @TableField(value = "public_key")
private String publicKey;
// @TableField(value = "private_key")
private String privateKey;
}

View File

@ -0,0 +1,26 @@
package cd.casic.module.machine.dal.model;
/**
* 基于SM2的秘钥对
* 本项目中配置的自己使用可根据自己的需求进行更换
*
*/
public class Keypair {
/**
* 公钥
*/
public static String PUBLIC_KEY = "04298364ec840088475eae92a591e01284d1abefcda348b47eb324bb521bb03b0b2a5bc393f6b71dabb8f15c99a0050818b56b23f31743b93df9cf8948f15ddb54";
/**
* 私钥
*/
public static String PRIVATE_KEY = "3037723d47292171677ec8bd7dc9af696c7472bc5f251b2cec07e65fdef22e25";
/**
* SM4的对称秘钥生产环境需要改成自己使用的
* 16 进制字符串要求为 128 比特
*/
public static String KEY = "0123456789abcdeffedcba9876543210";
}

View File

@ -0,0 +1,27 @@
package cd.casic.module.machine.dal.mysql;
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
import cd.casic.module.machine.controller.vo.MachineEnvVO;
import cd.casic.module.machine.dal.dataobject.MachineEnvDO;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
/**
* 环境变量Mapper接口
*/
@Mapper
public interface MachineEnvMapper extends BaseMapperX<MachineEnvDO> {
default PageResult<MachineEnvDO> selectPage(MachineEnvVO machineEnvVO) {
LambdaQueryWrapperX<MachineEnvDO> machineEnvDOLambdaQueryWrapperX = new LambdaQueryWrapperX<MachineEnvDO>()
.likeIfPresent(MachineEnvDO::getEnvKey, machineEnvVO.getEnvKey())
.likeIfPresent(MachineEnvDO::getDescription, machineEnvVO.getDescription());
if (machineEnvVO.getMachineId() != null && machineEnvVO.getMachineId() > 0) {
machineEnvDOLambdaQueryWrapperX.eqIfPresent(MachineEnvDO::getMachineId, machineEnvVO.getMachineId());
}
return selectPage(machineEnvVO, machineEnvDOLambdaQueryWrapperX);
}
}

View File

@ -0,0 +1,56 @@
package cd.casic.module.machine.dal.mysql;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
import cd.casic.module.machine.controller.vo.MachineInfoVO;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MachineInfoMapper extends BaseMapperX<MachineInfoDO> {
default Boolean existsByTag(String tag) {
return selectOne(new QueryWrapper<MachineInfoDO>().eq("tag", tag)) != null;
}
default void updateStatus(Long machineInfoId, Integer status) {
UpdateWrapper<MachineInfoDO> set = new UpdateWrapper<>();
set.eq("id", machineInfoId).set("status", status);
this.update(null, set);
}
default void bindingSecretKey(List<Long> machineInfoIds, Long secretKeyId,Boolean enableBind) {
UpdateWrapper<MachineInfoDO> wrapper = new UpdateWrapper<>();
wrapper.in("id", machineInfoIds);
if (enableBind){
wrapper.set("secret_key_id", secretKeyId);// 匹配 ID 集合
}else {
wrapper.set("secret_key_id", null);
}
this.update(null, wrapper);
}
default PageResult<MachineInfoDO> selectPage(MachineInfoVO machineInfoVO) {
LambdaQueryWrapperX<MachineInfoDO> machineInfoDOLambdaQueryWrapperX = new LambdaQueryWrapperX<MachineInfoDO>()
.likeIfPresent(MachineInfoDO::getName, machineInfoVO.getName())
.likeIfPresent(MachineInfoDO::getTag, machineInfoVO.getTag())
.likeIfPresent(MachineInfoDO::getDescription, machineInfoVO.getDescription())
.likeIfPresent(MachineInfoDO::getUsername, machineInfoVO.getUsername())
.likeIfPresent(MachineInfoDO::getHostIp, machineInfoVO.getHostIp());
if (machineInfoVO.getStatus() != -1) {
machineInfoDOLambdaQueryWrapperX.eqIfPresent(MachineInfoDO::getStatus, machineInfoVO.getStatus());
}
return selectPage(machineInfoVO, machineInfoDOLambdaQueryWrapperX);
}
default List<MachineInfoDO> selectBindMachineBySecretKey(Long secretKeyId) {
LambdaQueryWrapperX<MachineInfoDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<MachineInfoDO>()
.eq(MachineInfoDO::getSecretKeyId, secretKeyId);
return selectList(lambdaQueryWrapperX);
}
}

View File

@ -0,0 +1,29 @@
package cd.casic.module.machine.dal.mysql;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
import cd.casic.module.machine.controller.vo.MachineProxyVO;
import cd.casic.module.machine.dal.dataobject.MachineProxyDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 机器代理Mapper接口
*/
@Mapper
public interface MachineProxyMapper extends BaseMapperX<MachineProxyDO> {
default PageResult<MachineProxyDO> selectPage(MachineProxyVO machineProxyVO) {
LambdaQueryWrapperX<MachineProxyDO> machineProxyDOLambdaQueryWrapperX = new LambdaQueryWrapperX<MachineProxyDO>()
.eqIfPresent(MachineProxyDO::getHostIp, machineProxyVO.getHostIp())
.likeIfPresent(MachineProxyDO::getDescription, machineProxyVO.getDescription());
if (machineProxyVO.getStatus() != -1) {
machineProxyDOLambdaQueryWrapperX.eqIfPresent(MachineProxyDO::getStatus, machineProxyVO.getStatus());
}
if (machineProxyVO.getProxyType() != -1) {
machineProxyDOLambdaQueryWrapperX.eqIfPresent(MachineProxyDO::getProxyType, machineProxyVO.getProxyType());
}
return selectPage(machineProxyVO, machineProxyDOLambdaQueryWrapperX);
}
}

View File

@ -0,0 +1,18 @@
package cd.casic.module.machine.dal.mysql;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SecretKeyMapper extends BaseMapperX<SecretKeyDO> {
//查询列表
default PageResult<SecretKeyDO> selectPage(SecretKeyVO secretKeyVO) {
return selectPage(secretKeyVO, new LambdaQueryWrapperX<SecretKeyDO>()
.likeIfPresent(SecretKeyDO::getName, secretKeyVO.getName())
.likeIfPresent(SecretKeyDO::getDescription, secretKeyVO.getDescription()));
}
}

View File

@ -0,0 +1,25 @@
package cd.casic.module.machine.enums;
import cd.casic.framework.commons.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum AuthenticationType implements IntArrayValuable {
PASSWORD(1,"密码认证"),
SECRET_KEY(2,"密钥认证");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AuthenticationType::getCode).toArray();
private final int code;
private final String message;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,24 @@
package cd.casic.module.machine.enums;
import cd.casic.framework.commons.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum MachineInfoStatus implements IntArrayValuable {
ENABLE(1, "启用"),
UN_ENABLE(0, "停用");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MachineInfoStatus::getCode).toArray();
private final int code;
private final String message;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,24 @@
package cd.casic.module.machine.enums;
import cd.casic.framework.commons.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum MachineInfoType implements IntArrayValuable {
Linux(1,"Linux"),
WINDOWS(2,"Windows");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MachineInfoType::getCode).toArray();
private final int code;
private final String message;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,33 @@
package cd.casic.module.machine.enums;
import cd.casic.framework.commons.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
@Getter
@AllArgsConstructor
public enum MachineProxyStatus implements IntArrayValuable {
/**
* 代理状态 (online, offline, installing, updating, error)
*/
ONLINE(1, "online"),
OFFLINE(2, "offline"),
INSTALLING(3, "installing"),
UPDATING(4, "updating"),
ERROR(5, "error");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MachineProxyStatus::getCode).toArray();
private final int code;
private final String message;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,31 @@
package cd.casic.module.machine.enums;
import cd.casic.framework.commons.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum MachineProxyType implements IntArrayValuable {
HTTP(1, "http"),
SOCKS4(2, "socks4"),
SOCKS5(3, "socks5");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MachineProxyType::getCode).toArray();
/**
* 状态值
*/
private final Integer code;
/**
* 状态名
*/
private final String message;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,45 @@
package cd.casic.module.machine.service;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.controller.vo.MachineEnvVO;
import cd.casic.module.machine.dal.dataobject.MachineEnvDO;
import jakarta.validation.Valid;
/**
* 环境变量服务接口
*/
public interface MachineEnvService {
/**
* 创建或更新机器的环境变量一对一关系
*/
Long createEnv(@Valid MachineEnvVO machineEnvVO);
/**
* 删除机器的环境变量
*/
void deleteEnv(Long machineEvnId);
/**
* 获取机器的环境变量
*
* @param machineId 机器ID
* @return 环境变量DTO
*/
MachineEnvVO getEnv(Long machineId);
/**
* @return 环境变量列表
*/
PageResult<MachineEnvDO> getEnvPage(@Valid MachineEnvVO machineEnvVO);
/**
* 批量删除
*/
void deleteEnvList(String ids);
/*
* 修改环境变量
*/
void updateEnv(@Valid MachineEnvVO machineEnvVO);
}

View File

@ -0,0 +1,69 @@
package cd.casic.module.machine.service;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.controller.vo.MachineInfoVO;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import jakarta.validation.Valid;
import java.util.List;
public interface MachineInfoService {
/**
* 新增机器
*
* @return 新增机器的id
*/
Long createMachine(MachineInfoVO MachineInfoVO);
/**
* 查看机器列表
*
* @return 机器列表
*/
PageResult<MachineInfoDO> listMachineInfo(@Valid MachineInfoVO MachineInfoVO);
/**
* 更新机器信息
*/
void updateMachineInfo(@Valid MachineInfoVO machineInfoVO);
/**
* 变更机器状态
*/
Integer updateStatus(@Valid MachineInfoVO machineInfoVO);
/**
* 绑定密钥
*/
void bindingSecretKey(SecretKeyVO secretKeyVO);
/**
* 批量删除机器
*
* @param machineInfoIds 机器id列表
*/
void deleteMachineInfoList(String machineInfoIds);
/**
* 删除机器信息
*
* @param machineInfoId 机器id
*/
void deleteMachineInfo(Long machineInfoId);
/**
* 获取绑定的密钥
*
* @param secretKeyId 密钥id
* @return 绑定的机器列表
*/
List<MachineInfoDO> selectBindMachineBySecretKey(Long secretKeyId);
/**
* 验证机器是否存在
*
* @param id 机器id
*/
MachineInfoDO validateMachineInfoExists(Long id);
}

View File

@ -0,0 +1,49 @@
package cd.casic.module.machine.service;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.controller.vo.MachineProxyVO;
import cd.casic.module.machine.dal.dataobject.MachineProxyDO;
import jakarta.validation.Valid;
import java.util.Map;
/**
* 机器代理服务接口
*/
public interface MachineProxyService {
/**
* 注册新的机器代理
*/
Long createProxy(@Valid MachineProxyVO machineProxyVO);
/**
* 更新代理状态
*/
void updateProxy(@Valid MachineProxyVO machineProxyVO);
/**
* 删除代理
*
*/
void delete(Long id);
/**
* 获取所有代理的状态统计
*
* @return 状态统计Map
*/
Map<Integer, Long> getAllProxyStatus();
/**
* 批量删除代理
*
* @param proxyIds 代理ID列表
*/
void deleteProxyList(String proxyIds);
/**
* 获取代理列表(分页)
*/
PageResult<MachineProxyDO> getProxyPage(@Valid MachineProxyVO machineProxyVO);
}

View File

@ -0,0 +1,48 @@
package cd.casic.module.machine.service;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import jakarta.validation.Valid;
import java.util.List;
public interface SecretKeyService {
/**
* 新增密钥
*/
Long createSecretKey(@Valid SecretKeyVO secretKeyVO);
/**
* 更新密钥
*/
void updateSecretKey(@Valid SecretKeyVO secretKeyVO);
/**
* 获取密钥列表(分页)
*/
PageResult<SecretKeyDO> getSecretKeyPage(@Valid SecretKeyVO secretKeyVO);
/**
* 批量删除密钥
* @param ids 密钥id集合
*/
void deleteSecretKeyList(List<Long> ids);
/**
* 根据id获取密钥对象
*/
SecretKeyVO getSecretKey(Long id);
/**
* 获取绑定的密钥的机器列表
*/
List<MachineInfoDO> getBindMachine(Long secretKeyId);
/**
* 获取公钥内容
*/
String getPublicKeyContent(Long secretKeyId);
}

View File

@ -0,0 +1,105 @@
package cd.casic.module.machine.service.impl;
import cd.casic.module.machine.controller.vo.MachineEnvVO;
import cd.casic.module.machine.dal.dataobject.MachineEnvDO;
import cd.casic.module.machine.dal.mysql.MachineEnvMapper;
import cd.casic.module.machine.service.MachineEnvService;
import cd.casic.framework.commons.pojo.PageResult;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cd.casic.framework.commons.util.object.BeanUtils;
import java.util.Arrays;
import java.util.List;
import static cd.casic.framework.commons.exception.util.ServiceExceptionUtil.exception;
import static cd.casic.module.machine.contants.MachineErrorCodeConstants.*;
/**
* 环境变量服务实现类
*/
@Service("machineEnvService")
public class MachineEnvServiceImpl implements MachineEnvService {
@Resource
private MachineEnvMapper machineEnvMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createEnv(MachineEnvVO machineEnvVO) {
validateMachineEnvAdd(machineEnvVO);
// 检查键是否合法
validateKey(machineEnvVO.getEnvKey());
MachineEnvDO machineEnvDO = BeanUtils.toBean(machineEnvVO, MachineEnvDO.class);
machineEnvMapper.insert(machineEnvDO);
return machineEnvDO.getId();
}
@Override
public void deleteEnv(Long machineEvnId) {
machineEnvMapper.deleteById(machineEvnId);
}
@Override
public MachineEnvVO getEnv(Long machineId) {
MachineEnvDO machineEnvDO = validateMachineEnvExists(machineId);
return BeanUtils.toBean(machineEnvDO, MachineEnvVO.class);
}
@Override
public PageResult<MachineEnvDO> getEnvPage(MachineEnvVO machineEnvVO) {
return machineEnvMapper.selectPage(machineEnvVO);
}
@Override
public void deleteEnvList(String ids) {
//ids转换为List,使用流
List<Long> machineEnvIds = Arrays.stream(ids.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(Long::parseLong)
.toList();
machineEnvMapper.deleteBatchIds(machineEnvIds);
}
@Override
public void updateEnv(MachineEnvVO machineEnvVO) {
MachineEnvDO machineEnvDO = validateMachineEnvExists(machineEnvVO.getId());
BeanUtils.copyProperties(machineEnvVO, machineEnvDO);
machineEnvMapper.updateById(machineEnvDO);
}
@VisibleForTesting
MachineEnvDO validateMachineEnvExists(Long id) {
if (id == null) {
return null;
}
MachineEnvDO machineEnvDO = machineEnvMapper.selectById(id);
if (machineEnvDO == null) {
throw exception(MACHINE_ENV_NOT_EXISTS);
}
return machineEnvDO;
}
@VisibleForTesting
void validateMachineEnvAdd(MachineEnvVO machineEnvVO) {
if (machineEnvVO.getEnvKey() == null || machineEnvVO.getEnvValue() == null) {
throw exception(MACHINE_ENV_NULL);
}
}
// 检查环境变量键是否合法
@VisibleForTesting
private void validateKey(String key) {
if (!key.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")) {
throw exception(MACHINE_ENV_KEY_ILLEGAL);
}
}
}

View File

@ -0,0 +1,176 @@
package cd.casic.module.machine.service.impl;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cd.casic.module.machine.enums.AuthenticationType;
import cd.casic.module.machine.enums.MachineInfoType;
import cd.casic.module.machine.dal.mysql.MachineInfoMapper;
import cd.casic.module.machine.controller.vo.MachineInfoVO;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.enums.MachineInfoStatus;
import cd.casic.module.machine.service.MachineInfoService;
import cd.casic.module.machine.service.SecretKeyService;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import cd.casic.framework.commons.util.object.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import static cd.casic.framework.commons.exception.util.ServiceExceptionUtil.exception;
import static cd.casic.module.machine.contants.MachineErrorCodeConstants.*;
/**
* 机器信息服务实现类
*/
@Slf4j
@Service("machineInfoToService")
public class MachineInfoServiceImpl implements MachineInfoService {
@Resource
private SecretKeyService secretKeyService;
@Resource
private MachineInfoMapper machineInfoMapper;
@Override
public Long createMachine(MachineInfoVO machineInfoVO) {
validateMachineEnvAdd(machineInfoVO);
validateMachineTagUnique(machineInfoVO.getTag());
MachineInfoDO machineInfoDO = BeanUtils.toBean(machineInfoVO, MachineInfoDO.class);
if (machineInfoVO.getAuthenticationType() == 2) {
Long secretKeyId = machineInfoDO.getSecretKeyId();
SecretKeyVO secretKey = secretKeyService.getSecretKey(secretKeyId);
if (secretKey == null) {
throw exception(SECRET_KEY_NOT_EXISTS);
}
}
machineInfoMapper.insert(machineInfoDO);
return machineInfoDO.getId();
}
@Override
public void updateMachineInfo(MachineInfoVO machineInfoVO) {
validateMachineEnvAdd(machineInfoVO);
String newTag = machineInfoVO.getTag();
MachineInfoDO machineInfoDO = validateMachineInfoExists(machineInfoVO.getId());
String oldTag = machineInfoDO.getTag();
if (!newTag.equals(oldTag)) {
validateMachineTagUnique(newTag);
}
BeanUtils.copyProperties(machineInfoVO, machineInfoDO);
machineInfoMapper.updateById(machineInfoDO);
}
@Override
public Integer updateStatus(MachineInfoVO machineInfoVO) {
machineInfoMapper.updateStatus(machineInfoVO.getId(), machineInfoVO.getStatus());
return machineInfoVO.getStatus();
}
@Override
public PageResult<MachineInfoDO> listMachineInfo(MachineInfoVO machineInfoVO) {
return machineInfoMapper.selectPage(machineInfoVO);
}
@Override
public void bindingSecretKey(SecretKeyVO secretKeyVO) {
machineInfoMapper.bindingSecretKey(secretKeyVO.getMachineInfoIds(), secretKeyVO.getId(), secretKeyVO.getEnableBind());
}
@Override
@Transactional//其中一个在线那么就回滚
public void deleteMachineInfoList(String machineInfoIds) {
List<Long> machineInfoIdList = Arrays.stream(machineInfoIds.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(Long::parseLong)
.toList();
machineInfoIdList.forEach(this::deleteMachineInfo);
}
@Override
public void deleteMachineInfo(Long machineInfoId) {
MachineInfoDO machineInfoDO = validateMachineInfoExists(machineInfoId);
validateMachineEnable(machineInfoDO);
machineInfoMapper.deleteById(machineInfoId);
}
@Override
public List<MachineInfoDO> selectBindMachineBySecretKey(Long secretKeyId) {
return machineInfoMapper.selectBindMachineBySecretKey(secretKeyId);
}
@VisibleForTesting
void validateMachineEnvAdd(MachineInfoVO machineInfoVO) {
if (machineInfoVO.getHostIp().isEmpty()) {
throw exception(MACHINE_INFO_HOST_IP_NULL);
}
if (machineInfoVO.getUsername().isEmpty()) {
throw exception(MACHINE_INFO_USER_NAME_NULL);
}
if (machineInfoVO.getTag().isEmpty()) {
throw exception(MACHINE_INFO_TAG_NULL);
}
if (machineInfoVO.getAuthenticationType() != null) {
boolean flag = true;
for (int type : AuthenticationType.ARRAYS) {
if (type == machineInfoVO.getAuthenticationType()) {
flag = false;
break;
}
}
if (flag) {
throw exception(MACHINE_INFO_AUTHENTICATION_TYPE_NOT_EXISTS);
}
} else {
throw exception(MACHINE_INFO_AUTHENTICATION_TYPE_NULL);
}
if (machineInfoVO.getMachineInfoType() != null) {
boolean flag = true;
for (int type : MachineInfoType.ARRAYS) {
if (type == machineInfoVO.getMachineInfoType()) {
flag = false;
break;
}
}
if (flag) {
throw exception(MACHINE_INFO_TYPE_NOT_EXISTS);
}
} else {
throw exception(MACHINE_INFO_TYPE_NULL);
}
}
@VisibleForTesting
void validateMachineTagUnique(String tag) {
if (machineInfoMapper.existsByTag(tag)) {
throw exception(MACHINE_INFO_TAG_EXISTS);
}
}
@Override
public MachineInfoDO validateMachineInfoExists(Long id) {
if (id == null) {
throw exception(MACHINE_INFO_NULL);
}
MachineInfoDO machineInfoDO = machineInfoMapper.selectById(id);
if (machineInfoDO == null) {
throw exception(MACHINE_INFO_NULL);
}
return machineInfoDO;
}
@VisibleForTesting
void validateMachineEnable(MachineInfoDO machineInfoDO) {
if (machineInfoDO.getStatus() == MachineInfoStatus.ENABLE.getCode()) {
throw exception(MACHINE_ENABLE);
}
}
}

View File

@ -0,0 +1,131 @@
package cd.casic.module.machine.service.impl;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.module.machine.controller.vo.MachineProxyVO;
import cd.casic.module.machine.dal.dataobject.MachineProxyDO;
import cd.casic.module.machine.enums.MachineProxyStatus;
import cd.casic.module.machine.enums.MachineProxyType;
import cd.casic.module.machine.dal.mysql.MachineProxyMapper;
import cd.casic.module.machine.service.MachineProxyService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import cd.casic.framework.commons.util.object.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cd.casic.framework.commons.exception.util.ServiceExceptionUtil.exception;
import static cd.casic.module.machine.contants.MachineErrorCodeConstants.*;
import static com.baomidou.mybatisplus.extension.toolkit.Db.save;
/**
* 机器代理服务实现类
*/
@Service("machineProxyService")
public class MachineProxyServiceImpl implements MachineProxyService {
@Resource
private MachineProxyMapper machineProxyMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createProxy(MachineProxyVO machineProxyVO) {
validateMachineProxyAdd(machineProxyVO);
// 创建代理记录
MachineProxyDO machineProxyDO = BeanUtils.toBean(machineProxyVO, MachineProxyDO.class);
save(machineProxyDO);
return machineProxyDO.getId();
}
@Override
public void updateProxy(MachineProxyVO machineProxyVO) {
// 参数校验
MachineProxyDO machineProxyDO = validateMachineProxyExists(machineProxyVO.getId());
// 更新状态
BeanUtils.copyProperties(machineProxyVO, machineProxyDO);
machineProxyMapper.updateById(machineProxyDO);
}
@Override
public void delete(Long id) {
MachineProxyDO machineProxyDO = validateMachineProxyExists(id);
validateMachineProxyOnline(machineProxyDO);
machineProxyMapper.deleteById(id);
}
@VisibleForTesting
void validateMachineProxyOnline(MachineProxyDO machineProxyDO) {
if (machineProxyDO.getStatus() == MachineProxyStatus.ONLINE.getCode()) {
throw exception(MACHINE_PROXY_IS_ONLINE);
}
}
@Override
public Map<Integer, Long> getAllProxyStatus() {
List<MachineProxyDO> proxyList = machineProxyMapper.selectList(new QueryWrapper<>());
if (CollectionUtils.isEmpty(proxyList)) {
return Collections.emptyMap();
}
return proxyList.stream()
.map(MachineProxyDO::getStatus)
.collect(Collectors.groupingBy(
Function.identity(),
// 统计每个分组的元素数量
Collectors.counting()
));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteProxyList(String ids) {
if (ids == null) {
return;
}
List<Long> machineProxyIds = Arrays.stream(ids.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(Long::parseLong)
.toList();
// 批量逻辑删除
machineProxyIds.forEach(this::delete);
}
@Override
public PageResult<MachineProxyDO> getProxyPage(MachineProxyVO machineProxyVO) {
return machineProxyMapper.selectPage(machineProxyVO);
}
@VisibleForTesting
MachineProxyDO validateMachineProxyExists(Long id) {
if (id == null) {
throw exception(MACHINE_PROXY_NOT_EXISTS);
}
MachineProxyDO machineProxyDO = machineProxyMapper.selectById(id);
if (machineProxyDO == null) {
throw exception(MACHINE_PROXY_NOT_EXISTS);
}
return machineProxyDO;
}
@VisibleForTesting
void validateMachineProxyAdd(MachineProxyVO machineProxyVO) {
if (machineProxyVO.getHostIp() == null) {
throw exception(MACHINE_PROXY_HOST_IP_NULL);
}
if (machineProxyVO.getUsername() == null) {
throw exception(MACHINE_PROXY_USER_NAME_NULL);
}
// 校验代理类型
int[] arrays = MachineProxyType.ARRAYS;
if (Arrays.stream(arrays).filter(i -> i == machineProxyVO.getProxyType()).findAny().isEmpty()) {
throw exception(MACHINE_PROXY_TYPE_NOT_EXISTS);
}
}
}

View File

@ -0,0 +1,111 @@
package cd.casic.module.machine.service.impl;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.module.machine.controller.vo.SecretKeyVO;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
import cd.casic.module.machine.dal.mysql.SecretKeyMapper;
import cd.casic.module.machine.service.MachineInfoService;
import cd.casic.module.machine.service.SecretKeyService;
import cd.casic.module.machine.utils.CryptogramUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.script.ScriptException;
import java.util.List;
import java.util.Objects;
import static cd.casic.framework.commons.exception.util.ServiceExceptionUtil.exception;
import static cd.casic.module.machine.contants.MachineErrorCodeConstants.*;
/**
* 密钥服务实现类
*/
@Service("secretKeyService")
public class SecretKeyServiceImpl implements SecretKeyService {
@Resource
private MachineInfoService machineInfoService;
@Resource
private SecretKeyMapper secretKeyMapper;
@Override
public SecretKeyVO getSecretKey(Long id) {
SecretKeyDO secretKeyDO = validateSecretKeyExists(id);
return BeanUtils.toBean(secretKeyDO, SecretKeyVO.class);
}
@Override
public List<MachineInfoDO> getBindMachine(Long secretKeyId) {
return machineInfoService.selectBindMachineBySecretKey(secretKeyId);
}
@Override
public String getPublicKeyContent(Long secretKeyId) {
return secretKeyMapper.selectById(secretKeyId).getPublicKey();
}
@Override
public Long createSecretKey(SecretKeyVO secretKeyVO) {
validateSecretKeyAdd(secretKeyVO);
SecretKeyDO secretKeyDO = BeanUtils.toBean(secretKeyVO, SecretKeyDO.class);
try {
//密码加密
secretKeyDO.setPassword(CryptogramUtil.doEncrypt(secretKeyVO.getPassword()));
//公钥加密
secretKeyDO.setPublicKey(CryptogramUtil.doEncrypt(secretKeyVO.getPublicKey()));
} catch (ScriptException e) {
throw exception(ENCRYPT_OR_DECRYPT_FAIL);
}
secretKeyMapper.insert(secretKeyDO);
return secretKeyDO.getId();
}
@Override
public void updateSecretKey(SecretKeyVO secretKeyVO) {
SecretKeyDO secretKeyDO = validateSecretKeyExists(secretKeyVO.getId());
BeanUtils.copyProperties(secretKeyVO, secretKeyDO);
secretKeyMapper.updateById(secretKeyDO);
}
@Override
@Transactional
public void deleteSecretKeyList(List<Long> ids) {
SecretKeyVO secretKeyVO = new SecretKeyVO()
.setMachineInfoIds(ids)
.setEnableBind(false);
machineInfoService.bindingSecretKey(secretKeyVO);
secretKeyMapper.deleteBatchIds(ids);
}
@Override
public PageResult<SecretKeyDO> getSecretKeyPage(SecretKeyVO secretKeyVO) {
return secretKeyMapper.selectPage(secretKeyVO, new LambdaQueryWrapper<SecretKeyDO>()
.like(Objects.nonNull(secretKeyVO.getName()), SecretKeyDO::getName, secretKeyVO.getName())
.like(Objects.nonNull(secretKeyVO.getDescription()), SecretKeyDO::getDescription, secretKeyVO.getDescription()));
}
@VisibleForTesting
void validateSecretKeyAdd(SecretKeyVO secretKeyVO) {
if (secretKeyVO == null) {
throw exception(SECRET_KEY_NULL);
}
}
@VisibleForTesting
SecretKeyDO validateSecretKeyExists(Long id) {
if (id == null) {
throw exception(SECRET_KEY_NOT_EXISTS);
}
SecretKeyDO secretKeyDO = secretKeyMapper.selectById(id);
if (secretKeyDO == null) {
throw exception(SECRET_KEY_NOT_EXISTS);
}
return secretKeyDO;
}
}

View File

@ -0,0 +1,111 @@
package cd.casic.module.machine.utils;
import cd.casic.module.machine.dal.model.Keypair;
import cn.hutool.log.Log;
import com.antherd.smcrypto.sm2.Sm2;
import com.antherd.smcrypto.sm3.Sm3;
import com.antherd.smcrypto.sm4.Sm4;
import com.antherd.smcrypto.sm4.Sm4Options;
import javax.script.ScriptException;
public class CryptogramUtil {
private static final Log log = Log.get();
/**
* 加密方法Sm2 的专门针对前后端分离非对称秘钥对的方式暴露出去的公钥对传输过程中的密码加个密
*
* @param str 待加密数据
* @return 加密后的密文
* @author yubaoshan
*/
public static String doSm2Encrypt(String str) throws ScriptException {
return Sm2.doEncrypt(str, Keypair.PUBLIC_KEY);
}
/**
* 解密方法
* 如果采用加密机的方法用try catch 捕捉异常返回原文值即可
*
* @param str 密文
* @return 解密后的明文
* @author yubaoshan
*/
public static String doSm2Decrypt(String str) throws ScriptException {
// 解密
return Sm2.doDecrypt(str, Keypair.PRIVATE_KEY);
}
/**
* 加密方法
*
* @param str 待加密数据
* @return 加密后的密文
* @author yubaoshan
*/
public static String doEncrypt(String str) throws ScriptException {
// SM4 加密 cbc模式
Sm4Options sm4Options4 = new Sm4Options();
sm4Options4.setMode("cbc");
sm4Options4.setIv("fedcba98765432100123456789abcdef");
return Sm4.encrypt(str, Keypair.KEY, sm4Options4);
}
/**
* 解密方法
* 如果采用加密机的方法用try catch 捕捉异常返回原文值即可
*
* @param str 密文
* @return 解密后的明文
* @author yubaoshan
*/
public static String doDecrypt(String str) throws ScriptException {
// 解密cbc 模式输出 utf8 字符串
Sm4Options sm4Options8 = new Sm4Options();
sm4Options8.setMode("cbc");
sm4Options8.setIv("fedcba98765432100123456789abcdef");
String docString = Sm4.decrypt(str, Keypair.KEY, sm4Options8);
if (docString.isEmpty()) {
log.warn(">>> 字段解密失败,返回原文值:{}", str);
return str;
} else {
return docString;
}
}
/**
* 纯签名
*
* @param str 待签名数据
* @return 签名结果
* @author yubaoshan
*/
public static String doSignature(String str) throws ScriptException {
return Sm2.doSignature(str, Keypair.PRIVATE_KEY);
}
/**
* 验证签名结果
*
* @param originalStr 签名原文数据
* @param str 签名结果
* @return 是否通过
* @author yubaoshan
*/
public static boolean doVerifySignature(String originalStr, String str) throws ScriptException {
return Sm2.doVerifySignature(originalStr, str, Keypair.PUBLIC_KEY);
}
/**
* 通过杂凑算法取得hash值用于做数据完整性保护
*
* @param str 字符串
* @return hash
* @author yubaoshan
*/
public static String doHashValue(String str) throws ScriptException {
return Sm3.sm3(str);
}
}

View File

@ -77,7 +77,7 @@ public class StageController {
*/ */
@PostMapping(path="/deleteTasksOrStage/{taskId}") @PostMapping(path="/deleteTasksOrStage/{taskId}")
public CommonResult<Void> deleteTasksOrStage(@NotNull@PathVariable String taskId){ public CommonResult<Void> deleteTasksOrStage(@NotNull@PathVariable String taskId){
stageService.deleteStagesOrTask(taskId); stageService.deleteStagesAndTask(taskId);
return CommonResult.success(); return CommonResult.success();
} }
/** /**

View File

@ -1,6 +1,7 @@
package cd.casic.ci.api; package cd.casic.ci.api;
import cd.casic.ci.process.dto.req.template.TemplateCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateQueryReq; import cd.casic.ci.process.dto.req.template.TemplateQueryReq;
import cd.casic.ci.process.dto.resp.template.TemplateFindResp; import cd.casic.ci.process.dto.resp.template.TemplateFindResp;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq; import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
@ -31,32 +32,11 @@ public class TemplateManagerController {
@Resource @Resource
private TemplateManagerService templateManagerService; private TemplateManagerService templateManagerService;
// @PostMapping(path="/createTemplate") @PostMapping(path="/createTemplate")
// public CommonResult<String> createTemplate(@RequestBody @Valid TemplateCreateReq req){ public CommonResult<String> createTemplate(@RequestBody @Valid TemplateCreateReq req){
// String templateId = templateManagerService.createTemplateManager(req);
// String templateId = templateManagerService.createTemplate(req); return CommonResult.success(templateId);
// }
// return CommonResult.success(templateId);
// }
//
//
// @PostMapping(path="/deletePipeline")
// public CommonResult<Void> deletePipeline(@RequestBody @Valid PipelineReq req){
//
// templateManagerService.deletePipeline(req);
//
// return CommonResult.success();
// }
//
//
// @PostMapping(path="/updatePipeline")
// public CommonResult<Void> updatePipeline(@RequestBody @NotNull @Valid PipelineUpdateReq pipeline){
//
// templateManagerService.updatePipeline(pipeline);
//
// return CommonResult.success();
// }
@PostMapping(path="/findTemplatePage") @PostMapping(path="/findTemplatePage")
public CommonResult<PageResult<TemplateFindResp>> findTemplatePage(@RequestBody @NotNull @Valid TemplateQueryReq query){ public CommonResult<PageResult<TemplateFindResp>> findTemplatePage(@RequestBody @NotNull @Valid TemplateQueryReq query){

View File

@ -0,0 +1,129 @@
package cd.casic.ci.api;
import cd.casic.ci.process.dto.req.stage.StageCreateReq;
import cd.casic.ci.process.dto.req.stage.StageUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageUpdateReq;
import cd.casic.ci.process.dto.resp.context.SingletonRunContextResp;
import cd.casic.ci.process.dto.resp.stage.StageResp;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
import cd.casic.ci.process.process.dataObject.template.TemplateStage;
import cd.casic.ci.process.process.service.stage.StageService;
import cd.casic.ci.process.process.service.template.TemplateStageService;
import cd.casic.framework.commons.pojo.CommonResult;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* @pi.protocol: http
* @pi.groupName: 流水线多阶段控制器
*/
@RestController
@RequestMapping("/templateStage")
public class TemplateStageController {
@Resource
private TemplateStageService stageService;
/**
* @pi.name:创建流水线阶段及任务
* @pi.path:/stage/createStage
* @pi.methodType:post
* @pi.request-type:json
* @pi.param: model=stage
*/
@PostMapping(path="/createStage")
public CommonResult<String> createStagesOrTask(@RequestBody TemplateStageCreateReq stage){
String taskId = stageService.createStagesOrTask(stage);
return CommonResult.success(taskId);
}
/**
* @pi.name:查询流水线阶段信息
* @pi.path:/stage/finAllStage
* @pi.methodType:post
* @pi.request-type: formdata
* @pi.param: name=pipelineId;dataType=string;value=pipelineId;
*/
@PermitAll
@PostMapping(path="/findAllStage/{templateId}")
public CommonResult<List<TemplateStageResp>> findAllPipelineTaskOrTask(@NotNull @PathVariable String templateId){
List<TemplateStageResp> stageRespList = stageService.findAllStagesTask(templateId);
return CommonResult.success(stageRespList);
}
/**
* @pi.name:更新流水线阶段任务名称Or移动流水线阶段
* @pi.path:/stage/createStage
* @pi.methodType:post
* @pi.request-type:json
* @pi.param: model=stage
*/
@PostMapping(path="/updateStage")
public CommonResult<Void> updateStageTask(@RequestBody @Valid @NotNull TemplateStageUpdateReq stage){
stageService.updateStagesTask(stage);
return CommonResult.success();
}
/**
* @pi.name:删除流水线阶段及任务
* @pi.path:/stage/deleteStage
* @pi.methodType:post
* @pi.request-type: formdata
* @pi.param: name=taskId;dataType=string;value=taskId;
*/
@PostMapping(path="/deleteTasksOrStage/{taskId}")
public CommonResult<Void> deleteTasksOrStage(@NotNull@PathVariable String taskId){
stageService.deleteStagesAndTask(taskId);
return CommonResult.success();
}
// /**
// * 复制stage节点
// * */
// @PostMapping(path="/copyStage/{stageId}")
// public CommonResult<Void> copyStage(@NotEmpty@PathVariable String stageId){
// stageService.copyStage(stageId);
// return CommonResult.success();
// }
@PostMapping("/deleteFirstStage/{stageId}")
public CommonResult<Void> deleteFirstStage(@PathVariable String stageId){
stageService.deleteFirstStage(stageId);
return CommonResult.success();
}
}

View File

@ -0,0 +1,46 @@
package cd.casic.ci.api;
import cd.casic.ci.process.dto.req.task.TaskUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateTaskUpdateReq;
import cd.casic.ci.process.dto.resp.task.TasksResp;
import cd.casic.ci.process.dto.resp.template.TemplateTasksResp;
import cd.casic.ci.process.process.service.task.TaskService;
import cd.casic.ci.process.process.service.template.TemplateTaskService;
import cd.casic.framework.commons.pojo.CommonResult;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/templateTask")
public class TemplateTasksController {
@Resource
private TemplateTaskService taskService;
/**
* @pi.name:查询任务及任务详情
* @pi.path:/tasks/findOneTasksOrTask
* @pi.methodType:post
* @pi.request-type: formdata
* @pi.param: name=taskId;dataType=string;value=taskId;
*/
@PostMapping(path="/findOneTasksOrTask/{taskId}")
public CommonResult<TemplateTasksResp> findOneTasksOrTask(@NotNull @PathVariable String taskId){
return CommonResult.success(taskService.getRespById(taskId));
}
// /**
// * 复制task节点
// * */
// @PostMapping(path="/copyTask/{taskId}")
// public CommonResult<Void> copyTask(@NotEmpty @PathVariable String taskId){
// taskService.copyTask(taskId);
// return CommonResult.success();
// }
@PostMapping(path="/updateTask")
public CommonResult<Boolean> updateTask(@RequestBody TemplateTaskUpdateReq req){
Boolean b = taskService.updateTask(req);
return CommonResult.success(b);
}
}

View File

@ -3,19 +3,21 @@ package cd.casic.ci.api;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerDownloadResp;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp; import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq; import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.service.testCase.TestCaseManagerService; import cd.casic.ci.process.process.service.testCase.TestCaseManagerService;
import cd.casic.framework.commons.pojo.CommonResult; import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult; import cd.casic.framework.commons.pojo.PageResult;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List; import java.util.List;
/** /**
@ -83,5 +85,8 @@ public class TestCaseManagerController {
return CommonResult.success(resp); return CommonResult.success(resp);
} }
@GetMapping("/downLoadById")
public CommonResult<TestCaseManagerDownloadResp> downLoadByManagerId(@RequestParam String managerId){
return CommonResult.success(testCaseManagerService.downLoadById(managerId));
}
} }

View File

@ -0,0 +1,17 @@
package cd.casic.ci.process.constant;
import lombok.Getter;
@Getter
public class PipelineTargetTypeConstant {
public static final String SOURCE_CODE="SOURCE_CODE";
public static final String BIN="BIN";
public static final String FIRM_WARE="FIRM_WARE";
public static final String WEB_SITE="WEB_SITE";
private final String msg;
PipelineTargetTypeConstant(String msg) {
this.msg = msg;
}
}

View File

@ -12,4 +12,18 @@ import lombok.Data;
@Data @Data
public class TemplateCreateReq{ public class TemplateCreateReq{
/**
* 模板名称
*/
private String templateName;
/**
* 模板分类
*/
private String templateType;
/**
* 描述
*/
private String remark;
} }

View File

@ -0,0 +1,13 @@
package cd.casic.ci.process.dto.req.template;
import cd.casic.ci.process.dto.req.task.TaskCreateReq;
import lombok.Data;
@Data
public class TemplateStageCreateReq {
// 阶段stageId
private String stageId;
// 如果需要新增阶段则传这个
private Integer stageSort;
private TemplateTaskCreateReq task;
}

View File

@ -0,0 +1,13 @@
package cd.casic.ci.process.dto.req.template;
import lombok.Data;
@Data
public class TemplateStageUpdateReq {
// 更新名称
private String stageName;
// 更新sort
private Integer stageSort;
private String id;
private String pipelineId;
}

View File

@ -0,0 +1,16 @@
package cd.casic.ci.process.dto.req.template;
import lombok.Data;
import java.util.Map;
@Data
public class TemplateTaskCreateReq {
// 第二级stageId如果没有值则新建第二级stage
private String stageId;
private String taskName;
private String templateId;
private String taskType;
private Integer taskSort;
private Map<String,Object> taskProperties;
}

View File

@ -0,0 +1,14 @@
package cd.casic.ci.process.dto.req.template;
import lombok.Data;
import java.util.Map;
@Data
public class TemplateTaskUpdateReq {
// 第二级stageId如果没有值则新建第二级stage
private String id;
private String taskName;
private String taskType;
private Map<String,Object> taskProperties;
}

View File

@ -22,6 +22,8 @@ public class TestCaseInfoResp {
// 测试文件地址存储路径或URL // 测试文件地址存储路径或URL
private String testFileList; private String testFileList;
private String testFilePath;
// 描述信息 // 描述信息
private String remark; private String remark;

View File

@ -0,0 +1,9 @@
package cd.casic.ci.process.dto.resp.testCase;
import lombok.Data;
@Data
public class TestCaseManagerDownloadResp {
private String fileName;
private String file;
}

View File

@ -3,10 +3,9 @@ package cd.casic.ci.process.engine.worker;
import cd.casic.ci.process.common.WorkAtom; import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.runContext.TaskRunContext; import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker; import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
* 数据库模糊测试 * 数据库模糊测试
* */ * */
@ -17,9 +16,99 @@ public class DBFuzzTestingWorker extends BaseWorker {
@Override @Override
public void execute(TaskRunContext context) { public void execute(TaskRunContext context) {
PipBaseElement contextDef = context.getContextDef(); // PipBaseElement contextDef = context.getContextDef();
String id = contextDef.getId(); // String id = contextDef.getId();
log.info("==============触发worker执行========"); // log.info("==============触发worker执行========");
log.info("==========运行context{}===========", JSON.toJSONString(context)); // log.info("==========运行context{}===========", JSON.toJSONString(context));
// int statusCode = -1;
//
// String login = "http://192.168.100.100:10200/oauth/token";
// String create = "http://192.168.100.100:10200/api/fuzz/add";
// String control = "http://192.168.100.100:10200/api/fuzz/control";
// String getTestDetail = "http://192.168.100.100:10200/api/fuzz/getTestDetail";
// String genReport = "http://192.168.100.100:10200/api/fuzz/genReport";
//// static String = "http://192.168.100.100:10200/api/fuzz/add";
// PipelineNodeConfigInfo nodeConfigInfo = workerParam.getPipelineNodeConfigInfo();
// String taskId = workerParam.getPipelineLogger().getUuid();
// NodeLogger nodeLogger = nodeLoggerThreadLocal.get();
//
// try {
// log.info("attr : {}", nodeConfigInfo.getInfo());
// log.info("节点信息:" + nodeConfigInfo.getInfo());
// //将节点的配置信息反编译成对象
// DbTestConfigInfo dbTestConfigInfo = JSON.parseObject(nodeConfigInfo.getInfo(), DbTestConfigInfo.class);
// HashMap<String, Object> hashMap = new HashMap<>();
// hashMap.put("code", "f258d8cc7585bc71a10e9f9edba017f7");
// hashMap.put("grant_type", "client_code");
// hashMap.put("client_id", "client");
// HttpResponse logRes = HttpRequest.post(login)
// .form(hashMap)/*.header(Header.CONTENT_TYPE, String.valueOf(ContentType.APPLICATION_JSON))*/.execute();
// log.info(String.valueOf(logRes.isOk()));
// if (!logRes.isOk()) {
// nodeLogger.appendNow("获取token失败");
// }
// JSONObject loginJson = JSONObject.parseObject(logRes.body());
// String accessToken = loginJson.get("access_token").toString();
// nodeLogger.appendNow("authorize success\n");
// nodeLogger.appendNow("access_token is " + accessToken);
//// 2 create project
// JSONObject jsonObject = new JSONObject();
// jsonObject.put("node", dbTestConfigInfo.getNode());
// jsonObject.put("engineType", "1");
// jsonObject.put("taskId", taskId);
// jsonObject.put("taskParams", "");
// jsonObject.put("taskName", dbTestConfigInfo.getTaskName());
// HttpResponse createRes = HttpRequest.post(create)
// .body(String.valueOf(jsonObject)).bearerAuth(accessToken).execute();
// if (!createRes.isOk()) {
// nodeLogger.appendNow("创建项目失败");
// return String.valueOf(statusCode);
// }
// JSONObject taskjson = JSONObject.parseObject(createRes.body());
// nodeLogger.appendNow("create project success\n");
// nodeLogger.appendNow("project taskId is " + taskId);
//// 3 启动停止测试
// JSONObject controlObject = new JSONObject();
// controlObject.put("taskId", taskId);
// // 1 start other stop
// controlObject.put("code", 1);
// HttpResponse controlRes = HttpRequest.post(control)
// .body(String.valueOf(controlObject)).bearerAuth(accessToken).execute();
// log.info(String.valueOf(controlRes.isOk()));
// if (!controlRes.isOk()) {
// nodeLogger.appendNow("启动项目失败");
// return String.valueOf(statusCode);
//
// }
// JSONObject controlJson = JSONObject.parseObject(createRes.body());
// nodeLogger.appendNow("control start success\n");
// nodeLogger.appendNow("control start code is " + controlJson.get("data\n"));
//// 4 获取测试详情保存历史数据
// HashMap<String, Object> haap = new HashMap<>();
// haap.put("taskId", taskId);
// HttpResponse testDetail = HttpRequest.get(getTestDetail)
// .form(haap).bearerAuth(accessToken).execute();
// if (!testDetail.isOk()) {
// nodeLogger.appendNow("获取测试详情失败");
// return String.valueOf(statusCode);
// }
// JSONObject testDetailBody = JSONObject.parseObject(testDetail.body());
// log.info(testDetailBody.toString());
// FuzzDbTest fuzzDbTest = new FuzzDbTest();
// fuzzDbTest.setNodeUuid(nodeConfigInfo.getNodeUuid());
// fuzzDbTest.setTaskId(taskId);
// fuzzDbTestService.save(fuzzDbTest);
// statusCode = 0;
// } catch (Exception e) {
// String errorMessage = "该节点配置信息为空,请先配置该节点信息" + "\r\n";
// errorHandle(e, errorMessage);
// }
//
// if (statusCode == 0) {
// log.info("{}节点执行完成", getName());
// } else {
// log.error("{}节点执行失败", getName());
// }
// return String.valueOf(statusCode);
} }
} }

View File

@ -24,7 +24,6 @@ import java.util.Map;
*/ */
@Slf4j @Slf4j
@WorkAtom(taskType = "CUSTOM_IMAGE_EXECUTION_COMMAND") @WorkAtom(taskType = "CUSTOM_IMAGE_EXECUTION_COMMAND")
//@Plugin(taskType = "testSSH")
public class DIYImageExecuteCommandWorker extends SshWorker { public class DIYImageExecuteCommandWorker extends SshWorker {
@Override @Override

View File

@ -1,17 +1,18 @@
package cd.casic.ci.process.engine.worker; package cd.casic.ci.process.engine.worker.target;
import cd.casic.ci.process.common.WorkAtom; import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.runContext.TaskRunContext; import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker; import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.constant.PipelineTargetTypeConstant;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement; import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@WorkAtom(taskType = "Github") @WorkAtom(taskType = PipelineTargetTypeConstant.BIN)
public class TestGitWorker extends BaseWorker { public class TargetBinWorker extends BaseWorker {
@Override @Override

View File

@ -1,17 +1,18 @@
package cd.casic.ci.process.engine.worker; package cd.casic.ci.process.engine.worker.target;
import cd.casic.ci.process.common.WorkAtom; import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.runContext.TaskRunContext; import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker; import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.constant.PipelineTargetTypeConstant;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement; import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@WorkAtom(taskType = "GIT") @WorkAtom(taskType = PipelineTargetTypeConstant.FIRM_WARE)
public class TestWorker extends BaseWorker { public class TargetFirmWareWorker extends BaseWorker {
@Override @Override

View File

@ -1,9 +1,10 @@
package cd.casic.ci.process.engine.worker; package cd.casic.ci.process.engine.worker.target;
import cd.casic.ci.process.common.WorkAtom; import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.runContext.TaskRunContext; import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker; import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.constant.PipelineTargetTypeConstant;
import cd.casic.ci.process.process.service.machine.MachineInfoService; import cd.casic.ci.process.process.service.machine.MachineInfoService;
import cd.casic.ci.process.process.service.target.TargetVersionService; import cd.casic.ci.process.process.service.target.TargetVersionService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -14,8 +15,8 @@ import lombok.extern.slf4j.Slf4j;
* *
* */ * */
@Slf4j @Slf4j
@WorkAtom(taskType = "code") @WorkAtom(taskType = PipelineTargetTypeConstant.SOURCE_CODE)
public class TargetHandleWorker extends BaseWorker { public class TargetSourceCodeWorker extends BaseWorker {
@Resource @Resource
private TargetVersionService targetVersionService; private TargetVersionService targetVersionService;
@Resource @Resource

View File

@ -0,0 +1,14 @@
package cd.casic.ci.process.engine.worker.target;
import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.constant.PipelineTargetTypeConstant;
@WorkAtom(taskType = PipelineTargetTypeConstant.WEB_SITE)
public class TargetWebSiteWorker extends BaseWorker {
@Override
public void execute(TaskRunContext context) {
}
}

View File

@ -1,29 +0,0 @@
package cd.casic.ci.process.enums;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
@Getter
public enum PiplineTargetTypeEnum {
SOURCE_CODE("1","源程序"),
BIN("2","二进制"),
FIRM_WARE("3","二进制"),
WEB_SITE("4","web网站")
;
private final String code;
private final String msg;
PiplineTargetTypeEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
public static Map<String,PiplineTargetTypeEnum> getCodeMap(){
Map<String,PiplineTargetTypeEnum> map = new HashMap<>();
for (PiplineTargetTypeEnum value : values()) {
map.put(value.code, value);
}
return map;
}
}

View File

@ -29,6 +29,7 @@ public interface TargetVersionConverter {
void updateReqCopyToTargetVersion(TargetVersionUpdateReq req,@MappingTarget TargetVersion targetVersion); void updateReqCopyToTargetVersion(TargetVersionUpdateReq req,@MappingTarget TargetVersion targetVersion);
TargetVersion targetCreateReqToTargetVersionBean(TargetManagerCreateReq req); TargetVersion targetCreateReqToTargetVersionBean(TargetManagerCreateReq req);
TargetVersionCreateReq targetCreateReqToTargetVersionCreateReq(TargetManagerCreateReq req);
TargetVersion versionCreateReqToTargetVersionBean(TargetVersionCreateReq req); TargetVersion versionCreateReqToTargetVersionBean(TargetVersionCreateReq req);
} }

View File

@ -1,5 +1,6 @@
package cd.casic.ci.process.process.converter; package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dto.req.template.TemplateCreateReq;
import cd.casic.ci.process.dto.resp.template.TemplateFindResp; import cd.casic.ci.process.dto.resp.template.TemplateFindResp;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp; import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
import cd.casic.ci.process.dto.resp.template.TemplateTasksResp; import cd.casic.ci.process.dto.resp.template.TemplateTasksResp;
@ -27,5 +28,5 @@ public interface TemplateConverter {
PipStage respToStage(TemplateStageResp resp); PipStage respToStage(TemplateStageResp resp);
TemplateStageResp stageTemplateToResp(TemplateStage stage); TemplateStageResp stageTemplateToResp(TemplateStage stage);
PipTask templateTaskToTask(TemplateTasksResp resp); PipTask templateTaskToTask(TemplateTasksResp resp);
TemplateManager managerCreateReqToManager(TemplateCreateReq req);
} }

View File

@ -0,0 +1,18 @@
package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dto.resp.stage.StageResp;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
import cd.casic.ci.process.process.dataObject.stage.PipStage;
import cd.casic.ci.process.process.dataObject.template.TemplateStage;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper(componentModel = "spring")
public interface TemplateStageConverter {
TemplateStageConverter INSTANCE = Mappers.getMapper(TemplateStageConverter.class);
public TemplateStageResp converter(TemplateStage stage);
public List<TemplateStageResp> converter(List<TemplateStage> stage);
}

View File

@ -0,0 +1,14 @@
package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dto.resp.task.TasksResp;
import cd.casic.ci.process.dto.resp.template.TemplateTasksResp;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.dataObject.template.TemplateTask;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper(componentModel = "spring")
public interface TemplateTaskConverter {
TemplateTaskConverter INSTANCE = Mappers.getMapper(TemplateTaskConverter.class);
TemplateTasksResp doToResp(TemplateTask task);
}

View File

@ -46,4 +46,8 @@ public class TargetVersion extends PipBaseElement {
* 文件地址路径 * 文件地址路径
*/ */
private String filePath; private String filePath;
/**
* 目标版本构成成分
* */
private String versionCompose;
} }

View File

@ -25,16 +25,6 @@ public class TemplateManager extends PipBaseElement {
*/ */
private String templateType; private String templateType;
/**
* 模板编码
*/
private String templateCode;
/**
* 排序
*/
private Integer sort;
/** /**
* 描述 * 描述
*/ */

View File

@ -31,10 +31,12 @@ public interface StageService extends IService<PipStage> {
List<PipStage> findAllFirstStagesAndChild(String pipelineId); List<PipStage> findAllFirstStagesAndChild(String pipelineId);
/** /**
* 删除阶段及任务 * 删除阶段及任务,如果当前节点是当前阶段最后一个节点
* 会自动删除阶段
*
* @param taskId 配置id * @param taskId 配置id
*/ */
void deleteStagesOrTask(String taskId); void deleteStagesAndTask(String taskId);
/** /**
* 删除流水线所有阶段 * 删除流水线所有阶段

View File

@ -189,7 +189,7 @@ public class StageServiceImpl extends ServiceImpl<PipStageDao, PipStage> impleme
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteStagesOrTask(String taskId) { public void deleteStagesAndTask(String taskId) {
PipTask taskQuery = new PipTask(); PipTask taskQuery = new PipTask();
taskQuery.setId(taskId); taskQuery.setId(taskId);
List<PipTask> taskList = taskService.getTask(taskQuery); List<PipTask> taskList = taskService.getTask(taskQuery);

View File

@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -77,11 +78,12 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
} }
this.save(targetManager); this.save(targetManager);
TargetVersionCreateReq targetVersion = TargetVersionConverter.INSTANCE.targetCreateReqToTargetVersionCreateReq(req);
createVersion(targetVersion);
// //保存第一个版本
//保存第一个版本 // targetVersion.setTargetId(targetManager.getId());
TargetVersion targetVersion = TargetVersionConverter.INSTANCE.targetCreateReqToTargetVersionBean(req); // targetVersionService.save(targetVersion);
targetVersion.setTargetId(targetManager.getId());
targetVersionService.save(targetVersion);
} }
@Override @Override
@ -231,7 +233,7 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>(); QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>();
wrapper.eq("version",targetVersion.getVersion()); wrapper.eq("version",targetVersion.getVersion());
wrapper.eq("target_id",targetVersion.getTargetId()); wrapper.eq("target_id",targetVersion.getTargetId());
if (!ObjectUtils.isEmpty(targetVersionDao.selectList(wrapper))){ if (!CollectionUtils.isEmpty(targetVersionDao.selectList(wrapper))){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"版本已存在"); throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"版本已存在");
} }
@ -291,4 +293,7 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
} }
return buffer.toByteArray(); return buffer.toByteArray();
} }
private void setTargetVersionCompose(TargetVersion targetVersion){
}
} }

View File

@ -1,6 +1,7 @@
package cd.casic.ci.process.process.service.template; package cd.casic.ci.process.process.service.template;
import cd.casic.ci.process.dto.req.template.TemplateCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateQueryReq; import cd.casic.ci.process.dto.req.template.TemplateQueryReq;
import cd.casic.ci.process.dto.resp.template.TemplateFindResp; import cd.casic.ci.process.dto.resp.template.TemplateFindResp;
import cd.casic.ci.process.process.dataObject.template.TemplateManager; import cd.casic.ci.process.process.dataObject.template.TemplateManager;
@ -18,15 +19,7 @@ import java.util.List;
* @Description: * @Description:
*/ */
public interface TemplateManagerService extends IService<TemplateManager> { public interface TemplateManagerService extends IService<TemplateManager> {
// String createTemplate(@Valid TemplateCreateReq req); String createTemplateManager(TemplateCreateReq req);
//
// void deletePipeline(@Valid PipelineReq req);
//
// void updatePipeline(@Valid PipelineUpdateReq pipeline);
//
// void pipelineClone(@Valid PipelineReq req);
//
// TreeRunContextResp getPipelineRunState(String pipelineId);
PageResult<TemplateFindResp> findTemplatePage(@Valid TemplateQueryReq query); PageResult<TemplateFindResp> findTemplatePage(@Valid TemplateQueryReq query);

View File

@ -0,0 +1,43 @@
package cd.casic.ci.process.process.service.template;
import cd.casic.ci.process.dto.req.stage.StageCreateReq;
import cd.casic.ci.process.dto.req.stage.StageUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageUpdateReq;
import cd.casic.ci.process.dto.resp.stage.StageResp;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
import cd.casic.ci.process.process.dataObject.stage.PipStage;
import cd.casic.ci.process.process.dataObject.template.TemplateStage;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
public interface TemplateStageService extends IService<TemplateStage> {
/**
* 创建阶段及关联任务
* @param stage 阶段信息
* @return 阶段id
*/
String createStagesOrTask(TemplateStageCreateReq stage);
/**
* 查询所有阶段任务
* @param templateId 流水线id
* @return 任务
*/
List<TemplateStageResp> findAllStagesTask(String templateId);
List<TemplateStage> findAllFirstStagesAndChild(String templateId);
void deleteFirstStage(String stageId);
/**
* 删除阶段及任务
* @param taskId 配置id
*/
void deleteStagesAndTask(String taskId);
public void updateStagesTask(TemplateStageUpdateReq stage);
}

View File

@ -0,0 +1,24 @@
package cd.casic.ci.process.process.service.template;
import cd.casic.ci.process.dto.req.task.TaskUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateTaskUpdateReq;
import cd.casic.ci.process.dto.resp.task.TasksResp;
import cd.casic.ci.process.dto.resp.template.TemplateTasksResp;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.dataObject.template.TemplateTask;
import cd.casic.ci.process.util.WebFrameworkUtils;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import com.baomidou.mybatisplus.extension.service.IService;
import org.apache.commons.lang3.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public interface TemplateTaskService extends IService<TemplateTask> {
List<TemplateTask> getTask(TemplateTask pipTask);
List<TemplateTask> getTaskByStageIdList(List<String> stageIdList);
TemplateTasksResp getRespById(String taskId);
public Boolean updateTask(TemplateTaskUpdateReq req);
}

View File

@ -1,6 +1,7 @@
package cd.casic.ci.process.process.service.template.impl; package cd.casic.ci.process.process.service.template.impl;
import cd.casic.ci.process.dto.req.template.TemplateCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateQueryReq; import cd.casic.ci.process.dto.req.template.TemplateQueryReq;
import cd.casic.ci.process.dto.resp.template.TemplateFindResp; import cd.casic.ci.process.dto.resp.template.TemplateFindResp;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp; import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
@ -59,304 +60,11 @@ public class TemplateManagerServiceImpl extends ServiceImpl<TemplateManagerDao,
@Resource @Resource
private TemplateConverter templateConverter; private TemplateConverter templateConverter;
// @Override public String createTemplateManager(TemplateCreateReq req){
// @Transactional(rollbackFor = Exception.class) TemplateManager templateManager = templateConverter.managerCreateReqToManager(req);
// public String createTemplate(PipelineCreateReq pipelineReq) { save(templateManager);
// return templateManager.getId();
// PipPipeline pipeline = new PipPipeline(); }
// BeanUtils.copyProperties(pipelineReq, pipeline);
// // 随机颜色
// int randomNumber = (int)(Math.random() * 5) + 1;
// pipeline.setColor(randomNumber);
//
// pipeline.setCreateTime(LocalDateTime.now());
// if (Objects.isNull(pipeline.getCreator())){
// pipeline.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// }
//
// pipeline.setState(1);
// pipeline.setMachineId("1");
//
// //新增对应的配置类数据
// if (!ObjectUtils.isEmpty(pipelineReq.getResourceReq())){
// PipResource resource = new PipResource();
// BeanUtils.copyProperties(pipelineReq.getResourceReq(),resource);
// resource.setCreator(pipeline.getCreator());
// resource.setCreateTime(LocalDateTime.now());
// resourceService.save(resource);
//
// pipeline.setResourceId(resource.getId());
// }
//
// this.save(pipeline);
//
// //TODO 根据模板覆写对应的阶段信息以及节点信息
//// List<StageReq> stageReqList = templateService.findStageById(pipelineReq.getTemplateId());
//// stageReqList.forEach(o->{
//// o.setPipelineId(pipeline.getId());
//// });
// //新增初始阶段无串行并行任务
// PipStage stageReq1 = new PipStage();
// stageReq1.setPipelineId(pipeline.getId());
// stageReq1.setStageName("阶段-1");
// stageReq1.setCreateTime(LocalDateTime.now());
// stageReq1.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// stageReq1.setStageSort(1);
// stageReq1.setParentId("-1");
// stageReq1.setCode(true);
// stageService.save(stageReq1);
//
// PipStage childStage1 = new PipStage();
// childStage1.setPipelineId(pipeline.getId());
// childStage1.setStageName("源码");
// childStage1.setCreateTime(LocalDateTime.now());
// childStage1.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childStage1.setStageSort(1);
// childStage1.setCode(false);
// childStage1.setParentId(stageReq1.getId());
// stageService.save(childStage1);
//
// PipTask childTask11 = new PipTask();
// childTask11.setCreateTime(LocalDateTime.now());
// childTask11.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childTask11.setTaskName("串行任务-1-1");
// childTask11.setPipelineId(pipeline.getId());
// childTask11.setTaskType("CODE");
// childTask11.setTaskSort(1);
// childTask11.setStageId(childStage1.getId());
// taskService.save(childTask11);
//
// //新增第二个阶段包含串行和并行任务
// PipStage stageReq2 = new PipStage();
// stageReq2.setPipelineId(pipeline.getId());
// stageReq2.setStageName("阶段-2");
// stageReq2.setCreateTime(LocalDateTime.now());
// stageReq2.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// stageReq2.setStageSort(2);
// stageReq2.setParentId("-1");
// stageReq2.setCode(true);
// stageService.save(stageReq2);
//
// //新增并行阶段
// PipStage childStage21 = new PipStage();
// childStage21.setStageName("并行阶段-2-1");
// childStage21.setPipelineId(pipeline.getId());
// childStage21.setCreateTime(LocalDateTime.now());
// childStage21.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childStage21.setStageSort(1);
// childStage21.setCode(false);
// childStage21.setParentId(stageReq2.getId());
// stageService.save(childStage21);
//
// //新增串行阶段
// PipTask childTask21 = new PipTask();
// childTask21.setPipelineId(pipeline.getId());
// childTask21.setTaskName("串行任务-2-1");
// childTask21.setCreateTime(LocalDateTime.now());
// childTask21.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childTask21.setTaskType("TEST_CASE_GENERATION");
// childTask21.setTaskSort(1);
// childTask21.setStageId(childStage21.getId());
// taskService.save(childTask21);
//
// //------------------------------------------------------------------
//// PipStage childStage22 = new PipStage();
//// childStage22.setStageName("并行阶段-2-2");
//// childStage22.setPipelineId(pipeline.getId());
//// childStage22.setCreateTime(LocalDateTime.now());
//// childStage22.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
//// childStage22.setStageSort(2);
//// childStage22.setCode(false);
//// childStage22.setParentId(stageReq2.getId());
//// stageService.save(childStage22);
////
//// PipTask childTask22 = new PipTask();
//// childTask22.setCreateTime(LocalDateTime.now());
//// childTask22.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
//// childTask22.setTaskName("串行任务-2-2");
//// childTask22.setPipelineId(pipeline.getId());
//// childTask22.setTaskType("test");
//// childTask22.setTaskSort(2);
//// childTask22.setStageId(childStage22.getId());
//// taskService.save(childTask22);
//
// //创建第三个阶段
// PipStage stageReq3 = new PipStage();
// stageReq3.setPipelineId(pipeline.getId());
// stageReq3.setStageName("阶段-3");
// stageReq3.setCreateTime(LocalDateTime.now());
// stageReq3.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// stageReq3.setStageSort(3);
// stageReq3.setParentId("-1");
// stageReq3.setCode(true);
// stageService.save(stageReq3);
//
// PipStage childStage31 = new PipStage();
// childStage31.setStageName("并行任务-3-1");
// childStage31.setPipelineId(pipeline.getId());
// childStage31.setCreateTime(LocalDateTime.now());
// childStage31.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childStage31.setStageSort(1);
// childStage31.setCode(false);
// childStage31.setParentId(stageReq3.getId());
// stageService.save(childStage31);
//
// PipTask childTask31 = new PipTask();
// childTask31.setCreateTime(LocalDateTime.now());
// childTask31.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// childTask31.setTaskName("串行任务-3-1");
// childTask31.setPipelineId(pipeline.getId());
// childTask31.setTaskType("AFL");
// childTask31.setTaskSort(1);
// childTask31.setStageId(childStage31.getId());
// taskService.save(childTask31);
//
// //创建第四个阶段
// //TODO
//// PipStage stageReq4 = new PipStage();
//// stageReq4.setPipelineId(pipeline.getId());
//// stageReq4.setStageName("阶段-4");
//// stageReq4.setCreateTime(LocalDateTime.now());
//// stageReq4.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
//// stageReq4.setStageSort(4);
//// stageReq4.setParentId("-1");
//// stageReq4.setCode(true);
//// stageService.save(stageReq4);
////
//// PipStage childStage41 = new PipStage();
//// childStage41.setStageName("并行任务-4-1");
//// childStage41.setPipelineId(pipeline.getId());
//// childStage41.setCreateTime(LocalDateTime.now());
//// childStage41.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
//// childStage41.setStageSort(1);
//// childStage41.setCode(false);
//// childStage41.setParentId(stageReq4.getId());
//// stageService.save(childStage41);
////
//// PipTask childTask41 = new PipTask();
//// childTask41.setCreateTime(LocalDateTime.now());
//// childTask41.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
//// childTask41.setTaskName("串行任务-4-1");
//// childTask41.setPipelineId(pipeline.getId());
//// childTask41.setTaskType("REPORT");
//// childTask41.setTaskSort(1);
//// childTask41.setStageId(childStage41.getId());
//// taskService.save(childTask41);
//
// //TODO 创建对应的鉴权关系
// //TODO 创建对应的消息分发
// return pipeline.getId();
// }
//
// @Override
// public List<PipelineFindResp> findPipelineList(PipelineQueryReq pipelineQueryReq) {
// QueryWrapper<PipPipeline> wrapper = new QueryWrapper<>();
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getId())){
// wrapper.eq("id",pipelineQueryReq.getId());
// }
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getIdList())){
// wrapper.in("id",pipelineQueryReq.getId());
// }
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getName())){
// wrapper.like("name",pipelineQueryReq.getName());
// }
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getCreator())){
// wrapper.eq("creator",pipelineQueryReq.getCreator());
// }
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getCollect())){
// wrapper.eq("collect",pipelineQueryReq.getCollect());
// }
// if (!ObjectUtils.isEmpty(pipelineQueryReq.getGroupId())){
// wrapper.eq("group_id",pipelineQueryReq.getGroupId());
// }
//// Page<PipPipeline> page = new Page<>(pipelineQueryReq.getPageNo(), pipelineQueryReq.getPageSize());
//// Page<PipPipeline> pipPipelinePage = pipelineDao.selectPage(page, wrapper);
//
// List<PipPipeline> pipPipelines = pipelineDao.selectList(wrapper);
// if (ObjectUtils.isEmpty(pipPipelines)){
// return new ArrayList<>(0);
// }
//
// List<PipelineFindResp> respList = PipelineConverter.INSTANCE.toRespList(pipPipelines);
//
// //对流水线进行流水线信息赋值
// respList.forEach(this::setStageAndTask);
// //对用户姓名进行赋值
// respList.forEach(this::setUserName);
// return respList;
// }
//
//
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void deletePipeline(PipelineReq req) {
// if (StringUtils.isEmpty(req.getId())){
// throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"id不能为空");
// }
//
// String pipelineId = req.getId();
//
// if (ObjectUtils.isEmpty(pipelineId)){
// throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"请求参数不能为空");
// }
//
// PipPipeline pipeline = pipelineDao.selectById(pipelineId);
// if (ObjectUtils.isEmpty(pipeline)){
// throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"流水线不存在");
// }
// pipelineDao.deleteById(pipelineId);
//
// //根据流水线id查询节点和配置信息
// PipStage pipStage = new PipStage();
// pipStage.setPipelineId(pipelineId);
// List<PipStage> pipStageList = stageService.getPipStageList(pipStage);
// if (!CollectionUtils.isEmpty(pipStageList)){
// List<String> list = pipStageList.stream().map(PipStage::getId).toList();
// pipStageDao.deleteByIds(list);
// }
//
// PipTask pipTask = new PipTask();
// pipTask.setPipelineId(pipelineId);
// List<PipTask> task = taskService.getTask(pipTask);
// if (!CollectionUtils.isEmpty(task)){
// List<String> list = task.stream().map(PipTask::getId).toList();
// pipTaskDao.deleteByIds(list);
// }
//
// //删除resource表数据
// if (StringUtils.isNotEmpty(pipeline.getResourceId())){
// PipResource pipResource = pipResourceDao.selectById(pipeline.getResourceId());
//
// if (!ObjectUtils.isEmpty(pipResource)){
// pipResourceDao.deleteById(pipeline.getResourceId());
// }
// }
// }
//
// @Override
// public void updatePipeline(PipelineUpdateReq pipeline) {
// PipPipeline pipPipeline = new PipPipeline();
// BeanUtils.copyProperties(pipeline,pipPipeline);
// pipPipeline.setUpdateTime(LocalDateTime.now());
// pipPipeline.setUpdater(String.valueOf(WebFrameworkUtils.getLoginUserId()));
// pipelineDao.updateById(pipPipeline);
// }
//
// @Override
// public PipelineFindResp findPipelineById(PipelineQueryReq pipelineQueryReq) {
// if (StringUtils.isEmpty(pipelineQueryReq.getId())){
// throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"id参数不能为空");
// }
// PipPipeline pipeline = pipelineDao.selectById(pipelineQueryReq.getId());
// if (ObjectUtils.isEmpty(pipeline)){
// throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"数据错误,请联系管理员");
// }
// PipelineFindResp resp = PipelineConverter.INSTANCE.toResp(pipeline);
// setStageAndTask(resp);
//
// return resp;
// }
@Override @Override
public PageResult<TemplateFindResp> findTemplatePage(TemplateQueryReq query) { public PageResult<TemplateFindResp> findTemplatePage(TemplateQueryReq query) {

View File

@ -0,0 +1,368 @@
package cd.casic.ci.process.process.service.template.impl;
import cd.casic.ci.process.dto.req.stage.StageUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageCreateReq;
import cd.casic.ci.process.dto.req.template.TemplateStageUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateTaskCreateReq;
import cd.casic.ci.process.dto.resp.template.TemplateStageResp;
import cd.casic.ci.process.process.converter.TemplateStageConverter;
import cd.casic.ci.process.process.dao.template.TemplateStageDao;
import cd.casic.ci.process.process.dataObject.template.TemplateStage;
import cd.casic.ci.process.process.dataObject.template.TemplateTask;
import cd.casic.ci.process.process.service.template.TemplateStageService;
import cd.casic.ci.process.process.service.template.TemplateTaskService;
import cd.casic.ci.process.util.WebFrameworkUtils;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class TemplateStageServiceImpl extends ServiceImpl<TemplateStageDao, TemplateStage> implements TemplateStageService {
@Resource
private TemplateStageDao stageDao;
@Resource
private TemplateTaskService templateTaskService;
@Resource
private TemplateStageConverter stageConverter;
@Transactional(rollbackFor = Exception.class)
@Override
public String createStagesOrTask(TemplateStageCreateReq stageReq) {
String firstStageId = stageReq.getStageId();
Integer stageSort = stageReq.getStageSort();
TemplateTaskCreateReq task = stageReq.getTask();
String taskName = task.getTaskName();
String secondStageId = task.getStageId();
Map<String,Object> taskProperties = task.getTaskProperties();
String taskType = task.getTaskType();
Integer taskSort = task.getTaskSort();
String templateId = task.getTemplateId();
Long loginUserId = WebFrameworkUtils.getLoginUserId();
TemplateStage firstStage = null;
// 判断是否需要新建阶段,如果没有传第一级tageId而传了sort就是需要创建阶段
if (StringUtils.isEmpty(firstStageId)) {
// 新建stage
firstStage = new TemplateStage();
firstStage.setStageName("阶段-"+stageSort);
if (stageSort == null) {
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"参数有误");
}
firstStage.setStageSort(stageSort);
firstStage.setCreateTime(LocalDateTime.now());
firstStage.setParentId("-1");
firstStage.setTemplateId(templateId);
firstStage.setCreator(String.valueOf(loginUserId));
firstStage.setUpdater(String.valueOf(loginUserId));
firstStage.setUpdateTime(LocalDateTime.now());
TemplateStage stageQuery = new TemplateStage();
stageQuery.setTemplateId(templateId);
stageQuery.setParentId("-1");
List<TemplateStage> otherStageList = getTemplateStageList(stageQuery);
if (!CollectionUtils.isEmpty(otherStageList)) {
for (TemplateStage stage : otherStageList) {
if (stageSort<=stage.getStageSort()) {
stage.setStageSort(stage.getStageSort()+1);
}
}
updateBatchById(otherStageList);
}
save(firstStage);
} else {
TemplateStage stageQuery = new TemplateStage();
stageQuery.setId(firstStageId);
stageQuery.setParentId("-1");
List<TemplateStage> pipStageList = getTemplateStageList(stageQuery);
if (!CollectionUtils.isEmpty(pipStageList)) {
firstStage = pipStageList.get(0);
} else {
throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"阶段不存在");
}
}
if (firstStage == null) {
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"创建节点失败");
}
TemplateStage secondStage = null;
if (secondStageId==null||taskSort==null) {
// 添加并行节点
secondStage = new TemplateStage();
TemplateStage stageQuery = new TemplateStage();
stageQuery.setParentId(firstStage.getId());
stageQuery.setTemplateId(templateId);
List<TemplateStage> pipStageList = getTemplateStageList(stageQuery);
if (CollectionUtils.isEmpty(pipStageList)) {
secondStage.setStageSort(1);
} else {
secondStage.setStageSort(pipStageList.size()+1);
}
secondStage.setCreateTime(LocalDateTime.now());
secondStage.setUpdateTime(LocalDateTime.now());
secondStage.setCreator(String.valueOf(loginUserId));
secondStage.setParentId(firstStage.getId());
secondStage.setTemplateId(templateId);
secondStage.setUpdater(String.valueOf(loginUserId));
save(secondStage);
taskSort=1;
secondStageId = secondStage.getId();
} else {
secondStage = getById(secondStageId);
}
if (secondStage == null) {
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"创建节点失败");
}
List<TemplateTask> taskValues = templateTaskService.getTaskByStageIdList(Arrays.asList(secondStage.getId()));
if (!CollectionUtils.isEmpty(taskValues)) {
for (TemplateTask taskValue : taskValues) {
if (taskValue.getTaskSort()>=taskSort) {
taskValue.setTaskSort(taskValue.getTaskSort()+1);
}
}
templateTaskService.updateBatchById(taskValues);
}
// 保存task
TemplateTask pipTask = new TemplateTask();
pipTask.setTaskType(taskType);
pipTask.setTaskSort(taskSort);
pipTask.setStageId(secondStageId);
pipTask.setTaskName(taskName);
pipTask.setCreateTime(LocalDateTime.now());
pipTask.setTaskProperties(taskProperties);
pipTask.setTemplateId(templateId);
pipTask.setUpdateTime(LocalDateTime.now());
pipTask.setCreator(String.valueOf(loginUserId));
pipTask.setUpdater(String.valueOf(loginUserId));
templateTaskService.save(pipTask);
return pipTask.getId();
}
@Override
public List<TemplateStageResp> findAllStagesTask(String pipelineId) {
//获取流水线主节点
List<TemplateStage> stageMainStage = findAllMainStage(pipelineId);
if (stageMainStage.isEmpty()){
return Collections.emptyList();
}
List<TemplateStageResp> list = new ArrayList<>();
for (TemplateStage stage : stageMainStage) {
String stagesId = stage.getId();
//获取从节点
List<TemplateStage> allSecondStage = findSecondStageAndTask(stagesId);
List<TemplateStageResp> stageRespList = stageConverter.converter(allSecondStage);
TemplateStageResp stageResp = stageConverter.converter(stage);
stageResp.setStageList(stageRespList);
list.add(stageResp);
}
list.sort(Comparator.comparing(TemplateStageResp::getStageSort));
return list;
}
@Override
public List<TemplateStage> findAllFirstStagesAndChild(String pipelineId) {
//获取流水线主节点
List<TemplateStage> stageMainStage = findAllMainStage(pipelineId);
if (stageMainStage.isEmpty()){
return Collections.emptyList();
}
for (TemplateStage stage : stageMainStage) {
String stagesId = stage.getId();
//获取从节点
List<TemplateStage> allStageStage = findSecondStageAndTask(stagesId);
stage.setStageList(allStageStage);
}
stageMainStage.sort(Comparator.comparing(TemplateStage::getStageSort));
return stageMainStage;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteStagesAndTask(String taskId) {
TemplateTask taskQuery = new TemplateTask();
taskQuery.setId(taskId);
List<TemplateTask> taskList = templateTaskService.getTask(taskQuery);
if (CollectionUtils.isEmpty(taskList)) {
return;
}
TemplateTask task = taskList.get(0);
templateTaskService.removeById(taskId);
// 查询上一级stage下有无其他task 没有则连着stage删除
String stageId = task.getStageId();
String pipelineId = task.getTemplateId();
taskQuery = new TemplateTask();
taskQuery.setStageId(stageId);
List<TemplateTask> otherTask = templateTaskService.getTask(taskQuery);
if (CollectionUtils.isEmpty(otherTask)) {
// 删除当前task的父stage然后判断父stage的父级有无其他子级如果没有就继续删除当前阶段
TemplateStage stageQuery = new TemplateStage();
stageQuery.setTemplateId(pipelineId);
stageQuery.setId(stageId);
List<TemplateStage> currStageList = getTemplateStageList(stageQuery);
if (CollectionUtils.isEmpty(currStageList)) {
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"stage不存在");
}
TemplateStage currStage = currStageList.get(0);
deleteStages(stageId);
String parentId = currStage.getParentId();
stageQuery = new TemplateStage();
stageQuery.setParentId(parentId);
// 查询同阶段其他二级stage如果不存在其他stage则删除阶段stage并整理sort值
List<TemplateStage> otherStageList = getTemplateStageList(stageQuery);
if (CollectionUtils.isEmpty(otherStageList)) {
//没有其他并行路径就需要删除当前阶段
deleteStages(parentId);
} else {
for (TemplateStage stage : otherStageList) {
if (currStage.getStageSort()<stage.getStageSort()) {
stage.setStageSort(stage.getStageSort()-1);
}
}
updateBatchById(otherStageList);
}
} else {
for (TemplateTask pipTask : otherTask) {
if (task.getTaskSort()<pipTask.getTaskSort()) {
pipTask.setTaskSort(pipTask.getTaskSort()-1);
}
}
templateTaskService.updateBatchById(otherTask);
}
}
public List<TemplateStage> getTemplateStageList(TemplateStage pipStage){
LambdaQueryWrapper<TemplateStage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.isNotEmpty(pipStage.getId()),TemplateStage::getId,pipStage.getId());
wrapper.eq(StringUtils.isNotEmpty(pipStage.getTemplateId()),TemplateStage::getTemplateId,pipStage.getTemplateId());
wrapper.eq(StringUtils.isNotEmpty(pipStage.getParentId()),TemplateStage::getParentId,pipStage.getParentId());
return stageDao.selectList(wrapper);
}
public List<TemplateStage> findAllMainStage(String pipelineId) {
LambdaQueryWrapper<TemplateStage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TemplateStage::getTemplateId,pipelineId);
wrapper.eq(TemplateStage::getParentId,"-1");
return stageDao.selectList(wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateStagesTask(TemplateStageUpdateReq stage) {
String id = stage.getId();
String stageName = stage.getStageName();
Integer currStageSort = stage.getStageSort();
Long loginUserId = WebFrameworkUtils.getLoginUserId();
TemplateStage updateStage = getById(id);
if (updateStage==null) {
return;
}
updateStage.setUpdater(String.valueOf(loginUserId));
updateStage.setUpdateTime(LocalDateTime.now());
if (currStageSort == null) {
updateStage.setStageName(stageName);
updateById(updateStage);
} else{
Integer oldStageSort = updateStage.getStageSort();
if (oldStageSort.equals(currStageSort)) {
return;
}
TemplateStage query = new TemplateStage();
query.setTemplateId(updateStage.getTemplateId());
query.setParentId("-1");
List<TemplateStage> stageList = getTemplateStageList(query);
if (oldStageSort<currStageSort) {
// 往右移动
for (TemplateStage pipStage : stageList) {
if (!pipStage.getId().equals(updateStage.getId())) {
if (pipStage.getStageSort()>oldStageSort&&pipStage.getStageSort()<=currStageSort) {
pipStage.setStageSort(pipStage.getStageSort()-1);
}
} else{
pipStage.setStageSort(currStageSort);
}
}
} else {
// 往左移动
for (TemplateStage pipStage : stageList) {
if (!pipStage.getId().equals(updateStage.getId())) {
if (pipStage.getStageSort()<oldStageSort&&pipStage.getStageSort()>=currStageSort) {
pipStage.setStageSort(pipStage.getStageSort()+1);
}
} else {
pipStage.setStageSort(currStageSort);
}
}
}
updateBatchById(stageList);
}
}
public void deleteStages(String stageId) {
stageDao.deleteById(stageId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteFirstStage(String stageId) {
List<TemplateStage> secondStageAndTask = findSecondStageAndTask(stageId);
for (TemplateStage stage : secondStageAndTask) {
List<TemplateTask> taskValues = stage.getTaskValues();
if (!CollectionUtils.isEmpty(taskValues)) {
List<String> taskIdList = taskValues.stream().map(TemplateTask::getId).toList();
templateTaskService.removeBatchByIds(taskIdList);
}
}
List<String> secondStageIdList = secondStageAndTask.stream().map(TemplateStage::getId).toList();
removeBatchByIds(secondStageIdList);
TemplateStage byId = getById(stageId);
List<TemplateStage> allMainStage = findAllMainStage(byId.getTemplateId());
List<TemplateStage> updateList = new ArrayList<>(allMainStage.size());
for (TemplateStage stage : allMainStage) {
if (byId.getStageSort()<stage.getStageSort()) {
stage.setStageSort(stage.getStageSort()-1);
updateList.add(stage);
}
}
//如果删除的为最后一个新增阶段则无需更新前面阶段的sort值
if (!CollectionUtils.isEmpty(updateList)){
stageDao.updateBatch(updateList);
}
stageDao.deleteById(stageId);
}
public List<TemplateStage> findSecondStageAndTask(String stagesId){
List<TemplateStage> otherStage = findSecondStage(stagesId);
List<TemplateStage> list = new ArrayList<>();
List<String> stageIdList = otherStage.stream().map(TemplateStage::getId).toList();
if (stageIdList.isEmpty()) {
throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"当前阶段下不存在节点");
}
Map<String, List<TemplateTask>> stageIdTaskMap = templateTaskService.getTaskByStageIdList(stageIdList).stream().collect(Collectors.groupingBy(TemplateTask::getStageId));
for (TemplateStage stage : otherStage) {
//获取阶段配置及任务
String otherId = stage.getId();
List<TemplateTask> allStageTask = stageIdTaskMap.get(otherId);
allStageTask.sort(Comparator.comparing(TemplateTask::getTaskSort));
stage.setTaskValues(allStageTask);
list.add(stage);
}
return list;
}
// 获取主stage阶段下的子stage
public List<TemplateStage> findSecondStage(String stageId){
LambdaQueryWrapper<TemplateStage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TemplateStage::getParentId,stageId);
return stageDao.selectList(wrapper);
}
}

View File

@ -0,0 +1,76 @@
package cd.casic.ci.process.process.service.template.impl;
import cd.casic.ci.process.dto.req.task.TaskUpdateReq;
import cd.casic.ci.process.dto.req.template.TemplateTaskUpdateReq;
import cd.casic.ci.process.dto.resp.task.TasksResp;
import cd.casic.ci.process.dto.resp.template.TemplateTasksResp;
import cd.casic.ci.process.process.converter.TemplateTaskConverter;
import cd.casic.ci.process.process.dao.template.TemplateTaskDao;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.dataObject.template.TemplateTask;
import cd.casic.ci.process.process.service.template.TemplateTaskService;
import cd.casic.ci.process.util.WebFrameworkUtils;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
public class TemplateTaskServiceImpl extends ServiceImpl<TemplateTaskDao, TemplateTask> implements TemplateTaskService {
@Resource
private TemplateTaskDao taskDao;
@Resource
private TemplateTaskConverter taskConverter;
@Override
public List<TemplateTask> getTask(TemplateTask task) {
LambdaQueryWrapper<TemplateTask> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.isNotEmpty(task.getId()),TemplateTask::getId,task.getId());
wrapper.eq(StringUtils.isNotEmpty(task.getTemplateId()),TemplateTask::getTemplateId,task.getTemplateId());
wrapper.eq(StringUtils.isNotEmpty(task.getStageId()),TemplateTask::getStageId,task.getStageId());
return taskDao.selectList(wrapper);
}
@Override
public List<TemplateTask> getTaskByStageIdList(List<String> stageIdList){
LambdaQueryWrapper<TemplateTask> wrapper = new LambdaQueryWrapper<>();
wrapper.in(TemplateTask::getStageId,stageIdList);
return taskDao.selectList(wrapper);
}
@Override
public TemplateTasksResp getRespById(String taskId){
TemplateTask pipTask = new TemplateTask();
pipTask.setId(taskId);
List<TemplateTask> taskList = getTask(pipTask);
if (CollectionUtils.isEmpty(taskList)) {
return null;
}
return taskConverter.doToResp(taskList.get(0));
}
@Override
public Boolean updateTask(TemplateTaskUpdateReq req) {
if (StringUtils.isEmpty(req.getId())) {
throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"传入id有问题");
}
TemplateTask byId = getById(req.getId());
if (byId == null) {
throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"task不存在");
}
String taskName = req.getTaskName();
Map<String, Object> taskProperties = req.getTaskProperties();
String taskType = req.getTaskType();
byId.setTaskProperties(taskProperties);
byId.setTaskType(taskType);
byId.setTaskName(taskName);
byId.setUpdater(WebFrameworkUtils.getLoginUserIdStr());
byId.setUpdateTime(LocalDateTime.now());
return updateById(byId);
}
}

View File

@ -3,12 +3,17 @@ package cd.casic.ci.process.process.service.testCase;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerDownloadResp;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp; import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp;
import cd.casic.ci.process.process.dataObject.testCase.TestCaseManager; import cd.casic.ci.process.process.dataObject.testCase.TestCaseManager;
import cd.casic.framework.commons.pojo.PageResult; import cd.casic.framework.commons.pojo.PageResult;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.io.IOException;
import java.util.List; import java.util.List;
/** /**
@ -32,4 +37,6 @@ public interface TestCaseManagerService extends IService<TestCaseManager> {
TestCaseManagerResp findById(String id); TestCaseManagerResp findById(String id);
TestCaseManagerDownloadResp downLoadById(String id );
} }

View File

@ -4,6 +4,7 @@ package cd.casic.ci.process.process.service.testCase.impl;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerQueryReq;
import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq; import cd.casic.ci.process.dto.req.testCase.TestCaseManagerReq;
import cd.casic.ci.process.dto.resp.testCase.TestCaseInfoResp; import cd.casic.ci.process.dto.resp.testCase.TestCaseInfoResp;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerDownloadResp;
import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp; import cd.casic.ci.process.dto.resp.testCase.TestCaseManagerResp;
import cd.casic.ci.process.process.converter.TestCaseManagerConverter; import cd.casic.ci.process.process.converter.TestCaseManagerConverter;
import cd.casic.ci.process.process.dao.testCase.TestCaseInfoDao; import cd.casic.ci.process.process.dao.testCase.TestCaseInfoDao;
@ -23,21 +24,22 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.*;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import java.util.ArrayList; import java.io.ByteArrayOutputStream;
import java.util.List; import java.io.InputStream;
import java.util.Map; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/** /**
* @author HopeLi * @author HopeLi
@ -64,7 +66,8 @@ public class TestCaseManagerServiceImpl extends ServiceImpl<TestCaseManagerDao,
@Resource @Resource
private TestCaseInfoService testCaseInfoService; private TestCaseInfoService testCaseInfoService;
@Resource
private TargetFileUploadProperties properties;
@Override @Override
public String create(TestCaseManagerReq req) { public String create(TestCaseManagerReq req) {
TestCaseManager testCaseManager = TestCaseManagerConverter.INSTANCE.toBean(req); TestCaseManager testCaseManager = TestCaseManagerConverter.INSTANCE.toBean(req);
@ -147,6 +150,44 @@ public class TestCaseManagerServiceImpl extends ServiceImpl<TestCaseManagerDao,
return testCaseManagerResp; return testCaseManagerResp;
} }
@Override
public TestCaseManagerDownloadResp downLoadById(String id) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ZipOutputStream zipOutputStream = new ZipOutputStream(bos)){
JSch jsch = new JSch();
Session session = jsch.getSession(properties.getUsername(), properties.getRemoteHost(), properties.getRemotePort());
session.setPassword(properties.getPassword());
// 跳过 host key 检查
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
sftp.connect();
List<TestCaseInfoResp> byManagerIds = testCaseInfoService.findByManagerIds(Collections.singletonList(id));
for (TestCaseInfoResp byManagerId : byManagerIds) {
InputStream inputStream = sftp.get(byManagerId.getTestFilePath());
String fileName = byManagerId.getFileName();
ZipEntry zipEntry = new ZipEntry(fileName);
zipOutputStream.putNextEntry(zipEntry);
IOUtils.copy(inputStream,zipOutputStream);
zipOutputStream.closeEntry();
inputStream.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
byte[] byteArray = bos.toByteArray();
String file = Base64.getEncoder().encodeToString(byteArray);
TestCaseManagerDownloadResp testCaseManagerDownloadResp = new TestCaseManagerDownloadResp();
testCaseManagerDownloadResp.setFile(file);
testCaseManagerDownloadResp.setFileName("SEED.zip");
return testCaseManagerDownloadResp;
}
private void setUserName(TestCaseManagerResp testCaseManagerResp) { private void setUserName(TestCaseManagerResp testCaseManagerResp) {
if (!StringUtils.isEmpty(testCaseManagerResp.getCreator())){ if (!StringUtils.isEmpty(testCaseManagerResp.getCreator())){
@ -219,13 +260,15 @@ public class TestCaseManagerServiceImpl extends ServiceImpl<TestCaseManagerDao,
for (TestCaseInfoResp testCaseInfo : testCaseInfos) { for (TestCaseInfoResp testCaseInfo : testCaseInfos) {
JSONArray array= JSONArray.parseArray(testCaseInfo.getTestFileList()); JSONArray array= JSONArray.parseArray(testCaseInfo.getTestFileList());
if (!array.isEmpty()) { if (!array.isEmpty()) {
JSONObject jsonObject = array.getJSONObject(0); for (int i = 0; i < array.size(); i++) {
Integer fileSize = jsonObject.getInteger("size"); JSONObject jsonObject = array.getJSONObject(i);
size+=fileSize; Integer fileSize = jsonObject.getInteger("size");
size+=fileSize;
}
} }
} }
managerInfo.setFileCount(fileCount); managerInfo.setFileCount(fileCount);
managerInfo.setFileSize(getSizeStr(size)); managerInfo.setFileSize(getSizeStr(size*2));
} }
} }
private String getSizeStr(Integer size){ private String getSizeStr(Integer size){

View File

@ -2,23 +2,25 @@ package cd.casic.ci.process.properties;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@ConfigurationProperties(prefix = "target.file-upload") @ConfigurationProperties(prefix = "target.file-upload")
@Data @Data
@EnableConfigurationProperties
public class TargetFileUploadProperties { public class TargetFileUploadProperties {
//远程服务器IP或主机名 //远程服务器IP或主机名
private String remoteHost = "175.6.27.252"; private String remoteHost;
//远程服务器端口 (通常是 22) null <= 0 时使用默认端口 22 //远程服务器端口 (通常是 22) null <= 0 时使用默认端口 22
private Integer remotePort; private Integer remotePort;
//远程服务器用户名 //远程服务器用户名
private String username = "roots"; private String username;
//远程服务器密码 (如果使用密码认证) //远程服务器密码 (如果使用密码认证)
private String password = "hnidc0327cn!@#xhh"; private String password;
//SSH Key 文件路径 (如果使用密钥认证password 参数可以为 null) //SSH Key 文件路径 (如果使用密钥认证password 参数可以为 null)
private String sshKeyPath; private String sshKeyPath;
//远程服务器存放文件的目录 (例如: /home/user/uploads/) //远程服务器存放文件的目录 (例如: /home/user/uploads/)
private String remoteDir = "/home/ops/ops-pro/file/"; private String remoteDir;
} }

View File

@ -19,6 +19,7 @@
<module>module-ci-execute</module> <module>module-ci-execute</module>
<module>module-ci-process-api</module> <module>module-ci-process-api</module>
<module>module-ci-process-biz</module> <module>module-ci-process-biz</module>
<module>module-ci-machine</module>
</modules> </modules>
<artifactId>modules</artifactId> <artifactId>modules</artifactId>

View File

@ -0,0 +1,41 @@
package cd.casic.server;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
public class ClocTest {
public void fileExit(){
File file = new File("/ops-pro/ops-server/src/test/resources/java.zip");
}
@Test
public void test01() throws IOException, InterruptedException {
// 构建命令
ProcessBuilder pb = new ProcessBuilder("D:/cloc/cloc.exe", "/ops-pro/ops-server/src/test/resources/java.zip", "--json");
pb.redirectErrorStream(true); // 合并标准输出和错误输出
// 启动进程
Process process = pb.start();
StringBuilder stringBuilder = new StringBuilder();
// 读取输出
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
}
System.out.println(stringBuilder.toString());
// 等待进程结束并获取返回值
int exitCode = process.waitFor();
System.out.println("命令执行结束,返回值:" + exitCode);
}
}

View File

@ -11,6 +11,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.util.Properties;
import java.util.Vector; import java.util.Vector;
@SpringBootTest(classes = {OpsServerApplication.class}) @SpringBootTest(classes = {OpsServerApplication.class})

View File

@ -0,0 +1,69 @@
package cd.casic.server;
import cd.casic.ci.process.process.dataObject.machine.MachineInfo;
import cd.casic.ci.process.properties.TargetFileUploadProperties;
import cd.casic.ci.process.util.CryptogramUtil;
import cd.casic.ci.process.util.SftpUploadUtil;
import com.jcraft.jsch.*;
import jakarta.annotation.Resource;
import jodd.io.IOUtil;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.io.*;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
public class ZipFileTest {
@Resource
TargetFileUploadProperties properties;
String[] testFilePath = new String[]{
"/home/ops/ops-pro/file/af4b1435-8fb0-453d-acef-eaec75c67dd8/QQ图片20250623102626.png",
"/home/ops/ops-pro/file/7ffb5bb7-9ea2-4d8b-9e0e-b6c3f99107b5/新建 文本文档.txt",
"/home/ops/ops-pro/file/2622340c-20db-48fc-bca2-d867da3149aa/.nodemid",
"/home/ops/ops-pro/file/f601e6d7-050f-4c92-a353-e1db64e048e1/1 (2).txt",
"/home/ops/ops-pro/file/9bf7c208-0576-4408-833e-e0d7eecc5a8a/office账户.txt",
"/home/ops/ops-pro/file/332143a2-52da-4e29-8a3d-78071d4e3559/office账户.txt",
"/home/ops/ops-pro/file/bbf03a24-5a48-4863-b1b9-c52bb00a8b0f/office账户.txt",
"/home/ops/ops-pro/file/6ae5f778-e12c-48f2-bce1-8748e2435e26/脚本.txt",
"/home/ops/ops-pro/file/47c98d3b-553a-4934-b4c4-f9b185eac04a/1.txt",
"/home/ops/ops-pro/file/cafb8135-f1d1-42db-bb02-1444cda937fd/ximenzi.txt",
"/home/ops/ops-pro/file/0e78423d-b4b6-4442-b225-e66309515d42/office账户.txt",
"/home/ops/ops-pro/file/40831b9c-eb35-4eb9-973a-f087b48105e6/office账户.txt"
};
@Test
public void testZip() throws JSchException, SftpException {
JSch jsch = new JSch();
Session session = jsch.getSession(properties.getUsername(), properties.getRemoteHost(), properties.getRemotePort());
session.setPassword(properties.getPassword());
// 跳过 host key 检查
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
sftp.connect();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (String path : testFilePath) {
InputStream inputStream = sftp.get(path);
String fileName = path.substring(path.lastIndexOf("/"));
try (ZipOutputStream zipOutputStream = new ZipOutputStream(bos)){
ZipEntry zipEntry = new ZipEntry(fileName);
zipOutputStream.putNextEntry(zipEntry);
IOUtils.copy(inputStream,zipOutputStream);
zipOutputStream.closeEntry();
inputStream.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
System.out.println(bos.size());
}
}