543 lines
18 KiB
Ruby
543 lines
18 KiB
Ruby
class Api::V1::Projects::PipelinesController < Api::V1::BaseController
|
||
before_action :require_manager_above
|
||
|
||
def index
|
||
@pipelines = Action::Pipeline.where(project_id: @project.id).order(updated_at: :desc)
|
||
@pipelines = paginate @pipelines
|
||
end
|
||
|
||
def create
|
||
size = Action::Pipeline.where(pipeline_name: params[:pipeline_name], project_id: @project.id).size
|
||
tip_exception("已经存在#{params[:pipeline_name]}流水线!") if size > 0
|
||
@pipeline = Action::Pipeline.new(pipeline_name: params[:pipeline_name], project_id: @project.id)
|
||
@pipeline.file_name = ".gitea/workflows/#{@pipeline.pipeline_name}.yaml"
|
||
@pipeline.json = demo.to_json
|
||
# @pipeline.json = params[:json] if params[:json]
|
||
@pipeline.yaml = build_pipeline_yaml(@pipeline)
|
||
@pipeline.save!
|
||
sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
|
||
tip_exception("#{@pipeline.file_name}已存在") if sha
|
||
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||
tip_exception(interactor.error) unless interactor.success?
|
||
render_ok({ id: @pipeline.id })
|
||
end
|
||
|
||
def update
|
||
@pipeline = Action::Pipeline.find(params[:id])
|
||
@pipeline.update!(pipeline_name: params[:pipeline_name])
|
||
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||
tip_exception(interactor.error) unless interactor.success?
|
||
render_ok
|
||
end
|
||
|
||
def destroy
|
||
@pipeline = Action::Pipeline.find(params[:id])
|
||
if pipeline
|
||
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||
tip_exception(interactor.error) unless interactor.success?
|
||
@pipeline.destroy!
|
||
end
|
||
render_ok
|
||
end
|
||
|
||
def show
|
||
@pipeline = Action::Pipeline.find_by(id: params[:id])
|
||
@pipeline = Action::Pipeline.new(id: 0, pipeline_name: "test-ss", yaml: build_yaml) if @pipeline.blank?
|
||
end
|
||
|
||
def build_pipeline_yaml(pipeline)
|
||
if pipeline.json.present?
|
||
@name = pipeline.pipeline_name
|
||
params_nodes = JSON.parse(pipeline.json)["nodes"].select { |node| !["on-push", "on-schedule"].include?(node["component_name"]) }
|
||
on_nodes = JSON.parse(pipeline.json)["nodes"].select { |node| ["on-push", "on-schedule"].include?(node["component_name"]) }
|
||
@on_nodes = build_nodes(on_nodes)
|
||
@steps_nodes = build_nodes(params_nodes)
|
||
yaml = ERB.new(File.read(File.join(Rails.root, "app/views/api/v1/projects/pipelines", "build_pipeline.yaml.erb"))).result(binding)
|
||
# 删除空行内容
|
||
@pipeline_yaml = yaml.gsub(/^\s*\n/, "")
|
||
else
|
||
@pipeline_yaml = params[:yaml]
|
||
end
|
||
@pipeline_yaml
|
||
end
|
||
|
||
def build_yaml
|
||
@name = "love me"
|
||
params_nodes = JSON.parse(demo.to_json)["nodes"].select { |node| !["on-push", "on-schedule"].include?(node["component_name"]) }
|
||
on_nodes = JSON.parse(demo.to_json)["nodes"].select { |node| ["on-push", "on-schedule"].include?(node["component_name"]) }
|
||
@on_nodes = build_nodes(on_nodes)
|
||
@steps_nodes = []
|
||
params_nodes.each do |input_node|
|
||
# Rails.logger.info "input_node=====0===#{input_node["component_name"]}======#{input_node["in_parameters"]}"
|
||
node = Action::Node.find_by(name: input_node["component_name"])
|
||
node.cust_name = input_node["component_label"] if input_node["component_label"].present?
|
||
input_values = {}
|
||
if input_node["in_parameters"].present?
|
||
# Rails.logger.info "@in_parameters=====11===#{input_node["component_name"]}======#{input_node["in_parameters"]}"
|
||
input_node["in_parameters"].each_key do |input_key|
|
||
# Rails.logger.info "@in_parameters.input_key===#{input_key}"
|
||
# Rails.logger.info "@in_parameters.input_value===#{input_node["in_parameters"][input_key]["value"]}"
|
||
input_values = input_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
|
||
end
|
||
node.input_values = input_values
|
||
# Rails.logger.info "@input_values node===#{node.input_values.to_json}"
|
||
end
|
||
@steps_nodes.push(node)
|
||
end
|
||
Rails.logger.info "@@on_nodes===#{@on_nodes.to_json}"
|
||
Rails.logger.info "@steps_nodes===#{@steps_nodes.to_json}"
|
||
yaml = ERB.new(File.read(File.join(Rails.root, "app/views/api/v1/projects/pipelines", "build_pipeline.yaml.erb"))).result(binding)
|
||
@pipeline_yaml = yaml.gsub(/^\s*\n/, "")
|
||
Rails.logger.info "========================="
|
||
Rails.logger.info @pipeline_yaml
|
||
@pipeline_yaml
|
||
end
|
||
|
||
private
|
||
|
||
def get_pipeline_file_sha(file_name, branch)
|
||
file_path_uri = URI.parse(file_name)
|
||
interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: branch || 'master')
|
||
if interactor.success?
|
||
file = interactor.result
|
||
file['sha']
|
||
end
|
||
end
|
||
|
||
def content_params
|
||
{
|
||
filepath: ".gitea/workflows/#{@pipeline.pipeline_name}.yaml",
|
||
branch: @pipeline.branch,
|
||
new_branch: @pipeline.branch,
|
||
content: build_pipeline_yaml(@pipeline),
|
||
message: 'create pipeline',
|
||
committer: {
|
||
email: current_user.mail,
|
||
name: current_user.login
|
||
},
|
||
identifier: @project.identifier
|
||
}
|
||
end
|
||
|
||
def build_nodes(params_nodes)
|
||
steps_nodes = []
|
||
params_nodes.each do |input_node|
|
||
node = Action::Node.find_by(name: input_node["component_name"])
|
||
node.cust_name = input_node["component_label"] if input_node["component_label"].present?
|
||
input_values = {}
|
||
if input_node["in_parameters"].present?
|
||
# Rails.logger.info "@in_parameters=====11===#{input_node["component_name"]}======#{input_node["in_parameters"]}"
|
||
input_node["in_parameters"].each_key do |input_key|
|
||
# Rails.logger.info "@in_parameters.input_key===#{input_key}"
|
||
# Rails.logger.info "@in_parameters.input_value===#{input_node["in_parameters"][input_key]["value"]}"
|
||
input_values = input_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
|
||
end
|
||
# Rails.logger.info "@input_values node1===#{input_values}"
|
||
node.input_values = input_values
|
||
# Rails.logger.info "@input_values node===#{node.input_values.to_json}"
|
||
end
|
||
steps_nodes.push(node)
|
||
end
|
||
steps_nodes
|
||
end
|
||
|
||
def demo
|
||
{
|
||
"nodes": [
|
||
{
|
||
"id": "git-clone-245734ab",
|
||
"category_id": 1,
|
||
"component_name": "on-schedule",
|
||
"component_label": "触发器",
|
||
"working_directory": "",
|
||
"command": "",
|
||
"in_parameters": {
|
||
"--cro": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "push代码",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "",
|
||
"placeholder": "私有仓库填写ssh地址,公有仓库填写https git地址",
|
||
"describe": "代码仓库地址",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "15 4,5 * * *"
|
||
},
|
||
"--paths-ignore": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "push代码",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "",
|
||
"placeholder": "私有仓库填写ssh地址,公有仓库填写https git地址",
|
||
"describe": "代码仓库地址",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "**.md"
|
||
}
|
||
},
|
||
"out_parameters": {
|
||
"--code_output": {
|
||
"type": "str",
|
||
"label": "代码输出路径",
|
||
"path": "/code",
|
||
"require": 1,
|
||
"value": "/code"
|
||
}
|
||
},
|
||
"description": "代码拉取组件",
|
||
"icon_path": "component-icon-1",
|
||
"create_by": "admin",
|
||
"create_time": "2024-03-02T05:41:25.000+00:00",
|
||
"update_by": "admin",
|
||
"update_time": "2024-03-02T05:41:25.000+00:00",
|
||
"state": 1,
|
||
"image": "172.20.32.187/pipeline-component/built-in/git:202312071000",
|
||
"env_variables": "",
|
||
"x": 532,
|
||
"y": 202,
|
||
"label": "代码拉取",
|
||
"img": "/assets/images/component-icon-1.png",
|
||
"isCluster": false,
|
||
"type": "rect-node",
|
||
"size": [110, 36],
|
||
"--code_path": "https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git",
|
||
"--branch": "train_ci_test",
|
||
"--depth": "1",
|
||
"--code_output": "/code"
|
||
},
|
||
{
|
||
"id": "git-clone-245734ab",
|
||
"category_id": 1,
|
||
"component_name": "git-clone",
|
||
"component_label": "代码拉取",
|
||
"working_directory": "",
|
||
"command": "",
|
||
"in_parameters": {
|
||
|
||
},
|
||
"out_parameters": {
|
||
"--code_output": {
|
||
"type": "str",
|
||
"label": "代码输出路径",
|
||
"path": "/code",
|
||
"require": 1,
|
||
"value": "/code"
|
||
}
|
||
},
|
||
"description": "代码拉取组件",
|
||
"icon_path": "component-icon-1",
|
||
"create_by": "admin",
|
||
"create_time": "2024-03-02T05:41:25.000+00:00",
|
||
"update_by": "admin",
|
||
"update_time": "2024-03-02T05:41:25.000+00:00",
|
||
"state": 1,
|
||
"image": "172.20.32.187/pipeline-component/built-in/git:202312071000",
|
||
"env_variables": "",
|
||
"x": 532,
|
||
"y": 202,
|
||
"label": "代码拉取",
|
||
"img": "/assets/images/component-icon-1.png",
|
||
"isCluster": false,
|
||
"type": "rect-node",
|
||
"size": [110, 36],
|
||
"--code_path": "https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git",
|
||
"--branch": "train_ci_test",
|
||
"--depth": "1",
|
||
"--code_output": "/code"
|
||
},
|
||
{
|
||
"id": "git-clone-245734ab",
|
||
"category_id": 1,
|
||
"component_name": "setup-java",
|
||
"component_label": "安装java环境",
|
||
"working_directory": "",
|
||
"command": "",
|
||
"in_parameters": {
|
||
"--distribution": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "代码仓库地址",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "",
|
||
"placeholder": "私有仓库填写ssh地址,公有仓库填写https git地址",
|
||
"describe": "代码仓库地址",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "jdkfile"
|
||
},
|
||
"--java-version": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "代码分支/tag",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "master",
|
||
"placeholder": "",
|
||
"describe": "代码分支或者tag",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "11.0.0"
|
||
},
|
||
"--architecture": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "克隆深度",
|
||
"require": 0,
|
||
"choice": [],
|
||
"default": "1",
|
||
"placeholder": "",
|
||
"describe": "代码克隆深度",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "x64"
|
||
},
|
||
"--mvn-toolchain-vendor": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "ssh私钥",
|
||
"require": 0,
|
||
"choice": [],
|
||
"default": "1",
|
||
"placeholder": "",
|
||
"describe": "ssh私钥,确保ssh公钥已经托管到代码平台,否则可能拉取失败",
|
||
"editable": 1,
|
||
"value": "Oracle"
|
||
}
|
||
},
|
||
"out_parameters": {
|
||
"--code_output": {
|
||
"type": "str",
|
||
"label": "代码输出路径",
|
||
"path": "/code",
|
||
"require": 1,
|
||
"value": "/code"
|
||
}
|
||
},
|
||
"description": "代码拉取组件",
|
||
"icon_path": "component-icon-1",
|
||
"create_by": "admin",
|
||
"create_time": "2024-03-02T05:41:25.000+00:00",
|
||
"update_by": "admin",
|
||
"update_time": "2024-03-02T05:41:25.000+00:00",
|
||
"state": 1,
|
||
"image": "172.20.32.187/pipeline-component/built-in/git:202312071000",
|
||
"env_variables": "",
|
||
"x": 532,
|
||
"y": 202,
|
||
"label": "代码拉取",
|
||
"img": "/assets/images/component-icon-1.png",
|
||
"isCluster": false,
|
||
"type": "rect-node",
|
||
"size": [110, 36],
|
||
"--code_path": "https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git",
|
||
"--branch": "train_ci_test",
|
||
"--depth": "1",
|
||
"--code_output": "/code"
|
||
},
|
||
{
|
||
"id": "git-clone-245734ab",
|
||
"category_id": 1,
|
||
"component_name": "shell",
|
||
"component_label": "执行shell命令",
|
||
"working_directory": "",
|
||
"command": "",
|
||
"in_parameters": {
|
||
"--run": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "代码仓库地址",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "",
|
||
"placeholder": "私有仓库填写ssh地址,公有仓库填写https git地址",
|
||
"describe": "代码仓库地址",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "service nginx restart"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"id": "git-clone-245734ab",
|
||
"category_id": 1,
|
||
"component_name": "scp",
|
||
"component_label": "scp",
|
||
"working_directory": "",
|
||
"command": "",
|
||
"in_parameters": {
|
||
"--run": {
|
||
"type": "str",
|
||
"item_type": "",
|
||
"label": "代码仓库地址",
|
||
"require": 1,
|
||
"choice": [],
|
||
"default": "",
|
||
"placeholder": "私有仓库填写ssh地址,公有仓库填写https git地址",
|
||
"describe": "代码仓库地址",
|
||
"editable": 1,
|
||
"condition": "",
|
||
"value": "service nginx restart"
|
||
}
|
||
}
|
||
}
|
||
|
||
],
|
||
# "edges": [
|
||
# {
|
||
# "source": "git-clone-245734ab",
|
||
# "target": "model-train-09b1491",
|
||
# "style": {
|
||
# "active": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "selected": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 2,
|
||
# "shadowColor": "rgb(95, 149, 255)",
|
||
# "shadowBlur": 10,
|
||
# "text-shape": {
|
||
# "fontWeight": 500
|
||
# }
|
||
# },
|
||
# "highlight": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 2,
|
||
# "text-shape": {
|
||
# "fontWeight": 500
|
||
# }
|
||
# },
|
||
# "inactive": {
|
||
# "stroke": "rgb(234, 234, 234)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "disable": {
|
||
# "stroke": "rgb(245, 245, 245)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "endArrow": {
|
||
# "path": "M 6,0 L 9,-1.5 L 9,1.5 Z",
|
||
# "d": 4.5,
|
||
# "fill": "#CDD0DC"
|
||
# },
|
||
# "cursor": "pointer",
|
||
# "lineWidth": 1,
|
||
# "opacity": 1,
|
||
# "stroke": "#CDD0DC",
|
||
# "radius": 1
|
||
# },
|
||
# "nodeStateStyle": {
|
||
# "hover": {
|
||
# "opacity": 1,
|
||
# "stroke": "#8fe8ff"
|
||
# }
|
||
# },
|
||
# "labelCfg": {
|
||
# "autoRotate": true,
|
||
# "style": {
|
||
# "fontSize": 10,
|
||
# "fill": "#FFF"
|
||
# }
|
||
# },
|
||
# "id": "edge-0.11773197923997381714446043619",
|
||
# "startPoint": {
|
||
# "x": 532,
|
||
# "y": 220.25,
|
||
# "anchorIndex": 1
|
||
# },
|
||
# "endPoint": {
|
||
# "x": 530,
|
||
# "y": 304.75,
|
||
# "anchorIndex": 0
|
||
# },
|
||
# "targetAnchor": 0,
|
||
# "type": "cubic-vertical",
|
||
# "curveOffset": [0, 0],
|
||
# "curvePosition": [0.5, 0.5],
|
||
# "minCurveOffset": [0, 0],
|
||
# "depth": 0
|
||
# },
|
||
# {
|
||
# "source": "model-train-09b1491",
|
||
# "target": "model-evaluate-b401ff0",
|
||
# "style": {
|
||
# "active": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "selected": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 2,
|
||
# "shadowColor": "rgb(95, 149, 255)",
|
||
# "shadowBlur": 10,
|
||
# "text-shape": {
|
||
# "fontWeight": 500
|
||
# }
|
||
# },
|
||
# "highlight": {
|
||
# "stroke": "rgb(95, 149, 255)",
|
||
# "lineWidth": 2,
|
||
# "text-shape": {
|
||
# "fontWeight": 500
|
||
# }
|
||
# },
|
||
# "inactive": {
|
||
# "stroke": "rgb(234, 234, 234)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "disable": {
|
||
# "stroke": "rgb(245, 245, 245)",
|
||
# "lineWidth": 1
|
||
# },
|
||
# "endArrow": {
|
||
# "path": "M 6,0 L 9,-1.5 L 9,1.5 Z",
|
||
# "d": 4.5,
|
||
# "fill": "#CDD0DC"
|
||
# },
|
||
# "cursor": "pointer",
|
||
# "lineWidth": 1,
|
||
# "opacity": 1,
|
||
# "stroke": "#CDD0DC",
|
||
# "radius": 1
|
||
# },
|
||
# "nodeStateStyle": {
|
||
# "hover": {
|
||
# "opacity": 1,
|
||
# "stroke": "#8fe8ff"
|
||
# }
|
||
# },
|
||
# "labelCfg": {
|
||
# "autoRotate": true,
|
||
# "style": {
|
||
# "fontSize": 10,
|
||
# "fill": "#FFF"
|
||
# }
|
||
# },
|
||
# "id": "edge-0.28238605806531771714446047075",
|
||
# "startPoint": {
|
||
# "x": 530,
|
||
# "y": 341.25,
|
||
# "anchorIndex": 1
|
||
# },
|
||
# "endPoint": {
|
||
# "x": 520,
|
||
# "y": 431.75,
|
||
# "anchorIndex": 0
|
||
# },
|
||
# "targetAnchor": 0,
|
||
# "type": "cubic-vertical",
|
||
# "curveOffset": [0, 0],
|
||
# "curvePosition": [0.5, 0.5],
|
||
# "minCurveOffset": [0, 0],
|
||
# "depth": 0
|
||
# }
|
||
# ]
|
||
}
|
||
end
|
||
end
|