v4 提交新的模型,但是模型不能运行,如果要运行,把ci-process卸载pom
This commit is contained in:
parent
a9820840f4
commit
42759b8f40
52
.idea/CopilotChatHistory.xml
generated
52
.idea/CopilotChatHistory.xml
generated
File diff suppressed because one or more lines are too long
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -14,8 +14,8 @@
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.6.2/mapstruct-1.6.2.jar" />
|
||||
</processorPath>
|
||||
<module name="ci-scm-repository" />
|
||||
<module name="spring-boot-starter-protection" />
|
||||
<module name="pipeline-ci-process-api" />
|
||||
<module name="spring-boot-starter-protection" />
|
||||
<module name="spring-boot-starter-monitor" />
|
||||
<module name="module-system-biz" />
|
||||
<module name="ci-quality" />
|
||||
|
@ -19,12 +19,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JSON 工具类
|
||||
* JSON 工具类 ,经量用hutool的
|
||||
*
|
||||
* @author mianbin
|
||||
*/
|
||||
@Slf4j
|
||||
public class JsonUtils {
|
||||
public class JsonUtils extends JSONUtil {
|
||||
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@ -104,7 +104,7 @@ public class JsonUtils {
|
||||
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
|
||||
* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。
|
||||
*
|
||||
* @param text 字符串
|
||||
* @param text 字符串
|
||||
* @param clazz 类型
|
||||
* @return 对象
|
||||
*/
|
||||
@ -139,7 +139,7 @@ public class JsonUtils {
|
||||
/**
|
||||
* 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null
|
||||
*
|
||||
* @param text 字符串
|
||||
* @param text 字符串
|
||||
* @param typeReference 类型引用
|
||||
* @return 指定类型的对象
|
||||
*/
|
||||
|
@ -25,7 +25,14 @@ public interface IModelTemplate {
|
||||
@Schema(title = "变量", required = true)
|
||||
Map<String, String> getVariables();
|
||||
|
||||
|
||||
/**
|
||||
* 判读是否来自于模板
|
||||
*
|
||||
* @return true 是来自于模板|false 不是来自于模板
|
||||
*/
|
||||
default boolean fromTemplate() {
|
||||
return getTemplate() != null && !getTemplate().isEmpty();
|
||||
String template = getTemplate();
|
||||
return template != null && !template.isEmpty();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cd.casic.ci.common.pipeline.container;
|
||||
|
||||
import cd.casic.ci.common.pipeline.type.agent.AgentType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
@ -1,12 +1,16 @@
|
||||
package cd.casic.ci.common.pipeline.container;
|
||||
|
||||
import cd.casic.ci.common.pipeline.IModelTemplate;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.time.BuildRecordTimeCost;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -20,8 +24,8 @@ import java.util.Map;
|
||||
* @Filename:Container
|
||||
* @description:Todo
|
||||
*/
|
||||
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@Schema(title = "流水线模型-多态基类")
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
|
||||
@JsonSubTypes({
|
||||
@ -29,50 +33,65 @@ import java.util.Map;
|
||||
@JsonSubTypes.Type(value = NormalContainer.class, name = NormalContainer.classType),
|
||||
@JsonSubTypes.Type(value = VMBuildContainer.class, name = VMBuildContainer.classType)
|
||||
})
|
||||
public interface Container extends IModelTemplate {
|
||||
String getId();
|
||||
void setId(String id);
|
||||
String getName();
|
||||
void setName(String name);
|
||||
List<Element> getElements();
|
||||
void setElements(List<Element> elements);
|
||||
String getStatus();
|
||||
void setStatus(String status);
|
||||
Long getStartEpoch();
|
||||
void setStartEpoch(Long startEpoch);
|
||||
Long getSystemElapsed();
|
||||
void setSystemElapsed(Long systemElapsed);
|
||||
Long getElementElapsed();
|
||||
void setElementElapsed(Long elementElapsed);
|
||||
Boolean getCanRetry();
|
||||
void setCanRetry(Boolean canRetry);
|
||||
String getContainerId();
|
||||
void setContainerId(String containerId);
|
||||
String getContainerHashId();
|
||||
void setContainerHashId(String containerHashId);
|
||||
String getStartVMStatus();
|
||||
void setStartVMStatus(String startVMStatus);
|
||||
Integer getExecuteCount();
|
||||
void setExecuteCount(Integer executeCount);
|
||||
String getJobId();
|
||||
void setJobId(String jobId);
|
||||
Boolean getContainPostTaskFlag();
|
||||
void setContainPostTaskFlag(Boolean containPostTaskFlag);
|
||||
Boolean getMatrixGroupFlag();
|
||||
void setMatrixGroupFlag(Boolean matrixGroupFlag);
|
||||
BuildRecordTimeCost getTimeCost();
|
||||
void setTimeCost(BuildRecordTimeCost timeCost);
|
||||
Integer getStartVMTaskSeq();
|
||||
void setStartVMTaskSeq(Integer startVMTaskSeq);
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public abstract class Container implements IModelTemplate {
|
||||
private String id;
|
||||
private String name;
|
||||
private List<Element> elements;
|
||||
private String status;
|
||||
@Deprecated
|
||||
private Long startEpoch;
|
||||
@Deprecated
|
||||
private Long systemElapsed;
|
||||
@Deprecated
|
||||
private Long elementElapsed;
|
||||
private Boolean canRetry;
|
||||
private String containerId;
|
||||
private String containerHashId;
|
||||
private String startVMStatus;
|
||||
private Integer executeCount;
|
||||
private String jobId;
|
||||
private Boolean containPostTaskFlag;
|
||||
private Boolean matrixGroupFlag;
|
||||
private BuildRecordTimeCost timeCost;
|
||||
private Integer startVMTaskSeq;
|
||||
|
||||
void resetBuildOption(int executeCount);
|
||||
void transformCompatibility();
|
||||
Map<String, Object> genTaskParams();
|
||||
String getClassType();
|
||||
Container getContainerById(String vmSeqId);
|
||||
void retryFreshMatrixOption();
|
||||
List<Container> fetchGroupContainers();
|
||||
Map<String, String> fetchMatrixContext();
|
||||
Boolean containerEnabled();
|
||||
void setContainerEnable(Boolean enable);
|
||||
}
|
||||
public void resetBuildOption(int executeCount) {
|
||||
this.status = null;
|
||||
this.timeCost = null;
|
||||
this.startEpoch = null;
|
||||
this.elementElapsed = null;
|
||||
this.systemElapsed = null;
|
||||
this.startVMStatus = null;
|
||||
this.executeCount = executeCount;
|
||||
}
|
||||
|
||||
public void transformCompatibility() {
|
||||
if (elements != null) {
|
||||
elements.forEach(Element::transformCompatibility);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> genTaskParams() {
|
||||
Map<String, Object> configParams = JSONUtil.parseObj(this).toBean(Map.class);
|
||||
if (elements != null && !elements.isEmpty()) {
|
||||
configParams.put("elements", List.of());
|
||||
}
|
||||
return configParams;
|
||||
}
|
||||
|
||||
public abstract String getClassType();
|
||||
|
||||
public abstract Container getContainerById(String vmSeqId);
|
||||
|
||||
public abstract void retryFreshMatrixOption();
|
||||
|
||||
public abstract List<Container> fetchGroupContainers();
|
||||
|
||||
public abstract Map<String, String> fetchMatrixContext();
|
||||
|
||||
public abstract boolean containerEnabled();
|
||||
|
||||
public abstract void setContainerEnable(boolean enable);
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
package cd.casic.ci.common.pipeline.container;
|
||||
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.option.JobControlOption;
|
||||
import cd.casic.ci.common.pipeline.option.MatrixControlOption;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.time.BuildRecordTimeCost;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -130,6 +135,11 @@ public class NormalContainer implements Container {
|
||||
jobControlOption = jobControlOption != null ? jobControlOption.copy(enable) : new JobControlOption(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetBuildOption(int executeCount) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformCompatibility() {
|
||||
if (jobControlOption != null && jobControlOption.getTimeoutVar() == null || jobControlOption.getTimeoutVar().isBlank()) {
|
||||
@ -139,4 +149,24 @@ public class NormalContainer implements Container {
|
||||
mutexGroup.setTimeoutVar(String.valueOf(mutexGroup.getTimeout()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> genTaskParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRef() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package cd.casic.ci.common.pipeline.container;
|
||||
|
||||
import cd.casic.ci.common.pipeline.IModelTemplate;
|
||||
import cd.casic.ci.common.pipeline.option.StageControlOption;
|
||||
import cd.casic.ci.common.pipeline.pojo.StagePauseCheck;
|
||||
import cd.casic.ci.common.pipeline.pojo.time.BuildRecordTimeCost;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -17,89 +20,103 @@ import java.util.Map;
|
||||
* @Filename:Stage
|
||||
* @description:Todo
|
||||
*/
|
||||
public class Stage {
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Schema(title = "流水线模型-阶段")
|
||||
public class Stage implements IModelTemplate {
|
||||
@Schema(title = "容器集合", required = true)
|
||||
private List<Container> containers;
|
||||
@Schema(title = "阶段ID (系统标识,用户不可编辑)", required = false)
|
||||
private String id;
|
||||
@Schema(title = "阶段名称", required = true)
|
||||
private String name;
|
||||
@Schema(title = "阶段ID (用户可编辑)", required = false)
|
||||
private String stageIdForUser;
|
||||
@Schema(title = "阶段标签", required = false, readOnly = true)
|
||||
private List<String> tag;
|
||||
@Schema(title = "阶段状态", required = false, readOnly = true)
|
||||
private String status;
|
||||
@Schema(title = "阶段启动时间", required = false, readOnly = true)
|
||||
@Deprecated
|
||||
private Long startEpoch;
|
||||
@Schema(title = "容器运行时间", required = false, readOnly = true)
|
||||
@Deprecated
|
||||
private Long elapsed;
|
||||
@Schema(title = "用户自定义环境变量", required = false)
|
||||
private Map<String, String> customBuildEnv;
|
||||
@Schema(title = "是否启用容器失败快速终止阶段", required = false)
|
||||
private Boolean fastKill;
|
||||
@Schema(title = "标识是否为FinallyStage,每个Model只能包含一个FinallyStage,并且处于最后位置", required = false)
|
||||
private Boolean finally;
|
||||
@Schema(title = "当前Stage是否能重试", required = false)
|
||||
private Boolean canRetry;
|
||||
@Schema(title = "流程控制选项", required = true)
|
||||
private StageControlOption stageControlOption;
|
||||
@Schema(title = "stage准入配置", required = false)
|
||||
private StagePauseCheck checkIn;
|
||||
@Schema(title = "stage准出配置", required = false)
|
||||
private StagePauseCheck checkOut;
|
||||
@Schema(title = "步骤运行次数", required = false, readOnly = true)
|
||||
private Integer executeCount;
|
||||
@Schema(title = "各项耗时", required = true)
|
||||
private BuildRecordTimeCost timeCost;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Schema(title = "流水线模型-阶段")
|
||||
public class Stage implements IModelTemplate {
|
||||
@Schema(title = "容器集合", required = true)
|
||||
private List<Container> containers;
|
||||
@Schema(title = "阶段ID (系统标识,用户不可编辑)", required = false)
|
||||
private String id;
|
||||
@Schema(title = "阶段名称", required = true)
|
||||
private String name;
|
||||
@Schema(title = "阶段ID (用户可编辑)", required = false)
|
||||
private String stageIdForUser;
|
||||
@Schema(title = "阶段标签", required = false, readOnly = true)
|
||||
private List<String> tag;
|
||||
@Schema(title = "阶段状态", required = false, readOnly = true)
|
||||
private String status;
|
||||
@Schema(title = "阶段启动时间", required = false, readOnly = true)
|
||||
@Deprecated
|
||||
private Long startEpoch;
|
||||
@Schema(title = "容器运行时间", required = false, readOnly = true)
|
||||
@Deprecated
|
||||
private Long elapsed;
|
||||
@Schema(title = "用户自定义环境变量", required = false)
|
||||
private Map<String, String> customBuildEnv;
|
||||
@Schema(title = "是否启用容器失败快速终止阶段", required = false)
|
||||
private Boolean fastKill;
|
||||
@Schema(title = "标识是否为FinallyStage,每个Model只能包含一个FinallyStage,并且处于最后位置", required = false)
|
||||
private Boolean finallyStage;
|
||||
@Schema(title = "当前Stage是否能重试", required = false)
|
||||
private Boolean canRetry;
|
||||
@Schema(title = "流程控制选项", required = true)
|
||||
private StageControlOption stageControlOption;
|
||||
@Schema(title = "stage准入配置", required = false)
|
||||
private StagePauseCheck checkIn;
|
||||
@Schema(title = "stage准出配置", required = false)
|
||||
private StagePauseCheck checkOut;
|
||||
@Schema(title = "步骤运行次数", required = false, readOnly = true)
|
||||
private Integer executeCount;
|
||||
@Schema(title = "各项耗时", required = true)
|
||||
private BuildRecordTimeCost timeCost;
|
||||
|
||||
public void resetBuildOption(Boolean init) {
|
||||
if (init != null && init) {
|
||||
status = null;
|
||||
startEpoch = null;
|
||||
elapsed = null;
|
||||
}
|
||||
if (checkIn != null) {
|
||||
checkIn.fixReviewGroups(init != null && init);
|
||||
}
|
||||
if (checkOut != null) {
|
||||
checkOut.fixReviewGroups(init != null && init);
|
||||
}
|
||||
if (stageControlOption != null && stageControlOption.getManualTrigger() && checkIn == null) {
|
||||
checkIn = StagePauseCheck.convertControlOption(stageControlOption);
|
||||
}
|
||||
if (finally !=null && finally){
|
||||
canRetry = false;
|
||||
}
|
||||
public void resetBuildOption(Boolean init) {
|
||||
if (init != null && init) {
|
||||
status = null;
|
||||
startEpoch = null;
|
||||
elapsed = null;
|
||||
}
|
||||
|
||||
public Container getContainer(String vmSeqId) {
|
||||
if (containers != null) {
|
||||
for (Container container : containers) {
|
||||
Container foundContainer = container.getContainerById(vmSeqId);
|
||||
if (foundContainer != null) {
|
||||
return foundContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (checkIn != null) {
|
||||
checkIn.fixReviewGroups(init != null && init);
|
||||
}
|
||||
|
||||
public void transformCompatibility() {
|
||||
if (containers != null) {
|
||||
for (Container container : containers) {
|
||||
container.transformCompatibility();
|
||||
}
|
||||
}
|
||||
if (checkOut != null) {
|
||||
checkOut.fixReviewGroups(init != null && init);
|
||||
}
|
||||
|
||||
public Boolean stageEnabled() {
|
||||
return stageControlOption != null ? stageControlOption.getEnable() : true;
|
||||
if (stageControlOption != null && stageControlOption.getManualTrigger() && checkIn == null) {
|
||||
checkIn = StagePauseCheck.convertControlOption(stageControlOption);
|
||||
}
|
||||
if (finallyStage !=null && finallyStage){
|
||||
canRetry = false;
|
||||
}
|
||||
}
|
||||
|
||||
public Container getContainer(String vmSeqId) {
|
||||
if (containers != null) {
|
||||
for (Container container : containers) {
|
||||
Container foundContainer = container.getContainerById(vmSeqId);
|
||||
if (foundContainer != null) {
|
||||
return foundContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void transformCompatibility() {
|
||||
if (containers != null) {
|
||||
for (Container container : containers) {
|
||||
container.transformCompatibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean stageEnabled() {
|
||||
return stageControlOption != null ? stageControlOption.getEnable() : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRef() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package cd.casic.ci.common.pipeline.container;
|
||||
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.enums.VMBaseOS;
|
||||
import cd.casic.ci.common.pipeline.option.JobControlOption;
|
||||
import cd.casic.ci.common.pipeline.option.MatrixControlOption;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.time.BuildRecordTimeCost;
|
||||
import cd.casic.ci.common.pipeline.type.DispatchType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -154,7 +161,7 @@ public class VMBuildContainer implements Container {
|
||||
|
||||
@Override
|
||||
public void setContainerEnable(Boolean enable) {
|
||||
jobControlOption = jobControlOption != null ? jobControlOption.copy(enable) : new JobControlOption(enable);
|
||||
jobControlOption = jobControlOption != null ? jobControlOption.setEnable(enable) : new JobControlOption(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,32 @@
|
||||
package cd.casic.ci.common.pipeline.dialect;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.dialect
|
||||
* @Project:ops-pro
|
||||
* @name:ClassicPipelineDialect
|
||||
* @Date:2025/03/27 10:36
|
||||
* @Filename:ClassicPipelineDialect
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ClassicPipelineDialect implements IPipelineDialect {
|
||||
@Override
|
||||
public String getPipelineDialectType() {
|
||||
return PipelineDialectType.CLASSIC.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportUseExpression() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportChineseVarName() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package cd.casic.ci.common.pipeline.dialect;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.dialect
|
||||
* @Project:ops-pro
|
||||
* @name:ConstrainedPipelineDialect
|
||||
* @Date:2025/03/27 10:36
|
||||
* @Filename:ConstrainedPipelineDialect
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ConstrainedPipelineDialect implements IPipelineDialect {
|
||||
@Override
|
||||
public String getPipelineDialectType() {
|
||||
return PipelineDialectType.CONSTRAINED.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportUseExpression() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportChineseVarName() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cd.casic.ci.common.pipeline.dialect;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.dialect
|
||||
* @Project:ops-pro
|
||||
* @name:IPipelineDialect
|
||||
* @Date:2025/03/27 10:35
|
||||
* @Filename:IPipelineDialect
|
||||
* @description:Todo
|
||||
*/
|
||||
public interface IPipelineDialect {
|
||||
String getPipelineDialectType();
|
||||
|
||||
/**
|
||||
* 1. 仅支持双花括号,避免出现 bash 脚本变量在执行前被系统赋值的问题
|
||||
* 2. 流程控制选项、插件入参、Job设置等流水线配置中均可使用函数
|
||||
*/
|
||||
boolean supportUseExpression();
|
||||
/**
|
||||
* 是否支持中文变量名
|
||||
*/
|
||||
boolean supportChineseVarName();
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cd.casic.ci.common.pipeline.dialect;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.dialect
|
||||
* @Project:ops-pro
|
||||
* @name:PipelineDialectType
|
||||
* @Date:2025/03/27 10:36
|
||||
* @Filename:PipelineDialectType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
public enum PipelineDialectType {
|
||||
CLASSIC(new ClassicPipelineDialect()),
|
||||
CONSTRAINED(new ConstrainedPipelineDialect());
|
||||
|
||||
private final IPipelineDialect dialect;
|
||||
|
||||
PipelineDialectType(IPipelineDialect dialect) {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cd.casic.ci.common.pipeline.dialect;
|
||||
|
||||
import cd.casic.ci.common.pipeline.enums.ChannelCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.dialect
|
||||
* @Project:ops-pro
|
||||
* @name:PipelineDialectUtil
|
||||
* @Date:2025/03/27 10:36
|
||||
* @Filename:PipelineDialectUtil
|
||||
* @description:Todo
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class PipelineDialectUtil {
|
||||
public static IPipelineDialect getPipelineDialect(String pipelineDialectType) {
|
||||
return pipelineDialectType != null ? PipelineDialectType.valueOf(pipelineDialectType).getDialect() : PipelineDialectType.CLASSIC.getDialect();
|
||||
}
|
||||
|
||||
public static IPipelineDialect getPipelineDialect(Boolean inheritedDialect, String projectDialect, String pipelineDialect) {
|
||||
return getPipelineDialectType(inheritedDialect, projectDialect, pipelineDialect).getDialect();
|
||||
}
|
||||
|
||||
public static PipelineDialectType getPipelineDialectType(Boolean inheritedDialect, String projectDialect, String pipelineDialect) {
|
||||
if (inheritedDialect == null || inheritedDialect) {
|
||||
if (projectDialect != null) {
|
||||
return PipelineDialectType.valueOf(projectDialect);
|
||||
}
|
||||
} else if (pipelineDialect != null) {
|
||||
return PipelineDialectType.valueOf(pipelineDialect);
|
||||
}
|
||||
return PipelineDialectType.CLASSIC;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cd.casic.ci.common.pipeline.enums;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -0,0 +1,83 @@
|
||||
package cd.casic.ci.common.pipeline.extend;
|
||||
|
||||
import cd.casic.ci.common.pipeline.Model;
|
||||
import cd.casic.ci.common.pipeline.container.Container;
|
||||
import cd.casic.ci.common.pipeline.dialect.IPipelineDialect;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.atom.BeforeDeleteParam;
|
||||
import cd.casic.ci.common.pipeline.pojo.setting.PipelineSetting;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.extend
|
||||
* @Project:ops-pro
|
||||
* @name:ModelCheckPlugin
|
||||
* @Date:2025/03/27 10:39
|
||||
* @Filename:ModelCheckPlugin
|
||||
* @description:Todo
|
||||
*/
|
||||
public interface ModelCheckPlugin {
|
||||
|
||||
/**
|
||||
* 检查[model]编排的完整性,并返回[JobSize + ElementSize = MetaSize]所有元素数量
|
||||
*
|
||||
* @param userId 操作人
|
||||
* @param oauthUser 当前流水线权限代持人
|
||||
* @param pipelineDialect 流水线方言,只有新增/编辑流水线或模版时才需要传入
|
||||
* @throws ErrorCodeException 检查失败或异常
|
||||
*/
|
||||
int checkModelIntegrity(
|
||||
Model model,
|
||||
String projectId,
|
||||
String userId,
|
||||
boolean isTemplate,
|
||||
String oauthUser,
|
||||
IPipelineDialect pipelineDialect,
|
||||
String pipelineId
|
||||
) throws ErrorCodeException;
|
||||
|
||||
/**
|
||||
* 检查[setting]配置的完整性
|
||||
*
|
||||
* @throws ErrorCodeException 检查失败或异常
|
||||
*/
|
||||
void checkSettingIntegrity(PipelineSetting setting, String projectId) throws ErrorCodeException;
|
||||
|
||||
/**
|
||||
* 清理Model--不删除里面的Element内的逻辑
|
||||
*/
|
||||
void clearUpModel(Model model);
|
||||
|
||||
/**
|
||||
* 在删除element前做的一些处理
|
||||
* 对比sourceModel,并清理model中与之不同的Element
|
||||
*
|
||||
* @param existModel 目标Model(要清理的Model)
|
||||
* @param sourceModel 源要比较的Model
|
||||
*/
|
||||
void beforeDeleteElementInExistsModel(
|
||||
Model existModel,
|
||||
Model sourceModel,
|
||||
BeforeDeleteParam param
|
||||
);
|
||||
|
||||
/**
|
||||
* 检查[container]下的[element]插件的超时配置是否合法。
|
||||
* 如果使用了变量,则从变量表[contextMap]进行替换,如果值不符合,则抛出异常[ErrorCodeException]
|
||||
*/
|
||||
void checkElementTimeoutVar(Container container, Element element, Map<String, String> contextMap) throws ErrorCodeException;
|
||||
|
||||
/**
|
||||
* 检查[container]下互斥组配置是否合法,
|
||||
* 如果使用了变量,则从变量表[contextMap]进行替换,如果值不符合,则抛出异常[ErrorCodeException]
|
||||
*/
|
||||
void checkMutexGroup(Container container, Map<String, String> contextMap) throws ErrorCodeException;
|
||||
|
||||
/**
|
||||
* 检查是否是[finallyStage]Stage的Job[container]下[JobControlOption]配置是否合法。
|
||||
* 如果使用了变量,则从变量表[contextMap]进行替换,如果值不符合,则抛出异常[ErrorCodeException]
|
||||
*/
|
||||
void checkJobCondition(Container container, boolean finallyStage, Map<String, String> contextMap) throws ErrorCodeException;
|
||||
}
|
@ -1,6 +1,16 @@
|
||||
package cd.casic.ci.common.pipeline.pojo;
|
||||
|
||||
import cd.casic.ci.common.pipeline.EnvReplacementParser;
|
||||
import cd.casic.ci.common.pipeline.dialect.IPipelineDialect;
|
||||
import cd.casic.ci.common.pipeline.enums.BuildStatus;
|
||||
import cd.casic.ci.common.pipeline.enums.ManualReviewAction;
|
||||
import cd.casic.ci.common.pipeline.option.StageControlOption;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.atom.ManualReviewParam;
|
||||
import cn.hutool.captcha.generator.RandomGenerator;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@ -20,6 +30,7 @@ import java.util.stream.Collectors;
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "stage准入准出配置模型")
|
||||
public class StagePauseCheck {
|
||||
@ -192,11 +203,12 @@ public class StagePauseCheck {
|
||||
}
|
||||
|
||||
public static StagePauseCheck convertControlOption(StageControlOption stageControlOption) {
|
||||
|
||||
return new StagePauseCheck()
|
||||
.setManualTrigger(stageControlOption.getManualTrigger())
|
||||
.setStatus(stageControlOption.getTriggered() ? BuildStatus.REVIEW_PROCESSED.name() : null)
|
||||
.setReviewGroups(List.of(new StageReviewGroup()
|
||||
.setId(UUIDUtil.generate())
|
||||
.setId(IdUtil.fastUUID())
|
||||
.setReviewers(stageControlOption.getTriggerUsers())
|
||||
.setStatus(stageControlOption.getTriggered() ? ManualReviewAction.PROCESS.name() : null)
|
||||
.setParams(stageControlOption.getReviewParams())))
|
||||
|
@ -4,9 +4,19 @@ import cd.casic.ci.common.pipeline.IModelTemplate;
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.enums.BuildStatus;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.agent.*;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.market.MarketBuildAtomElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.market.MarketBuildLessAtomElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.market.MarketCheckImageElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.matrix.MatrixStatusElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.quality.QualityGateInElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.quality.QualityGateOutElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.*;
|
||||
import cd.casic.ci.common.pipeline.pojo.time.BuildRecordTimeCost;
|
||||
import cd.casic.ci.common.pipeline.pojo.transfer.PreStep;
|
||||
import cd.casic.ci.common.pipeline.utils.ElementUtils;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@ -121,7 +131,7 @@ public abstract class Element implements IModelTemplate {
|
||||
}
|
||||
|
||||
public Map<String, Object> genTaskParams() {
|
||||
return JsonUtil.toMutableMap(this);
|
||||
return JSONUtil.parseObj(this).toBean(Map.class);
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@ -13,6 +14,7 @@ import lombok.Data;
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Schema(title = "插件属性")
|
||||
public class ElementProp {
|
||||
private String name;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.market;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.market;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.market;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.market;
|
||||
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.market;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.market;
|
||||
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.market;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.market;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.matrix;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.matrix;
|
||||
|
||||
import cd.casic.ci.common.pipeline.NameAndValue;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.quality;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.quality;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.quality;
|
||||
package cd.casic.ci.common.pipeline.pojo.element.quality;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -0,0 +1,225 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.CodeEventType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.PathFilterType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeGitWebHookTriggerElement
|
||||
* @Date:2025/03/27 10:20
|
||||
* @Filename:CodeGitWebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "Git事件触发", description = CodeGitWebHookTriggerElement.classType)
|
||||
public class CodeGitWebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeGitWebHookTrigger";
|
||||
public static final String MERGE_ACTION_OPEN = "open";
|
||||
public static final String MERGE_ACTION_CLOSE = "close";
|
||||
public static final String MERGE_ACTION_REOPEN = "reopen";
|
||||
public static final String MERGE_ACTION_PUSH_UPDATE = "push-update";
|
||||
public static final String MERGE_ACTION_MERGE = "merge";
|
||||
public static final String PUSH_ACTION_CREATE_BRANCH = "new-branch";
|
||||
public static final String PUSH_ACTION_PUSH_FILE = "push-file";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "Git事件触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "分支名称", required = false)
|
||||
private String branchName;
|
||||
|
||||
@Schema(title = "用于排除的分支名", required = false)
|
||||
private String excludeBranchName;
|
||||
|
||||
@Schema(title = "路径过滤类型", required = true)
|
||||
private PathFilterType pathFilterType = PathFilterType.NamePrefixFilter;
|
||||
|
||||
@Schema(title = "用于包含的路径", required = false)
|
||||
private String includePaths;
|
||||
|
||||
@Schema(title = "用于排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "用户白名单", required = false)
|
||||
private List<String> includeUsers;
|
||||
|
||||
@Schema(title = "用于排除的user id", required = false)
|
||||
private List<String> excludeUsers;
|
||||
|
||||
@Schema(title = "事件类型", required = false)
|
||||
private CodeEventType eventType;
|
||||
|
||||
@Schema(title = "是否为block", required = false)
|
||||
private Boolean block;
|
||||
|
||||
@Schema(title = "新版的git原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的git代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Schema(title = "tag名称", required = false)
|
||||
private String tagName;
|
||||
|
||||
@Schema(title = "用于排除的tag名称", required = false)
|
||||
private String excludeTagName;
|
||||
|
||||
@Schema(title = "tag从哪条分支创建", required = false)
|
||||
private String fromBranches;
|
||||
|
||||
@Schema(title = "用于排除的源分支名称", required = false)
|
||||
private String excludeSourceBranchName;
|
||||
|
||||
@Schema(title = "用于包含的源分支名称", required = false)
|
||||
private String includeSourceBranchName;
|
||||
|
||||
@Schema(title = "webhook队列", required = false)
|
||||
private Boolean webhookQueue = false;
|
||||
|
||||
@Schema(title = "code review 状态", required = false)
|
||||
private List<String> includeCrState;
|
||||
|
||||
@Schema(title = "code review 类型", required = false)
|
||||
private List<String> includeCrTypes;
|
||||
|
||||
@Schema(title = "code note comment", required = false)
|
||||
private String includeNoteComment;
|
||||
|
||||
@Schema(title = "code note 类型", required = false)
|
||||
private List<String> includeNoteTypes;
|
||||
|
||||
@Schema(title = "是否启用回写")
|
||||
private Boolean enableCheck = true;
|
||||
|
||||
@Schema(title = "issue事件action")
|
||||
private List<String> includeIssueAction;
|
||||
|
||||
@Schema(title = "mr事件action")
|
||||
private List<String> includeMrAction;
|
||||
|
||||
@Schema(title = "push事件action")
|
||||
private List<String> includePushAction;
|
||||
|
||||
@Schema(title = "是否启用第三方过滤")
|
||||
private Boolean enableThirdFilter = false;
|
||||
|
||||
@Schema(title = "第三方应用地址")
|
||||
private String thirdUrl;
|
||||
|
||||
@Schema(title = "第三方应用鉴权token")
|
||||
private String thirdSecretToken;
|
||||
|
||||
@Schema(title = "跳过WIP")
|
||||
private Boolean skipWip = false;
|
||||
|
||||
public CodeGitWebHookTriggerElement(String name, String id, String status) {
|
||||
super(name, id, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementProp> triggerCondition() {
|
||||
List<ElementProp> props;
|
||||
switch (eventType) {
|
||||
case PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(includePushAction)),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(includeMrAction)),
|
||||
TriggerElementPropUtils.selector("skip-wip", List.of((skipWip != null ? skipWip.toString() : "false"))),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST_ACCEPT:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", "merge"),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case TAG_PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("tagName", tagName),
|
||||
TriggerElementPropUtils.vuexInput("excludeTagName", excludeTagName),
|
||||
TriggerElementPropUtils.vuexInput("fromBranches", fromBranches),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case REVIEW:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeCrState", includeCrState),
|
||||
TriggerElementPropUtils.selector("includeCrTypes", includeCrTypes)
|
||||
);
|
||||
break;
|
||||
case ISSUES:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeIssueAction", includeIssueAction)
|
||||
);
|
||||
break;
|
||||
case NOTE:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeNoteTypes", includeNoteTypes),
|
||||
TriggerElementPropUtils.vuexInput("includeNoteComment", includeNoteComment)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
props = List.of();
|
||||
}
|
||||
return props.stream().filter(java.util.Objects::nonNull).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.CodeEventType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.PathFilterType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeGithubWebHookTriggerElement
|
||||
* @Date:2025/03/27 9:42
|
||||
* @Filename:CodeGithubWebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "Github事件触发", description = CodeGithubWebHookTriggerElement.classType)
|
||||
public class CodeGithubWebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeGithubWebHookTrigger";
|
||||
public static final String MERGE_ACTION_OPEN = "open";
|
||||
public static final String MERGE_ACTION_CLOSE = "close";
|
||||
public static final String MERGE_ACTION_REOPEN = "reopen";
|
||||
public static final String MERGE_ACTION_PUSH_UPDATE = "push-update";
|
||||
public static final String MERGE_ACTION_MERGE = "merge";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "GitHub事件触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "分支名称", required = false)
|
||||
private String branchName;
|
||||
|
||||
@Schema(title = "用于排除的分支名称", required = false)
|
||||
private String excludeBranchName;
|
||||
|
||||
@Schema(title = "路径过滤类型", required = true)
|
||||
private PathFilterType pathFilterType = PathFilterType.NamePrefixFilter;
|
||||
|
||||
@Schema(title = "用于包含的路径", required = false)
|
||||
private String includePaths;
|
||||
|
||||
@Schema(title = "用于排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "用户白名单", required = false)
|
||||
private List<String> includeUsers;
|
||||
|
||||
@Schema(title = "用于排除的user id", required = false)
|
||||
private String excludeUsers;
|
||||
|
||||
@Schema(title = "tag名称", required = false)
|
||||
private String tagName;
|
||||
|
||||
@Schema(title = "用于排除的tag名称", required = false)
|
||||
private String excludeTagName;
|
||||
|
||||
@Schema(title = "tag从哪条分支创建", required = false)
|
||||
private String fromBranches;
|
||||
|
||||
@Schema(title = "用于排除的源分支名称", required = false)
|
||||
private String excludeSourceBranchName;
|
||||
|
||||
@Schema(title = "用于包含的源分支名称", required = false)
|
||||
private String includeSourceBranchName;
|
||||
|
||||
@Schema(title = "webhook队列", required = false)
|
||||
private Boolean webhookQueue = false;
|
||||
|
||||
@Schema(title = "code review 类型", required = false)
|
||||
private List<String> includeCrTypes;
|
||||
|
||||
@Schema(title = "是否启用回写")
|
||||
private Boolean enableCheck = true;
|
||||
|
||||
@Schema(title = "push事件action")
|
||||
private List<String> includePushAction;
|
||||
|
||||
@Schema(title = "是否启用第三方过滤")
|
||||
private Boolean enableThirdFilter = false;
|
||||
|
||||
@Schema(title = "事件类型", required = false)
|
||||
private CodeEventType eventType;
|
||||
|
||||
@Schema(title = "新版的github原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的github代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Schema(title = "code review 状态", required = false)
|
||||
private List<String> includeCrState;
|
||||
|
||||
@Schema(title = "code note comment", required = false)
|
||||
private String includeNoteComment;
|
||||
|
||||
@Schema(title = "code note 类型", required = false)
|
||||
private List<String> includeNoteTypes;
|
||||
|
||||
@Schema(title = "issue事件action")
|
||||
private List<String> includeIssueAction;
|
||||
|
||||
@Schema(title = "pull request事件action")
|
||||
private List<String> includeMrAction = List.of(MERGE_ACTION_OPEN, MERGE_ACTION_REOPEN, MERGE_ACTION_PUSH_UPDATE);
|
||||
|
||||
public CodeGithubWebHookTriggerElement(String name, String id, String status) {
|
||||
super(name, id, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.CodeEventType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.PathFilterType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeGitlabWebHookTriggerElement
|
||||
* @Date:2025/03/27 10:22
|
||||
* @Filename:CodeGitlabWebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "GitLab仓库代码提交触发", description = CodeGitlabWebHookTriggerElement.classType)
|
||||
public class CodeGitlabWebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeGitlabWebHookTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "Gitlab变更触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "分支名称", required = false)
|
||||
private String branchName;
|
||||
|
||||
@Schema(title = "新版的gitlab原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的gitlab代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Schema(title = "事件类型", required = false)
|
||||
private CodeEventType eventType = CodeEventType.PUSH;
|
||||
|
||||
@Schema(title = "用于排除的分支名", required = false)
|
||||
private String excludeBranchName;
|
||||
|
||||
@Schema(title = "路径过滤类型", required = true)
|
||||
private PathFilterType pathFilterType = PathFilterType.NamePrefixFilter;
|
||||
|
||||
@Schema(title = "用于包含的路径", required = false)
|
||||
private String includePaths;
|
||||
|
||||
@Schema(title = "用于排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "用于包含的user id", required = false)
|
||||
private List<String> includeUsers;
|
||||
|
||||
@Schema(title = "用于排除的user id", required = false)
|
||||
private List<String> excludeUsers;
|
||||
|
||||
@Schema(title = "是否为block", required = false)
|
||||
private Boolean block;
|
||||
|
||||
@Schema(title = "tag名称", required = false)
|
||||
private String tagName;
|
||||
|
||||
@Schema(title = "用于排除的tag名称", required = false)
|
||||
private String excludeTagName;
|
||||
|
||||
@Schema(title = "用于排除的源分支名称", required = false)
|
||||
private String excludeSourceBranchName;
|
||||
|
||||
@Schema(title = "用于包含的源分支名称", required = false)
|
||||
private String includeSourceBranchName;
|
||||
|
||||
@Schema(title = "用于包含的提交信息", required = false)
|
||||
private String includeCommitMsg;
|
||||
|
||||
@Schema(title = "用于排除的提交信息", required = false)
|
||||
private String excludeCommitMsg;
|
||||
|
||||
@Schema(title = "push事件action")
|
||||
private List<String> includePushAction;
|
||||
|
||||
@Schema(title = "mr事件action")
|
||||
private List<String> includeMrAction;
|
||||
|
||||
public CodeGitlabWebHookTriggerElement(String name, String id, String status) {
|
||||
super(name, id, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementProp> triggerCondition() {
|
||||
List<ElementProp> props;
|
||||
switch (eventType) {
|
||||
case PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(includePushAction)),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(includeMrAction)),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST_ACCEPT:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", "merge"),
|
||||
TriggerElementPropUtils.vuexInput("branchName", branchName),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", excludeBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", includeSourceBranchName),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", includePaths),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
);
|
||||
break;
|
||||
case TAG_PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("tagName", tagName),
|
||||
TriggerElementPropUtils.vuexInput("excludeTagName", excludeTagName)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
props = List.of();
|
||||
}
|
||||
return props.stream().filter(java.util.Objects::nonNull).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.CodeEventType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeP4WebHookTriggerElement
|
||||
* @Date:2025/03/27 10:20
|
||||
* @Filename:CodeP4WebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "p4事件触发", description = CodeP4WebHookTriggerElement.classType)
|
||||
public class CodeP4WebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeP4WebHookTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "P4事件触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "数据", required = true)
|
||||
private CodeP4WebHookTriggerData data;
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementProp> triggerCondition() {
|
||||
CodeP4WebHookTriggerInput input = data.getInput();
|
||||
List<ElementProp> props;
|
||||
switch (input.getEventType()) {
|
||||
case CHANGE_COMMIT:
|
||||
case CHANGE_SUBMIT:
|
||||
case CHANGE_CONTENT:
|
||||
case SHELVE_COMMIT:
|
||||
case SHELVE_SUBMIT:
|
||||
case SHELVE_DELETE:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("includePaths", input.getIncludePaths()),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", input.getExcludePaths())
|
||||
);
|
||||
break;
|
||||
default:
|
||||
props = List.of();
|
||||
}
|
||||
return props.stream().filter(java.util.Objects::nonNull).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
class CodeP4WebHookTriggerData {
|
||||
private CodeP4WebHookTriggerInput input;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
class CodeP4WebHookTriggerInput {
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "新版的git原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的git代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Schema(title = "用于包含的路径", required = false)
|
||||
private String includePaths;
|
||||
|
||||
@Schema(title = "用于排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "事件类型", required = false)
|
||||
private CodeEventType eventType;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.PathFilterType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeSVNWebHookTriggerElement
|
||||
* @Date:2025/03/27 10:09
|
||||
* @Filename:CodeSVNWebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "SVN仓库代码提交触发", description = CodeSVNWebHookTriggerElement.classType)
|
||||
public class CodeSVNWebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeSVNWebHookTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "SVN事件触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "路径过滤类型", required = true)
|
||||
private PathFilterType pathFilterType = PathFilterType.NamePrefixFilter;
|
||||
|
||||
@Schema(title = "相对路径", required = true)
|
||||
private String relativePath;
|
||||
|
||||
@Schema(title = "排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "用户黑名单", required = false)
|
||||
private List<String> excludeUsers;
|
||||
|
||||
@Schema(title = "用户白名单", required = false)
|
||||
private List<String> includeUsers;
|
||||
|
||||
@Schema(title = "新版的svn原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的svn代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementProp> triggerCondition() {
|
||||
return List.of(
|
||||
TriggerElementPropUtils.vuexInput("relativePath", relativePath),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", excludePaths),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", includeUsers),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", excludeUsers)
|
||||
).stream().filter(java.util.Objects::nonNull).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.CodeEventType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.enums.PathFilterType;
|
||||
import cd.casic.ci.common.pipeline.utils.TriggerElementPropUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:CodeTGitWebHookTriggerElement
|
||||
* @Date:2025/03/27 10:05
|
||||
* @Filename:CodeTGitWebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "TGit事件触发", description = CodeTGitWebHookTriggerElement.classType)
|
||||
public class CodeTGitWebHookTriggerElement extends WebHookTriggerElement {
|
||||
public static final String classType = "codeTGitWebHookTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "TGit事件触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "数据", required = true)
|
||||
private CodeTGitWebHookTriggerData data;
|
||||
|
||||
public CodeTGitWebHookTriggerElement(String name, String id, String status) {
|
||||
super(name, id, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.WEB_HOOK.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementProp> triggerCondition() {
|
||||
CodeTGitWebHookTriggerInput input = data.getInput();
|
||||
List<ElementProp> props;
|
||||
switch (input.getEventType()) {
|
||||
case PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(input.getIncludePushAction())),
|
||||
TriggerElementPropUtils.vuexInput("branchName", input.getBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", input.getExcludeBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", input.getIncludePaths()),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", input.getExcludePaths()),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", input.getIncludeUsers()),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", input.getExcludeUsers())
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", joinToString(input.getIncludeMrAction())),
|
||||
TriggerElementPropUtils.selector("skip-wip", List.of((input.getSkipWip() != null ? input.getSkipWip().toString() : "false"))),
|
||||
TriggerElementPropUtils.vuexInput("branchName", input.getBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", input.getExcludeBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", input.getIncludeSourceBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", input.getIncludeSourceBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", input.getIncludePaths()),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", input.getExcludePaths()),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", input.getIncludeUsers()),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", input.getExcludeUsers())
|
||||
);
|
||||
break;
|
||||
case MERGE_REQUEST_ACCEPT:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("action", "merge"),
|
||||
TriggerElementPropUtils.vuexInput("branchName", input.getBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("excludeBranchName", input.getExcludeBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", input.getIncludeSourceBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includeSourceBranchName", input.getIncludeSourceBranchName()),
|
||||
TriggerElementPropUtils.vuexInput("includePaths", input.getIncludePaths()),
|
||||
TriggerElementPropUtils.vuexInput("excludePaths", input.getExcludePaths()),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", input.getIncludeUsers()),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", input.getExcludeUsers())
|
||||
);
|
||||
break;
|
||||
case TAG_PUSH:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.vuexInput("tagName", input.getTagName()),
|
||||
TriggerElementPropUtils.vuexInput("excludeTagName", input.getExcludeTagName()),
|
||||
TriggerElementPropUtils.vuexInput("fromBranches", input.getFromBranches()),
|
||||
TriggerElementPropUtils.staffInput("includeUsers", input.getIncludeUsers()),
|
||||
TriggerElementPropUtils.staffInput("excludeUsers", input.getExcludeUsers())
|
||||
);
|
||||
break;
|
||||
case REVIEW:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeCrState", input.getIncludeCrState())
|
||||
);
|
||||
break;
|
||||
case ISSUES:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeIssueAction", input.getIncludeIssueAction())
|
||||
);
|
||||
break;
|
||||
case NOTE:
|
||||
props = List.of(
|
||||
TriggerElementPropUtils.selector("includeNoteTypes", input.getIncludeNoteTypes()),
|
||||
TriggerElementPropUtils.vuexInput("includeNoteComment", input.getIncludeNoteComment())
|
||||
);
|
||||
break;
|
||||
default:
|
||||
props = List.of();
|
||||
}
|
||||
return props.stream().filter(java.util.Objects::nonNull).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
class CodeTGitWebHookTriggerData {
|
||||
private CodeTGitWebHookTriggerInput input;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
class CodeTGitWebHookTriggerInput {
|
||||
@Schema(title = "仓库ID", required = true)
|
||||
private String repositoryHashId;
|
||||
|
||||
@Schema(title = "分支名称", required = false)
|
||||
private String branchName;
|
||||
|
||||
@Schema(title = "用于排除的分支名", required = false)
|
||||
private String excludeBranchName;
|
||||
|
||||
@Schema(title = "路径过滤类型", required = true)
|
||||
private PathFilterType pathFilterType = PathFilterType.NamePrefixFilter;
|
||||
|
||||
@Schema(title = "用于包含的路径", required = false)
|
||||
private String includePaths;
|
||||
|
||||
@Schema(title = "用于排除的路径", required = false)
|
||||
private String excludePaths;
|
||||
|
||||
@Schema(title = "用户白名单", required = false)
|
||||
private List<String> includeUsers;
|
||||
|
||||
@Schema(title = "用于排除的user id", required = false)
|
||||
private List<String> excludeUsers;
|
||||
|
||||
@Schema(title = "事件类型", required = false)
|
||||
private CodeEventType eventType;
|
||||
|
||||
@Schema(title = "是否为block", required = false)
|
||||
private Boolean block;
|
||||
|
||||
@Schema(title = "新版的git原子的类型")
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "新版的git代码库名")
|
||||
private String repositoryName;
|
||||
|
||||
@Schema(title = "tag名称", required = false)
|
||||
private String tagName;
|
||||
|
||||
@Schema(title = "用于排除的tag名称", required = false)
|
||||
private String excludeTagName;
|
||||
|
||||
@Schema(title = "tag从哪条分支创建", required = false)
|
||||
private String fromBranches;
|
||||
|
||||
@Schema(title = "用于排除的源分支名称", required = false)
|
||||
private String excludeSourceBranchName;
|
||||
|
||||
@Schema(title = "用于包含的源分支名称", required = false)
|
||||
private String includeSourceBranchName;
|
||||
|
||||
@Schema(title = "webhook队列", required = false)
|
||||
private Boolean webhookQueue = false;
|
||||
|
||||
@Schema(title = "code review 状态", required = false)
|
||||
private List<String> includeCrState;
|
||||
|
||||
@Schema(title = "code review 类型", required = false)
|
||||
private List<String> includeCrTypes;
|
||||
|
||||
@Schema(title = "code note comment", required = false)
|
||||
private String includeNoteComment;
|
||||
|
||||
@Schema(title = "code note 类型", required = false)
|
||||
private List<String> includeNoteTypes;
|
||||
|
||||
@Schema(title = "是否启用回写")
|
||||
private Boolean enableCheck = true;
|
||||
|
||||
@Schema(title = "issue事件action")
|
||||
private List<String> includeIssueAction;
|
||||
|
||||
@Schema(title = "mr事件action")
|
||||
private List<String> includeMrAction;
|
||||
|
||||
@Schema(title = "push事件action")
|
||||
private List<String> includePushAction;
|
||||
|
||||
@Schema(title = "是否启用第三方过滤")
|
||||
private Boolean enableThirdFilter = false;
|
||||
|
||||
@Schema(title = "跳过WIP")
|
||||
private Boolean skipWip = false;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:ManualTriggerElement
|
||||
* @Date:2025/03/27 10:04
|
||||
* @Filename:ManualTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "手动触发")
|
||||
public class ManualTriggerElement extends Element {
|
||||
public static final String classType = "manualTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "手动触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "是否可跳过插件", required = false)
|
||||
private Boolean canElementSkip;
|
||||
|
||||
@Schema(title = "是否使用最近一次的参数进行构建", required = false)
|
||||
private Boolean useLatestParameters;
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
private Set<String> startTypeSet = Set.of(StartType.MANUAL.name(), StartType.SERVICE.name(), StartType.PIPELINE.name());
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return startTypeSet.contains(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:RemoteTriggerElement
|
||||
* @Date:2025/03/27 10:01
|
||||
* @Filename:RemoteTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "远程触发触发")
|
||||
public class RemoteTriggerElement extends Element {
|
||||
|
||||
public static final String classType = "remoteTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "远程触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "是否可跳过插件", required = false)
|
||||
private Boolean canElementSkip;
|
||||
|
||||
@Schema(title = "远程触发token", required = true)
|
||||
private String remoteToken;
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.api.enums.TriggerRepositoryType;
|
||||
import cd.casic.ci.common.pipeline.enums.StartType;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:TimerTriggerElement
|
||||
* @Date:2025/03/27 10:00
|
||||
* @Filename:TimerTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "定时触发")
|
||||
public class TimerTriggerElement extends Element {
|
||||
public static final String classType = "timerTrigger";
|
||||
|
||||
@Schema(title = "任务名称", required = true)
|
||||
private String name = "定时触发";
|
||||
|
||||
@Schema(title = "id", required = false)
|
||||
private String id;
|
||||
|
||||
@Schema(title = "状态", required = false)
|
||||
private String status;
|
||||
|
||||
@Schema(title = "定时表达式", required = false)
|
||||
@Deprecated
|
||||
private String expression;
|
||||
|
||||
@Schema(title = "改进后的表达式", required = false)
|
||||
private List<String> newExpression;
|
||||
|
||||
@Schema(title = "高级定时表达式", required = false)
|
||||
private List<String> advanceExpression;
|
||||
|
||||
@Schema(title = "源代码未更新则不触发构建", required = false)
|
||||
private Boolean noScm;
|
||||
|
||||
@Schema(title = "指定代码库分支", required = false)
|
||||
private List<String> branches;
|
||||
|
||||
@Schema(title = "代码库类型", required = false)
|
||||
private TriggerRepositoryType repositoryType;
|
||||
|
||||
@Schema(title = "代码库HashId", required = false)
|
||||
private String repoHashId;
|
||||
|
||||
@Schema(title = "指定代码库别名", required = false)
|
||||
private String repoName;
|
||||
|
||||
@Override
|
||||
public String getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
private boolean isOldExpress() {
|
||||
return (newExpression == null || newExpression.isEmpty()) &&
|
||||
(advanceExpression == null || advanceExpression.isEmpty());
|
||||
}
|
||||
|
||||
private String checkAndSetSecond(String expression) {
|
||||
String trimmedExpression = expression.trim();
|
||||
String[] expressionParts = trimmedExpression.split(" ");
|
||||
if (!"0".equals(expressionParts[0])) {
|
||||
List<String> newExpressionParts = Arrays.asList(expressionParts);
|
||||
newExpressionParts.set(0, "0");
|
||||
return String.join(" ", newExpressionParts);
|
||||
}
|
||||
return trimmedExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findFirstTaskIdByStartType(StartType startType) {
|
||||
return StartType.TIME_TRIGGER.name().equals(startType.name()) ? this.id : super.findFirstTaskIdByStartType(startType);
|
||||
}
|
||||
|
||||
public boolean enableRepoConfig() {
|
||||
return TriggerRepositoryType.SELF.equals(repositoryType) ||
|
||||
(TriggerRepositoryType.ID.equals(repositoryType) && repoHashId != null && !repoHashId.isBlank()) ||
|
||||
(TriggerRepositoryType.NAME.equals(repositoryType) && repoName != null && !repoName.isBlank());
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger
|
||||
* @Project:ops-pro
|
||||
* @name:WebHookTriggerElement
|
||||
* @Date:2025/03/27 9:59
|
||||
* @Filename:WebHookTriggerElement
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "Webhook基础类")
|
||||
public abstract class WebHookTriggerElement extends Element {
|
||||
public WebHookTriggerElement(String name, String id, String status) {
|
||||
super(name, id, status);
|
||||
}
|
||||
|
||||
public List<ElementProp> triggerCondition() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public String joinToString(List<String> list) {
|
||||
return list == null || list.isEmpty() ? "" : String.join(",", list);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger.enums;
|
||||
|
||||
import cd.casic.ci.common.api.enums.ScmType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger.enums
|
||||
* @Project:ops-pro
|
||||
* @name:CodeEventType
|
||||
* @Date:2025/03/27 10:26
|
||||
* @Filename:CodeEventType
|
||||
* @description:Todo
|
||||
*/
|
||||
public enum CodeEventType {
|
||||
// Git events
|
||||
PUSH,
|
||||
TAG_PUSH,
|
||||
MERGE_REQUEST,
|
||||
MERGE_REQUEST_ACCEPT,
|
||||
ISSUES,
|
||||
NOTE,
|
||||
REVIEW,
|
||||
// GitHub events
|
||||
CREATE,
|
||||
PULL_REQUEST,
|
||||
// SVN events
|
||||
POST_COMMIT,
|
||||
LOCK_COMMIT,
|
||||
PRE_COMMIT,
|
||||
// Perforce (P4) events
|
||||
CHANGE_COMMIT,
|
||||
PUSH_SUBMIT,
|
||||
CHANGE_CONTENT,
|
||||
CHANGE_SUBMIT,
|
||||
PUSH_CONTENT,
|
||||
PUSH_COMMIT,
|
||||
FIX_ADD,
|
||||
FIX_DELETE,
|
||||
FORM_COMMIT,
|
||||
SHELVE_COMMIT,
|
||||
SHELVE_DELETE,
|
||||
SHELVE_SUBMIT,
|
||||
|
||||
// Sub-pipeline
|
||||
PARENT_PIPELINE;
|
||||
|
||||
public static final String MESSAGE_CODE_PREFIX = "EVENT_TYPE";
|
||||
|
||||
// Git events
|
||||
public static final List<CodeEventType> CODE_GIT_EVENTS = List.of(
|
||||
PUSH, MERGE_REQUEST, MERGE_REQUEST_ACCEPT, TAG_PUSH, NOTE, REVIEW, ISSUES
|
||||
);
|
||||
|
||||
// GitHub events
|
||||
public static final List<CodeEventType> CODE_GITHUB_EVENTS = List.of(
|
||||
PUSH, PULL_REQUEST, CREATE, REVIEW, ISSUES, NOTE
|
||||
);
|
||||
|
||||
// Perforce (P4) events
|
||||
public static final List<CodeEventType> CODE_P4_EVENTS = List.of(
|
||||
CHANGE_COMMIT, CHANGE_SUBMIT, CHANGE_CONTENT, SHELVE_COMMIT, SHELVE_SUBMIT
|
||||
);
|
||||
|
||||
// GitLab events
|
||||
public static final List<CodeEventType> CODE_GITLAB_EVENTS = List.of(
|
||||
PUSH, MERGE_REQUEST, MERGE_REQUEST_ACCEPT, TAG_PUSH
|
||||
);
|
||||
|
||||
// Tencent Git (TGit) events
|
||||
public static final List<CodeEventType> CODE_TGIT_EVENTS = List.of(
|
||||
PUSH, MERGE_REQUEST, MERGE_REQUEST_ACCEPT, TAG_PUSH, NOTE, ISSUES
|
||||
);
|
||||
|
||||
// SVN events
|
||||
public static final List<CodeEventType> CODE_SVN_EVENTS = List.of(
|
||||
POST_COMMIT, PRE_COMMIT, LOCK_COMMIT
|
||||
);
|
||||
|
||||
public static List<CodeEventType> getEventsByScmType(ScmType scmType) {
|
||||
if (scmType == null) {
|
||||
return List.of(values());
|
||||
}
|
||||
switch (scmType) {
|
||||
case CODE_GIT:
|
||||
return new ArrayList<>(CODE_GIT_EVENTS);
|
||||
case CODE_TGIT:
|
||||
return new ArrayList<>(CODE_TGIT_EVENTS);
|
||||
case GITHUB:
|
||||
return new ArrayList<>(CODE_GITHUB_EVENTS);
|
||||
case CODE_GITLAB:
|
||||
return new ArrayList<>(CODE_GITLAB_EVENTS);
|
||||
case CODE_SVN:
|
||||
return new ArrayList<>(CODE_SVN_EVENTS);
|
||||
case CODE_P4:
|
||||
return new ArrayList<>(CODE_P4_EVENTS);
|
||||
default:
|
||||
return List.of(values());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger.enums;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger.enums
|
||||
* @Project:ops-pro
|
||||
* @name:CodeType
|
||||
* @Date:2025/03/27 10:28
|
||||
* @Filename:CodeType
|
||||
* @description:Todo
|
||||
*/
|
||||
public enum CodeType {
|
||||
SVN,
|
||||
GIT,
|
||||
GITLAB,
|
||||
GITHUB,
|
||||
TGIT,
|
||||
P4
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.element.trigger.enums;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.element.trigger.enums
|
||||
* @Project:ops-pro
|
||||
* @name:PathFilterType
|
||||
* @Date:2025/03/27 10:28
|
||||
* @Filename:PathFilterType
|
||||
* @description:Todo
|
||||
*/
|
||||
public enum PathFilterType {
|
||||
NamePrefixFilter,
|
||||
RegexBasedFilter
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cd.casic.ci.common.pipeline.pojo.git;
|
||||
|
||||
import cd.casic.ci.common.pipeline.enums.GitPullModeType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.pojo.git
|
||||
* @Project:ops-pro
|
||||
* @name:GitPullMode
|
||||
* @Date:2025/03/27 10:24
|
||||
* @Filename:GitPullMode
|
||||
* @description:Todo
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class GitPullMode {
|
||||
private GitPullModeType type;
|
||||
private String value;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package cd.casic.ci.common.pipeline.type;
|
||||
|
||||
import cn.hutool.http.useragent.OS;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type
|
||||
* @Project:ops-pro
|
||||
* @name:BuildType
|
||||
* @Date:2025/03/27 10:45
|
||||
* @Filename:BuildType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BuildType {
|
||||
ESXI("蓝盾公共构建资源", List.of(OS.MACOS), false, false, false),
|
||||
MACOS("云托管: MacOS on DevCloud", List.of(OS.MACOS), false, false, false),
|
||||
WINDOWS("云托管:Windows on DevCloud", List.of(OS.WINDOWS), false, false, false),
|
||||
KUBERNETES("Kubernetes构建资源", List.of(OS.LINUX), false, false, false),
|
||||
PUBLIC_DEVCLOUD("公共:Docker on DevCloud", List.of(OS.LINUX), true, false, false),
|
||||
PUBLIC_BCS("公共:Docker on Bcs", List.of(OS.LINUX), false, false, false),
|
||||
THIRD_PARTY_AGENT_ID("私有:单构建机", List.of(OS.MACOS, OS.LINUX, OS.WINDOWS), false, true, true),
|
||||
THIRD_PARTY_AGENT_ENV("私有:构建集群", List.of(OS.MACOS, OS.LINUX, OS.WINDOWS), false, true, true),
|
||||
THIRD_PARTY_PCG("PCG公共构建资源", List.of(OS.LINUX), false, false, false),
|
||||
THIRD_PARTY_DEVCLOUD("腾讯自研云(云devnet资源)", List.of(OS.LINUX), false, false, false),
|
||||
GIT_CI("工蜂CI", List.of(OS.LINUX), false, false, false),
|
||||
DOCKER("Docker公共构建机", List.of(OS.LINUX), true, true, true),
|
||||
STREAM("stream", List.of(OS.LINUX), false, false, false),
|
||||
AGENT_LESS("无编译环境", List.of(OS.LINUX), false, false, false);
|
||||
|
||||
private final String value;
|
||||
private final List<OS> osList;
|
||||
private final boolean enableApp;
|
||||
private final boolean clickable;
|
||||
private final boolean visible;
|
||||
|
||||
public String getI18n(String language) {
|
||||
return MessageUtil.getMessageByLocale("buildType." + this.name(), language);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cd.casic.ci.common.pipeline.type;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type
|
||||
* @Project:ops-pro
|
||||
* @name:DispatchRouteKeySuffix
|
||||
* @Date:2025/03/27 10:45
|
||||
* @Filename:DispatchRouteKeySuffix
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DispatchRouteKeySuffix {
|
||||
DOCKER_VM(".docker.vm"),
|
||||
DOCKER_VM_DEMOTE(".docker.vm.demote"),
|
||||
KUBERNETES(".kubernetes"),
|
||||
KUBERNETES_DEMOTE(".kubernetes.demote"),
|
||||
PCG(".pcg.sumeru"),
|
||||
DEVCLOUD(".devcloud.public"),
|
||||
BCS(".bcs.public"),
|
||||
IDC(".idc.public"),
|
||||
GITCI(".gitci.public"),
|
||||
STREAM(".stream.docker"),
|
||||
STREAM_DEMOTE(".stream.docker.demote"),
|
||||
CODECC(".codecc.scan"),
|
||||
MACOS(".macos"),
|
||||
WINDOWS(".windows");
|
||||
|
||||
private final String routeKeySuffix;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package cd.casic.ci.common.pipeline.type;
|
||||
|
||||
import cd.casic.ci.common.pipeline.type.agent.ThirdPartyAgentEnvDispatchType;
|
||||
import cd.casic.ci.common.pipeline.type.agent.ThirdPartyAgentIDDispatchType;
|
||||
import cd.casic.ci.common.pipeline.utils.EnvUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type
|
||||
* @Project:ops-pro
|
||||
* @name:DispatchType
|
||||
* @Date:2025/03/27 10:45
|
||||
* @Filename:DispatchType
|
||||
* @description:Todo
|
||||
*/
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "buildType", visible = false)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = DockerDispatchType.class, name = "DOCKER"),
|
||||
@JsonSubTypes.Type(value = KubernetesDispatchType.class, name = "KUBERNETES"),
|
||||
@JsonSubTypes.Type(value = ThirdPartyAgentIDDispatchType.class, name = "THIRD_PARTY_AGENT_ID"),
|
||||
@JsonSubTypes.Type(value = ThirdPartyAgentEnvDispatchType.class, name = "THIRD_PARTY_AGENT_ENV"),
|
||||
@JsonSubTypes.Type(value = ThirdPartyDevCloudDispatchType.class, name = "THIRD_PARTY_DEVCLOUD")
|
||||
})
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class DispatchType {
|
||||
private String value;
|
||||
private DispatchRouteKeySuffix routeKeySuffix;
|
||||
|
||||
public void replaceVariable(Map<String, String> variables) {
|
||||
this.value = EnvUtils.parseEnv(value, variables);
|
||||
replaceField(variables);
|
||||
}
|
||||
|
||||
public abstract BuildType buildType();
|
||||
|
||||
protected abstract void replaceField(Map<String, String> variables);
|
||||
|
||||
public abstract void cleanDataBeforeSave();
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package cd.casic.ci.common.pipeline.type;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type
|
||||
* @Project:ops-pro
|
||||
* @name:StoreDispatchType
|
||||
* @Date:2025/03/27 10:45
|
||||
* @Filename:StoreDispatchType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class StoreDispatchType extends DispatchType {
|
||||
@Schema(title = "docker构建版本", required = false)
|
||||
private String dockerBuildVersion;
|
||||
|
||||
@Schema(title = "镜像类型", required = false)
|
||||
private ImageType imageType = ImageType.BKDEVOPS;
|
||||
|
||||
@Schema(title = "凭证id", required = false)
|
||||
private String credentialId = "";
|
||||
|
||||
@Schema(title = "凭证项目id", required = false)
|
||||
private String credentialProject = "";
|
||||
|
||||
@Schema(title = "商店镜像代码", required = false)
|
||||
private String imageCode = "";
|
||||
|
||||
@Schema(title = "商店镜像版本", required = false)
|
||||
private String imageVersion = "";
|
||||
|
||||
@Schema(title = "商店镜像名称", required = false)
|
||||
private String imageName = "";
|
||||
|
||||
@Schema(title = "商店镜像公共标识", required = false)
|
||||
private Boolean imagePublicFlag = false;
|
||||
|
||||
@Schema(title = "商店镜像研发来源", required = false)
|
||||
private String imageRDType = "";
|
||||
|
||||
@Schema(title = "商店镜像是否推荐", required = false)
|
||||
private Boolean recommendFlag = true;
|
||||
|
||||
public StoreDispatchType(String dockerBuildVersion, DispatchRouteKeySuffix routeKeySuffix) {
|
||||
super(Optional.ofNullable(dockerBuildVersion).orElse("StoreDispatchType empty image"), routeKeySuffix);
|
||||
this.dockerBuildVersion = dockerBuildVersion;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package cd.casic.ci.common.pipeline.type.agent;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type.agent
|
||||
* @Project:ops-pro
|
||||
* @name:AgentType
|
||||
* @Date:2025/03/27 10:47
|
||||
* @Filename:AgentType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AgentType {
|
||||
ID, // This is only for old pipeline, new pipelines will use name
|
||||
NAME,
|
||||
REUSE_JOB_ID; // 是否复用其他job的Agent节点
|
||||
|
||||
public boolean isReuse() {
|
||||
return this == REUSE_JOB_ID;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package cd.casic.ci.common.pipeline.type.agent;
|
||||
|
||||
import cd.casic.ci.common.pipeline.type.DispatchType;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type.agent
|
||||
* @Project:ops-pro
|
||||
* @name:ThirdPartyAgentDispatch
|
||||
* @Date:2025/03/27 10:47
|
||||
* @Filename:ThirdPartyAgentDispatch
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public abstract class ThirdPartyAgentDispatch extends DispatchType {
|
||||
private String value;
|
||||
private AgentType agentType;
|
||||
private String workspace;
|
||||
private ThirdPartyAgentDockerInfo dockerInfo;
|
||||
private ReusedInfo reusedInfo;
|
||||
|
||||
public ThirdPartyAgentDispatch(String value, AgentType agentType, String workspace, ThirdPartyAgentDockerInfo dockerInfo, ReusedInfo reusedInfo) {
|
||||
super(value);
|
||||
this.value = value;
|
||||
this.agentType = agentType;
|
||||
this.workspace = workspace;
|
||||
this.dockerInfo = dockerInfo;
|
||||
this.reusedInfo = reusedInfo;
|
||||
}
|
||||
|
||||
public boolean idType() {
|
||||
return (agentType == AgentType.ID) || (reusedInfo != null && reusedInfo.getAgentType() == AgentType.ID) ||
|
||||
(agentType == AgentType.REUSE_JOB_ID && reusedInfo == null);
|
||||
}
|
||||
|
||||
public boolean hasReuseMutex() {
|
||||
return this.agentType.isReuse() || this.reusedInfo != null;
|
||||
}
|
||||
|
||||
public boolean isEnv() {
|
||||
return this instanceof ThirdPartyAgentEnvDispatchType;
|
||||
}
|
||||
|
||||
public boolean isSingle() {
|
||||
return this instanceof ThirdPartyAgentIDDispatchType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void replaceField(Map<String, String> variables);
|
||||
|
||||
@Override
|
||||
public abstract void cleanDataBeforeSave();
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package cd.casic.ci.common.pipeline.type.agent;
|
||||
|
||||
import cd.casic.ci.common.pipeline.utils.EnvUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type.agent
|
||||
* @Project:ops-pro
|
||||
* @name:ThirdPartyAgentDockerInfo
|
||||
* @Date:2025/03/27 10:47
|
||||
* @Filename:ThirdPartyAgentDockerInfo
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ThirdPartyAgentDockerInfo {
|
||||
private String image;
|
||||
private Credential credential;
|
||||
private DockerOptions options;
|
||||
private String imagePullPolicy;
|
||||
private ImageType imageType = ImageType.THIRD;
|
||||
private ThirdPartyAgentDockerInfoStoreImage storeImage;
|
||||
|
||||
public void replaceField(Map<String, String> variables) {
|
||||
image = EnvUtils.parseEnv(image, variables);
|
||||
if (credential != null) {
|
||||
if (!credential.getUser().isBlank()) {
|
||||
credential.setUser(EnvUtils.parseEnv(credential.getUser(), variables));
|
||||
}
|
||||
if (!credential.getPassword().isBlank()) {
|
||||
credential.setPassword(EnvUtils.parseEnv(credential.getPassword(), variables));
|
||||
}
|
||||
if (!credential.getCredentialId().isBlank()) {
|
||||
credential.setCredentialId(EnvUtils.parseEnv(credential.getCredentialId(), variables));
|
||||
}
|
||||
}
|
||||
if (options != null) {
|
||||
options.setVolumes(options.getVolumes().stream().map(v -> EnvUtils.parseEnv(v, variables)).toList());
|
||||
options.setMounts(options.getMounts().stream().map(m -> EnvUtils.parseEnv(m, variables)).toList());
|
||||
options.setGpus(EnvUtils.parseEnv(options.getGpus(), variables));
|
||||
options.setPrivileged(Boolean.parseBoolean(EnvUtils.parseEnv(String.valueOf(options.getPrivileged()), variables)));
|
||||
}
|
||||
if (imagePullPolicy != null) {
|
||||
imagePullPolicy = EnvUtils.parseEnv(imagePullPolicy, variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class Credential {
|
||||
private String user;
|
||||
private String password;
|
||||
private String credentialId;
|
||||
private String acrossTemplateId;
|
||||
private String jobId;
|
||||
private String credentialProjectId;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class DockerOptions {
|
||||
private List<String> volumes;
|
||||
private List<String> mounts;
|
||||
private String gpus;
|
||||
private Boolean privileged;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class ThirdPartyAgentDockerInfoStoreImage {
|
||||
private String imageName;
|
||||
private String imageCode;
|
||||
private String imageVersion;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class ThirdPartyAgentDockerInfoDispatch {
|
||||
private String agentId;
|
||||
private String secretKey;
|
||||
private String image;
|
||||
private Credential credential;
|
||||
private DockerOptions options;
|
||||
private String imagePullPolicy;
|
||||
|
||||
public ThirdPartyAgentDockerInfoDispatch(String agentId, String secretKey, ThirdPartyAgentDockerInfo info) {
|
||||
this.agentId = agentId;
|
||||
this.secretKey = secretKey;
|
||||
this.image = info.getImage();
|
||||
this.credential = info.getCredential();
|
||||
this.options = info.getOptions();
|
||||
this.imagePullPolicy = info.getImagePullPolicy();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package cd.casic.ci.common.pipeline.type.agent;
|
||||
|
||||
import cd.casic.ci.common.pipeline.type.BuildType;
|
||||
import cd.casic.ci.common.pipeline.utils.EnvUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type.agent
|
||||
* @Project:ops-pro
|
||||
* @name:ThirdPartyAgentEnvDispatchType
|
||||
* @Date:2025/03/27 10:48
|
||||
* @Filename:ThirdPartyAgentEnvDispatchType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ThirdPartyAgentEnvDispatchType extends ThirdPartyAgentDispatch {
|
||||
@JsonProperty("value")
|
||||
private String envName;
|
||||
private String workspace;
|
||||
private String envProjectId;
|
||||
private AgentType agentType = AgentType.NAME;
|
||||
private ThirdPartyAgentDockerInfo dockerInfo;
|
||||
private ReusedInfo reusedInfo;
|
||||
|
||||
public ThirdPartyAgentEnvDispatchType(String envName, String workspace, String envProjectId, ThirdPartyAgentDockerInfo dockerInfo, ReusedInfo reusedInfo) {
|
||||
super(envName, agentType, workspace, dockerInfo, reusedInfo);
|
||||
this.envName = envName;
|
||||
this.workspace = workspace;
|
||||
this.envProjectId = envProjectId;
|
||||
this.dockerInfo = dockerInfo;
|
||||
this.reusedInfo = reusedInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanDataBeforeSave() {
|
||||
this.envName = this.envName.trim();
|
||||
this.envProjectId = this.envProjectId != null ? this.envProjectId.trim() : null;
|
||||
this.workspace = this.workspace != null ? this.workspace.trim() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceField(Map<String, String> variables) {
|
||||
envName = EnvUtils.parseEnv(envName, variables);
|
||||
envProjectId = EnvUtils.parseEnv(envProjectId, variables);
|
||||
if (workspace != null && !workspace.isBlank()) {
|
||||
workspace = EnvUtils.parseEnv(workspace, variables);
|
||||
}
|
||||
if (dockerInfo != null) {
|
||||
dockerInfo.replaceField(variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildType buildType() {
|
||||
return BuildType.THIRD_PARTY_AGENT_ENV;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package cd.casic.ci.common.pipeline.type.agent;
|
||||
|
||||
import cd.casic.ci.common.pipeline.type.BuildType;
|
||||
import cd.casic.ci.common.pipeline.utils.EnvUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type.agent
|
||||
* @Project:ops-pro
|
||||
* @name:ThirdPartyAgentIDDispatchType
|
||||
* @Date:2025/03/27 10:48
|
||||
* @Filename:ThirdPartyAgentIDDispatchType
|
||||
* @description:Todo
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ThirdPartyAgentIDDispatchType extends ThirdPartyAgentDispatch {
|
||||
@JsonProperty("value")
|
||||
private String displayName;
|
||||
private String workspace;
|
||||
private AgentType agentType = AgentType.NAME;
|
||||
private ThirdPartyAgentDockerInfo dockerInfo;
|
||||
private ReusedInfo reusedInfo;
|
||||
|
||||
public ThirdPartyAgentIDDispatchType(String displayName, String workspace, ThirdPartyAgentDockerInfo dockerInfo, ReusedInfo reusedInfo) {
|
||||
super(displayName, agentType, workspace, dockerInfo, reusedInfo);
|
||||
this.displayName = displayName;
|
||||
this.workspace = workspace;
|
||||
this.dockerInfo = dockerInfo;
|
||||
this.reusedInfo = reusedInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanDataBeforeSave() {
|
||||
this.displayName = this.displayName.trim();
|
||||
this.workspace = this.workspace != null ? this.workspace.trim() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceField(Map<String, String> variables) {
|
||||
displayName = EnvUtils.parseEnv(displayName, variables);
|
||||
if (workspace != null && !workspace.isBlank()) {
|
||||
workspace = EnvUtils.parseEnv(workspace, variables);
|
||||
}
|
||||
if (dockerInfo != null) {
|
||||
dockerInfo.replaceField(variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildType buildType() {
|
||||
return BuildType.THIRD_PARTY_AGENT_ID;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.type
|
||||
* @Project:ops-pro
|
||||
* @name:package-info
|
||||
* @Date:2025/03/27 10:44
|
||||
* @Filename:package-info
|
||||
* @description:Todo
|
||||
*/
|
||||
package cd.casic.ci.common.pipeline.type;
|
@ -0,0 +1,79 @@
|
||||
package cd.casic.ci.common.pipeline.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.utils
|
||||
* @Project:ops-pro
|
||||
* @name:EnvUtils
|
||||
* @Date:2025/03/27 15:20
|
||||
* @Filename:EnvUtils
|
||||
* @description:Todo
|
||||
*/
|
||||
public class EnvUtils {
|
||||
private static final Pattern tPattern = Pattern.compile("(\\$[{](?<single>[^$^{}]+)})|(\\$[{]{2}(?<double>[^$^{}]+)[}]{2})");
|
||||
|
||||
public static String parseEnv(String command, Map<String, String> data) {
|
||||
return parseEnv(command, data, false, false);
|
||||
}
|
||||
|
||||
public static String parseEnv(String command, Map<String, String> data, boolean replaceWithEmpty, boolean isEscape) {
|
||||
return parseEnv(command, data, replaceWithEmpty, isEscape, new HashMap<>());
|
||||
}
|
||||
|
||||
public static String parseEnv(String command, Map<String, String> data, boolean replaceWithEmpty, boolean isEscape, Map<String, String> contextMap) {
|
||||
if (command == null || command.isEmpty()) {
|
||||
return command == null ? "" : command;
|
||||
}
|
||||
return parseTokenTwice(command, data, contextMap, replaceWithEmpty, isEscape, 1);
|
||||
}
|
||||
|
||||
private static String parseTokenTwice(String command, Map<String, String> data, Map<String, String> contextMap, boolean replaceWithEmpty, boolean isEscape, int depth) {
|
||||
if (depth < 0) {
|
||||
return command;
|
||||
}
|
||||
Matcher matcher = tPattern.matcher(command);
|
||||
StringBuffer buff = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
String key = matcher.group("single");
|
||||
if (key == null) {
|
||||
key = matcher.group("double");
|
||||
}
|
||||
key = key.trim();
|
||||
String value = data.get(key);
|
||||
if (value == null && contextMap != null) {
|
||||
value = contextMap.get(key);
|
||||
}
|
||||
if (value == null) {
|
||||
value = !replaceWithEmpty ? matcher.group() : "";
|
||||
} else {
|
||||
if (depth > 0 && tPattern.matcher(value).find()) {
|
||||
value = parseTokenTwice(value, data, contextMap, replaceWithEmpty, isEscape, depth - 1);
|
||||
} else if (isEscape) {
|
||||
value = escapeSpecialWord(value);
|
||||
}
|
||||
}
|
||||
matcher.appendReplacement(buff, Matcher.quoteReplacement(value));
|
||||
}
|
||||
matcher.appendTail(buff);
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
private static String escapeSpecialWord(String keyword) {
|
||||
String replaceWord = keyword;
|
||||
if (!keyword.isEmpty()) {
|
||||
String[] wordList = {"\\", "\""};
|
||||
for (String word : wordList) {
|
||||
if (replaceWord.contains(word)) {
|
||||
replaceWord = replaceWord.replace(word, "\\" + word);
|
||||
}
|
||||
}
|
||||
}
|
||||
return replaceWord;
|
||||
}
|
||||
}
|
@ -8,10 +8,16 @@ import cd.casic.ci.common.pipeline.container.VMBuildContainer;
|
||||
import cd.casic.ci.common.pipeline.enums.BuildStatus;
|
||||
import cd.casic.ci.common.pipeline.enums.JobRunCondition;
|
||||
import cd.casic.ci.common.pipeline.option.JobControlOption;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementAdditionalOptions;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.ManualTriggerElement;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.trigger.RemoteTriggerElement;
|
||||
import cd.casic.framework.commons.util.reflect.ReflectUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cd.casic.ci.common.pipeline.pojo.element.ElementAdditionalOptions.RunCondition.*;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.common.pipeline.utils
|
||||
@ -99,9 +105,9 @@ public class ModelUtils {
|
||||
} else {
|
||||
element.setCanRetry(null);
|
||||
}
|
||||
} else if (additionalOptions.getRunCondition() == RunCondition.PRE_TASK_FAILED_ONLY ||
|
||||
additionalOptions.getRunCondition() == RunCondition.PRE_TASK_FAILED_BUT_CANCEL ||
|
||||
additionalOptions.getRunCondition() == RunCondition.PRE_TASK_FAILED_EVEN_CANCEL) {
|
||||
} else if (additionalOptions.getRunCondition() == PRE_TASK_FAILED_ONLY ||
|
||||
additionalOptions.getRunCondition() == PRE_TASK_FAILED_BUT_CANCEL ||
|
||||
additionalOptions.getRunCondition() == PRE_TASK_FAILED_EVEN_CANCEL) {
|
||||
element.setCanRetry(null);
|
||||
element.setCanSkip(null);
|
||||
failElements.forEach(e -> {
|
||||
@ -166,8 +172,8 @@ public class ModelUtils {
|
||||
public static Set<String> getModelAtoms(Model model) {
|
||||
var atomCodes = new HashSet<String>();
|
||||
for (var stage : model.getStages()) {
|
||||
for (var container : stage.getContainers()) {
|
||||
for (var element : container.getElements()) {
|
||||
for (Container container : stage.getContainers()) {
|
||||
for (Element element : container.getElements()) {
|
||||
atomCodes.add(element.getAtomCode());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
|
||||
*
|
||||
* A copy of the MIT License is included in this file.
|
||||
*
|
||||
*
|
||||
* Terms of the MIT License:
|
||||
* ---------------------------------------------------
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
||||
* the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cd.casic.ci.common.pipeline.utils;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ObjectReplaceEnvVarUtil {
|
||||
/**
|
||||
* 把对象字段值中的占位符替换成环境变量
|
||||
*
|
||||
* @param obj 需要把占位符替换环境变量的对象(对象如果是集合对象,注意要选择支持增加、删除等操作的集合类型,不要选择类似SingletonMap这种)
|
||||
* @param envMap 环境变量Map
|
||||
* @return 变量替换后的对象
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public static Object replaceEnvVar(Object obj, Map<String, String> envMap) {
|
||||
if (obj instanceof Map) {
|
||||
// 递归替换map对象中的变量
|
||||
Set<Map.Entry<String, Object>> entrySet = ((Map) obj).entrySet();
|
||||
for (Map.Entry entry : entrySet) {
|
||||
Object value = entry.getValue();
|
||||
if (!isNormalReplaceEnvVar(value)) {
|
||||
entry.setValue(replaceEnvVar(value, envMap));
|
||||
} else {
|
||||
entry.setValue(handleNormalEnvVar(value, envMap));
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof List) {
|
||||
// 递归替换list对象中的变量
|
||||
List dataList = (List) obj;
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
Object value = dataList.get(i);
|
||||
if (!isNormalReplaceEnvVar(value)) {
|
||||
dataList.set(i, replaceEnvVar(value, envMap));
|
||||
} else {
|
||||
dataList.set(i, handleNormalEnvVar(value, envMap));
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof Set) {
|
||||
// 递归替换set对象中的变量
|
||||
Set objSet = (Set) obj;
|
||||
Set replaceObjSet = new HashSet(objSet);
|
||||
Iterator it = replaceObjSet.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object value = it.next();
|
||||
objSet.remove(value);
|
||||
if (!isNormalReplaceEnvVar(value)) {
|
||||
objSet.add(replaceEnvVar(value, envMap));
|
||||
} else {
|
||||
objSet.add(handleNormalEnvVar(value, envMap));
|
||||
}
|
||||
}
|
||||
} else if (isNormalReplaceEnvVar(obj)) {
|
||||
// 替换基本类型对象或字符串对象中的变量
|
||||
obj = handleNormalEnvVar(obj, envMap);
|
||||
} else {
|
||||
try {
|
||||
// 把对象转换成map后进行递归替换变量
|
||||
Map<String, Object> dataMap = JSONUtil.toBean(JSONUtil.toJsonStr(obj), Map.class);
|
||||
replaceEnvVar(dataMap, envMap);
|
||||
obj = JSONUtil.toBean(JSONUtil.toJsonStr(dataMap), obj.getClass());
|
||||
} catch (Throwable e) {
|
||||
// 转换不了map的对象则进行直接替换
|
||||
obj = EnvUtils.parseEnv(JSONUtil.toJsonStr(obj), envMap, false, false);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static Object handleNormalEnvVar(Object obj, Map<String, String> envMap) {
|
||||
// 只有字符串参数才需要进行变量替换,其它基本类型参数无需进行变量替换
|
||||
if (obj instanceof String) {
|
||||
String objStr = ((String) obj).trim();
|
||||
if (JSONUtil.isJsonObj(objStr)) {
|
||||
try {
|
||||
Object dataObj = JSONUtil.toBean((String) obj, Map.class);
|
||||
// string能正常转换成map,则说明是json串,那么把dataObj进行递归替换变量后再转成json串
|
||||
dataObj = replaceEnvVar(dataObj, envMap);
|
||||
obj = JSONUtil.toJsonStr(dataObj);
|
||||
} catch (Throwable e) {
|
||||
// 转换不了map的字符串对象则直接替换
|
||||
obj = EnvUtils.parseEnv(JSONUtil.toJsonStr(obj), envMap, false, false);
|
||||
}
|
||||
} else if (JSONUtil.isJsonObj(objStr)) {
|
||||
try {
|
||||
JSONUtil.toList(JSONUtil.parseArray((String) obj), Object.class);
|
||||
Object dataObj = JSONUtil.toList((String) obj, List.class);
|
||||
// string能正常转成list,说明是json串,把dataObj进行递归替换变量后再转成json串
|
||||
dataObj = replaceEnvVar(dataObj, envMap);
|
||||
obj = JSONUtil.toJsonStr(dataObj);
|
||||
} catch (Throwable e1) {
|
||||
// 转换不了list的字符串对象则直接替换
|
||||
obj = EnvUtils.parseEnv(JSONUtil.toJsonStr(obj), envMap, false, false);
|
||||
}
|
||||
} else {
|
||||
// 转换不了map或者list的字符串对象则直接替换
|
||||
obj = EnvUtils.parseEnv(JSONUtil.toJsonStr(obj), envMap, false, false);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断对象是否是普通替换对象
|
||||
*
|
||||
* @param obj 需要把占位符替换环境变量的对象(对象如果是集合对象,注意要选择支持增加、删除等操作的集合类型,不要选择类似SingletonMap这种)
|
||||
* @return 是否是普通替换对象
|
||||
*/
|
||||
private static Boolean isNormalReplaceEnvVar(Object obj) {
|
||||
return obj == null || ReflectUtil.INSTANCE.isNativeType(obj) || obj instanceof String;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package cd.casic.ci.common.pipeline.utils;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.BuildParameters;
|
||||
import cd.casic.ci.common.pipeline.pojo.element.Element;
|
||||
import cd.casic.framework.commons.util.json.JsonUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,5 +1,7 @@
|
||||
package cd.casic.ci.common.pipeline.utils;
|
||||
|
||||
import cd.casic.ci.common.pipeline.pojo.element.ElementProp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -17,20 +19,20 @@ public class TriggerElementPropUtils {
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return new ElementProp(name, value.split(","), ElementPropType.VUEX_INPUT);
|
||||
return new ElementProp(name, value.split(","), ElementProp.ElementPropType.VUEX_INPUT);
|
||||
}
|
||||
|
||||
public static ElementProp staffInput(String name, List<String> value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new ElementProp(name, value, ElementPropType.STAFF_INPUT);
|
||||
return new ElementProp(name, value, ElementProp.ElementPropType.STAFF_INPUT);
|
||||
}
|
||||
|
||||
public static ElementProp selector(String name, List<String> value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new ElementProp(name, value, ElementPropType.SELECTOR);
|
||||
return new ElementProp(name, value, ElementProp.ElementPropType.SELECTOR);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,11 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cd.casic.ci</groupId>
|
||||
<artifactId>ci-commons</artifactId>
|
||||
<artifactId>commons-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cd.casic.ci</groupId>
|
||||
<artifactId>commons-pipeline</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cd.casic.ci</groupId>
|
||||
|
@ -0,0 +1,143 @@
|
||||
package cd.casic.ci.process.api.process.utils;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.process.api.process.utils
|
||||
* @Project:ops-pro
|
||||
* @name:Constants
|
||||
* @Date:2025/03/27 11:09
|
||||
* @Filename:Constants
|
||||
*/
|
||||
public class Constants {
|
||||
public static final String PIPELINE_VERSION = "BK_CI_PIPELINE_VERSION";
|
||||
public static final String PIPELINE_START_PARENT_PROJECT_ID = "BK_CI_PARENT_PROJECT_ID";
|
||||
public static final String PIPELINE_START_PARENT_PIPELINE_ID = "BK_CI_PARENT_PIPELINE_ID";
|
||||
public static final String PIPELINE_START_PARENT_PIPELINE_NAME = "BK_CI_PARENT_PIPELINE_NAME";
|
||||
public static final String PIPELINE_START_PARENT_BUILD_ID = "BK_CI_PARENT_BUILD_ID";
|
||||
public static final String PIPELINE_START_PARENT_BUILD_NUM = "BK_CI_PARENT_BUILD_NUM";
|
||||
public static final String PIPELINE_START_PARENT_BUILD_TASK_ID = "BK_CI_PARENT_BUILD_TASK_ID";
|
||||
public static final String PIPELINE_START_PARENT_EXECUTE_COUNT = "BK_CI_PARENT_EXECUTE_COUNT";
|
||||
public static final String PIPELINE_START_USER_ID = "BK_CI_START_USER_ID";
|
||||
public static final String PIPELINE_START_USER_NAME = "BK_CI_START_USER_NAME";
|
||||
public static final String PIPELINE_START_WEBHOOK_USER_ID = "BK_CI_START_WEBHOOK_USER_ID";
|
||||
public static final String PIPELINE_START_PIPELINE_USER_ID = "BK_CI_START_PIPELINE_USER_ID";
|
||||
public static final String PIPELINE_START_SERVICE_USER_ID = "BK_CI_START_SERVICE_USER_ID";
|
||||
public static final String PIPELINE_START_MANUAL_USER_ID = "BK_CI_START_MANUAL_USER_ID";
|
||||
public static final String PIPELINE_START_TIME_TRIGGER_USER_ID = "BK_CI_START_TIME_TRIGGER_USER_ID";
|
||||
public static final String PIPELINE_START_REMOTE_USER_ID = "BK_CI_START_REMOTE_USER_ID";
|
||||
public static final String PIPELINE_START_REMOTE_CLIENT_IP = "BK_CI_START_REMOTE_CLIENT_IP";
|
||||
public static final String PIPELINE_START_TYPE = "BK_CI_START_TYPE";
|
||||
public static final String PIPELINE_START_CHANNEL = "BK_CI_START_CHANNEL";
|
||||
public static final String PIPELINE_BUILD_NUM = "BK_CI_BUILD_NUM";
|
||||
public static final String PIPELINE_BUILD_LAST_UPDATE = "BK_CI_BUILD_LAST_UPDATE";
|
||||
public static final String PIPELINE_BUILD_SVN_REVISION = "BK_CI_BUILD_SVN_REVISION";
|
||||
public static final String PIPELINE_BUILD_NUM_ALIAS = "BK_CI_BUILD_NUM_ALIAS";
|
||||
public static final String PIPELINE_BUILD_URL = "BK_CI_BUILD_URL";
|
||||
public static final String PIPELINE_TIMER_DISABLE = "BK_CI_TIMER_DISABLE";
|
||||
public static final String PIPELINE_START_SUB_RUN_MODE = "BK_CI_SUB_PIPELINE_RUN_MODE";
|
||||
|
||||
public static final String GIT_MR_NUMBER = "BK_CI_GIT_MR_NUMBER";
|
||||
public static final String GITHUB_PR_NUMBER = "BK_CI_GITHUB_PR_NUMBER";
|
||||
|
||||
public static final String PIPELINE_NAME = "BK_CI_PIPELINE_NAME";
|
||||
public static final String PIPELINE_ID = "BK_CI_PIPELINE_ID";
|
||||
public static final String WORKSPACE = "WORKSPACE";
|
||||
|
||||
public static final String PIPELINE_TIME_DURATION = "BK_CI_BUILD_TOTAL_TIME";
|
||||
|
||||
public static final String PIPELINE_BUILD_ID = "BK_CI_BUILD_ID";
|
||||
public static final String PIPELINE_VMSEQ_ID = "BK_CI_BUILD_JOB_ID";
|
||||
public static final String PIPELINE_ELEMENT_ID = "BK_CI_BUILD_TASK_ID";
|
||||
public static final String PIPELINE_TURBO_TASK_ID = "BK_CI_TURBO_ID";
|
||||
public static final String PROJECT_NAME = "BK_CI_PROJECT_NAME";
|
||||
public static final String REPORT_DYNAMIC_ROOT_URL = "BK_CI_REPORT_DYNAMIC_ROOT_URL";
|
||||
|
||||
public static final String PROJECT_NAME_CHINESE = "BK_CI_PROJECT_NAME_CN";
|
||||
|
||||
public static final String PIPELINE_START_MOBILE = "BK_CI_IS_MOBILE";
|
||||
|
||||
public static final String PIPELINE_START_TASK_ID = "BK_CI_START_TASK_ID";
|
||||
public static final String PIPELINE_RETRY_COUNT = "BK_CI_RETRY_COUNT";
|
||||
public static final String PIPELINE_RETRY_BUILD_ID = "BK_CI_RETRY_BUILD_ID";
|
||||
public static final String PIPELINE_RETRY_START_TASK_ID = "BK_CI_RETRY_TASK_ID";
|
||||
public static final String PIPELINE_RETRY_ALL_FAILED_CONTAINER = "BK_CI_RETRY_ALL_FAILED_CONTAINER";
|
||||
public static final String PIPELINE_SKIP_FAILED_TASK = "BK_CI_SKIP_FAILED_TASK";
|
||||
|
||||
public static final String BK_CI_BUILD_FAIL_TASKS = "BK_CI_BUILD_FAIL_TASKS";
|
||||
public static final String BK_CI_BUILD_FAIL_TASKNAMES = "BK_CI_BUILD_FAIL_TASKNAMES";
|
||||
|
||||
public static final String PIPELINE_VIEW_MY_PIPELINES = "myPipeline";
|
||||
public static final String PIPELINE_VIEW_MY_LIST_PIPELINES = "myListPipeline";
|
||||
public static final String PIPELINE_VIEW_FAVORITE_PIPELINES = "collect";
|
||||
public static final String PIPELINE_VIEW_ALL_PIPELINES = "allPipeline";
|
||||
public static final String PIPELINE_VIEW_UNCLASSIFIED = "unclassified";
|
||||
public static final String PIPELINE_VIEW_RECENT_USE = "recentUse";
|
||||
|
||||
public static final String PIPELINE_MATERIAL_URL = "BK_CI_PIEPLEINE_MATERIAL_URL";
|
||||
public static final String PIPELINE_MATERIAL_BRANCHNAME = "BK_CI_PIPELINE_MATERIAL_BRANCHNAME";
|
||||
public static final String PIPELINE_MATERIAL_ALIASNAME = "BK_CI_PIPELINE_MATERIAL_ALIASNAME";
|
||||
public static final String PIPELINE_MATERIAL_NEW_COMMIT_ID = "BK_CI_PIPELINE_MATERIAL_NEW_COMMIT_ID";
|
||||
public static final String PIPELINE_MATERIAL_NEW_COMMIT_COMMENT = "BK_CI_PIPELINE_MATERIAL_NEW_COMMIT_COMMENT";
|
||||
public static final String PIPELINE_MATERIAL_NEW_COMMIT_TIMES = "BK_CI_PIPELINE_MATERIAL_NEW_COMMIT_TIMES";
|
||||
|
||||
public static final String MAJORVERSION = "BK_CI_MAJOR_VERSION";
|
||||
public static final String MINORVERSION = "BK_CI_MINOR_VERSION";
|
||||
public static final String FIXVERSION = "BK_CI_FIX_VERSION";
|
||||
public static final String BUILD_NO = "BK_CI_BUILD_NO";
|
||||
public static final String BUILD_STATUS = "BK_CI_BUILD_STATUS";
|
||||
public static final String BK_DOCKER_TARGE_IMAGE_TAG = "BK_DOCKER_TARGE_IMAGE_TAG";
|
||||
public static final String BK_DOCKER_TARGE_IMAGE_NAME = "BK_DOCKER_TARGE_IMAGE_NAME";
|
||||
|
||||
public static final String JOB_RETRY_TASK_ID = "job.retry_task_id";
|
||||
|
||||
public static final String PIPELINE_CREATE_USER = "BK_CI_PIPELINE_CREATE_USER";
|
||||
public static final String PIPELINE_UPDATE_USER = "BK_CI_PIPELINE_UPDATE_USER";
|
||||
public static final String PIPELINE_BUILD_REMARK = "BK_CI_BUILD_REMARK";
|
||||
public static final String PIPELINE_ATOM_NAME = "BK_CI_ATOM_NAME";
|
||||
public static final String PIPELINE_ATOM_CODE = "BK_CI_ATOM_CODE";
|
||||
public static final String PIPELINE_ATOM_VERSION = "BK_CI_ATOM_VERSION";
|
||||
public static final String PIPELINE_TASK_NAME = "BK_CI_TASK_NAME";
|
||||
public static final String PIPELINE_STEP_ID = "BK_CI_STEP_ID";
|
||||
public static final String PIPELINE_ATOM_TIMEOUT = "BK_CI_ATOM_TIMEOUT";
|
||||
public static final String PIPELINE_DIALECT = "BK_CI_PIPELINE_DIALECT";
|
||||
|
||||
public static final String BK_CI_MATERIAL_ID = "BK_CI_MATERIAL_ID";
|
||||
public static final String BK_CI_MATERIAL_NAME = "BK_CI_MATERIAL_NAME";
|
||||
public static final String BK_CI_MATERIAL_URL = "BK_CI_MATERIAL_URL";
|
||||
|
||||
public static final String BK_CI_AUTHORIZER = "BK_CI_AUTHORIZER";
|
||||
|
||||
public static final int PIPELINE_SETTING_MAX_QUEUE_SIZE_DEFAULT = 10;
|
||||
public static final int TASK_FAIL_RETRY_MAX_COUNT = 5;
|
||||
public static final int TASK_FAIL_RETRY_MIN_COUNT = 1;
|
||||
public static final int PIPELINE_SETTING_MAX_QUEUE_SIZE_MIN = 0;
|
||||
public static final int PIPELINE_SETTING_MAX_QUEUE_SIZE_MAX = 200;
|
||||
public static final int PIPELINE_SETTING_MAX_CON_QUEUE_SIZE_DEFAULT = 50;
|
||||
public static final int PIPELINE_SETTING_MAX_CON_QUEUE_SIZE_MAX = 200;
|
||||
public static final int PIPELINE_SETTING_WAIT_QUEUE_TIME_MINUTE_DEFAULT = 1;
|
||||
public static final int PIPELINE_SETTING_WAIT_QUEUE_TIME_MINUTE_MIN = 1;
|
||||
public static final int PIPELINE_SETTING_WAIT_QUEUE_TIME_MINUTE_MAX = 1440;
|
||||
public static final int PIPELINE_TASK_MESSAGE_STRING_LENGTH_MAX = 4000;
|
||||
public static final int PIPELINE_MESSAGE_STRING_LENGTH_MAX = 30000;
|
||||
public static final int PIPELINE_CON_RUNNING_CONTAINER_SIZE_MAX = 30;
|
||||
public static final int PIPELINE_MATRIX_MAX_CON_RUNNING_SIZE_DEFAULT = 5;
|
||||
public static final int PIPELINE_MATRIX_CON_RUNNING_SIZE_MAX = 20;
|
||||
public static final int PIPELINE_STAGE_CONTAINERS_COUNT_MAX = 256;
|
||||
public static final int PIPELINE_CONDITION_EXPRESSION_LENGTH_MAX = 512;
|
||||
public static final int PIPELINE_VARIABLES_STRING_LENGTH_MAX = 4000;
|
||||
|
||||
public static final String PIPELINE_TIME_START = "BK_CI_BUILD_START_TIME";
|
||||
public static final String PIPELINE_TIME_END = "BK_CI_BUILD_END_TIME";
|
||||
public static final String PIPELINE_BUILD_MSG = "BK_CI_BUILD_MSG";
|
||||
|
||||
public static final int PIPELINE_RES_NUM_MIN = 50;
|
||||
|
||||
public static final String KEY_PIPELINE_ID = "pipelineId";
|
||||
public static final String KEY_PIPELINE_NAME = "pipelineName";
|
||||
public static final String KEY_PROJECT_ID = "projectId";
|
||||
public static final String KEY_TEMPLATE_ID = "templateId";
|
||||
public static final String KEY_STAGE = "stage";
|
||||
public static final String KEY_JOB = "job";
|
||||
public static final String KEY_TASK = "task";
|
||||
public static final String KEY_TASK_ATOM = "taskAtom";
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package cd.casic.ci.process.api.process.utils;
|
||||
|
||||
import cd.casic.ci.log.scm.dal.pojo.CodeP4Repository;
|
||||
import cd.casic.ci.log.scm.dal.pojo.CodeSvnRepository;
|
||||
import cd.casic.ci.ticket.dal.enums.CredentialType;
|
||||
import cd.casic.framework.commons.util.encrypt.DHUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.process.api.process.utils
|
||||
* @Project:ops-pro
|
||||
* @name:CredentialUtils
|
||||
* @Date:2025/03/27 14:35
|
||||
* @Filename:CredentialUtils
|
||||
* @description:Todo
|
||||
*/
|
||||
@Slf4j
|
||||
public class CredentialUtils {
|
||||
|
||||
public static Credential getCredential(Repository repository, List<String> credentials, CredentialType credentialType) {
|
||||
if (repository instanceof CodeSvnRepository && ((CodeSvnRepository) repository).getSvnType() == CodeSvnRepository.SVN_TYPE_HTTP) {
|
||||
return switch (credentialType) {
|
||||
case USERNAME_PASSWORD -> {
|
||||
if (credentials.size() <= 1) {
|
||||
log.warn("Fail to get the username of the svn repo {}", repository);
|
||||
yield new Credential(repository.getUserName(), credentials.get(0), null);
|
||||
} else {
|
||||
yield new Credential(credentials.get(0), credentials.get(1), null);
|
||||
}
|
||||
}
|
||||
case TOKEN_USERNAME_PASSWORD -> {
|
||||
yield new Credential(
|
||||
credentials.get(0),
|
||||
credentials.getOrDefault(1, ""),
|
||||
credentials.getOrDefault(2, ""),
|
||||
null
|
||||
);
|
||||
}
|
||||
default -> new Credential(repository.getUserName(), credentials.get(0), null);
|
||||
};
|
||||
} else if (repository instanceof CodeSvnRepository && credentialType == CredentialType.TOKEN_SSH_PRIVATEKEY) {
|
||||
return new Credential(
|
||||
credentials.get(0),
|
||||
credentials.getOrDefault(1, ""),
|
||||
repository.getUserName(),
|
||||
credentials.getOrDefault(2, "")
|
||||
);
|
||||
} else if (repository instanceof CodeP4Repository && credentialType == CredentialType.USERNAME_PASSWORD) {
|
||||
return new Credential(credentials.get(0), "", credentials.get(1));
|
||||
} else {
|
||||
String privateKey = credentials.get(0);
|
||||
String passPhrase = credentials.size() > 1 && !credentials.get(1).isEmpty() ? credentials.get(1) : null;
|
||||
return new Credential(repository.getUserName(), privateKey, passPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
public static String decode(String encode, String publicKey, byte[] privateKey) {
|
||||
if (!StringUtils.hasText(encode)) return "";
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(encode);
|
||||
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey);
|
||||
return new String(DHUtil.decrypt(decodedBytes, publicKeyBytes, privateKey));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Credential {
|
||||
private String username;
|
||||
private String privateKey;
|
||||
private String passPhrase;
|
||||
private String svnToken;
|
||||
private CredentialType credentialType;
|
||||
|
||||
public Credential(String username, String privateKey, String passPhrase) {
|
||||
this.username = username;
|
||||
this.privateKey = privateKey;
|
||||
this.passPhrase = passPhrase;
|
||||
}
|
||||
|
||||
public Credential(String svnToken, String username, String privateKey, String passPhrase) {
|
||||
this.svnToken = svnToken;
|
||||
this.username = username;
|
||||
this.privateKey = privateKey;
|
||||
this.passPhrase = passPhrase;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package cd.casic.ci.process.api.process.utils;
|
||||
|
||||
import cd.casic.ci.process.api.process.constant.ProcessMessageCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @Author:mianbin
|
||||
* @Package:cd.casic.ci.process.api.process.utils
|
||||
* @Project:ops-pro
|
||||
* @name:DependOnUtils
|
||||
* @Date:2025/03/27 14:39
|
||||
* @Filename:DependOnUtils
|
||||
* @description:Todo
|
||||
*/
|
||||
@Slf4j
|
||||
public class DependOnUtils {
|
||||
|
||||
private static final Pattern REGEX = Pattern.compile("[,;]");
|
||||
|
||||
public static void checkRepeatedJobId(Stage stage) {
|
||||
Set<String> jobIdSet = new HashSet<>();
|
||||
for (Container c : stage.getContainers()) {
|
||||
String jobId = c.getJobId();
|
||||
if (jobId == null || jobId.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (jobIdSet.contains(jobId)) {
|
||||
String jobName = getContainerName(stage, c, jobId);
|
||||
throw new ErrorCodeException(
|
||||
Response.Status.CONFLICT.getStatusCode(),
|
||||
ProcessMessageCode.ERROR_PIPELINE_JOBID_EXIST,
|
||||
new String[]{jobName, jobId},
|
||||
jobName + " 的jobId(" + jobId + ")已存在"
|
||||
);
|
||||
}
|
||||
jobIdSet.add(jobId);
|
||||
}
|
||||
removeNonexistentJob(stage, jobIdSet);
|
||||
}
|
||||
|
||||
private static void removeNonexistentJob(Stage stage, Set<String> jobIdSet) {
|
||||
for (Container c : stage.getContainers()) {
|
||||
JobControlOption jobControlOption = null;
|
||||
if (c instanceof VMBuildContainer) {
|
||||
jobControlOption = ((VMBuildContainer) c).getJobControlOption();
|
||||
} else if (c instanceof NormalContainer) {
|
||||
jobControlOption = ((NormalContainer) c).getJobControlOption();
|
||||
}
|
||||
if (jobControlOption == null) {
|
||||
continue;
|
||||
}
|
||||
if (jobControlOption.getDependOnType() != DependOnType.ID || jobControlOption.getDependOnId() == null || jobControlOption.getDependOnId().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<String> existJobIds = jobControlOption.getDependOnId().stream()
|
||||
.filter(jobIdSet::contains)
|
||||
.toList();
|
||||
jobControlOption.setDependOnId(existJobIds);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initDependOn(Stage stage, Map<String, String> params) {
|
||||
Map<String, Container> allJobId2JobMap = new HashMap<>();
|
||||
for (Container c : stage.getContainers()) {
|
||||
String jobId = c.getJobId();
|
||||
if (jobId == null || jobId.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
allJobId2JobMap.put(jobId, c);
|
||||
}
|
||||
if (allJobId2JobMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, List<String>> cycleCheckJobMap = new HashMap<>();
|
||||
for (Container c : stage.getContainers()) {
|
||||
JobControlOption jobControlOption = null;
|
||||
if (c instanceof VMBuildContainer) {
|
||||
jobControlOption = ((VMBuildContainer) c).getJobControlOption();
|
||||
} else if (c instanceof NormalContainer) {
|
||||
jobControlOption = ((NormalContainer) c).getJobControlOption();
|
||||
}
|
||||
if (jobControlOption == null) {
|
||||
continue;
|
||||
}
|
||||
List<String> dependOnJobIds = getDependOnJobIds(new DependOnConfig(
|
||||
jobControlOption.getDependOnType(),
|
||||
jobControlOption.getDependOnId(),
|
||||
jobControlOption.getDependOnName()
|
||||
), params);
|
||||
if (dependOnJobIds.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (c.getJobId() != null) {
|
||||
cycleCheckJobMap.put(c.getJobId(), dependOnJobIds);
|
||||
}
|
||||
Map<String, String> containerId2JobIds = new HashMap<>();
|
||||
for (String dependOnJobId : dependOnJobIds) {
|
||||
Container dependOnJob = allJobId2JobMap.get(dependOnJobId);
|
||||
if (dependOnJob == null) {
|
||||
continue;
|
||||
}
|
||||
containerId2JobIds.put(dependOnJob.getId(), dependOnJobId);
|
||||
}
|
||||
if (!containerId2JobIds.isEmpty()) {
|
||||
jobControlOption.setDependOnContainerId2JobIds(containerId2JobIds);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> visited = new HashMap<>();
|
||||
for (String jobId : cycleCheckJobMap.keySet()) {
|
||||
dsf(jobId, cycleCheckJobMap, visited, stage, allJobId2JobMap);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean enableDependOn(Container container) {
|
||||
JobControlOption jobControlOption = null;
|
||||
if (container instanceof VMBuildContainer) {
|
||||
jobControlOption = ((VMBuildContainer) container).getJobControlOption();
|
||||
} else if (container instanceof NormalContainer) {
|
||||
jobControlOption = ((NormalContainer) container).getJobControlOption();
|
||||
}
|
||||
if (jobControlOption == null) {
|
||||
return false;
|
||||
}
|
||||
return switch (jobControlOption.getDependOnType()) {
|
||||
case ID -> jobControlOption.getDependOnId() != null && !jobControlOption.getDependOnId().isEmpty();
|
||||
case NAME -> jobControlOption.getDependOnName() != null && !jobControlOption.getDependOnName().isEmpty();
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static List<String> getDependOnJobIds(DependOnConfig dependOnConfig, Map<String, String> params) {
|
||||
return switch (dependOnConfig.getDependOnType()) {
|
||||
case ID -> dependOnConfig.getDependOnId() != null ? dependOnConfig.getDependOnId() : Collections.emptyList();
|
||||
case NAME -> {
|
||||
if (dependOnConfig.getDependOnName() == null || dependOnConfig.getDependOnName().isEmpty()) {
|
||||
yield Collections.emptyList();
|
||||
} else {
|
||||
String[] dependONames = dependOnConfig.getDependOnName().split(REGEX);
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String name : dependONames) {
|
||||
result.add(EnvUtils.parseEnv(name, params));
|
||||
}
|
||||
yield result;
|
||||
}
|
||||
}
|
||||
default -> Collections.emptyList();
|
||||
};
|
||||
}
|
||||
|
||||
private static void dsf(String jobId, Map<String, List<String>> dependOnMap, Map<String, Integer> visited, Stage stage, Map<String, Container> allJobId2JobMap) {
|
||||
if (visited.getOrDefault(jobId, 0) == 1) {
|
||||
String jobName = getContainerName(stage, allJobId2JobMap.get(jobId), jobId);
|
||||
String dependJobName = getContainerName(stage, allJobId2JobMap.get(dependOnJobId), dependOnJobId);
|
||||
throw new ErrorCodeException(
|
||||
ProcessMessageCode.ERROR_PIPELINE_DEPENDON_CYCLE,
|
||||
new String[]{jobName, dependJobName}
|
||||
);
|
||||
}
|
||||
if (visited.getOrDefault(jobId, 0) == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.put(jobId, 1);
|
||||
List<String> dependOnJobIds = dependOnMap.getOrDefault(jobId, Collections.emptyList());
|
||||
for (String dependOnJobId : dependOnJobIds) {
|
||||
dsf(dependOnJobId, dependOnMap, visited, stage, allJobId2JobMap);
|
||||
}
|
||||
visited.put(jobId, 2);
|
||||
}
|
||||
|
||||
private static String getContainerName(Stage stage, Container container, String jobId) {
|
||||
if (container == null) {
|
||||
return jobId;
|
||||
}
|
||||
String namePrefix = stage.getName() != null ? stage.getName().replaceFirst("stage-", "") : "";
|
||||
return namePrefix + "-" + container.getId();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user