开发code-quality
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
代码分析器
|
||||
扫描代码文件,检测常见问题
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def analyze_file(file_path):
|
||||
"""分析单个代码文件"""
|
||||
issues = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
lines = content.split('\n')
|
||||
|
||||
# 检测模式
|
||||
patterns = {
|
||||
'TODO': r'TODO|FIXME|XXX|HACK',
|
||||
'empty_function': r'def\s+\w+\s*\([^)]*\)\s*:\s*(pass|#\s*.*|.{0})',
|
||||
'empty_method': r'(def|async\s+def)\s+\w+\s*\([^)]*\)\s*:\s*(pass|.{0})',
|
||||
'commented_code': r'^\s*#.*=[^#\n]|^\s*#.*\([^)]*\)',
|
||||
'placeholder': r'(NotImplementedError|raise\s+NotImplemented|pass\s*#.*placeholder)',
|
||||
'debug_print': r'print\([^)]*\)|console\.log\([^)]*\)',
|
||||
}
|
||||
|
||||
for line_num, line in enumerate(lines, 1):
|
||||
for issue_type, pattern in patterns.items():
|
||||
if re.search(pattern, line, re.IGNORECASE):
|
||||
issues.append({
|
||||
'type': issue_type,
|
||||
'line': line_num,
|
||||
'content': line.strip(),
|
||||
'file': str(file_path)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
issues.append({
|
||||
'type': 'read_error',
|
||||
'message': str(e),
|
||||
'file': str(file_path)
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def detect_project_changes(project_root):
|
||||
"""检测项目中的代码变更"""
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
# 获取 Git 变更的文件
|
||||
result = subprocess.run(
|
||||
['git', 'diff', '--name-only', 'HEAD'],
|
||||
cwd=project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
changed_files = result.stdout.strip().split('\n')
|
||||
changed_files = [f for f in changed_files if f]
|
||||
|
||||
# 过滤代码文件
|
||||
code_extensions = {'.py', '.js', '.ts', '.jsx', '.tsx', '.java', '.go', '.rs', '.c', '.cpp', '.h'}
|
||||
code_files = [
|
||||
Path(project_root) / f
|
||||
for f in changed_files
|
||||
if Path(f).suffix.lower() in code_extensions
|
||||
]
|
||||
return code_files
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 如果 Git 不可用,扫描所有代码文件
|
||||
code_extensions = {'.py', '.js', '.ts', '.jsx', '.tsx', '.java', '.go', '.rs', '.c', '.cpp', '.h'}
|
||||
project_path = Path(project_root)
|
||||
code_files = []
|
||||
|
||||
for ext in code_extensions:
|
||||
code_files.extend(project_path.rglob(f'*{ext}'))
|
||||
|
||||
return code_files
|
||||
|
||||
|
||||
def analyze_code_quality(project_root):
|
||||
"""分析代码质量"""
|
||||
all_issues = {
|
||||
'todo': [],
|
||||
'empty_functions': [],
|
||||
'commented_code': [],
|
||||
'placeholders': [],
|
||||
'debug_statements': [],
|
||||
'other': []
|
||||
}
|
||||
|
||||
# 获取需要分析的文件
|
||||
files_to_analyze = detect_project_changes(project_root)
|
||||
|
||||
for file_path in files_to_analyze:
|
||||
if not file_path.exists():
|
||||
continue
|
||||
|
||||
issues = analyze_file(file_path)
|
||||
|
||||
for issue in issues:
|
||||
issue_type = issue['type']
|
||||
|
||||
if issue_type == 'TODO':
|
||||
all_issues['todo'].append(issue)
|
||||
elif 'empty' in issue_type:
|
||||
all_issues['empty_functions'].append(issue)
|
||||
elif issue_type == 'commented_code':
|
||||
all_issues['commented_code'].append(issue)
|
||||
elif issue_type == 'placeholder':
|
||||
all_issues['placeholders'].append(issue)
|
||||
elif issue_type == 'debug_print':
|
||||
all_issues['debug_statements'].append(issue)
|
||||
else:
|
||||
all_issues['other'].append(issue)
|
||||
|
||||
return all_issues
|
||||
|
||||
|
||||
def calculate_completeness_score(issues):
|
||||
"""计算完整度评分"""
|
||||
total_issues = sum(len(v) for v in issues.values())
|
||||
|
||||
# 严重问题权重
|
||||
critical_issues = len(issues['empty_functions']) + len(issues['placeholders'])
|
||||
minor_issues = len(issues['todo']) + len(issues['commented_code']) + len(issues['debug_statements'])
|
||||
|
||||
# 计算分数(0-100)
|
||||
score = 100 - (critical_issues * 15) - (minor_issues * 5)
|
||||
return max(0, min(100, score))
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
# 从命令行参数或 stdin 获取项目路径
|
||||
if len(sys.argv) > 1:
|
||||
project_root = sys.argv[1]
|
||||
else:
|
||||
project_root = os.getcwd()
|
||||
|
||||
# 执行分析
|
||||
issues = analyze_code_quality(project_root)
|
||||
score = calculate_completeness_score(issues)
|
||||
|
||||
# 输出结果
|
||||
result = {
|
||||
'score': score,
|
||||
'issues': issues,
|
||||
'total_issues': sum(len(v) for v in issues.values()),
|
||||
'summary': {
|
||||
'todo_count': len(issues['todo']),
|
||||
'empty_functions_count': len(issues['empty_functions']),
|
||||
'commented_code_count': len(issues['commented_code']),
|
||||
'placeholder_count': len(issues['placeholders']),
|
||||
'debug_statements_count': len(issues['debug_statements'])
|
||||
}
|
||||
}
|
||||
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user