fix: auto-fix code issues (cron)

- 修复重复导入/字段
- 修复异常处理
- 修复PEP8格式问题
- 添加类型注解
- 修复缺失的urllib.parse导入
This commit is contained in:
OpenClaw Bot
2026-02-28 06:03:09 +08:00
parent ff83cab6c7
commit fe3d64a1d2
41 changed files with 4501 additions and 1176 deletions

View File

@@ -9,7 +9,14 @@ from pathlib import Path
class CodeIssue:
def __init__(self, file_path: str, line_no: int, issue_type: str, message: str, severity: str = "info"):
def __init__(
self,
file_path: str,
line_no: int,
issue_type: str,
message: str,
severity: str = "info",
):
self.file_path = file_path
self.line_no = line_no
self.issue_type = issue_type
@@ -74,17 +81,29 @@ class CodeReviewer:
# 9. 检查敏感信息
self._check_sensitive_info(content, lines, rel_path)
def _check_bare_exceptions(self, content: str, lines: list[str], file_path: str) -> None:
def _check_bare_exceptions(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查裸异常捕获"""
for i, line in enumerate(lines, 1):
if re.search(r"except\s*:\s*$", line.strip()) or re.search(r"except\s+Exception\s*:\s*$", line.strip()):
if re.search(r"except\s*:\s*$", line.strip()) or re.search(
r"except\s+Exception\s*:\s*$", line.strip()
):
# 跳过有注释说明的情况
if "# noqa" in line or "# intentional" in line.lower():
continue
issue = CodeIssue(file_path, i, "bare_exception", "裸异常捕获,应该使用具体异常类型", "warning")
issue = CodeIssue(
file_path,
i,
"bare_exception",
"裸异常捕获,应该使用具体异常类型",
"warning",
)
self.issues.append(issue)
def _check_duplicate_imports(self, content: str, lines: list[str], file_path: str) -> None:
def _check_duplicate_imports(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查重复导入"""
imports = {}
for i, line in enumerate(lines, 1):
@@ -96,30 +115,50 @@ class CodeReviewer:
name = name.strip().split()[0] # 处理 'as' 别名
key = f"{module}.{name}" if module else name
if key in imports:
issue = CodeIssue(file_path, i, "duplicate_import", f"重复导入: {key}", "warning")
issue = CodeIssue(
file_path,
i,
"duplicate_import",
f"重复导入: {key}",
"warning",
)
self.issues.append(issue)
imports[key] = i
def _check_pep8_issues(self, content: str, lines: list[str], file_path: str) -> None:
def _check_pep8_issues(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查 PEP8 问题"""
for i, line in enumerate(lines, 1):
# 行长度超过 120
if len(line) > 120:
issue = CodeIssue(file_path, i, "line_too_long", f"行长度 {len(line)} 超过 120 字符", "info")
issue = CodeIssue(
file_path,
i,
"line_too_long",
f"行长度 {len(line)} 超过 120 字符",
"info",
)
self.issues.append(issue)
# 行尾空格
if line.rstrip() != line:
issue = CodeIssue(file_path, i, "trailing_whitespace", "行尾有空格", "info")
issue = CodeIssue(
file_path, i, "trailing_whitespace", "行尾有空格", "info"
)
self.issues.append(issue)
# 多余的空行
if i > 1 and line.strip() == "" and lines[i - 2].strip() == "":
if i < len(lines) and lines[i].strip() == "":
issue = CodeIssue(file_path, i, "extra_blank_line", "多余的空行", "info")
issue = CodeIssue(
file_path, i, "extra_blank_line", "多余的空行", "info"
)
self.issues.append(issue)
def _check_unused_imports(self, content: str, lines: list[str], file_path: str) -> None:
def _check_unused_imports(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查未使用的导入"""
try:
tree = ast.parse(content)
@@ -147,10 +186,14 @@ class CodeReviewer:
# 排除一些常见例外
if name in ["annotations", "TYPE_CHECKING"]:
continue
issue = CodeIssue(file_path, lineno, "unused_import", f"未使用的导入: {name}", "info")
issue = CodeIssue(
file_path, lineno, "unused_import", f"未使用的导入: {name}", "info"
)
self.issues.append(issue)
def _check_string_formatting(self, content: str, lines: list[str], file_path: str) -> None:
def _check_string_formatting(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查混合字符串格式化"""
has_fstring = False
has_percent = False
@@ -165,10 +208,18 @@ class CodeReviewer:
has_format = True
if has_fstring and (has_percent or has_format):
issue = CodeIssue(file_path, 0, "mixed_formatting", "文件混合使用多种字符串格式化方式,建议统一为 f-string", "info")
issue = CodeIssue(
file_path,
0,
"mixed_formatting",
"文件混合使用多种字符串格式化方式,建议统一为 f-string",
"info",
)
self.issues.append(issue)
def _check_magic_numbers(self, content: str, lines: list[str], file_path: str) -> None:
def _check_magic_numbers(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查魔法数字"""
# 常见的魔法数字模式
magic_patterns = [
@@ -190,36 +241,88 @@ class CodeReviewer:
match = re.search(r"(\d{3,})", code_part)
if match:
num = int(match.group(1))
if num in [200, 404, 500, 401, 403, 429, 1000, 1024, 2048, 4096, 8080, 3000, 8000]:
if num in [
200,
404,
500,
401,
403,
429,
1000,
1024,
2048,
4096,
8080,
3000,
8000,
]:
continue
issue = CodeIssue(file_path, i, "magic_number", f"{msg}: {num}", "info")
issue = CodeIssue(
file_path, i, "magic_number", f"{msg}: {num}", "info"
)
self.issues.append(issue)
def _check_sql_injection(self, content: str, lines: list[str], file_path: str) -> None:
def _check_sql_injection(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查 SQL 注入风险"""
for i, line in enumerate(lines, 1):
# 检查字符串拼接的 SQL
if re.search(r'execute\s*\(\s*["\'].*%s', line) or re.search(r'execute\s*\(\s*f["\']', line):
if re.search(r'execute\s*\(\s*["\'].*%s', line) or re.search(
r'execute\s*\(\s*f["\']', line
):
if "?" not in line and "%s" in line:
issue = CodeIssue(file_path, i, "sql_injection_risk", "可能的 SQL 注入风险 - 需要人工确认", "error")
issue = CodeIssue(
file_path,
i,
"sql_injection_risk",
"可能的 SQL 注入风险 - 需要人工确认",
"error",
)
self.manual_review_issues.append(issue)
def _check_cors_config(self, content: str, lines: list[str], file_path: str) -> None:
def _check_cors_config(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查 CORS 配置"""
for i, line in enumerate(lines, 1):
if "allow_origins" in line and '["*"]' in line:
issue = CodeIssue(file_path, i, "cors_wildcard", "CORS 允许所有来源 - 需要人工确认", "warning")
issue = CodeIssue(
file_path,
i,
"cors_wildcard",
"CORS 允许所有来源 - 需要人工确认",
"warning",
)
self.manual_review_issues.append(issue)
def _check_sensitive_info(self, content: str, lines: list[str], file_path: str) -> None:
def _check_sensitive_info(
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查敏感信息"""
for i, line in enumerate(lines, 1):
# 检查硬编码密钥
if re.search(r'(password|secret|key|token)\s*=\s*["\'][^"\']+["\']', line, re.IGNORECASE):
if "os.getenv" not in line and "environ" not in line and "getenv" not in line:
if re.search(
r'(password|secret|key|token)\s*=\s*["\'][^"\']+["\']',
line,
re.IGNORECASE,
):
if (
"os.getenv" not in line
and "environ" not in line
and "getenv" not in line
):
# 排除一些常见假阳性
if not re.search(r'["\']\*+["\']', line) and not re.search(r'["\']<[^"\']*>["\']', line):
issue = CodeIssue(file_path, i, "hardcoded_secret", "可能的硬编码敏感信息 - 需要人工确认", "error")
if not re.search(r'["\']\*+["\']', line) and not re.search(
r'["\']<[^"\']*>["\']', line
):
issue = CodeIssue(
file_path,
i,
"hardcoded_secret",
"可能的硬编码敏感信息 - 需要人工确认",
"error",
)
self.manual_review_issues.append(issue)
def auto_fix(self) -> None:
@@ -289,7 +392,9 @@ class CodeReviewer:
if self.fixed_issues:
report.append(f"共修复 {len(self.fixed_issues)} 个问题:\n")
for issue in self.fixed_issues:
report.append(f"- ✅ {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}")
report.append(
f"- ✅ {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}"
)
else:
report.append("")
@@ -297,7 +402,9 @@ class CodeReviewer:
if self.manual_review_issues:
report.append(f"共发现 {len(self.manual_review_issues)} 个问题:\n")
for issue in self.manual_review_issues:
report.append(f"- ⚠️ {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}")
report.append(
f"- ⚠️ {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}"
)
else:
report.append("")
@@ -305,7 +412,9 @@ class CodeReviewer:
if self.issues:
report.append(f"共发现 {len(self.issues)} 个问题:\n")
for issue in self.issues:
report.append(f"- 📝 {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}")
report.append(
f"- 📝 {issue.file_path}:{issue.line_no} - {issue.issue_type}: {issue.message}"
)
else:
report.append("")