Skip to content

Skill 代码审查

本项目构建一个代码审查 Skill,用户上传代码文件后,自动分析代码质量、风格问题和潜在 Bug。

目标:掌握工具链集成与结构化问题报告的生成。


项目需求分析

功能支持语言工具
语法检查Pythonpy_compile(内置)
代码风格检查Pythonflake8
代码复杂度分析Pythonradon
JavaScript 检查JS/TSeslint(npx)
综合问题报告所有自定义聚合脚本

目录结构

bash
code-reviewer/
├── SKILL.md
└── scripts/
    ├── requirements.txt
    ├── check_python.py
    ├── check_js.py
    └── generate_report.py

Python 代码检查脚本

实例

python

# 文件路径:scripts/check_python.py

import subprocess

import sys

import json

import os

def ensure_tools():

    """确保检查工具已安装"""

    for pkg in ["flake8", "radon"]:

        try:

            __import__(pkg.replace("-", "_"))

        except ImportError:

            subprocess.run([sys.executable, "-m", "pip", "install", pkg,

                            "--break-system-packages", "--quiet"])

def check_syntax(file_path: str) -> dict:

    """检查 Python 语法"""

    result = subprocess.run(

        [sys.executable, "-m", "py_compile", file_path],

        capture_output=True, text=True

    )

    if result.returncode == 0:

        return {"passed": True, "errors": []}

    return {

        "passed": False,

        "errors": [result.stderr.strip()]

    }

def check_style(file_path: str) -> list:

    """运行 flake8 检查代码风格,返回问题列表"""

    result = subprocess.run(

        ["python", "-m", "flake8", file_path,

         "--max-line-length=100",

         "--format=%(row)d:%(col)d %(code)s %(text)s"],

        capture_output=True, text=True

    )

    issues = []

    for line in result.stdout.strip().splitlines():

        parts = line.split(" ", 2)

        if len(parts) >= 3:

            loc, code, text = parts

            row, col = loc.split(":")

            issues.append({

                "line": int(row), "col": int(col),

                "code": code,     "message": text

            })

    return issues

def check_complexity(file_path: str) -> list:

    """用 radon 分析函数复杂度,返回复杂度高的函数"""

    result = subprocess.run(

        ["python", "-m", "radon", "cc", file_path, "-s", "--json"],

        capture_output=True, text=True

    )

    try:

        data      = json.loads(result.stdout)

        functions = data.get(file_path, [])

        # 只返回复杂度等级 C 以上(复杂度 > 10)的函数

        return [

            {"name": f["name"], "complexity": f["complexity"],

             "rank": f["rank"], "line": f["lineno"]}

            for f in functions

            if f.get("rank", "A") in ("C", "D", "E", "F")

        ]

    except Exception:

        return []

def review_python(file_path: str) -> dict:

    """执行完整的 Python 代码审查"""

    if not os.path.exists(file_path):

        return {"status": "error", "message": f"文件不存在:{file_path}"}

    ensure_tools()

    syntax     = check_syntax(file_path)

    style      = check_style(file_path) if syntax["passed"] else []

    complexity = check_complexity(file_path) if syntax["passed"] else []

    # 计算总体评级

    error_count   = len([i for i in style if i["code"].startswith("E")])

    warning_count = len([i for i in style if i["code"].startswith("W")])

    if not syntax["passed"]:

        grade = "F"

    elif error_count > 10:

        grade = "C"

    elif error_count > 3:

        grade = "B"

    else:

        grade = "A"

    return {

        "status":          "success",

        "file":            os.path.basename(file_path),

        "grade":           grade,

        "syntax_ok":       syntax["passed"],

        "syntax_errors":   syntax["errors"],

        "style_issues":    style[:20],          # 最多展示 20 条

        "style_count":     len(style),

        "error_count":     error_count,

        "warning_count":   warning_count,

        "complex_functions": complexity

    }

if __name__ == "__main__":

    result = review_python(sys.argv[1] if len(sys.argv) > 1 else "")

    print(json.dumps(result, ensure_ascii=False, indent=2))

输出:

json
{
  "status": "success",
  "file": "runoob_app.py",
  "grade": "B",
  "syntax_ok": true,
  "style_issues": [
    {"line": 12, "col": 1, "code": "E302", "message": "expected 2 blank lines"},
    {"line": 34, "col": 80, "code": "E501", "message": "line too long (103 > 100)"}
  ],
  "style_count": 5,
  "error_count": 3,
  "warning_count": 2,
  "complex_functions": []
}

SKILL.md 完整内容

bash
---
name: code-reviewer
version: 1.0.0
description: >
  自动审查用户上传的代码文件,检查语法错误、风格问题和代码复杂度,
  生成带评级的问题报告并给出改进建议。当用户需要代码审查、
  检查代码质量、查找 Bug、评估代码规范时触发。
---

# 代码审查助手

## 执行流程

### 第一步:识别代码文件

获取用户上传的代码文件路径,识别编程语言(根据扩展名):
- .py Python 审查
- .js / .ts JavaScript/TypeScript 审查
- 其他格式 告知暂不支持,列出支持的格式

### 第二步:运行自动化检查

Python 文件运行:
```bash
cd scripts/
python check_python.py <文件路径>
```

### 第三步:生成并解读报告

根据 JSON 输出,以人性化方式呈现结果:

1. **总体评级**:A(优秀)/ B(良好)/ C(需改进)/ F(语法错误)
2. **问题汇总表格**:行号、问题代码、描述
3. **Top 3 优先修复项**:选出最严重的 3 个问题,给出修复建议和示例

若文件无问题,给出简短正面评价:
> 代码检查通过!共扫描 X 行,未发现语法错误和明显风格问题。

测试用例

实例

python

# 文件路径:scripts/tests/test_sample.py(用于测试审查 Skill 的样本文件)

# 故意包含一些常见问题,用于验证审查功能

import os,sys   # E401: 多个 import 在同一行(风格问题)

import json

def processData(data):  # N802: 函数名应为 snake_case

    x = 1  # F841: 局部变量 x 赋值后未使用

    result=[]  # E225: 赋值号周围缺少空格

    for i in data:

        if i > 0:

            result.append(i)

        elif i == 0:

            pass

        else:

            result.append(-i)

    return result

class myClass:  # N801: 类名应为 CamelCase

    pass

运行审查:

bash
cd scripts/
python check_python.py tests/test_sample.py

输出:

json
{
  "status": "success",
  "file": "test_sample.py",
  "grade": "B",
  "syntax_ok": true,
  "style_count": 5,
  "error_count": 4,
  "warning_count": 1,
  "complex_functions": []
}

AI 思考中...

Skills 设计模式与最佳实践

Skill 数据清洗与分析

基于 VitePress 构建,部署于 GitHub Pages