Explorar o código

fix: 优化初始化流水线部分代码结构

wpt hai 11 meses
pai
achega
18b6c0009a

+ 42 - 21
web/src/main/java/cn/seecoder/web/core/pipeline/PipelineFactory.java

@@ -1,76 +1,97 @@
 package cn.seecoder.web.core.pipeline;
 
+import cn.seecoder.web.core.pipeline.config.HandlerConfigTable;
 import cn.seecoder.web.core.pipeline.handler.AbstractHandler;
+import cn.seecoder.web.core.pipeline.pipeline.PipelineImpl;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.http.HttpStatus;
-import cn.seecoder.web.core.pipeline.config.HandlerConfigTable;
-import cn.seecoder.web.core.pipeline.pipeline.PipelineImpl;
 
 import java.util.List;
 
 /**
- * @author PuHong Weng
- * @date 2021/3/10
- * @description:
+ * PipelineFactory
+ * 流水线初始化工厂类
  */
 public class PipelineFactory {
+
     /**
-     * 流水线初始化
+     * 初始化流水线
      * <p>
-     * 注意 namespace deployName 只能为 小写英文字母 . - _ 的组合,这是因为docker镜像名的限制
+     * 注意 namespace 和 deployName 只能为小写英文字母、数字、.、-、_ 的组合,
+     * 这是因为 Docker 镜像名的限制。
      *
-     * @param configJson configJson 流水线配置的json字符串
-     * @param namespace  流水线的k8s namespace,devcloud后端采用Project中的"name-id"作为namespace
-     * @param deployName 流水线部署k8s的应用名称,devcloud后端采用Pipeline中的name作为project name
-     * @return
+     * @param id         流水线 ID
+     * @param configJson 流水线配置 JSON 字符串
+     * @param namespace  流水线的 K8s namespace
+     * @param deployName 流水线部署的应用名称
+     * @return 初始化完成的 Pipeline
+     * @throws PipelineException 初始化异常
      */
-    public static Pipeline init(Integer id, String configJson, String namespace, String deployName) throws PipelineException {
-        //初始化context
+    public static Pipeline init(Integer id, String configJson, String namespace, String deployName)
+            throws PipelineException {
+
+        // 初始化 Context
         Context context = Context.builder()
                 .pipelineId(id)
-                .deployName(deployName)
                 .namespace(namespace)
+                .deployName(deployName)
                 .build();
+
+        // 构建 Handler 链
         Handler firstHandler = initHandlerChainAndContext(configJson);
+
         return new PipelineImpl(firstHandler, context);
     }
 
     /**
-     * 根据 handlerConfig 构筑 Handler 的流水线,以及将配置属性统一放入 Context
+     * 根据 handler 配置构建 Handler 流水线,并将配置属性统一放入 Context
+     *
+     * @param configJson 流水线配置 JSON 字符串
+     * @return Handler 链的头节点
+     * @throws PipelineException 构建异常
      */
     private static Handler initHandlerChainAndContext(String configJson) throws PipelineException {
-        //写法方便做个头结点,没有任何用
+
+        // 使用空头节点方便链表操作
         AbstractHandler head = new AbstractHandler() {
             @Override
             public void process(Context context) throws PipelineException {
+                // 空实现
             }
         };
         Handler cur = head;
 
         ObjectMapper mapper = new ObjectMapper();
-        List<ObjectNode> handlers;
         try {
-            handlers = mapper.readValue(configJson, new TypeReference<List<ObjectNode>>() {
+            // 解析 JSON 为 ObjectNode 列表
+            List<ObjectNode> handlers = mapper.readValue(configJson, new TypeReference<List<ObjectNode>>() {
             });
+
             for (ObjectNode node : handlers) {
-                //用于判断此步骤是否启用
+                // 跳过未启用的步骤
                 if (!node.get("active").asBoolean()) {
                     continue;
                 }
-                String name = node.get("name").toString().replaceAll("\"", "");
+
+                String name = node.get("name").asText();
                 JsonNode configs = node.get("configs");
-                // 每个步骤并不一定对应一个Handler,而是可能对应多个Handler
+
+                // 每个步骤可能对应多个 Handler
                 cur.setNextHandler(HandlerConfigTable.transToHandler(name, configs));
+
+                // 移动到链尾
                 while (cur.getNextHandler() != null) {
                     cur = cur.getNextHandler();
                 }
             }
+
         } catch (Exception e) {
             throw new PipelineException(HttpStatus.SC_BAD_REQUEST, PipelineException.CONFIG_TRANSFER_ERROR, e);
         }
+
         return head.getNextHandler();
     }
 }

+ 53 - 27
web/src/main/java/cn/seecoder/web/core/pipeline/config/HandlerConfigTable.java

@@ -12,21 +12,22 @@ import java.lang.reflect.Field;
 import java.util.*;
 
 /**
- * @author PuHong Weng
- * @date 2021/3/10
- * @description: 记录流水线配置json中 name到具体Handler的映射
+ * Handler 配置表
+ * 根据流水线配置 JSON 中的 name 映射到具体 Handler 类
+ * 并通过反射将 JSON 配置注入 Handler 实例
  */
 @Slf4j
 public class HandlerConfigTable {
 
     /**
-     * 根据名称映射对应的流水线执行类
+     * name -> Handler 类映射表
      */
     private static final Map<String, List<Class<?>>> handlerConfigMap;
 
-
     static {
         handlerConfigMap = new HashMap<>();
+
+        // 构建单个 Handler 映射
         handlerConfigMap.put("node-image-build", Collections.singletonList(NodeImageBuildHandler.class));
         handlerConfigMap.put("java-image-build", Collections.singletonList(JavaImageBuildHandler.class));
         handlerConfigMap.put("k8s-deployment", Collections.singletonList(K8sDeploymentHandler.class));
@@ -40,39 +41,61 @@ public class HandlerConfigTable {
         handlerConfigMap.put("sonar-java-image-build", Collections.singletonList(SonarJavaImageBuildHandler.class));
         handlerConfigMap.put("k8s-job", Collections.singletonList(K8sJobHandler.class));
 
-        handlerConfigMap.put("sonar-java", Arrays.asList(SonarJavaImageBuildHandler.class, K8sJobHandler.class, SonarPostProcessHandler.class));
-        handlerConfigMap.put("sonar-java-deploy", Arrays.asList(SonarJavaImageBuildHandler.class, K8sJobHandler.class, SonarPostProcessHandler.class));
+        // 构建组合 Handler 映射
+        handlerConfigMap.put("sonar-java", Arrays.asList(
+                SonarJavaImageBuildHandler.class,
+                K8sJobHandler.class,
+                SonarPostProcessHandler.class
+        ));
+        handlerConfigMap.put("sonar-java-deploy", Arrays.asList(
+                SonarJavaImageBuildHandler.class,
+                K8sJobHandler.class,
+                SonarPostProcessHandler.class
+        ));
     }
 
+    /**
+     * 将 name 和配置 JSON 转换为 Handler 链
+     *
+     * @param name   Handler 名称
+     * @param config 配置 JSON
+     * @return Handler 链头节点
+     * @throws Exception 转换异常
+     */
     public static Handler transToHandler(String name, JsonNode config) throws Exception {
         Handler firstHandler = null;
         Handler lastHandler = null;
+
         try {
-            List<Class<?>> handlers = handlerConfigMap.get(name);
-            // 对所有Handler注入依赖
-            for (Class<?> handlerClass : handlers) {
+            List<Class<?>> handlerClasses = handlerConfigMap.get(name);
+            if (handlerClasses == null || handlerClasses.isEmpty()) {
+                return null;
+            }
+
+            ObjectMapper mapper = new ObjectMapper();
+
+            for (Class<?> handlerClass : handlerClasses) {
+                // 创建 Handler 实例
                 Handler handler = (Handler) handlerClass.newInstance();
-                //通过反射注入配置对应Handler类
-                Iterator<Map.Entry<String, JsonNode>> jsonNodeIterator = config.fields();
-                while (jsonNodeIterator.hasNext()) {
-                    Map.Entry<String, JsonNode> entry = jsonNodeIterator.next();
+
+                // 反射注入配置属性
+                Iterator<Map.Entry<String, JsonNode>> fields = config.fields();
+                while (fields.hasNext()) {
+                    Map.Entry<String, JsonNode> entry = fields.next();
                     String propertyName = entry.getKey();
-                    JsonNode propertyValues = entry.getValue();
-                    ObjectMapper mapper = new ObjectMapper();
-                    // 遍历json,去handler中获取对应的成员变量,因此要处理找不到变量的情况
-                    Field field;
+                    JsonNode propertyValue = entry.getValue();
+
                     try {
-                        field = handler.getClass().getDeclaredField(propertyName);
+                        Field field = handler.getClass().getDeclaredField(propertyName);
                         field.setAccessible(true);
-                        //注意,这种写法无法自动注入List<xx>等的字段,因为泛型信息由于java的机制被删除了
-                        // 所以最好还是传入一些基本类型或者String,在对应的handler自己解析
-                        field.set(handler, mapper.readValue(propertyValues.traverse(), field.getType()));
-                    } catch (NoSuchFieldException ignored){
-                        // 如果Handler中没有对应json中的config属性,跳过,直接取下一个属性。
-                        // 注意java中异常当场处理之后会从try后面继续运行
+                        // 将 JSON 值注入字段
+                        field.set(handler, mapper.readValue(propertyValue.traverse(), field.getType()));
+                    } catch (NoSuchFieldException ignored) {
+                        // 如果 Handler 中没有对应字段,直接跳过
                     }
                 }
-                // 设置 Handler
+
+                // 链接 Handler
                 if (firstHandler == null) {
                     firstHandler = handler;
                 }
@@ -81,9 +104,12 @@ public class HandlerConfigTable {
                 }
                 lastHandler = handler;
             }
+
         } catch (InstantiationException | IllegalAccessException e) {
-            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.CONFIG_TRANSFER_ERROR, e);
+            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,
+                    PipelineException.CONFIG_TRANSFER_ERROR, e);
         }
+
         return firstHandler;
     }
 }