Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions bkflow/pipeline_converter/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ class NodeTypes(str, Enum):
]


class ConstantTypes(str, Enum):
CUSTOM_CONSTANT = "custom"
COMPONENT_INPUTS_CONSTANT = "component_inputs"
COMPONENT_OUTPUTS_CONSTANT = "component_outputs"

CUSTOM_CONSTANT_TAGS = [
"bk_manage_user_selector.bk_user_selector",
"datetime.datetime",
"input.input",
"int.int",
"select.select",
"textarea.textarea",
"datetime_range.datetime_range",
"datatable.datatable",
"json_variable.json_variable",
]


class DataTypes(str, Enum):
DATA_MODEL = "data_model"
JSON = "json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def convert(self, *args, **kwargs):
for field in fields:
self.target_data[field.key] = {
"need_render": field.need_render,
"key": field.key,
"value": field.value,
"hook": False, # TODO: 可配置
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,85 @@
# -*- coding: utf-8 -*-
from bkflow.pipeline_converter.constants import ConstantTypes
from bkflow.pipeline_converter.converters.base import DataModelToPipelineTreeConverter
from bkflow.pipeline_converter.validators.constant import (
ComponentInputValidator,
ConstantValidator,
)
from bkflow.pipeline_converter.validators.node import NodeTypeValidator


class SourceInfoConverter(DataModelToPipelineTreeConverter):
def convert(self):
self.target_data = {}
for info in self.source_data:
self.target_data[info.key] = [info.value]
return self.target_data


class CustomConstantConverter(DataModelToPipelineTreeConverter):
validators = [NodeTypeValidator(ConstantTypes.CUSTOM_CONSTANT.value), ConstantValidator()]

def convert(self):
converter_data = self.source_data
self.target_data = {
"name": converter_data.name,
"key": f"${{{converter_data.key}}}",
"desc": converter_data.desc,
"value": converter_data.value,
"custom_type": converter_data.custom_type,
"show_type": converter_data.show_type,
"source_tag": converter_data.source_tag,
"source_type": ConstantTypes.CUSTOM_CONSTANT.value,
"source_info": SourceInfoConverter(converter_data.source_info).convert(),
"validation": converter_data.validation,
"version": converter_data.version,
"pre_render_make": False,
"is_meta": converter_data.is_meta,
}

return self.target_data


class ComponentInputConverter(DataModelToPipelineTreeConverter):
validators = [NodeTypeValidator(ConstantTypes.COMPONENT_INPUTS_CONSTANT.value), ComponentInputValidator()]

def convert(self):
converter_data = self.source_data
self.target_data = {
"name": converter_data.name,
"key": f"${{{converter_data.key}}}",
"desc": converter_data.desc,
"value": [converter_data.value],
"custom_type": converter_data.custom_type,
"show_type": converter_data.show_type,
"source_tag": converter_data.source_tag,
"source_type": ConstantTypes.COMPONENT_INPUTS_CONSTANT.value,
"source_info": SourceInfoConverter(converter_data.source_info).convert(),
"validation": converter_data.validation,
"version": converter_data.version,
"plugin_code": converter_data.plugin_code,
"extra_info": converter_data.extra_info,
}
return self.target_data


class ComponentOutputConverter(DataModelToPipelineTreeConverter):
validators = [NodeTypeValidator(ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value)]

def convert(self):
converter_data = self.source_data
self.target_data = {
"name": converter_data.name,
"key": f"${{{converter_data.key}}}",
"desc": converter_data.desc,
"value": converter_data.value,
"custom_type": converter_data.custom_type,
"show_type": converter_data.show_type,
"source_tag": converter_data.source_tag,
"source_type": ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value,
"source_info": SourceInfoConverter(converter_data.source_info).convert(),
"validation": converter_data.validation,
"plugin_code": converter_data.plugin_code,
"extra_info": converter_data.extra_info,
}
return self.target_data
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
from pipeline.parser.utils import replace_all_id
from pipeline.utils.uniqid import line_uniqid

from bkflow.pipeline_converter.constants import NodeTypes
from bkflow.pipeline_converter.constants import ConstantTypes, NodeTypes
from bkflow.pipeline_converter.converters.base import DataModelToPipelineTreeConverter
from bkflow.pipeline_converter.converters.data_model_to_web_pipeline.constant import (
ComponentInputConverter,
ComponentOutputConverter,
CustomConstantConverter,
)
from bkflow.pipeline_converter.converters.data_model_to_web_pipeline.gateway import (
ConditionalParallelGatewayConverter,
ConvergeGatewayConverter,
Expand All @@ -19,6 +24,7 @@
StartNodeConverter,
)
from bkflow.pipeline_converter.data_models import Flow, Node, Pipeline
from bkflow.pipeline_converter.hub import ConverterHub


class PipelineConverter(DataModelToPipelineTreeConverter):
Expand All @@ -28,6 +34,7 @@ def convert(self) -> dict:
"""
pipeline: Pipeline = self.source_data
nodes: List[Node] = pipeline.nodes
constants = pipeline.constants
self.target_data = {
PE.id: pipeline.id,
PE.name: pipeline.name,
Expand Down Expand Up @@ -57,6 +64,10 @@ def convert(self) -> dict:
elif node.type in NodeTypes.GATEWAYS:
gateway_data = gateway_mapping[node.type](node).convert()
self.target_data[PE.gateways][node.id] = gateway_data

# 常量数据转换
self.validate_constant(self.target_data[PE.activities], constants)
self.target_data[PE.constants] = self.constant_converter(constants)
# 连线数据转换
flows = self._generate_flows_by_nodes(nodes)
self.target_data[PE.flows] = {flow.id: flow.dict() for flow in flows}
Expand All @@ -73,6 +84,24 @@ def convert(self) -> dict:
replace_all_id(self.target_data)
return self.target_data

def constant_converter(self, constants):
constant_type_converter_cls_name_map = {
ConstantTypes.CUSTOM_CONSTANT.value: CustomConstantConverter.__name__,
ConstantTypes.COMPONENT_INPUTS_CONSTANT.value: ComponentInputConverter.__name__,
ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value: ComponentOutputConverter.__name__,
}
result = {}
for index, constant in enumerate(constants):
converter_cls = ConverterHub.get_converter_cls(
source=self.source,
target=self.target,
converter_name=constant_type_converter_cls_name_map[constant.type],
)
constant_data = converter_cls(constant).convert()
constant_data["index"] = index
result[constant_data.get("key")] = constant_data
return result

@staticmethod
def _generate_flows_by_nodes(nodes: List[Node]) -> List[Flow]:
"""生成流程中的连线信息"""
Expand Down Expand Up @@ -130,3 +159,34 @@ def remap_condition_keys_to_outgoing(gateways_data, flows):
flow_id = flow_id_map.get((gateway_id, condition_node))
new_conditions[flow_id] = {"name": condition["name"], "evaluate": condition["evaluate"]}
gateway["conditions"] = new_conditions

@staticmethod
def validate_constant(nodes, constants):
validate_types = [ConstantTypes.COMPONENT_INPUTS_CONSTANT.value, ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value]

for constant in constants:
# 只检查组件输入/输出类型的常量
if constant.type not in validate_types:
continue

constant_name = constant.name

for info in constant.source_info:
node_id = info.key
# 检查源节点是否存在
if node_id not in nodes:
raise ValueError(f"常量{constant_name}的源节点{node_id}不存在")

if constant.type == ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value:
continue

constant_node = nodes[node_id]["component"]
code, component_file = constant.source_tag.split(".")

# 检查组件code是否匹配
if code != constant_node["code"]:
raise ValueError(f"常量{constant_name}的source_tag字段信息与源节点{node_id}的组件信息不匹配")

# 检查目标字段是否存在
if component_file not in constant_node["data"]:
raise ValueError(f"常量{constant_name}的源节点{node_id}的字段{component_file}不存在")
Original file line number Diff line number Diff line change
@@ -1 +1,93 @@
# -*- coding: utf-8 -*-
from bkflow.pipeline_converter.constants import ConstantTypes
from bkflow.pipeline_converter.converters.base import JsonToDataModelConverter
from bkflow.pipeline_converter.data_models import (
ComponentInputConstant,
ComponentOutConstant,
CustomConstant,
SourceInfo,
)
from bkflow.pipeline_converter.validators.constant import (
JsonComponentInputValidator,
JsonConstantValidator,
)
from bkflow.pipeline_converter.validators.node import JsonNodeTypeValidator


class SourceInfoConverter(JsonToDataModelConverter):
def convert(self):
self.target_data = []
for info in self.source_data:
info_data = SourceInfo(key=info["key"], value=info["value"])
self.target_data.append(info_data)
return self.target_data


class CustomConstantConverter(JsonToDataModelConverter):
validators = [JsonNodeTypeValidator(ConstantTypes.CUSTOM_CONSTANT.value), JsonConstantValidator()]

def convert(self):
self.target_data = CustomConstant(
name=self.source_data["name"],
type=ConstantTypes.CUSTOM_CONSTANT.value,
key=self.source_data["key"],
value=self.source_data["value"],
custom_type=self.source_data["custom_type"],
source_tag=self.source_data["source_tag"],
pre_render_make=False,
source_info=SourceInfoConverter(self.source_data["source_info"]).convert(),
)
default_optional_field = ["desc", "source_info", "validation", "is_meta", "version", "show_type"]
for field in default_optional_field:
if field not in self.source_data:
continue
setattr(self.target_data, field, self.source_data[field])

return self.target_data


class ComponentInputConverter(JsonToDataModelConverter):
validators = [JsonNodeTypeValidator(ConstantTypes.COMPONENT_INPUTS_CONSTANT.value), JsonComponentInputValidator()]

def convert(self):
self.target_data = ComponentInputConstant(
name=self.source_data["name"],
key=self.source_data["key"],
value=self.source_data["value"],
custom_type=self.source_data["custom_type"],
source_tag=self.source_data["source_tag"],
type=ConstantTypes.COMPONENT_INPUTS_CONSTANT.value,
source_info=SourceInfoConverter(self.source_data["source_info"]).convert(),
version=self.source_data["version"],
extra_info=self.source_data["extra_info"],
)
default_optional_field = ["desc", "validation", "version", "show_type", "plugin_code"]
for field in default_optional_field:
if field not in self.source_data:
continue
setattr(self.target_data, field, self.source_data[field])

return self.target_data


class ComponentOutputConverter(JsonToDataModelConverter):
validators = [JsonNodeTypeValidator(ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value)]

def convert(self):
self.target_data = ComponentOutConstant(
name=self.source_data["name"],
key=self.source_data["key"],
value=self.source_data["value"],
custom_type=self.source_data["custom_type"],
source_tag=self.source_data["source_tag"],
type=ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value,
source_info=SourceInfoConverter(self.source_data["source_info"]).convert(),
extra_info=self.source_data["extra_info"],
)
default_optional_field = ["desc", "validation", "show_type", "plugin_code"]
for field in default_optional_field:
if field not in self.source_data:
continue
setattr(self.target_data, field, self.source_data[field])

return self.target_data
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# -*- coding: utf-8 -*-
from bkflow.pipeline_converter.constants import NodeTypes
from bkflow.pipeline_converter.constants import ConstantTypes, NodeTypes
from bkflow.pipeline_converter.converters.base import JsonToDataModelConverter
from bkflow.pipeline_converter.converters.json_to_data_model.constant import (
ComponentInputConverter,
ComponentOutputConverter,
CustomConstantConverter,
)
from bkflow.pipeline_converter.converters.json_to_data_model.gateway import (
ConditionalParallelGatewayConverter,
ConvergeGatewayConverter,
Expand All @@ -25,20 +30,34 @@ def convert(self) -> dict:

target_nodes = []
# TODO: 这块考虑抽象公共逻辑
node_type_converter_cls_name_map = {
data_type_converter_cls_name_map = {
NodeTypes.COMPONENT.value: ComponentNodeConverter.__name__,
NodeTypes.END_EVENT.value: EndNodeConverter.__name__,
NodeTypes.START_EVENT.value: StartNodeConverter.__name__,
NodeTypes.PARALLEL_GATEWAY.value: ParallelGatewayConverter.__name__,
NodeTypes.EXCLUSIVE_GATEWAY.value: ExclusiveGatewayConverter.__name__,
NodeTypes.CONDITIONAL_PARALLEL_GATEWAY.value: ConditionalParallelGatewayConverter.__name__,
NodeTypes.CONVERGE_GATEWAY.value: ConvergeGatewayConverter.__name__,
ConstantTypes.CUSTOM_CONSTANT.value: CustomConstantConverter.__name__,
ConstantTypes.COMPONENT_INPUTS_CONSTANT.value: ComponentInputConverter.__name__,
ConstantTypes.COMPONENT_OUTPUTS_CONSTANT.value: ComponentOutputConverter.__name__,
}
for node in self.source_data.get("nodes", []):
converter_cls = ConverterHub.get_converter_cls(
source=self.source, target=self.target, converter_name=node_type_converter_cls_name_map[node["type"]]
source=self.source, target=self.target, converter_name=data_type_converter_cls_name_map[node["type"]]
)
target_nodes.append(converter_cls(node).convert())
self.target_data.nodes = target_nodes

target_constants = []
for constant in self.source_data.get("constants", []):
converter_cls = ConverterHub.get_converter_cls(
source=self.source,
target=self.target,
converter_name=data_type_converter_cls_name_map[constant["type"]],
)
converted_data = converter_cls(constant).convert()
target_constants.append(converted_data)
self.target_data.constants = target_constants

return self.target_data
Loading
Loading