fix bug
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 1m27s
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 1m27s
This commit is contained in:
parent
7ee724f8ac
commit
fe62f9ca81
@ -16,8 +16,9 @@ GITHUB_REPO_RTC_WEB=
|
||||
GITHUB_REPO_AIRHUB_APP=
|
||||
|
||||
# 项目路径映射 (project_id -> 本地路径)
|
||||
PATH_rtc_backend=/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend
|
||||
PATH_rtc_web=/Users/maidong/Desktop/zyc/qy_gitlab/rtc_web
|
||||
PATH_RTC_BACKEND=/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend
|
||||
PATH_RTC_WEB=/Users/maidong/Desktop/zyc/qy_gitlab/rtc_web
|
||||
PATH_AIRHUB_APP=/Users/maidong/Desktop/zyc/qiyuan_gitea/rtc_prd/airhub_app
|
||||
|
||||
# 安全配置
|
||||
MAX_RETRY_COUNT=3
|
||||
|
||||
@ -20,7 +20,7 @@ class ClaudeService:
|
||||
self,
|
||||
prompt: str,
|
||||
cwd: str,
|
||||
tools: str = "Edit,Read,Write",
|
||||
allowed_tools: Optional[str] = None,
|
||||
) -> tuple[bool, str]:
|
||||
"""
|
||||
执行 Claude CLI 命令
|
||||
@ -28,7 +28,8 @@ class ClaudeService:
|
||||
Args:
|
||||
prompt: 提示词
|
||||
cwd: 工作目录
|
||||
tools: 可用工具
|
||||
allowed_tools: 可选,限制可用工具(逗号分隔)。
|
||||
为 None 时配合 --dangerously-skip-permissions 允许所有工具。
|
||||
|
||||
Returns:
|
||||
(成功与否, 输出内容)
|
||||
@ -37,11 +38,14 @@ class ClaudeService:
|
||||
cmd = [
|
||||
self.cli_path,
|
||||
"-p", prompt,
|
||||
"--tools", tools,
|
||||
"--dangerously-skip-permissions",
|
||||
]
|
||||
|
||||
logger.debug(f"执行 Claude CLI: {' '.join(cmd[:3])}...")
|
||||
if allowed_tools:
|
||||
cmd.extend(["--allowedTools", allowed_tools])
|
||||
|
||||
logger.debug(f"执行 Claude CLI (cwd={cwd})")
|
||||
logger.debug(f"Prompt 长度: {len(prompt)} 字符")
|
||||
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
@ -55,9 +59,10 @@ class ClaudeService:
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info("Claude CLI 执行成功")
|
||||
logger.debug(f"输出前 500 字符: {output[:500]}")
|
||||
return True, output.strip()
|
||||
else:
|
||||
logger.error(f"Claude CLI 执行失败: {output}")
|
||||
logger.error(f"Claude CLI 执行失败 (code={result.returncode}): {output[:500]}")
|
||||
return False, output.strip()
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
@ -90,7 +95,10 @@ class ClaudeService:
|
||||
|
||||
# 构造批量修复 Prompt
|
||||
prompt_parts = [
|
||||
f"请修复以下 {len(bugs)} 个 Bug:",
|
||||
f"你是一个自动化 Bug 修复代理。请直接修复以下 {len(bugs)} 个 Bug。",
|
||||
"",
|
||||
"重要:你必须使用工具(Read、Edit、Write 等)直接修改源代码文件来修复 Bug。",
|
||||
"不要只是分析问题或给出建议,你需要实际定位文件并编辑代码。",
|
||||
"",
|
||||
]
|
||||
|
||||
@ -100,12 +108,14 @@ class ClaudeService:
|
||||
|
||||
prompt_parts.extend([
|
||||
"## 修复要求",
|
||||
"1. 依次修复上述所有 Bug",
|
||||
"2. 每个 Bug 只做最小必要的改动",
|
||||
"3. 确保不破坏现有功能",
|
||||
"4. 修复完成后简要说明每个 Bug 的修复方式",
|
||||
"1. 先用 Grep/Glob 定位相关源代码文件",
|
||||
"2. 用 Read 读取文件内容,理解上下文",
|
||||
"3. 用 Edit 或 Write 直接修改代码来修复 Bug",
|
||||
"4. 每个 Bug 只做最小必要的改动",
|
||||
"5. 确保不破坏现有功能",
|
||||
"6. 修复完成后简要说明每个 Bug 的修复方式",
|
||||
"",
|
||||
"请开始修复。",
|
||||
"请立即开始修复,直接编辑文件。",
|
||||
])
|
||||
|
||||
prompt = "\n".join(prompt_parts)
|
||||
@ -135,7 +145,7 @@ class ClaudeService:
|
||||
3. 可能影响的其他文件
|
||||
"""
|
||||
|
||||
return self.execute_prompt(prompt, project_path, tools="Read")
|
||||
return self.execute_prompt(prompt, project_path, allowed_tools="Read,Grep,Glob")
|
||||
|
||||
def review_changes(self, diff: str, project_path: str) -> tuple[bool, str]:
|
||||
"""
|
||||
@ -164,4 +174,4 @@ class ClaudeService:
|
||||
如果审核通过,回复 "APPROVED"。否则说明问题。
|
||||
"""
|
||||
|
||||
return self.execute_prompt(prompt, project_path, tools="Read")
|
||||
return self.execute_prompt(prompt, project_path, allowed_tools="Read,Grep,Glob")
|
||||
|
||||
@ -88,15 +88,12 @@ class RepairScheduler:
|
||||
try:
|
||||
for project_id in self.projects:
|
||||
bugs = task_manager.fetch_pending_bugs(project_id)
|
||||
# 也拉取 UI 触发的 PENDING_FIX 状态
|
||||
pending_bugs = self._fetch_pending_fix_bugs(task_manager, project_id)
|
||||
all_bugs = bugs + pending_bugs
|
||||
|
||||
if not all_bugs:
|
||||
logger.info(f" [{project_id}] 无新 Bug")
|
||||
if not bugs:
|
||||
logger.info(f" [{project_id}] 无待修复 Bug")
|
||||
continue
|
||||
|
||||
count = len(all_bugs)
|
||||
count = len(bugs)
|
||||
total_found += count
|
||||
logger.info(f" [{project_id}] 发现 {count} 个待修复 Bug")
|
||||
|
||||
@ -120,51 +117,6 @@ class RepairScheduler:
|
||||
finally:
|
||||
task_manager.close()
|
||||
|
||||
@staticmethod
|
||||
def _fetch_pending_fix_bugs(
|
||||
task_manager: TaskManager, project_id: str
|
||||
) -> list:
|
||||
"""获取 PENDING_FIX 状态的 Bug(由 UI 触发)"""
|
||||
try:
|
||||
import httpx
|
||||
|
||||
params = {"status": "PENDING_FIX", "project_id": project_id}
|
||||
response = task_manager.client.get(
|
||||
f"{task_manager.base_url}/api/v1/bugs", params=params
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
from ..models import Bug, BugStatus
|
||||
|
||||
bugs = []
|
||||
for item in data.get("items", []):
|
||||
stack_trace = item.get("stack_trace")
|
||||
if isinstance(stack_trace, str):
|
||||
stack_trace = stack_trace.split("\n")
|
||||
|
||||
bug = Bug(
|
||||
id=item["id"],
|
||||
project_id=item["project_id"],
|
||||
environment=item.get("environment", "production"),
|
||||
level=item.get("level", "ERROR"),
|
||||
error={
|
||||
"type": item.get("error_type", "Unknown"),
|
||||
"message": item.get("error_message", ""),
|
||||
"file_path": item.get("file_path"),
|
||||
"line_number": item.get("line_number"),
|
||||
"stack_trace": stack_trace,
|
||||
},
|
||||
context=item.get("context"),
|
||||
status=BugStatus(item.get("status", "PENDING_FIX")),
|
||||
retry_count=item.get("retry_count", 0),
|
||||
)
|
||||
bugs.append(bug)
|
||||
return bugs
|
||||
except Exception as e:
|
||||
logger.debug(f"获取 PENDING_FIX Bug 失败: {e}")
|
||||
return []
|
||||
|
||||
def _run_repair(self, project_id: str) -> int:
|
||||
"""对指定项目执行修复,返回成功修复的数量"""
|
||||
if self._repairing:
|
||||
|
||||
@ -18,36 +18,40 @@ class TaskManager:
|
||||
|
||||
def fetch_pending_bugs(self, project_id: Optional[str] = None) -> list[Bug]:
|
||||
"""
|
||||
获取待修复的 Bug 列表
|
||||
获取待修复的 Bug 列表(包括 NEW 和 PENDING_FIX 状态)
|
||||
|
||||
Args:
|
||||
project_id: 可选,筛选特定项目
|
||||
|
||||
Returns:
|
||||
Bug 列表
|
||||
Bug 列表(已按 id 去重)
|
||||
"""
|
||||
all_bugs: dict[int, Bug] = {}
|
||||
|
||||
for status in ("NEW", "PENDING_FIX"):
|
||||
try:
|
||||
params = {"status": "NEW"}
|
||||
params: dict[str, str] = {"status": status}
|
||||
if project_id:
|
||||
params["project_id"] = project_id
|
||||
|
||||
response = self.client.get(
|
||||
f"{self.base_url}/api/v1/bugs",
|
||||
params=params
|
||||
params=params,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
bugs = []
|
||||
|
||||
for item in data.get("items", []):
|
||||
# stack_trace 可能是列表或字符串
|
||||
bug_id = item["id"]
|
||||
if bug_id in all_bugs:
|
||||
continue
|
||||
|
||||
stack_trace = item.get("stack_trace")
|
||||
if isinstance(stack_trace, str):
|
||||
stack_trace = stack_trace.split("\n")
|
||||
|
||||
bug = Bug(
|
||||
id=item["id"],
|
||||
all_bugs[bug_id] = Bug(
|
||||
id=bug_id,
|
||||
project_id=item["project_id"],
|
||||
environment=item.get("environment", "production"),
|
||||
level=item.get("level", "ERROR"),
|
||||
@ -62,14 +66,12 @@ class TaskManager:
|
||||
status=BugStatus(item.get("status", "NEW")),
|
||||
retry_count=item.get("retry_count", 0),
|
||||
)
|
||||
bugs.append(bug)
|
||||
|
||||
logger.info(f"获取到 {len(bugs)} 个待修复 Bug")
|
||||
return bugs
|
||||
|
||||
except httpx.HTTPError as e:
|
||||
logger.error(f"获取 Bug 列表失败: {e}")
|
||||
return []
|
||||
logger.error(f"获取 {status} 状态 Bug 列表失败: {e}")
|
||||
|
||||
bugs = list(all_bugs.values())
|
||||
logger.info(f"获取到 {len(bugs)} 个待修复 Bug(NEW + PENDING_FIX)")
|
||||
return bugs
|
||||
|
||||
def update_status(self, bug_id: int, status: BugStatus, message: str = "") -> bool:
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user