From a66dd7259492d469804d311c22696cb7512f8fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=A6=82=E5=A8=81?= Date: Mon, 25 Aug 2025 14:57:26 +0800 Subject: [PATCH] feat: git node --- backend/app/core/logger.py | 2 +- backend/app/main.py | 20 ++++++++- backend/app/nodes/__init__.py | 3 +- backend/app/nodes/cmd_node.py | 3 +- backend/app/nodes/git_node.py | 77 +++++++++++++++++++++++++++++++++-- 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/backend/app/core/logger.py b/backend/app/core/logger.py index 3a7af28..93b1d20 100644 --- a/backend/app/core/logger.py +++ b/backend/app/core/logger.py @@ -27,7 +27,7 @@ ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # 设置带颜色的 formatter -formatter = ColorFormatter("%(levelname)s: \t %(name)s - %(asctime)s\n%(message)s") +formatter = ColorFormatter("%(levelname)s: \t %(name)s - %(asctime)s - %(message)s") ch.setFormatter(formatter) logger.addHandler(ch) diff --git a/backend/app/main.py b/backend/app/main.py index 4f05d38..b285ee6 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -158,13 +158,17 @@ def create_app(): a800_node.set_id("1") nodes.append(a800_node) + a800_git_node = F.GitNode() + a800_git_node.set_id("2") + nodes.append(a800_git_node) + # 设置依赖关系 # node0 - "true" >> node1 - "true" >> node2 for i in range(len(nodes) -1): # nodes[i] - "error" >> nodes[i + 1] pass - flow = F.AsyncFlow(a800_node) + flow = F.AsyncFlow(a800_git_node) flow.set_params( { "0": { @@ -211,6 +215,20 @@ def create_app(): "port": 6378, "sudo": True, }, + "2": { + "host": "58.214.239.10", + "user": "dgx07", + "password": "f=bHt/.7kRo:KIXq", + "port": 6378, + "sudo": True, + "git_path": "/data/PAI/demo/dbpai-web", + "git_user": "liruwei", + "git_password": "Wsad.8246", + "git_url": "https://tencentgit.dabby.com.cn/dbpai/dbpai-web.git", + "git_branch": "v3.4.2", + "git_clone_type": "http/https", + "git_clone_depth": 0, + }, } ) shared = {} diff --git a/backend/app/nodes/__init__.py b/backend/app/nodes/__init__.py index 830632e..444a4a4 100644 --- a/backend/app/nodes/__init__.py +++ b/backend/app/nodes/__init__.py @@ -1,2 +1,3 @@ from core.pocket_flow import AsyncFlow -from .cmd_node import * \ No newline at end of file +from .cmd_node import * +from .git_node import * \ No newline at end of file diff --git a/backend/app/nodes/cmd_node.py b/backend/app/nodes/cmd_node.py index d428378..48394c5 100644 --- a/backend/app/nodes/cmd_node.py +++ b/backend/app/nodes/cmd_node.py @@ -1,5 +1,4 @@ from core.pocket_flow import AsyncNode -from core.logger import logger import asyncio import asyncssh @@ -23,6 +22,7 @@ async def async_run_cmd( text = line if not isinstance(text, str): text = line.decode() + print(text) yield stream_type, text.rstrip() if not host: @@ -129,7 +129,6 @@ class CmdNode(AsyncNode): err.append(str(line)) else: out.append(str(line)) - logger.info(line) err_str = "\n".join(err) out_str = "\n".join(out) diff --git a/backend/app/nodes/git_node.py b/backend/app/nodes/git_node.py index c5a8bea..972c0c0 100644 --- a/backend/app/nodes/git_node.py +++ b/backend/app/nodes/git_node.py @@ -1,17 +1,86 @@ from core.pocket_flow import AsyncNode +from core.logger import logger +from .cmd_node import async_run_cmd +from pathlib import Path class GitNode(AsyncNode): def set_id(self, id): self.id = id async def prep_async(self, shared): - pass + return { + "client": { + "host": self.params[self.id].get("host"), + "user": self.params[self.id].get("user"), + "password": self.params[self.id].get("password"), + "port": self.params[self.id].get("port"), + "sudo": self.params[self.id].get("sudo", False), + }, + "git": { + "url": self.params[self.id].get("git_url"), + "user": self.params[self.id].get("git_user"), + "password": self.params[self.id].get("git_password"), + "branch": self.params[self.id].get("git_branch"), + "path": self.params[self.id].get("git_path"), + "clone_type": self.params[self.id].get("git_clone_type", "http/https"), + "depth": self.params[self.id].get("git_clone_depth", 1) + }, + } async def exec_async(self, prep_res): + client:dict = prep_res.get("client") + git:dict = prep_res.get("git") + + path = git.get("path") + git_path = str(Path(path) / ".git") + parent_path = str(Path(path).parent) + clone_url:str = git.get('url') + clone_type = git.get("clone_type") + clone_branch = git.get("branch") + clone_depth = git.get("depth") + if clone_type == "http/https": + _info = clone_url.split("://") + user = git.get("user") + password = git.get("password") + clone_url = f"{_info[0]}://{user}:{password}@{_info[-1]}" + + cmd = ( + f"mkdir -p {parent_path} \n" + f"cd {parent_path} \n" + f"[ ! -d '{git_path}' ] && git clone -b {clone_branch} --single-branch --depth=1 --quiet {clone_url} \n" + f"cd {path} \n" + "git stash \n" + f"git fetch --depth=1 origin {clone_branch} --quiet \n" + f"git switch -C {clone_branch} FETCH_HEAD" + ) + + if clone_depth == 0: + cmd = f"{cmd} \n[ -e .git/shallow ] && git fetch --unshallow --quiet" + logger.info(cmd) + + err = [] + out = [] + + async for stream_type, line in async_run_cmd(**client, cmd=cmd): + if stream_type == "stderr": + err.append(str(line)) + else: + out.append(str(line)) + + err_str = "\n".join(err) + out_str = "\n".join(out) + + # 补充一下密码失效问题 + if "Sorry, try again." in out_str and not err_str: + err_str = "SSH connection failed no password was provided" + + return {"err": err_str, "out": out_str} + return None async def post_async(self, shared, prep_res, exec_res): - if exec_res: - return "true" - else: + shared[self.id] = exec_res + + if exec_res.get("err"): return "false" + return "true"