感谢你对 ModuleMirror 的关注!本文档将帮助你快速上手开发。
- Python 3.9+
- Git 2.30+
- Poetry 1.7+(包管理)
- tree-sitter C 编译器(用于解析器编译)
# 1. 克隆仓库
git clone https://github.com/your-org/ModuleMirror.git
cd ModuleMirror
# 2. 安装 Poetry(如未安装)
pip install poetry
# 3. 安装所有依赖(含开发依赖)
poetry install
# 4. 安装 API 可选依赖
poetry install --extras api
# 5. 安装 pre-commit 钩子
poetry run pre-commit install
# 6. 验证安装
poetry run python -c "import gh_similarity_detector; print('OK')"
poetry run pytest tests/ -q --tb=no # 快速验证测试pip install -e ".[api]"
pip install -e ".[dev]"| 变量 | 用途 | 默认值 |
|---|---|---|
MODULEMIRROR_LOG_LEVEL |
日志级别 | INFO |
MODULEMIRROR_LOG_FORMAT |
日志格式 (text/json) |
text |
GITHUB_TOKEN |
GitHub API Token | 无 |
MODULEMIRROR_DB_PATH |
SQLite 数据库路径 | ./fingerprints.db |
推荐扩展:
ms-python.python- Python 语言支持charliermarsh.ruff- Ruff lintermatangover.mypy- 类型检查
.vscode/settings.json 推荐配置:
{
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests", "-v"],
"editor.formatOnSave": true,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
},
"ruff.lineLength": 100
}- 设置 pytest 为默认测试运行器
- 配置 ruff 为外部工具
- 启用 mypy 检查器插件
gh_similarity_detector/
├── api/ # Web API 层(FastAPI)
│ ├── app.py # FastAPI 应用入口
│ └── routes/ # API 路由子模块
│ ├── detect.py # 检测路由
│ ├── history.py # 历史记录路由
│ ├── health.py # 健康检查路由
│ └── metrics.py # Prometheus metrics 路由
├── cli/ # CLI 层(Click)
│ ├── main.py # CLI 入口
│ └── db_commands.py # 数据库管理命令
├── config/ # 配置层
│ └── config.py # DetectionConfig(Pydantic v2)
├── core/ # 核心领域层
│ ├── fingerprint/ # 指纹计算
│ │ ├── winnowing.py # Winnowing 算法(O(n)优化)
│ │ ├── generator.py # 指纹生成器(并行化)
│ │ └── language_plugins.py # 语言插件体系
│ ├── similarity/ # 相似度计算
│ │ ├── calculator.py # Jaccard + 倒排索引 + 增量更新
│ │ └── ast_comparator.py # AST 深度比对
│ ├── plagiarism/ # 抄袭溯源
│ │ └── detector.py # PlagiarismDetector
│ ├── comparison/ # 多仓库对比
│ │ ├── multi_repo.py # MultiRepositoryComparator
│ │ ├── batch_detector.py # BatchDetector
│ │ └── result_comparator.py # ResultComparator
│ ├── orchestration/ # 流程编排
│ │ ├── pipeline.py # DetectionPipeline(含幂等性守卫)
│ │ └── checkpoint.py # 断点续传
│ ├── delta_detector.py # 增量检测
│ ├── project/ # 项目获取
│ ├── module/ # 模块提取
│ └── report/ # 报告生成
├── infrastructure/ # 基础设施层
│ ├── storage/ # 持久化(SQLite,已拆分)
│ │ ├── fingerprint_db.py # FingerprintDB 门面
│ │ ├── schema.py # DDL + 版本管理
│ │ ├── migrations.py # 迁移逻辑
│ │ ├── queries.py # CRUD 查询
│ │ └── _connection_pool.py # 连接池
│ ├── cache/ # 缓存(LRU + SHA256)
│ ├── github_client/ # GitHub API 客户端(含 Fallback)
│ ├── resilience/ # 弹性模式
│ │ ├── circuit_breaker.py # 断路器
│ │ ├── retry_strategies.py # 重试策略
│ │ ├── bulkhead.py # 并发隔离
│ │ ├── fallback.py # 降级策略
│ │ ├── timeout.py # 超时控制
│ │ ├── ssrf_protection.py # SSRF 防护
│ │ └── adaptive_rate_limiter.py # 自适应限流
│ ├── observability/ # 可观测性
│ │ ├── metrics.py # Prometheus 指标
│ │ ├── memory_profiler.py # 内存画像
│ │ └── alerting.py # 告警规则
│ ├── security/ # 安全
│ │ ├── authorization.py # 对象级授权
│ │ ├── api_security.py # API 安全管理
│ │ └── owasp_compliance.py # OWASP 合规
│ ├── lifecycle/ # 生命周期
│ │ └── graceful_shutdown.py # 优雅关闭
│ └── io/ # IO 流式处理
│ └── stream_reader.py # 大文件流式读取
├── models/ # 数据模型
├── utils/ # 工具集
│ ├── exceptions.py # 领域异常体系
│ ├── validation.py # Pydantic v2 校验
│ ├── sanitizer.py # 输入消毒
│ ├── logger.py # 结构化日志
│ ├── idempotency.py # 幂等性守卫
│ ├── resource_tracker.py # 资源泄露检测
│ ├── audit.py # 审计日志
│ └── math_utils.py # 数学工具
tests/ # 测试套件(890+ 测试)
├── conftest.py # 共享 fixtures + 工厂
├── test_property_based.py # Hypothesis 属性测试
└── ... # 各模块测试文件
ModuleMirror 采用六边形架构(Hexagonal Architecture),核心业务逻辑与基础设施严格分离:
适配器层(CLI / Web API / GitHub Client)
↓
应用层(DetectionPipeline 编排器)
↓
领域层(FingerprintEngine + SimilarityEngine + PlagiarismDetector)
↓
基础设施层(SQLite / Cache / Resilience / Observability)
详见 ADR.md,当前共 26 条架构决策记录。核心决策:
- ADR-001: Winnowing 算法选型(局部敏感性 + 全局稳定性)
- ADR-002: 六边形架构(领域与基础设施隔离)
- ADR-006: tree-sitter 多语言解析(统一 AST 抽象)
- ADR-011: SQLite 指纹库(嵌入式零部署)
- ADR-016: 幂等性守卫(DeterministicContext + result_hash)
源代码 → CodeTokenizer → k-gram → RollingHash → Winnowing指纹
↓
目标代码 → ... → Winnowing指纹 → Jaccard相似度 → AST验证 → 置信度评分
↓
HTML/JSON/Markdown 报告
main- 稳定发布分支develop- 开发集成分支feature/xxx- 功能分支fix/xxx- 修复分支refactor/xxx- 重构分支
- Fork 仓库 → 克隆到本地
- 创建分支
git checkout -b feature/xxx - 编写代码 + 测试 → 确保所有检查通过
- 本地验证
make check(lint + type + test + security) - 提交 PR → 填写 PR 模板 → 等待审查
- 在
language_plugins.py中创建新的LanguagePlugin子类 - 安装对应的
tree-sitter-<lang>包 - 在
PluginRegistry中注册 - 编写测试用例(参考
tests/test_language_plugins.py)
- 在
infrastructure/resilience/下创建模块 - 遵循 CircuitBreaker/Bulkhead 的设计模式
- 集成到
DetectionPipeline或GitHubClient - 编写单元测试 + 集成测试
- 格式化:ruff(line-length=100)
- 类型检查:mypy(strict 模式,
disallow_untyped_defs=true) - 安全扫描:bandit(0 HIGH 问题)
- 测试:pytest(覆盖率 ≥ 80%)
| 类型 | 风格 | 示例 |
|---|---|---|
| 模块/包 | snake_case | delta_detector.py |
| 类 | PascalCase | FingerprintGenerator |
| 函数/方法 | snake_case | compute_jaccard() |
| 常量 | UPPER_SNAKE | DEFAULT_KGRAM_SIZE |
| 私有方法 | _前缀 | _normalize_value() |
| Pydantic 模型 | PascalCase + Config/Result 后缀 | DetectionConfig, SimilarityResult |
按 ruff 默认规则:标准库 → 第三方 → 本项目,各组之间空一行。
使用项目定义的领域异常体系(utils/exceptions.py):
from gh_similarity_detector.utils.exceptions import (
ModuleMirrorError, # 基类
FingerprintError, # 指纹计算错误
SimilarityError, # 相似度计算错误
StorageError, # 存储层错误
ValidationError, # 数据校验错误
SecurityError, # 安全错误
InfrastructureError, # 基础设施错误
)不要使用裸 Exception,始终使用或定义领域异常子类。
使用结构化日志:
from gh_similarity_detector.utils.logger import logger
logger.info("Detection completed", extra={
"module_count": 10,
"similarity_threshold": 0.8,
"correlation_id": "req-123",
})不要使用 print() 输出调试信息。
# 完整检查(推荐)
ruff check .
mypy gh_similarity_detector/
pytest tests/ -v --cov=gh_similarity_detector --cov-fail-under=80
bandit -r gh_similarity_detector/ -ll
# 快速检查(日常开发)
ruff check .
pytest tests/ -x -q # -x: 首个失败即停make lint # ruff + mypy
make test # pytest + 覆盖率
make security # bandit
make check # 全部检查pytest tests/ -v # 全量测试
pytest tests/test_xxx.py -v # 单文件测试
pytest tests/test_xxx.py::test_func -v # 单测试函数
pytest tests/ -k "winnowing" -v # 按关键词筛选
pytest tests/ --cov --cov-report=html # 覆盖率报告
pytest tests/ -n auto # 并行测试(xdist)| 文件 | 类型 | 说明 |
|---|---|---|
test_*.py |
单元测试 | 各模块功能测试 |
test_property_based.py |
属性测试 | Hypothesis 驱动的属性验证 |
test_integration.py |
集成测试 | 跨模块集成验证 |
conftest.py |
Fixtures | 共享测试夹具 + 工厂 |
- 每个新功能必须附带测试
- 使用
conftest.py中的工厂函数创建测试数据 - 属性测试使用 Hypothesis(参考
test_property_based.py) - Mock 外部依赖(GitHub API、文件系统),不依赖网络
# 使用工厂创建测试数据
def test_similarity(sample_modules, sample_fingerprints):
result = calculator.calculate(sample_fingerprints[0], sample_fingerprints[1])
assert result.jaccard_similarity >= 0.0
assert result.jaccard_similarity <= 1.0- 新代码覆盖率 ≥ 80%
- 核心算法(Winnowing/Jaccard)覆盖率 ≥ 90%
- 不允许覆盖率回退
# 检查语言是否支持
from gh_similarity_detector.core.fingerprint.language_plugins import PluginRegistry
registry = PluginRegistry()
print(registry.list_languages()) # 查看已注册语言
# 检查 tree-sitter 版本
import tree_sitter
print(tree_sitter.__version__) # 应为 0.25+常见错误:language.query() 已废弃,使用 Query(language, query_str) + QueryCursor。
Python 3.3+ 的 hash() 默认随机化,导致指纹跨会话不一致。项目已使用确定性多项式哈希替代。
验证:
from gh_similarity_detector.core.fingerprint.winnowing import Winnowing
w = Winnowing(kgram_size=5, window_size=4)
fps1 = w.generate_fingerprints_from_code("def foo(): pass")
fps2 = w.generate_fingerprints_from_code("def foo(): pass")
assert fps1 == fps2 # 必须一致# 检查连接池状态
from gh_similarity_detector.infrastructure.storage.fingerprint_db import FingerprintDB
db = FingerprintDB("test.db")
# 查看连接池大小
print(db._pool.size()) # 默认 5如遇 database is locked,检查是否有未关闭的连接或长事务。
# 查看 Circuit Breaker 状态
from gh_similarity_detector.infrastructure.resilience.circuit_breaker import github_circuit
print(github_circuit.state) # CLOSED / OPEN / HALF_OPEN
# 查看自适应限流
from gh_similarity_detector.infrastructure.resilience.adaptive_rate_limiter import adaptive_limiter
print(adaptive_limiter.get_wait_time())# 使用内存画像分析
from gh_similarity_detector.infrastructure.observability.memory_profiler import MemoryProfiler
profiler = MemoryProfiler()
with profiler.track_allocations("detection"):
# ... 你的代码 ...
snapshot = profiler.take_snapshot()
print(snapshot)# 启用 DEBUG 级别日志
MODULEMIRROR_LOG_LEVEL=DEBUG pytest tests/ -v
# JSON 格式日志(适合生产环境)
MODULEMIRROR_LOG_FORMAT=json python -m gh_similarity_detector.cli.main detect ...
# 查看特定模块日志
MODULEMIRROR_LOG_LEVEL=DEBUG python -c "
from gh_similarity_detector.utils.logger import logger
import logging
logger.setLevel(logging.DEBUG)
# ... 你的调试代码 ...
"# Prometheus 指标查看
import requests
resp = requests.get("http://localhost:8000/metrics")
print(resp.text)
# Winnowing 性能基准
import time
from gh_similarity_detector.core.fingerprint.winnowing import Winnowing
w = Winnowing(kgram_size=5, window_size=4)
code = "def foo():\n" + " x = 1\n" * 10000
start = time.perf_counter()
fps = w.generate_fingerprints_from_code(code)
elapsed = time.perf_counter() - start
print(f"Generated {len(fps)} fingerprints in {elapsed:.3f}s")在测试中使用 breakpoint() 或 import pdb; pdb.set_trace():
def test_something():
result = complex_calculation()
breakpoint() # Python 3.7+ 内置
assert result.is_validfeat: 新功能描述fix: 修复描述refactor: 重构描述docs: 文档变更test: 测试补充perf: 性能优化chore: 构建/工具变更security: 安全修复
- 代码通过 ruff 检查
- 类型检查通过(mypy)
- 新代码有对应测试
- 测试覆盖率 ≥ 80%
- 无 bandit HIGH 安全问题
- PR 描述清晰说明变更原因和内容
- 大型变更先提 Issue 讨论
- 功能正确性:逻辑是否正确
- 测试充分性:是否有足够测试覆盖
- 代码风格:是否符合项目规范
- 安全性:是否引入安全隐患
- 性能:是否影响性能
- 向后兼容:是否破坏现有 API
提交 Issue 时请包含:
- 复现步骤:逐步操作说明
- 期望行为 vs 实际行为
- 环境信息:Python 版本、OS、ModuleMirror 版本
- 日志输出:
MODULEMIRROR_LOG_LEVEL=DEBUG下的完整日志 - 最小复现示例:如有可能
| 级别 | 描述 | 响应时间 |
|---|---|---|
| P0 致命 | 数据丢失/安全漏洞 | 24h |
| P1 严重 | 核心功能不可用 | 72h |
| P2 一般 | 功能异常但有变通 | 1 周 |
| P3 轻微 | UI/文档/体验问题 | 2 周 |
- 更新
pyproject.toml版本号 - 更新
CHANGELOG.md - 运行完整测试套件
- 创建 Git tag(
v0.x.y) - 构建 发布包(
poetry build) - 发布到 PyPI(
poetry publish) - 创建 GitHub Release