fix: auto-fix code issues (cron)
- 修复重复导入/字段 - 修复异常处理 - 修复PEP8格式问题 - 修复语法错误(运算符空格问题) - 修复类型注解格式
This commit is contained in:
@@ -19,30 +19,30 @@ class CodeIssue:
|
||||
line_no: int,
|
||||
issue_type: str,
|
||||
message: str,
|
||||
severity: str = "warning",
|
||||
original_line: str = "",
|
||||
):
|
||||
self.file_path = file_path
|
||||
self.line_no = line_no
|
||||
self.issue_type = issue_type
|
||||
self.message = message
|
||||
self.severity = severity
|
||||
self.original_line = original_line
|
||||
self.fixed = False
|
||||
severity: str = "warning",
|
||||
original_line: str = "",
|
||||
) -> None:
|
||||
self.file_path = file_path
|
||||
self.line_no = line_no
|
||||
self.issue_type = issue_type
|
||||
self.message = message
|
||||
self.severity = severity
|
||||
self.original_line = original_line
|
||||
self.fixed = False
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> None:
|
||||
return f"{self.file_path}:{self.line_no} [{self.severity}] {self.issue_type}: {self.message}"
|
||||
|
||||
|
||||
class CodeFixer:
|
||||
"""代码自动修复器"""
|
||||
|
||||
def __init__(self, project_path: str):
|
||||
self.project_path = Path(project_path)
|
||||
self.issues: list[CodeIssue] = []
|
||||
self.fixed_issues: list[CodeIssue] = []
|
||||
self.manual_issues: list[CodeIssue] = []
|
||||
self.scanned_files: list[str] = []
|
||||
def __init__(self, project_path: str) -> None:
|
||||
self.project_path = Path(project_path)
|
||||
self.issues: list[CodeIssue] = []
|
||||
self.fixed_issues: list[CodeIssue] = []
|
||||
self.manual_issues: list[CodeIssue] = []
|
||||
self.scanned_files: list[str] = []
|
||||
|
||||
def scan_all_files(self) -> None:
|
||||
"""扫描所有 Python 文件"""
|
||||
@@ -55,9 +55,9 @@ class CodeFixer:
|
||||
def _scan_file(self, file_path: Path) -> None:
|
||||
"""扫描单个文件"""
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
lines = content.split("\n")
|
||||
with open(file_path, "r", encoding = "utf-8") as f:
|
||||
content = f.read()
|
||||
lines = content.split("\n")
|
||||
except Exception as e:
|
||||
print(f"Error reading {file_path}: {e}")
|
||||
return
|
||||
@@ -85,7 +85,7 @@ class CodeFixer:
|
||||
) -> None:
|
||||
"""检查裸异常捕获"""
|
||||
for i, line in enumerate(lines, 1):
|
||||
# 匹配 except: 但不匹配 except Exception: 或 except SpecificError:
|
||||
# 匹配 except Exception: 但不匹配 except Exception: 或 except SpecificError:
|
||||
if re.search(r"except\s*:\s*$", line) or re.search(r"except\s*:\s*#", line):
|
||||
# 跳过注释说明的情况
|
||||
if "# noqa" in line or "# intentional" in line.lower():
|
||||
@@ -130,25 +130,25 @@ class CodeFixer:
|
||||
def _check_unused_imports(self, file_path: Path, content: str) -> None:
|
||||
"""检查未使用的导入"""
|
||||
try:
|
||||
tree = ast.parse(content)
|
||||
tree = ast.parse(content)
|
||||
except SyntaxError:
|
||||
return
|
||||
|
||||
imports = {}
|
||||
imports = {}
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
name = alias.asname if alias.asname else alias.name
|
||||
imports[name] = node.lineno
|
||||
name = alias.asname if alias.asname else alias.name
|
||||
imports[name] = node.lineno
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
for alias in node.names:
|
||||
name = alias.asname if alias.asname else alias.name
|
||||
name = alias.asname if alias.asname else alias.name
|
||||
if alias.name == "*":
|
||||
continue
|
||||
imports[name] = node.lineno
|
||||
imports[name] = node.lineno
|
||||
|
||||
# 检查使用
|
||||
used_names = set()
|
||||
used_names = set()
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Name):
|
||||
used_names.add(node.id)
|
||||
@@ -216,15 +216,15 @@ class CodeFixer:
|
||||
) -> None:
|
||||
"""检查敏感信息泄露"""
|
||||
# 排除的文件
|
||||
excluded_files = ["auto_code_fixer.py", "code_reviewer.py"]
|
||||
excluded_files = ["auto_code_fixer.py", "code_reviewer.py"]
|
||||
if any(excluded in str(file_path) for excluded in excluded_files):
|
||||
return
|
||||
|
||||
patterns = [
|
||||
(r'password\s*=\s*["\'][^"\']{8,}["\']', "硬编码密码"),
|
||||
(r'secret_key\s*=\s*["\'][^"\']{8,}["\']', "硬编码密钥"),
|
||||
(r'api_key\s*=\s*["\'][^"\']{8,}["\']', "硬编码 API Key"),
|
||||
(r'token\s*=\s*["\'][^"\']{8,}["\']', "硬编码 Token"),
|
||||
patterns = [
|
||||
(r'password\s* = \s*["\'][^"\']{8, }["\']', "硬编码密码"),
|
||||
(r'secret_key\s* = \s*["\'][^"\']{8, }["\']', "硬编码密钥"),
|
||||
(r'api_key\s* = \s*["\'][^"\']{8, }["\']', "硬编码 API Key"),
|
||||
(r'token\s* = \s*["\'][^"\']{8, }["\']', "硬编码 Token"),
|
||||
]
|
||||
|
||||
for i, line in enumerate(lines, 1):
|
||||
@@ -241,7 +241,7 @@ class CodeFixer:
|
||||
if any(x in line.lower() for x in ["your_", "example", "placeholder", "test", "demo"]):
|
||||
continue
|
||||
# 排除 Enum 定义
|
||||
if re.search(r'^\s*[A-Z_]+\s*=', line.strip()):
|
||||
if re.search(r'^\s*[A-Z_]+\s* = ', line.strip()):
|
||||
continue
|
||||
self.manual_issues.append(
|
||||
CodeIssue(
|
||||
@@ -256,17 +256,17 @@ class CodeFixer:
|
||||
|
||||
def fix_auto_fixable(self) -> None:
|
||||
"""自动修复可修复的问题"""
|
||||
auto_fix_types = {
|
||||
auto_fix_types = {
|
||||
"trailing_whitespace",
|
||||
"bare_exception",
|
||||
}
|
||||
|
||||
# 按文件分组
|
||||
files_to_fix = {}
|
||||
files_to_fix = {}
|
||||
for issue in self.issues:
|
||||
if issue.issue_type in auto_fix_types:
|
||||
if issue.file_path not in files_to_fix:
|
||||
files_to_fix[issue.file_path] = []
|
||||
files_to_fix[issue.file_path] = []
|
||||
files_to_fix[issue.file_path].append(issue)
|
||||
|
||||
for file_path, file_issues in files_to_fix.items():
|
||||
@@ -275,43 +275,43 @@ class CodeFixer:
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
lines = content.split("\n")
|
||||
with open(file_path, "r", encoding = "utf-8") as f:
|
||||
content = f.read()
|
||||
lines = content.split("\n")
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
original_lines = lines.copy()
|
||||
fixed_lines = set()
|
||||
original_lines = lines.copy()
|
||||
fixed_lines = set()
|
||||
|
||||
# 修复行尾空格
|
||||
for issue in file_issues:
|
||||
if issue.issue_type == "trailing_whitespace":
|
||||
line_idx = issue.line_no - 1
|
||||
line_idx = issue.line_no - 1
|
||||
if 0 <= line_idx < len(lines) and line_idx not in fixed_lines:
|
||||
if lines[line_idx].rstrip() != lines[line_idx]:
|
||||
lines[line_idx] = lines[line_idx].rstrip()
|
||||
lines[line_idx] = lines[line_idx].rstrip()
|
||||
fixed_lines.add(line_idx)
|
||||
issue.fixed = True
|
||||
issue.fixed = True
|
||||
self.fixed_issues.append(issue)
|
||||
|
||||
# 修复裸异常
|
||||
for issue in file_issues:
|
||||
if issue.issue_type == "bare_exception":
|
||||
line_idx = issue.line_no - 1
|
||||
line_idx = issue.line_no - 1
|
||||
if 0 <= line_idx < len(lines) and line_idx not in fixed_lines:
|
||||
line = lines[line_idx]
|
||||
# 将 except: 改为 except Exception:
|
||||
line = lines[line_idx]
|
||||
# 将 except Exception: 改为 except Exception:
|
||||
if re.search(r"except\s*:\s*$", line.strip()):
|
||||
lines[line_idx] = line.replace("except:", "except Exception:")
|
||||
lines[line_idx] = line.replace("except Exception:", "except Exception:")
|
||||
fixed_lines.add(line_idx)
|
||||
issue.fixed = True
|
||||
issue.fixed = True
|
||||
self.fixed_issues.append(issue)
|
||||
|
||||
# 如果文件有修改,写回
|
||||
if lines != original_lines:
|
||||
try:
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
with open(file_path, "w", encoding = "utf-8") as f:
|
||||
f.write("\n".join(lines))
|
||||
print(f"Fixed issues in {file_path}")
|
||||
except Exception as e:
|
||||
@@ -319,7 +319,7 @@ class CodeFixer:
|
||||
|
||||
def categorize_issues(self) -> dict[str, list[CodeIssue]]:
|
||||
"""分类问题"""
|
||||
categories = {
|
||||
categories = {
|
||||
"critical": [],
|
||||
"error": [],
|
||||
"warning": [],
|
||||
@@ -334,7 +334,7 @@ class CodeFixer:
|
||||
|
||||
def generate_report(self) -> str:
|
||||
"""生成修复报告"""
|
||||
report = []
|
||||
report = []
|
||||
report.append("# InsightFlow 代码审查报告")
|
||||
report.append("")
|
||||
report.append(f"扫描时间: {os.popen('date').read().strip()}")
|
||||
@@ -349,9 +349,9 @@ class CodeFixer:
|
||||
report.append("")
|
||||
|
||||
# 问题统计
|
||||
categories = self.categorize_issues()
|
||||
manual_critical = [i for i in self.manual_issues if i.severity == "critical"]
|
||||
manual_warning = [i for i in self.manual_issues if i.severity == "warning"]
|
||||
categories = self.categorize_issues()
|
||||
manual_critical = [i for i in self.manual_issues if i.severity == "critical"]
|
||||
manual_warning = [i for i in self.manual_issues if i.severity == "warning"]
|
||||
|
||||
report.append("## 问题分类统计")
|
||||
report.append("")
|
||||
@@ -393,17 +393,17 @@ class CodeFixer:
|
||||
# 其他问题
|
||||
report.append("## 📋 其他发现的问题")
|
||||
report.append("")
|
||||
other_issues = [
|
||||
other_issues = [
|
||||
i
|
||||
for i in self.issues
|
||||
if i not in self.fixed_issues
|
||||
]
|
||||
|
||||
# 按类型分组
|
||||
by_type = {}
|
||||
by_type = {}
|
||||
for issue in other_issues:
|
||||
if issue.issue_type not in by_type:
|
||||
by_type[issue.issue_type] = []
|
||||
by_type[issue.issue_type] = []
|
||||
by_type[issue.issue_type].append(issue)
|
||||
|
||||
for issue_type, issues in sorted(by_type.items()):
|
||||
@@ -424,21 +424,21 @@ def git_commit_and_push(project_path: str) -> tuple[bool, str]:
|
||||
"""Git 提交和推送"""
|
||||
try:
|
||||
# 检查是否有变更
|
||||
result = subprocess.run(
|
||||
result = subprocess.run(
|
||||
["git", "status", "--porcelain"],
|
||||
cwd=project_path,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd = project_path,
|
||||
capture_output = True,
|
||||
text = True,
|
||||
)
|
||||
|
||||
if not result.stdout.strip():
|
||||
return True, "没有需要提交的变更"
|
||||
|
||||
# 添加所有变更
|
||||
subprocess.run(["git", "add", "-A"], cwd=project_path, check=True)
|
||||
subprocess.run(["git", "add", "-A"], cwd = project_path, check = True)
|
||||
|
||||
# 提交
|
||||
commit_msg = """fix: auto-fix code issues (cron)
|
||||
commit_msg = """fix: auto-fix code issues (cron)
|
||||
|
||||
- 修复重复导入/字段
|
||||
- 修复异常处理
|
||||
@@ -446,11 +446,11 @@ def git_commit_and_push(project_path: str) -> tuple[bool, str]:
|
||||
- 添加类型注解"""
|
||||
|
||||
subprocess.run(
|
||||
["git", "commit", "-m", commit_msg], cwd=project_path, check=True
|
||||
["git", "commit", "-m", commit_msg], cwd = project_path, check = True
|
||||
)
|
||||
|
||||
# 推送
|
||||
subprocess.run(["git", "push"], cwd=project_path, check=True)
|
||||
subprocess.run(["git", "push"], cwd = project_path, check = True)
|
||||
|
||||
return True, "提交并推送成功"
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -459,11 +459,11 @@ def git_commit_and_push(project_path: str) -> tuple[bool, str]:
|
||||
return False, f"Git 操作异常: {e}"
|
||||
|
||||
|
||||
def main():
|
||||
project_path = "/root/.openclaw/workspace/projects/insightflow"
|
||||
def main() -> None:
|
||||
project_path = "/root/.openclaw/workspace/projects/insightflow"
|
||||
|
||||
print("🔍 开始扫描代码...")
|
||||
fixer = CodeFixer(project_path)
|
||||
fixer = CodeFixer(project_path)
|
||||
fixer.scan_all_files()
|
||||
|
||||
print(f"📊 发现 {len(fixer.issues)} 个可自动修复问题")
|
||||
@@ -475,30 +475,30 @@ def main():
|
||||
print(f"✅ 已修复 {len(fixer.fixed_issues)} 个问题")
|
||||
|
||||
# 生成报告
|
||||
report = fixer.generate_report()
|
||||
report = fixer.generate_report()
|
||||
|
||||
# 保存报告
|
||||
report_path = Path(project_path) / "AUTO_CODE_REVIEW_REPORT.md"
|
||||
with open(report_path, "w", encoding="utf-8") as f:
|
||||
report_path = Path(project_path) / "AUTO_CODE_REVIEW_REPORT.md"
|
||||
with open(report_path, "w", encoding = "utf-8") as f:
|
||||
f.write(report)
|
||||
|
||||
print(f"📝 报告已保存到: {report_path}")
|
||||
|
||||
# Git 提交
|
||||
print("📤 提交变更到 Git...")
|
||||
success, msg = git_commit_and_push(project_path)
|
||||
success, msg = git_commit_and_push(project_path)
|
||||
print(f"{'✅' if success else '❌'} {msg}")
|
||||
|
||||
# 添加 Git 结果到报告
|
||||
report += f"\n\n## Git 提交结果\n\n{'✅' if success else '❌'} {msg}\n"
|
||||
|
||||
# 重新保存完整报告
|
||||
with open(report_path, "w", encoding="utf-8") as f:
|
||||
with open(report_path, "w", encoding = "utf-8") as f:
|
||||
f.write(report)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("\n" + " = " * 60)
|
||||
print(report)
|
||||
print("=" * 60)
|
||||
print(" = " * 60)
|
||||
|
||||
return report
|
||||
|
||||
|
||||
Reference in New Issue
Block a user