gitlink-forgeplus/app/controllers/api/v1/projects/pipelines_controller.rb

608 lines
21 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Api::V1::Projects::PipelinesController < Api::V1::BaseController
before_action :require_operate_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.branch = params[:branch] || @project.default_branch
@pipeline.json = params[:pipeline_json].to_json
pipeline_yaml = build_pipeline_yaml(params[:pipeline_name], params[:pipeline_json])
tip_exception("流水线yaml内空不能为空") if pipeline_yaml.blank?
@pipeline.yaml = pipeline_yaml
@pipeline.save!
sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
tip_exception("#{@pipeline.file_name}已存在") if sha
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
tip_exception(interactor.error) unless interactor.success?
render_ok({ id: @pipeline.id })
end
def save_yaml
@pipeline = Action::Pipeline.new(pipeline_name: params[:pipeline_name], project_id: @project.id)
@pipeline.file_name = ".gitea/workflows/#{@pipeline.pipeline_name}.yaml"
@pipeline.branch = params[:branch] || @project.default_branch
@pipeline.json = params[:pipeline_json].to_json
pipeline_yaml = build_pipeline_yaml(params[:pipeline_name], params[:pipeline_json])
tip_exception("流水线yaml内空不能为空") if pipeline_yaml.blank?
@pipeline.yaml = pipeline_yaml
sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
interactor = sha.present? ? Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) : Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
tip_exception(interactor.error) unless interactor.success?
render_ok
end
def build_yaml
if params[:pipeline_json].present?
@pipeline_yaml = build_pipeline_yaml(params[:pipeline_name], params[:pipeline_json])
else
@pipeline_yaml = build_test_yaml
end
render plain: @pipeline_yaml
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_test_yaml) if @pipeline.blank?
end
def build_pipeline_yaml(pipeline_name, pipeline_json)
if pipeline_json.present?
@pipeline_name = pipeline_name
params_nodes = pipeline_json["nodes"].select { |node| !["on-push", "on-schedule"].include?(node["component_name"]) }
on_nodes = 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[:pipeline_yaml]
end
@pipeline_yaml
end
def build_test_yaml
@pipeline_name = "I like it"
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"])
next if node.blank?
node.cust_name = input_node["component_label"] if input_node["component_label"].present?
run_values = {}
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"]}"
if input_key.to_s.gsub("--", "") == "run"
run_values = run_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
else
input_values = input_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
end
end
node.run_values = run_values
node.input_values = input_values
# Rails.logger.info "@input_values run_values===#{node.run_values.to_json}"
# Rails.logger.info "@input_values input_values===#{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 || @project.default_branch)
if interactor.success?
file = interactor.result
file['sha']
else
nil
end
end
def content_params
{
filepath: ".gitea/workflows/#{URI.parse(@pipeline.pipeline_name)}.yaml",
branch: @pipeline.branch,
new_branch: @pipeline.branch,
content: @pipeline.yaml,
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"])
next if node.blank?
node.cust_name = input_node["component_label"] if input_node["component_label"].present?
run_values = {}
input_values = {}
if input_node["in_parameters"].present?
Rails.logger.info "@in_parameters=====11===#{input_node["component_name"]}======#{input_node["in_parameters"].keys}"
input_node["in_parameters"].keys.each 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"]}"
if input_key.to_s.gsub("--", "") == "run"
run_values = run_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
else
input_values = input_values.merge({ "#{input_key.gsub("--", "")}": "#{input_node["in_parameters"][input_key]["value"]}" })
end
end
node.run_values = run_values
# 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": {
"--cron": {
"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": "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": "echo env"
}
}
},
{
"id": "git-clone-245734ab",
"category_id": 1,
"component_name": "scp",
"component_label": "scp",
"working_directory": "",
"command": "",
"in_parameters": {
"--host": {
"type": "str",
"item_type": "",
"label": "代码仓库地址",
"require": 1,
"choice": [],
"default": "",
"placeholder": "私有仓库填写ssh地址公有仓库填写https git地址",
"describe": "代码仓库地址",
"editable": 1,
"condition": "",
"value": "192.168.1.114"
}
}
}
],
# "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