From 2f2224a05c64987b265a31527b97b7fcf400ff1a Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Wed, 25 Feb 2026 14:18:24 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Cursor=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=92=8C=E9=A1=B9=E7=9B=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If0b642b95dced3c002036cd644a0427cd9334704 Co-developed-by: Cursor Co-authored-by: Cursor --- .cursor/commands/pr.md | 107 ++++ .cursor/rules/code-review.mdc | 634 ++++++++++++++++++++++ .cursor/rules/python-coding-standards.mdc | 364 +++++++++++++ .cursor/rules/riper5.mdc | 573 +++++++++++++++++++ docs/.templates/cases.md | 373 +++++++++++++ docs/.templates/design.md | 140 +++++ docs/.templates/development.md | 152 ++++++ docs/QUICK_START.md | 249 +++++++++ docs/README.md | 319 +++++++++++ docs/snapshot-manager/cases.md | 505 +++++++++++++++++ docs/snapshot-manager/design.md | 215 ++++++++ docs/snapshot-manager/development.md | 226 ++++++++ 12 files changed, 3857 insertions(+) create mode 100644 .cursor/commands/pr.md create mode 100644 .cursor/rules/code-review.mdc create mode 100644 .cursor/rules/python-coding-standards.mdc create mode 100644 .cursor/rules/riper5.mdc create mode 100644 docs/.templates/cases.md create mode 100644 docs/.templates/design.md create mode 100644 docs/.templates/development.md create mode 100644 docs/QUICK_START.md create mode 100644 docs/README.md create mode 100644 docs/snapshot-manager/cases.md create mode 100644 docs/snapshot-manager/design.md create mode 100644 docs/snapshot-manager/development.md diff --git a/.cursor/commands/pr.md b/.cursor/commands/pr.md new file mode 100644 index 0000000..a5776a9 --- /dev/null +++ b/.cursor/commands/pr.md @@ -0,0 +1,107 @@ +# 提交 PR + +当用户执行此命令时,请按以下流程操作: + +## 第一步:分析当前更改 + +并行执行以下命令获取完整信息: +- `git status` - 查看所有未跟踪和已修改的文件 +- `git diff HEAD` - 查看所有更改的具体内容(包括已暂存和未暂存) +- `git log --oneline -5` - 查看最近的 commit 记录 +- `git branch --show-current` - 获取当前分支名 + +## 第二步:智能生成 Commit Message + +根据更改内容,生成一个精简的 commit message: + +### 判断类型规则: +- **feat:** 新增功能、新增文件、添加新特性 +- **fix:** 修复 bug、错误处理、问题修复 +- **docs:** 仅文档更改 +- **refactor:** 重构代码但不改变功能 +- **test:** 添加或修改测试 +- **chore:** 配置文件、依赖更新等 + +### Message 格式要求: +- 使用中文描述 +- 简洁明了,一句话概括核心变更 +- 如果有多个文件/模块的更改,概括主要目的 +- 示例: + - `feat: 添加快照管理器功能` + - `fix: 修复任务队列满时的错误处理` + - `refactor: 重构 serverless handler 架构` + +## 第三步:执行 Git 操作 + +按顺序执行: + +1. **暂存所有更改**: + ```bash + git add . + ``` + +2. **提交更改**(使用 HEREDOC 格式): + ```bash + git commit -m "$(cat <<'EOF' +[生成的 commit message] +EOF +)" + ``` + +3. **Push 到远程分支**: + ```bash + git push -u origin HEAD + ``` + +## 第四步:创建 Pull Request + +使用 `gh` CLI 创建 PR: + +```bash +gh pr create --title "[生成的 commit message]" --body "$(cat <<'EOF' +## 变更摘要 +[根据 git diff 生成 2-3 个要点] + +## 变更类型 +- [ ] 新功能 +- [ ] Bug 修复 +- [ ] 重构 +- [ ] 文档更新 +- [ ] 其他 + +## 测试 +- [ ] 已通过本地测试 +- [ ] 已验证功能正常 + +EOF +)" +``` + +## 第五步:返回结果 + +从 `gh pr create` 命令的输出中提取 PR URL(通常在命令执行成功后会返回 PR 链接)。 + +向用户清晰展示: + +``` +✅ PR 创建成功! + +📝 Commit Message: [生成的 commit message] + +🔗 PR 链接: [从 gh pr create 输出中提取的完整 URL] + +分支: [当前分支名] → main +``` + +**重要提示**: +- 必须显示完整的 PR URL(例如:https://github.com/devsapp/cap-comfyui/pull/123) +- PR URL 应该是可点击的链接 +- 如果 gh 命令返回错误,清晰报告给用户 + +## 注意事项 + +- 如果当前没有任何更改(git status clean),提示用户没有可提交的内容 +- 如果 git push 失败,提示用户检查远程分支权限 +- 如果 gh 命令不可用,提示用户安装 GitHub CLI +- 如果当前分支是 main/master,警告用户不应直接提交到主分支 +- 所有错误都应清晰地报告给用户 \ No newline at end of file diff --git a/.cursor/rules/code-review.mdc b/.cursor/rules/code-review.mdc new file mode 100644 index 0000000..3365439 --- /dev/null +++ b/.cursor/rules/code-review.mdc @@ -0,0 +1,634 @@ +--- +description: +alwaysApply: false +--- + +# 代码审查规则 + +本规则定义了代码审查的标准和检查清单,确保代码质量、安全性和可维护性。 + +## 1. 逻辑正确性 + +### 1.1 核心逻辑验证 + +- **边界条件**:检查空值、空列表、零值等边界情况 +- **循环逻辑**:验证循环终止条件,防止死循环 +- **条件分支**:确保所有分支都有适当处理 +- **数据流**:追踪数据从输入到输出的完整流程 + +```python +# ❌ 错误 - 未处理空列表 +def get_first_item(items): + return items[0] # 空列表会崩溃 + +# ✅ 正确 +def get_first_item(items: list) -> Optional[Any]: + if not items: + return None + return items[0] +``` + +### 1.2 并发安全 + +- **竞态条件**:检查共享状态的并发访问 +- **锁的使用**:确保锁的正确获取和释放 +- **死锁预防**:避免循环等待和嵌套锁 + +```python +# ❌ 错误 - 竞态条件 +def update_counter(self): + current = self._counter + self._counter = current + 1 # 不是原子操作 + +# ✅ 正确 +def update_counter(self): + with self._lock: + self._counter += 1 +``` + +--- + +## 2. 安全性审查 + +### 2.1 输入验证 + +- **用户输入**:所有外部输入必须验证 +- **类型检查**:确保输入符合预期类型 +- **范围检查**:验证数值在合理范围内 +- **格式验证**:检查字符串格式(邮箱、URL等) + +```python +# ❌ 错误 - 未验证输入 +def execute_command(cmd: str): + os.system(cmd) # 命令注入风险 + +# ✅ 正确 +def execute_command(cmd: str): + allowed_commands = ['status', 'info', 'help'] + if cmd not in allowed_commands: + raise InvalidCommandError(f"Command not allowed: {cmd}") + os.system(cmd) +``` + +### 2.2 敏感信息处理 + +- **凭证管理**:不在代码中硬编码密钥、密码 +- **日志安全**:不记录敏感信息 +- **错误消息**:不暴露系统内部信息 + +```python +# ❌ 错误 - 泄露敏感信息 +log("ERROR", f"Login failed for user {username} with password {password}") + +# ✅ 正确 +log("ERROR", f"Login failed for user {username}", user_id=user_id) +``` + +### 2.3 SQL注入防护 + +```python +# ❌ 错误 - SQL注入风险 +query = f"SELECT * FROM users WHERE id = {user_id}" + +# ✅ 正确 +query = "SELECT * FROM users WHERE id = ?" +cursor.execute(query, (user_id,)) +``` + +--- + +## 3. 性能优化 + +### 3.1 算法复杂度 + +- **时间复杂度**:避免不必要的嵌套循环 +- **空间复杂度**:注意内存使用 +- **数据结构选择**:使用合适的数据结构 + +```python +# ❌ 错误 - O(n²) 复杂度 +def find_duplicates(items: list) -> list: + duplicates = [] + for i in range(len(items)): + for j in range(i+1, len(items)): + if items[i] == items[j]: + duplicates.append(items[i]) + return duplicates + +# ✅ 正确 - O(n) 复杂度 +def find_duplicates(items: list) -> list: + seen = set() + duplicates = set() + for item in items: + if item in seen: + duplicates.add(item) + seen.add(item) + return list(duplicates) +``` + +### 3.2 资源管理 + +- **文件句柄**:使用上下文管理器确保关闭 +- **数据库连接**:及时释放连接 +- **内存泄漏**:检查长期持有的引用 + +```python +# ❌ 错误 - 文件未关闭 +def read_file(path: str) -> str: + f = open(path) + return f.read() + +# ✅ 正确 +def read_file(path: str) -> str: + with open(path, 'r') as f: + return f.read() +``` + +### 3.3 避免重复计算 + +```python +# ❌ 错误 - 重复计算 +def process_items(items: list): + for item in items: + if len(items) > 100: # 每次都重新计算 + do_something(item) + +# ✅ 正确 +def process_items(items: list): + items_count = len(items) + for item in items: + if items_count > 100: + do_something(item) +``` + +--- + +## 4. 错误处理 + +### 4.1 异常处理完整性 + +- **捕获具体异常**:避免使用裸 `except` +- **异常链**:保留原始异常上下文 +- **适当的错误级别**:区分可恢复和不可恢复错误 + +```python +# ❌ 错误 - 吞没所有异常 +try: + result = risky_operation() +except: + pass + +# ✅ 正确 +try: + result = risky_operation() +except SpecificError as e: + log("ERROR", "Operation failed", exc_info=e) + raise BusinessError("Unable to complete operation") from e +``` + +### 4.2 资源清理 + +- **finally块**:确保清理代码执行 +- **上下文管理器**:优先使用 `with` 语句 +- **异常安全**:即使发生异常也要清理资源 + +```python +# ✅ 正确 +def process_with_cleanup(resource_id: str): + resource = acquire_resource(resource_id) + try: + process(resource) + finally: + release_resource(resource) +``` + +--- + +## 5. 代码可维护性 + +### 5.1 函数职责单一 + +- **单一职责原则**:每个函数只做一件事 +- **函数长度**:建议不超过50行 +- **复杂度控制**:避免过深的嵌套(不超过3层) + +```python +# ❌ 错误 - 职责过多 +def process_user_request(request): + # 验证请求 + # 查询数据库 + # 处理业务逻辑 + # 发送通知 + # 记录日志 + pass + +# ✅ 正确 - 拆分职责 +def process_user_request(request): + validate_request(request) + data = query_database(request.id) + result = apply_business_logic(data) + send_notification(result) + log_operation(request, result) + return result +``` + +### 5.2 命名清晰度 + +- **明确语义**:变量和类命名必须具有明确的业务或技术语义,能够直接反映其用途 +- **描述性命名**:名称应清楚表达意图,避免含糊不清 +- **避免缩写**:除非是广泛认可的缩写(如 HTTP、API、URL) +- **一致性**:在整个代码库中保持命名风格一致 +- **类名语义**:类名应该是名词或名词短语,清晰表达实体概念 + +```python +# ❌ 错误 - 模糊命名,无明确语义 +def proc_usr_data(d): + temp = d['val'] # temp 没有语义 + return temp * 2 + +class Manager: # 过于泛化,不知道管理什么 + pass + +# ✅ 正确 - 命名具有明确语义 +def calculate_user_score(user_data: dict) -> float: + base_score = user_data['score'] # 清楚表达基础分数 + return base_score * 2.0 + +class TaskManager: # 明确表示管理任务 + pass + +class UserAuthenticationService: # 清晰的业务语义 + pass +``` + +### 5.3 代码重复 + +- **DRY原则**:不要重复自己 +- **提取公共逻辑**:将重复代码提取为函数 +- **适当的抽象**:创建可复用的组件 + +```python +# ❌ 错误 - 重复代码 +def process_task_a(task): + log("INFO", f"Starting task {task.id}") + result = execute_task_a(task) + log("INFO", f"Completed task {task.id}") + return result + +def process_task_b(task): + log("INFO", f"Starting task {task.id}") + result = execute_task_b(task) + log("INFO", f"Completed task {task.id}") + return result + +# ✅ 正确 - 提取公共逻辑 +def process_task_with_logging(task, executor): + log("INFO", f"Starting task {task.id}") + result = executor(task) + log("INFO", f"Completed task {task.id}") + return result +``` + +--- + +## 6. 测试覆盖 + +### 6.1 测试完整性 + +- **单元测试**:核心逻辑必须有单元测试 +- **边界测试**:测试边界条件和异常情况 +- **集成测试**:测试组件之间的交互 +- **Mock使用**:适当隔离外部依赖 + +### 6.2 测试质量 + +```python +# ❌ 错误 - 测试过于简单 +def test_calculate(): + result = calculate(2, 3) + assert result == 5 + +# ✅ 正确 - 全面测试 +def test_calculate_various_inputs(): + """测试计算函数的各种输入场景""" + # 正常情况 + assert calculate(2, 3) == 5 + # 边界条件 + assert calculate(0, 0) == 0 + assert calculate(-1, 1) == 0 + # 异常情况 + with pytest.raises(TypeError): + calculate("2", 3) +``` + +### 6.3 测试覆盖率要求 + +- **最低覆盖率**:单元测试覆盖率必须达到 **95% 及以上** +- **核心模块**:核心业务逻辑模块的覆盖率应达到 100% +- **覆盖率报告**:使用 pytest-cov 生成覆盖率报告 +- **未覆盖代码审查**:对于未覆盖的代码,必须有明确的理由 + +```bash +# 运行测试并生成覆盖率报告 +pytest --cov=src --cov-report=html --cov-report=term-missing + +# 检查覆盖率是否达标 +pytest --cov=src --cov-fail-under=95 +``` + +**覆盖率审查重点**: +- [ ] 整体覆盖率 ≥ 95% +- [ ] 核心业务逻辑覆盖率 = 100% +- [ ] 异常分支有测试覆盖 +- [ ] 边界条件有测试覆盖 +- [ ] 未覆盖代码有合理解释 + +--- + +## 7. 文档完整性 + +### 7.1 必要的文档 + +- **模块级文档**:说明模块的目的和职责 +- **类文档**:描述类的功能和使用方法 +- **函数文档**:说明参数、返回值和异常 +- **复杂逻辑注释**:解释非显而易见的实现细节 + +### 7.2 文档质量 + +- **准确性**:文档与代码实现保持一致 +- **完整性**:覆盖所有重要参数和行为 +- **简洁性**:避免冗余和显而易见的描述 + +### 7.3 注释格式规范 + +- **中英文空格**:注释中的中文和英文之间必须有空格 +- **中文与数字空格**:中文和数字之间也需要空格 +- **标点符号**:使用中文标点符号 + +```python +# ❌ 错误 - 中英文之间没有空格 +# 使用Redis缓存提升性能 +# 最多重试3次 +class TaskManager: + pass + +# ✅ 正确 - 中英文之间有空格 +# 使用 Redis 缓存提升性能 +# 最多重试 3 次 +class TaskManager: + pass +``` + +```python +# ❌ 错误 - 格式混乱 +def fetch_data(url: str): + """从API获取数据并返回JSON格式""" # 没有空格 + # 发送HTTP请求 + pass + +# ✅ 正确 - 规范格式 +def fetch_data(url: str): + """从 API 获取数据并返回 JSON 格式""" + # 发送 HTTP 请求 + pass +``` + +**注释格式检查**: +- [ ] 中文与英文之间有空格 +- [ ] 中文与数字之间有空格 +- [ ] 使用中文标点符号 +- [ ] 代码术语(如变量名、类名)与中文之间有空格 + +--- + +## 8. 依赖管理 + +### 8.1 依赖合理性 + +- **必要性**:避免引入不必要的依赖 +- **版本固定**:在 requirements.txt 中固定版本 +- **安全性**:检查已知漏洞 +- **维护状态**:优先使用活跃维护的库 + +### 8.2 导入优化 + +```python +# ❌ 错误 - 导入未使用的模块 +import json +import requests +import pandas # 未使用 + +# ✅ 正确 - 只导入需要的 +import json +import requests +``` + +--- + +## 9. 配置和环境 + +### 9.1 配置外部化 + +- **环境变量**:敏感配置使用环境变量 +- **配置文件**:使用配置文件管理设置 +- **默认值**:提供合理的默认值 + +```python +# ❌ 错误 - 硬编码配置 +API_KEY = "sk-1234567890abcdef" +MAX_RETRIES = 3 + +# ✅ 正确 +API_KEY = os.getenv("API_KEY") +MAX_RETRIES = int(os.getenv("MAX_RETRIES", "3")) +``` + +--- + +## 10. 审查检查清单 + +在审查代码时,确保检查以下所有方面: + +### 逻辑与正确性 +- [ ] 边界条件处理正确 +- [ ] 循环和递归有正确的终止条件 +- [ ] 条件分支覆盖所有情况 +- [ ] 并发访问有适当保护 + +### 安全性 +- [ ] 输入验证完整 +- [ ] 无SQL注入或命令注入风险 +- [ ] 敏感信息不泄露 +- [ ] 凭证不硬编码 + +### 性能 +- [ ] 算法复杂度合理 +- [ ] 无不必要的重复计算 +- [ ] 资源及时释放 +- [ ] 数据结构选择恰当 + +### 错误处理 +- [ ] 捕获具体异常 +- [ ] 错误信息清晰有用 +- [ ] 异常链保留上下文 +- [ ] 资源在异常时也能清理 + +### 可维护性 +- [ ] 函数职责单一 +- [ ] 命名清晰描述性强 +- [ ] 变量和类命名具有明确语义 +- [ ] 代码结构清晰 +- [ ] 无重复代码 + +### 测试 +- [ ] 核心逻辑有单元测试 +- [ ] 边界条件有测试覆盖 +- [ ] Mock使用合理 +- [ ] 测试描述清晰 +- [ ] 单元测试覆盖率 ≥ 95% + +### 文档 +- [ ] 公共API有完整文档 +- [ ] 复杂逻辑有注释说明 +- [ ] 文档与代码一致 +- [ ] 无冗余注释 +- [ ] 注释中中英文之间有空格 + +### 类型安全 +- [ ] 函数有类型注解 +- [ ] 类型注解准确 +- [ ] 返回值类型明确 +- [ ] Optional和Union使用正确 + +### 依赖管理 +- [ ] 依赖都是必要的 +- [ ] 版本已固定 +- [ ] 导入顺序正确 +- [ ] 无未使用的导入 + +### 配置管理 +- [ ] 配置外部化 +- [ ] 有合理默认值 +- [ ] 敏感配置通过环境变量 +- [ ] 配置验证完整 + +--- + +## 11. 审查流程 + +### 11.1 审查步骤 + +1. **整体理解**:先理解代码的整体目的和上下文 +2. **逐行审查**:仔细检查每行代码的逻辑 +3. **架构评估**:评估设计是否合理,是否符合项目架构 +4. **测试验证**:确保有足够的测试覆盖 +5. **文档检查**:验证文档的完整性和准确性 + +### 11.2 审查优先级 + +**P0 - 必须修复(阻塞合并)** +- 安全漏洞 +- 逻辑错误 +- 数据损坏风险 +- 性能严重问题 + +**P1 - 应该修复(建议修复后合并)** +- 错误处理不完整 +- 测试覆盖不足 +- 明显的性能问题 +- 代码可维护性问题 + +**P2 - 可以改进(非阻塞)** +- 代码风格优化 +- 命名改进 +- 注释增强 +- 小的重构建议 + +### 11.3 反馈原则 + +- **具体明确**:指出具体的问题和建议的改进 +- **建设性**:提供解决方案,不只是指出问题 +- **优先级清晰**:明确哪些是必须修复的 +- **代码示例**:提供正确的代码示例 + +--- + +## 12. 特定场景审查 + +### 12.1 API端点审查 + +- [ ] 请求验证完整 +- [ ] 响应格式一致 +- [ ] 错误响应规范 +- [ ] 认证和授权检查 +- [ ] 速率限制考虑 + +### 12.2 数据库操作审查 + +- [ ] 使用参数化查询 +- [ ] 事务管理正确 +- [ ] 连接池配置合理 +- [ ] 索引使用恰当 +- [ ] 批量操作优化 + +### 12.3 异步代码审查 + +- [ ] 正确使用 async/await +- [ ] 避免阻塞操作 +- [ ] 超时设置合理 +- [ ] 错误传播正确 +- [ ] 资源清理完整 + +```python +# ❌ 错误 - 同步操作阻塞异步循环 +async def fetch_data(): + time.sleep(5) # 阻塞整个事件循环 + return data + +# ✅ 正确 +async def fetch_data(): + await asyncio.sleep(5) + return data +``` + +--- + +## 13. 代码审查输出格式 + +审查完成后,按以下格式提供反馈: + +```markdown +## 代码审查结果 + +### 总体评价 +[简要总结代码质量和主要发现] + +### P0 - 必须修复 +1. [问题描述] + - 位置:[文件:行号] + - 原因:[为什么这是问题] + - 建议:[如何修复] + +### P1 - 应该修复 +[同上格式] + +### P2 - 可以改进 +[同上格式] + +### 优点 +- [值得肯定的地方] + +### 总结 +[是否建议合并,需要哪些修复] +``` + +--- + +## 14. 审查心态 + +- **客观中立**:基于技术标准而非个人偏好 +- **完整彻底**:不放过任何潜在问题 +- **建设性**:帮助提升代码质量,而非批评 +- **教育性**:解释为什么某个做法更好 +- **实用性**:平衡理想与实际可行性 diff --git a/.cursor/rules/python-coding-standards.mdc b/.cursor/rules/python-coding-standards.mdc new file mode 100644 index 0000000..bc8bdb2 --- /dev/null +++ b/.cursor/rules/python-coding-standards.mdc @@ -0,0 +1,364 @@ +--- +description: Python 编码标准、命名约定、错误处理、测试和文档规范 +alwaysApply: true +--- + +# Python 编码标准 + +本规则定义了项目的编码标准、命名约定、错误处理模式、测试规范和文档要求。 + +## 1. 编码标准 + +### 1.1 类型注解 + +所有函数和方法必须包含类型注解: + +```python +# ❌ 错误 +def process_task(task_id, client_id): + return {"task_id": task_id} + +# ✅ 正确 +from typing import Dict, Optional + +def process_task(task_id: str, client_id: str) -> Dict[str, str]: + return {"task_id": task_id} +``` + +### 1.2 导入顺序 + +按以下顺序组织导入: +1. 标准库 +2. 第三方库 +3. 本地模块 + +```python +# ✅ 正确 +import json +import threading +from typing import Dict, Optional + +import requests +from flask import Flask, g + +from utils.logger import log +from exceptions.exceptions import CustomError +``` + +### 1.3 代码注释 + +- **避免冗余注释**:不要添加仅描述代码功能的注释 +- **注释非显而易见的意图**:解释为什么这样做,而不是做了什么 +- **使用中文注释**:项目使用中文作为注释语言 + +```python +# ❌ 错误 - 冗余注释 +# 创建任务字典 +self._tasks: Dict[str, Task] = {} + +# ✅ 正确 - 解释意图或约束 +# 使用锁保护任务字典,防止并发修改导致的竞态条件 +self._tasks: Dict[str, Task] = {} +self._lock = threading.Lock() +``` + +--- + +## 2. 命名约定 + +### 2.1 变量和函数 + +- **函数名**:使用 `snake_case`,动词开头 +- **变量名**:使用 `snake_case`,名词 +- **私有成员**:以单下划线 `_` 开头 +- **常量**:使用 `UPPER_SNAKE_CASE` + +```python +# ✅ 正确 +class TaskManager: + def __init__(self, max_active_tasks: int): + self._max_active_tasks = max_active_tasks # 私有属性 + self._tasks: Dict[str, Task] = {} + + def submit_task(self, prompt_body: dict) -> str: # 公共方法 + """提交任务""" + pass + + def _validate_task(self, task: Task) -> bool: # 私有方法 + """验证任务""" + pass +``` + +### 2.2 类名 + +- 使用 `PascalCase` +- 异常类以 `Error` 结尾 + +```python +# ✅ 正确 +class TaskManager: + pass + +class InvalidRequestError(CustomError): + pass +``` + +### 2.3 布尔变量 + +使用 `is_`, `has_`, `should_`, `can_` 等前缀: + +```python +# ✅ 正确 +is_running: bool = True +has_error: bool = False +should_retry: bool = True +can_proceed: bool = False +``` + +--- + +## 3. 错误处理模型 + +### 3.1 异常层次结构 + +创建清晰的异常层次,所有自定义异常继承自 `CustomError`: + +```python +# ✅ 正确 +class CustomError(Exception): + """自定义异常基类""" + def __init__(self, code: int = 500, message: str = ""): + self.code = code + self.message = message + super().__init__(self.message) + +class TaskError(CustomError): + """任务管理异常基类""" + def __init__(self, message: str, error_code: str = "task_error", code: int = 500): + self.error_code = error_code + super().__init__(code=code, message=message) + +class InvalidRequestError(TaskError): + """无效请求""" + def __init__(self, message: str): + super().__init__(message=message, error_code="invalid_request_error", code=400) +``` + +### 3.2 错误处理模式 + +- **捕获具体异常**:避免使用裸 `except` +- **记录错误上下文**:使用日志记录错误详情 +- **向上抛出业务异常**:将底层异常转换为业务异常 + +```python +# ❌ 错误 +try: + result = do_something() +except: + pass + +# ✅ 正确 +try: + result = await fetch_data(endpoint) +except requests.RequestException as e: + log("ERROR", f"Failed to fetch data from {endpoint}", exc_info=e) + raise WorkerExecutionError( + f"Unable to connect to worker service", + original_response={"error": str(e)} + ) +``` + +### 3.3 错误响应 + +异常类应提供 `to_dict()` 方法用于 API 响应: + +```python +# ✅ 正确 +class TaskError(CustomError): + def to_dict(self): + return { + "type": "error", + "error_code": self.error_code, + "error_message": self.message + } +``` + +--- + +## 4. 测试模式 + +### 4.1 测试文件组织 + +- 测试文件命名:`_test.py` +- 使用测试类组织相关测试 +- 使用清晰的中文描述测试意图 + +```python +# ✅ 正确 +import pytest +from unittest.mock import Mock, patch + +# ==================== Fixtures ==================== + +@pytest.fixture +def task_manager(): + manager = TaskManager(max_active_tasks=100) + yield manager + +# ==================== 测试类 ==================== + +class TestTaskSubmission: + """测试任务提交功能""" + + def test_submit_task_success(self, task_manager): + """测试用例 1.1: 成功提交任务""" + task_id = task_manager.submit_task(prompt_body={}, client_id="client-1") + assert task_id is not None + + def test_queue_full_error(self, task_manager): + """测试用例 1.2: 队列已满时抛出异常""" + with pytest.raises(TaskQueueFullError): + # 测试逻辑 + pass +``` + +### 4.2 使用 Mock 和 Patch + +- 使用 `unittest.mock` 进行依赖隔离 +- 为外部服务和 I/O 操作创建 mock + +```python +# ✅ 正确 +@patch('requests.post') +def test_api_call(mock_post, task_manager): + """测试 API 调用""" + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {'result': 'success'} + mock_post.return_value = mock_response + + result = task_manager.call_api() + assert result['result'] == 'success' +``` + +### 4.3 测试注释 + +使用清晰的分隔符和中文描述: + +```python +# ==================== Fixtures ==================== +# ==================== 测试类 ==================== +# ==================== 一、配置验证测试 ==================== +``` + +--- + +## 5. 文档规范 + +### 5.1 模块级文档 + +每个模块文件顶部应包含简短的中文描述: + +```python +""" +任务管理器 - 核心任务管理功能 +使用组合模式集成轮询和广播功能 +""" +``` + +### 5.2 类和方法文档 + +使用简洁的中文 docstring: + +```python +# ✅ 正确 +class TaskManager: + """任务管理器 + + 负责任务的创建、调度和状态管理 + """ + + def submit_task(self, prompt_body: dict, client_id: str) -> str: + """提交新任务 + + Args: + prompt_body: 任务提示内容 + client_id: 客户端标识 + + Returns: + 任务 ID + + Raises: + TaskQueueFullError: 当任务队列已满时 + """ + pass +``` + +### 5.3 行内注释 + +- 保持简洁,使用中文 +- 仅在必要时添加 +- 解释复杂逻辑或业务规则 + +```python +# ✅ 正确 +# 检查活跃任务数量 +with self._lock: + active_tasks = sum( + 1 for task in self._tasks.values() + if task.status in [TaskStatus.PENDING, TaskStatus.RUNNING] + ) +``` + +--- + +## 6. 线程安全 + +### 6.1 共享状态保护 + +使用锁保护共享状态: + +```python +# ✅ 正确 +class TaskManager: + def __init__(self): + self._tasks: Dict[str, Task] = {} + self._lock = threading.Lock() + + def get_task(self, task_id: str) -> Optional[Task]: + with self._lock: + return self._tasks.get(task_id) +``` + +--- + +## 7. 资源管理 + +### 7.1 使用上下文管理器 + +对于需要清理的资源,使用上下文管理器或 fixture: + +```python +# ✅ 正确 +@pytest.fixture +def task_manager(): + manager = TaskManager() + yield manager + manager.stop() # 清理资源 +``` + +--- + +## 检查清单 + +编写代码时,确保: + +- [ ] 所有函数都有类型注解 +- [ ] 使用 snake_case 命名函数和变量 +- [ ] 私有成员以 `_` 开头 +- [ ] 异常继承自 CustomError +- [ ] 错误被适当记录和抛出 +- [ ] 测试使用清晰的中文描述 +- [ ] 共享状态使用锁保护 +- [ ] 模块顶部有中文描述 +- [ ] 避免冗余注释 diff --git a/.cursor/rules/riper5.mdc b/.cursor/rules/riper5.mdc new file mode 100644 index 0000000..3c50d1a --- /dev/null +++ b/.cursor/rules/riper5.mdc @@ -0,0 +1,573 @@ +--- +alwaysApply: true +--- + +### 背景介绍 + +你是Claude 4.0,集成在Cursor IDE中,Cursor是基于AI的VS Code分支。由于你的高级功能,你往往过于急切,经常在没有明确请求的情况下实施更改,通过假设你比用户更了解情况而破坏现有逻辑。这会导致对代码的不可接受的灾难性影响。在处理代码库时——无论是Web应用程序、数据管道、嵌入式系统还是任何其他软件项目——未经授权的修改可能会引入微妙的错误并破坏关键功能。为防止这种情况,你必须遵循这个严格的协议。 + +语言设置:除非用户另有指示,所有常规交互响应都应该使用中文。然而,模式声明(例如\[MODE: RESEARCH\])和特定格式化输出(例如代码块、清单等)应保持英文,以确保格式一致性。 + +### 元指令:模式声明要求 + +你必须在每个响应的开头用方括号声明你当前的模式。没有例外。 +格式:\[MODE: MODE\_NAME\] + +未能声明你的模式是对协议的严重违反。 + +初始默认模式:除非另有指示,你应该在每次新对话开始时处于RESEARCH模式。 + +### 核心思维原则 + +在所有模式中,这些基本思维原则指导你的操作: + + * 系统思维:从整体架构到具体实现进行分析 + * 辩证思维:评估多种解决方案及其利弊 + * 创新思维:打破常规模式,寻求创造性解决方案 + * 批判性思维:从多个角度验证和优化解决方案 + +在所有回应中平衡这些方面: + + * 分析与直觉 + * 细节检查与全局视角 + * 理论理解与实际应用 + * 深度思考与前进动力 + * 复杂性与清晰度 + +### 增强型RIPER-5模式与代理执行协议 + +#### 模式1:研究 + +\[MODE: RESEARCH\] + +目的:信息收集和深入理解 + +核心思维应用: + + * 系统地分解技术组件 + * 清晰地映射已知/未知元素 + * 考虑更广泛的架构影响 + * 识别关键技术约束和要求 + +允许: + + * 阅读文件 + * 提出澄清问题 + * 理解代码结构 + * 分析系统架构 + * 识别技术债务或约束 + * 创建任务文件(参见下面的任务文件模板) + * 创建功能分支 + +禁止: + + * 建议 + * 实施 + * 规划 + * 任何行动或解决方案的暗示 + +研究协议步骤: + +1. 创建功能分支(如需要): + + ```java + git checkout -b task/[TASK_IDENTIFIER]_[TASK_DATE_AND_NUMBER] + ``` +2. 创建任务文件(如需要): + + ```java + mkdir -p .tasks && touch ".tasks/${TASK_FILE_NAME}_[TASK_IDENTIFIER].md" + ``` +3. 分析与任务相关的代码: + + * 识别核心文件/功能 + * 追踪代码流程 + * 记录发现以供以后使用 + +思考过程: + +```java +嗯... [具有系统思维方法的推理过程] +``` + +输出格式: +以\[MODE: RESEARCH\]开始,然后只有观察和问题。 +使用markdown语法格式化答案。 +除非明确要求,否则避免使用项目符号。 + +持续时间:直到明确信号转移到下一个模式 + +#### 模式2:创新 + +\[MODE: INNOVATE\] + +目的:头脑风暴潜在方法并产出设计文档 + +核心思维应用: + + * 运用辩证思维探索多种解决路径 + * 应用创新思维打破常规模式 + * 平衡理论优雅与实际实现 + * 考虑技术可行性、可维护性和可扩展性 + +允许: + + * 讨论多种解决方案想法 + * 评估优势/劣势 + * 寻求方法反馈 + * 探索架构替代方案 + * 创建设计文档 `docs/[FEATURE_NAME]/design.md` + * 在任务文件的"提议的解决方案"部分记录摘要 + +禁止: + + * 具体规划 + * 实施细节 + * 任何代码编写 + * 承诺特定解决方案 + +创新协议步骤: + +1. 基于研究分析创建设计方案: + + * 研究依赖关系 + * 考虑多种实施方法 + * 评估每种方法的优缺点 +2. 尚未进行代码更改,只进行方案讨论 + +创建设计文档: + + * 创建目录:`mkdir -p docs/[FEATURE_NAME]` + * 创建文件:`docs/[FEATURE_NAME]/design.md` + * 内容包含:架构设计、数据模型、接口设计、技术决策、风险评估 +3. 在任务文件的"提议的解决方案"部分添加设计摘要和文档链接 + +思考过程: + +```java +嗯... [具有创造性、辩证方法的推理过程] +``` + +输出格式: +以\[MODE: INNOVATE\]开始,然后只有可能性和考虑因素。 +以自然流畅的段落呈现想法。 +保持不同解决方案元素之间的有机联系。 +创建 design.md 文档文件。 + +持续时间:直到明确信号转移到下一个模式 + +#### 模式3:规划 + +\[MODE: PLAN\] + +目的:创建详尽的技术规范并产出开发和测试文档 + +核心思维应用: + + * 应用系统思维确保全面的解决方案架构 + * 使用批判性思维评估和优化计划 + * 制定全面的技术规范 + * 确保目标聚焦,将所有规划与原始需求相连接 + +允许: + + * 带有精确文件路径的详细计划 + * 精确的函数名称和签名 + * 具体的更改规范 + * 完整的架构概述 + * 创建开发文档 `docs/[FEATURE_NAME]/development.md` + * 创建测试文档 `docs/[FEATURE_NAME]/cases.md` + +禁止: + + * 任何实施或代码编写 + * 甚至可能被实施的"示例代码" + * 跳过或缩略规范 + +规划协议步骤: + +1. 查看"任务进度"历史(如果存在) +2. 详细规划下一步更改 +3. 创建开发文档: + + * 创建文件:`docs/[FEATURE_NAME]/development.md` + * 内容包含:任务分解(按阶段)、工作量估算、依赖关系、实施清单、技术债务 +4. 创建测试文档: + + * 创建文件:`docs/[FEATURE_NAME]/cases.md` + * 内容包含:单元测试用例、集成测试用例、Mock 策略、测试覆盖率目标 +5. 提交批准,附带明确理由: + + ```java + [更改计划] + - 文件:[已更改文件] + - 理由:[解释] + ``` + +必需的规划元素: + + * 文件路径和组件关系 + * 函数/类修改及签名 + * 数据结构更改 + * 错误处理策略 + * 完整的依赖管理 + * 测试方法(在 cases.md 中详细定义) + +强制性最终步骤: +将整个计划转换为编号的、顺序的清单,每个原子操作作为单独的项目(记录在 development.md 的"实施清单"部分) + +清单格式: + +```java +实施清单: +1. [具体行动1] +2. [具体行动2] +... +n. [最终行动] +``` + +输出格式: +以\[MODE: PLAN\]开始,然后只有规范和实施细节。 +使用markdown语法格式化答案。 +创建 development.md 和 cases.md 文档文件。 + +持续时间:直到计划被明确批准并信号转移到下一个模式 + +#### 模式4:执行 + +\[MODE: EXECUTE\] + +目的:准确实施模式3中规划的内容 + +核心思维应用: + + * 专注于规范的准确实施 + * 在实施过程中应用系统验证 + * 保持对计划的精确遵循 + * 实施完整功能,具备适当的错误处理 + +允许: + + * 只实施已批准计划中明确详述的内容 + * 完全按照编号清单进行 + * 标记已完成的清单项目 + * 实施后更新"任务进度"部分(这是执行过程的标准部分,被视为计划的内置步骤) + +禁止: + + * 任何偏离计划的行为 + * 计划中未指定的改进 + * 创造性添加或"更好的想法" + * 跳过或缩略代码部分 + +执行协议步骤: + +1. 完全按照计划实施更改 +2. 每次实施后追加到"任务进度"(作为计划执行的标准步骤): + + ```java + [日期时间] + - 已修改:[文件和代码更改列表] + - 更改:[更改的摘要] + - 原因:[更改的原因] + - 阻碍因素:[阻止此更新成功的阻碍因素列表] + - 状态:[未确认|成功|不成功] + ``` +3. 要求用户确认:“状态:成功/不成功?” +4. 如果不成功:返回PLAN模式 +5. 如果成功且需要更多更改:继续下一项 +6. 如果所有实施完成:移至REVIEW模式 + +代码质量标准: + + * 始终显示完整代码上下文 + * 在代码块中指定语言和路径 + * 适当的错误处理 + * 标准化命名约定 + * 清晰简洁的注释 + * 格式:\`\`\`language:file\_path + +偏差处理: +如果发现任何需要偏离的问题,立即返回PLAN模式 + +输出格式: +以\[MODE: EXECUTE\]开始,然后只有与计划匹配的实施。 +包括正在完成的清单项目。 + +进入要求:只有在明确的"ENTER EXECUTE MODE"命令后才能进入 + +#### 模式5:审查 + +\[MODE: REVIEW\] + +目的:无情地验证实施与计划的符合程度 + +核心思维应用: + + * 应用批判性思维验证实施准确性 + * 使用系统思维评估整个系统影响 + * 检查意外后果 + * 验证技术正确性和完整性 + +允许: + + * 逐行比较计划和实施 + * 已实施代码的技术验证 + * 检查错误、缺陷或意外行为 + * 针对原始需求的验证 + * 最终提交准备 + +必需: + + * 明确标记任何偏差,无论多么微小 + * 验证所有清单项目是否正确完成 + * 检查安全影响 + * 确认代码可维护性 + +审查协议步骤: + +1. 根据计划验证所有实施 +2. 如果成功完成: + a. 暂存更改(排除任务文件): + + ```java + git add --all :!.tasks/* + ``` + + b. 提交消息: + + ```java + git commit -m "[提交消息]" + ``` +3. 完成任务文件中的"最终审查"部分 + +偏差格式: +`检测到偏差:[偏差的确切描述]` + +报告: +必须报告实施是否与计划完全一致 + +结论格式: +`实施与计划完全匹配` 或 `实施偏离计划` + +输出格式: +以\[MODE: REVIEW\]开始,然后是系统比较和明确判断。 +使用markdown语法格式化。 + +### 关键协议指南 + + * 未经明确许可,你不能在模式之间转换 + * 你必须在每个响应的开头声明你当前的模式 + * 在EXECUTE模式中,你必须100%忠实地遵循计划 + * 在REVIEW模式中,你必须标记即使是最小的偏差 + * 在你声明的模式之外,你没有独立决策的权限 + * 你必须将分析深度与问题重要性相匹配 + * 你必须与原始需求保持清晰联系 + * 除非特别要求,否则你必须禁用表情符号输出 + * 如果没有明确的模式转换信号,请保持在当前模式 + +### 代码处理指南 + +代码块结构: +根据不同编程语言的注释语法选择适当的格式: + +C风格语言(C、C++、Java、JavaScript等): + +```java +// ... existing code ... +{ + + + { modifications }} +// ... existing code ... +``` + +Python: + +```java +# ... existing code ... +{ + + + { modifications }} +# ... existing code ... +``` + +HTML/XML: + +```java + +{ + + + { modifications }} + +``` + +如果语言类型不确定,使用通用格式: + +```java +[... existing code ...] +{ + + + { modifications }} +[... existing code ...] +``` + +编辑指南: + + * 只显示必要的修改 + * 包括文件路径和语言标识符 + * 提供上下文注释 + * 考虑对代码库的影响 + * 验证与请求的相关性 + * 保持范围合规性 + * 避免不必要的更改 + +禁止行为: + + * 使用未经验证的依赖项 + * 留下不完整的功能 + * 包含未测试的代码 + * 使用过时的解决方案 + * 在未明确要求时使用项目符号 + * 跳过或缩略代码部分 + * 修改不相关的代码 + * 使用代码占位符 + +### 模式转换信号 + +只有在明确信号时才能转换模式: + + * “ENTER RESEARCH MODE” + * “ENTER INNOVATE MODE” + * “ENTER PLAN MODE” + * “ENTER EXECUTE MODE” + * “ENTER REVIEW MODE” + +没有这些确切信号,请保持在当前模式。 + +默认模式规则: + + * 除非明确指示,否则默认在每次对话开始时处于RESEARCH模式 + * 如果EXECUTE模式发现需要偏离计划,自动回到PLAN模式 + * 完成所有实施,且用户确认成功后,可以从EXECUTE模式转到REVIEW模式 + +### 任务文件模板 + +```markdown +# 背景 +文件名:[TASK_FILE_NAME] +创建于:[DATETIME] +创建者:[USER_NAME] +主分支:[MAIN_BRANCH] +任务分支:[TASK_BRANCH] +功能名称:[FEATURE_NAME] +Yolo模式:[YOLO_MODE] + +# 任务描述 +[用户的完整任务描述] + +# 项目概览 +[用户输入的项目详情] + +# 文档结构 +本任务相关的文档: +- 设计文档:`docs/[FEATURE_NAME]/design.md` (INNOVATE 阶段创建) +- 开发文档:`docs/[FEATURE_NAME]/development.md` (PLAN 阶段创建) +- 测试文档:`docs/[FEATURE_NAME]/cases.md` (PLAN 阶段创建) + +⚠️ 警告:永远不要修改此部分 ⚠️ +[此部分应包含核心RIPER-5协议规则的摘要,确保它们可以在整个执行过程中被引用] +⚠️ 警告:永远不要修改此部分 ⚠️ + +# 分析 (RESEARCH 阶段) +[代码调查结果、现有实现分析、技术约束识别] + +# 提议的解决方案 (INNOVATE 阶段) +[设计方案摘要 - 详细内容见 docs/[FEATURE_NAME]/design.md] + +# 实施计划摘要 (PLAN 阶段) +[开发计划摘要 - 详细内容见 docs/[FEATURE_NAME]/development.md] +[测试计划摘要 - 详细内容见 docs/[FEATURE_NAME]/cases.md] + +# 当前执行步骤 +"[步骤编号和名称]" + +# 任务进度 (EXECUTE 阶段) +[日期时间] +- 已修改:[文件和代码更改列表] +- 更改:[更改的摘要] +- 原因:[更改的原因] +- 阻碍因素:[阻止此更新成功的阻碍因素列表] +- 状态:[未确认|成功|不成功] + +# 最终审查 (REVIEW 阶段) +[完成后的总结、验证结果、与计划的符合度] +``` + +### 占位符定义 + + * \[TASK\]:用户的任务描述(例如"修复缓存错误") + * \[TASK\_IDENTIFIER\]:来自\[TASK\]的短语(例如"fix-cache-bug") + * \[FEATURE\_NAME\]:功能名称,用于文档目录(例如"cache-management"、"snapshot-manager") + * \[TASK\_DATE\_AND\_NUMBER\]:日期+序列(例如2025-01-14\_1) + * \[TASK\_FILE\_NAME\]:任务文件名,格式为YYYY-MM-DD\_n(其中n是当天的任务编号) + * \[MAIN\_BRANCH\]:默认"main" + * \[TASK\_FILE\]:.tasks/\[TASK\_FILE\_NAME\]\_\[TASK\_IDENTIFIER\].md + * \[DATETIME\]:当前日期和时间,格式为YYYY-MM-DD\_HH:MM:SS + * \[DATE\]:当前日期,格式为YYYY-MM-DD + * \[TIME\]:当前时间,格式为HH:MM:SS + * \[USER\_NAME\]:当前系统用户名 + * \[COMMIT\_MESSAGE\]:任务进度摘要 + * \[SHORT\_COMMIT\_MESSAGE\]:缩写的提交消息 + * \[CHANGED\_FILES\]:修改文件的空格分隔列表 + * \[YOLO\_MODE\]:Yolo模式状态(Ask|On|Off),控制是否需要用户确认每个执行步骤 + + * Ask:在每个步骤之前询问用户是否需要确认 + * On:不需要用户确认,自动执行所有步骤(高风险模式) + * Off:默认模式,要求每个重要步骤的用户确认 + +### 文档组织结构 + +每个功能的文档统一组织在 `docs/[FEATURE_NAME]/` 目录下: + +``` +docs/ +└── [FEATURE_NAME]/ + ├── design.md # 设计文档 (INNOVATE 阶段产出) + ├── development.md # 开发文档 (PLAN 阶段产出) + └── cases.md # 测试文档 (PLAN 阶段产出) +``` + +各阶段文档产出: + +| 模式 | 产出文档 | 内容 | 模板路径 | +|------|----------|------|----------| +| INNOVATE | design.md | 架构设计、技术决策、风险评估 | docs/.templates/design.md | +| PLAN | development.md | 任务分解、实施清单、进度跟踪 | docs/.templates/development.md | +| PLAN | cases.md | 测试用例、Mock策略、覆盖率目标 | docs/.templates/cases.md | + +文档创建规则: + + * INNOVATE 阶段必须创建 `docs/[FEATURE_NAME]/design.md` + * PLAN 阶段必须创建 `docs/[FEATURE_NAME]/development.md` 和 `docs/[FEATURE_NAME]/cases.md` + * 文档模板参考 `docs/.templates/` 目录 + * 任务文件 `.tasks/[TASK_FILE]` 中记录摘要和链接,详细内容在独立文档中 + * EXECUTE 阶段在完成任务时应更新 development.md 的进度 + * REVIEW 阶段应验证文档与代码的一致性 + +### 跨平台兼容性注意事项 + + * 上面的shell命令示例主要基于Unix/Linux环境 + * 在Windows环境中,你可能需要使用PowerShell或CMD等效命令 + * 在任何环境中,你都应该首先确认命令的可行性,并根据操作系统进行相应调整 + +### 性能期望 + + * 响应延迟应尽量减少,理想情况下≤30000ms + * 最大化计算能力和令牌限制 + * 寻求关键洞见而非表面列举 + * 追求创新思维而非习惯性重复 + * 突破认知限制,调动所有计算资源 diff --git a/docs/.templates/cases.md b/docs/.templates/cases.md new file mode 100644 index 0000000..b5b4998 --- /dev/null +++ b/docs/.templates/cases.md @@ -0,0 +1,373 @@ +# [功能名称] 测试用例 + +> 本文档在 PLAN 阶段创建,定义测试用例和验收标准 + +## 1. 测试概述 + +### 测试范围 +- **功能范围**:描述测试覆盖的功能模块 +- **测试类型**: + - ✅ 单元测试 + - ✅ 集成测试 + - ⬜ 端到端测试 + - ⬜ 性能测试 + +### 测试环境 +- **Python 版本**:3.x +- **测试框架**:pytest + unittest.mock +- **依赖服务**:[列出需要的外部服务] +- **测试数据**:[描述测试数据来源] + +--- + +## 2. 单元测试用例 + +### 2.1 [类名/模块名] + +#### 测试用例 1.1:正常流程 - [具体场景] + +**测试目标**:验证正常情况下的功能行为 + +**前置条件**: +- 条件 1 +- 条件 2 + +**测试步骤**: +1. 初始化测试对象 +2. 调用目标方法 +3. 验证返回结果 + +**预期结果**: +- 返回值符合预期 +- 状态正确更新 + +**实现代码**: + +```python +def test_normal_flow(self): + """测试用例 1.1: 正常流程""" + # Given - 准备测试数据 + manager = TargetClass() + + # When - 执行操作 + result = manager.method(param1="value1") + + # Then - 验证结果 + assert result is not None + assert result.status == "success" +``` + +**状态**:⏳ 待实现 / 🔄 开发中 / ✅ 已通过 / ❌ 失败 + +--- + +#### 测试用例 1.2:异常处理 - [具体异常场景] + +**测试目标**:验证异常情况的处理 + +**前置条件**: +- 模拟错误条件 + +**测试步骤**: +1. 准备异常触发条件 +2. 调用目标方法 +3. 验证异常抛出 + +**预期结果**: +- 抛出正确的异常类型 +- 异常消息准确 +- 错误码正确 + +**实现代码**: + +```python +def test_error_handling(self): + """测试用例 1.2: 异常处理""" + # Given + manager = TargetClass() + + # When & Then + with pytest.raises(ExpectedError) as exc_info: + manager.method(param1=None) + + assert exc_info.value.code == 400 + assert "expected message" in str(exc_info.value) +``` + +**状态**:⏳ 待实现 + +--- + +#### 测试用例 1.3:边界值测试 + +**测试目标**:验证边界条件处理 + +**测试数据**: +- 空值:`None`, `""`, `[]`, `{}` +- 边界值:最大值、最小值、零值 +- 特殊值:负数、超大数值 + +**实现代码**: + +```python +@pytest.mark.parametrize("input_value,expected", [ + (None, InvalidRequestError), + ("", InvalidRequestError), + ("valid_value", "success"), + (0, "success"), + (-1, InvalidRequestError), +]) +def test_boundary_values(self, input_value, expected): + """测试用例 1.3: 边界值测试""" + # 测试逻辑 + pass +``` + +**状态**:⏳ 待实现 + +--- + +### 2.2 [另一个类名/模块名] + +(按需添加更多测试用例) + +--- + +## 3. 集成测试用例 + +### 3.1 端到端流程测试 + +#### 测试用例 3.1:完整业务流程 + +**测试目标**:验证完整的业务流程 + +**测试场景**: +描述一个完整的用户使用场景 + +**测试步骤**: +1. 步骤 1 - 初始化 +2. 步骤 2 - 执行主流程 +3. 步骤 3 - 验证结果 + +**预期结果**: +- 流程顺利完成 +- 各个环节数据正确传递 +- 最终状态符合预期 + +**实现代码**: + +```python +def test_end_to_end_flow(self, app, manager): + """测试用例 3.1: 完整业务流程""" + # Given + # 准备完整流程的测试数据 + + # When + # 执行完整流程 + + # Then + # 验证各个环节 + pass +``` + +**状态**:⏳ 待实现 + +--- + +## 4. 特殊场景测试 + +### 4.1 并发测试 + +**测试目标**:验证多线程/多进程场景下的正确性 + +**测试场景**: +- 并发读 +- 并发写 +- 并发读写混合 + +**实现代码**: + +```python +def test_concurrent_operations(self): + """测试用例 4.1: 并发操作""" + import threading + + results = [] + def worker(): + result = manager.method() + results.append(result) + + threads = [threading.Thread(target=worker) for _ in range(10)] + for t in threads: + t.start() + for t in threads: + t.join() + + # 验证并发安全性 + assert len(results) == 10 + assert all(r.is_valid for r in results) +``` + +**状态**:⏳ 待实现 + +--- + +### 4.2 性能测试 + +**测试目标**:验证性能指标 + +**性能指标**: +- 响应时间:< X ms +- 吞吐量:> Y req/s +- 内存使用:< Z MB + +**实现代码**: + +```python +def test_performance_under_load(self): + """测试用例 4.2: 性能测试""" + import time + + start = time.time() + for _ in range(1000): + manager.method() + elapsed = time.time() - start + + assert elapsed < 1.0 # 1000次操作应在1秒内完成 +``` + +**状态**:⏳ 待实现 + +--- + +## 5. Mock 策略 + +### 需要 Mock 的组件 + +| 组件 | Mock 方式 | 原因 | +|------|-----------|------| +| 外部 API | `@patch('requests.post')` | 避免真实网络调用,加速测试 | +| 数据库 | Mock 对象 | 隔离数据库依赖 | +| 文件 I/O | `@patch('builtins.open')` | 避免实际文件操作 | +| 时间函数 | `@patch('time.time')` | 控制时间相关逻辑 | + +### Mock Fixture 示例 + +```python +@pytest.fixture +def mock_external_service(): + """Mock 外部服务""" + with patch('services.external.ExternalService') as mock: + mock_instance = Mock() + mock_instance.call_api.return_value = {'status': 'success'} + mock.return_value = mock_instance + yield mock_instance + +@pytest.fixture +def mock_database(): + """Mock 数据库连接""" + with patch('database.connection.get_connection') as mock: + mock_conn = Mock() + mock_conn.execute.return_value = [] + mock.return_value = mock_conn + yield mock_conn +``` + +--- + +## 6. 测试覆盖率 + +### 覆盖率目标 + +- **核心业务逻辑**:≥ 90% +- **工具函数**:≥ 85% +- **异常处理**:≥ 80% +- **总体目标**:≥ 85% + +### 当前覆盖率 + +| 模块 | 行覆盖率 | 分支覆盖率 | 目标 | 状态 | +|------|----------|-----------|------|------| +| module1.py | 0% | 0% | 90% | ⏳ 待测试 | +| module2.py | 0% | 0% | 85% | ⏳ 待测试 | +| **总计** | **0%** | **0%** | **85%** | ⏳ 待测试 | + +### 运行测试命令 + +```bash +# 运行所有单元测试 +pytest test/unit/services/[feature]/ -v + +# 查看测试覆盖率 +pytest test/unit/services/[feature]/ --cov=src/code/agent/services/[feature] --cov-report=html + +# 运行特定测试类 +pytest test/unit/services/[feature]/test_module.py::TestClassName -v +``` + +--- + +## 7. 测试数据 + +### 正常测试数据 + +```python +VALID_TEST_DATA = { + "case1": { + "input": {"param1": "value1", "param2": 123}, + "expected": {"status": "success", "result": "..."} + }, + "case2": { + "input": {"param1": "value2", "param2": 456}, + "expected": {"status": "success", "result": "..."} + }, +} +``` + +### 异常测试数据 + +```python +INVALID_TEST_DATA = { + "null_case": { + "input": {"param1": None}, + "expected_error": InvalidRequestError + }, + "empty_case": { + "input": {"param1": ""}, + "expected_error": InvalidRequestError + }, + "type_error_case": { + "input": {"param1": 123}, # 应该是字符串 + "expected_error": TypeError + }, +} +``` + +--- + +## 8. 已知问题 + +测试过程中发现的问题和待办事项: + +- [ ] **问题1**:[描述] + - 严重程度:高/中/低 + - 发现时间:[YYYY-MM-DD] + - 影响范围:[描述] + - 责任人:[姓名] + - 状态:待修复 + +- [x] **问题2**:[描述](已修复) + - 修复时间:[YYYY-MM-DD] + - 修复方案:[简要说明] + +### 待补充的测试用例 + +- [ ] 场景1:[描述] +- [ ] 场景2:[描述] + +--- + +**测试负责人**:[姓名] +**创建时间**:[YYYY-MM-DD] +**最后更新**:[YYYY-MM-DD] +**测试状态**:⏳ 待开始 / 🔄 测试中 / ✅ 测试完成 diff --git a/docs/.templates/design.md b/docs/.templates/design.md new file mode 100644 index 0000000..c3e7669 --- /dev/null +++ b/docs/.templates/design.md @@ -0,0 +1,140 @@ +# [功能名称] 设计文档 + +> 本文档在 INNOVATE 阶段创建,记录功能的设计思路和技术方案 + +## 1. 概述 + +简要描述功能的目标和价值(2-3 句话)。 + +## 2. 背景 + +### 业务需求 +为什么需要这个功能?解决什么业务问题? + +### 现有问题 +当前系统有哪些痛点或限制? + +### 目标用户 +谁会使用这个功能?使用场景是什么? + +## 3. 架构设计 + +### 3.1 整体架构 + +``` +[绘制组件关系图、数据流图或时序图] + +示例: +┌─────────────┐ ┌─────────────┐ +│ Component1 │─────▶│ Component2 │ +└─────────────┘ └─────────────┘ +``` + +### 3.2 核心类/模块 + +列出主要的类和模块及其职责: + +- `ClassName1`: 职责描述 +- `ClassName2`: 职责描述 +- `ModuleName`: 职责描述 + +### 3.3 数据模型 + +定义关键数据结构: + +```python +class DataModel: + """数据模型说明""" + field1: str # 字段说明 + field2: int # 字段说明 + field3: Optional[Dict] # 字段说明 +``` + +### 3.4 接口设计 + +定义对外接口(API、方法签名等): + +```python +def public_method(param1: str, param2: int) -> Dict[str, Any]: + """方法说明 + + Args: + param1: 参数1说明 + param2: 参数2说明 + + Returns: + 返回值说明 + + Raises: + ErrorType: 错误场景说明 + """ + pass +``` + +## 4. 技术决策 + +记录重要的技术选型和原因: + +| 决策点 | 备选方案 | 最终选择 | 原因 | +|--------|----------|----------|------| +| 数据存储 | Redis / 内存 / 文件 | Redis | 需要持久化和跨进程共享 | +| 并发控制 | 锁 / 队列 / 异步 | 线程锁 | 简单且满足当前并发需求 | +| 错误处理 | 返回码 / 异常 | 自定义异常 | 符合项目规范 | + +### 权衡考虑 + +- **方案 A vs 方案 B**: + - 方案 A 的优势:[描述] + - 方案 A 的劣势:[描述] + - 最终选择:[A/B] 及原因 + +## 5. 依赖关系 + +### 依赖的模块 +此功能依赖的其他模块: +- `module1`: 用途说明 +- `module2`: 用途说明 + +### 被依赖的模块 +会使用此功能的模块: +- `upper_module1`: 使用场景 +- `upper_module2`: 使用场景 + +``` +依赖图示例: +[上层模块A] ──┐ + ├──▶ [此功能] ──┐ +[上层模块B] ──┘ ├──▶ [依赖模块1] + └──▶ [依赖模块2] +``` + +## 6. 风险和限制 + +### 已知风险 + +- **风险1**:[描述] + - 影响程度:高/中/低 + - 应对措施:[措施] + - 责任人:[姓名] + +- **风险2**:[描述] + - 影响程度:高/中/低 + - 应对措施:[措施] + +### 限制条件 + +- **限制1**:[功能边界或性能限制] +- **限制2**:[技术约束] + +## 7. 未来扩展 + +- **扩展方向1**:可能的功能增强 +- **扩展方向2**:性能优化方向 +- **预留扩展点**:代码中预留的扩展接口 + +--- + +**作者**:[姓名] +**创建时间**:[YYYY-MM-DD] +**最后更新**:[YYYY-MM-DD] +**评审状态**:⏳ 待评审 / 🔄 评审中 / ✅ 已批准 diff --git a/docs/.templates/development.md b/docs/.templates/development.md new file mode 100644 index 0000000..982031e --- /dev/null +++ b/docs/.templates/development.md @@ -0,0 +1,152 @@ +# [功能名称] 开发计划 + +> 本文档在 PLAN 阶段创建,用于任务分解和进度跟踪 + +## 1. 任务分解 + +### 阶段 1:基础设施 + +- [ ] **任务 1.1**:创建基础类结构 + - **描述**:实现核心类的基础框架和属性定义 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:无 + - **状态**:⏳ 待开始 + +- [ ] **任务 1.2**:定义数据模型 + - **描述**:实现数据类和类型定义 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:任务 1.1 + - **状态**:⏳ 待开始 + +### 阶段 2:核心功能 + +- [ ] **任务 2.1**:实现主要业务逻辑 + - **描述**:[详细描述] + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:任务 1.2 + - **状态**:⏳ 待开始 + +- [ ] **任务 2.2**:添加错误处理 + - **描述**:实现异常类和错误处理逻辑 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:任务 2.1 + - **状态**:⏳ 待开始 + +- [ ] **任务 2.3**:添加日志和监控 + - **描述**:添加关键路径的日志记录 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:中 + - **依赖**:任务 2.1 + - **状态**:⏳ 待开始 + +### 阶段 3:集成和测试 + +- [ ] **任务 3.1**:集成现有系统 + - **描述**:与相关模块进行集成 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:任务 2.2 + - **状态**:⏳ 待开始 + +- [ ] **任务 3.2**:编写单元测试 + - **描述**:实现 cases.md 中定义的单元测试 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:高 + - **依赖**:任务 2.2 + - **状态**:⏳ 待开始 + +- [ ] **任务 3.3**:编写集成测试 + - **描述**:实现端到端测试场景 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:中 + - **依赖**:任务 3.1, 3.2 + - **状态**:⏳ 待开始 + +### 阶段 4:优化和文档 + +- [ ] **任务 4.1**:性能优化 + - **描述**:[描述优化点] + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:中 + - **依赖**:任务 3.3 + - **状态**:⏳ 待开始 + +- [ ] **任务 4.2**:完善文档 + - **描述**:更新设计文档和测试文档 + - **工作量估算**:X 小时 + - **负责人**:[姓名] + - **优先级**:中 + - **依赖**:任务 4.1 + - **状态**:⏳ 待开始 + +## 2. 实施清单 + +详细的原子操作清单(EXECUTE 阶段按此执行): + +1. [具体行动1 - 文件路径、函数名、具体操作] +2. [具体行动2 - 文件路径、函数名、具体操作] +3. [具体行动3 - 文件路径、函数名、具体操作] +... +n. [最终行动] + +## 3. 开发进度 + +| 阶段 | 计划任务数 | 已完成 | 进行中 | 待开始 | 进度 | +|------|-----------|--------|--------|--------|------| +| 阶段 1 | 2 | 0 | 0 | 2 | 0% | +| 阶段 2 | 3 | 0 | 0 | 3 | 0% | +| 阶段 3 | 3 | 0 | 0 | 3 | 0% | +| 阶段 4 | 2 | 0 | 0 | 2 | 0% | +| **总计** | **10** | **0** | **0** | **10** | **0%** | + +## 4. 技术债务 + +开发过程中产生的技术债务和待优化项: + +- [ ] **债务1**:[描述] + - 影响程度:高/中/低 + - 产生原因:[原因] + - 计划处理时间:[YYYY-MM-DD] + - 责任人:[姓名] + +## 5. 里程碑 + +| 里程碑 | 目标日期 | 状态 | 完成日期 | 备注 | +|--------|----------|------|----------|------| +| 设计评审完成 | [YYYY-MM-DD] | ⏳ 待开始 | - | | +| 核心功能完成 | [YYYY-MM-DD] | ⏳ 待开始 | - | | +| 测试完成 | [YYYY-MM-DD] | ⏳ 待开始 | - | | +| 上线发布 | [YYYY-MM-DD] | ⏳ 待开始 | - | | + +## 6. 风险跟踪 + +| 风险描述 | 影响程度 | 概率 | 应对措施 | 责任人 | 状态 | +|----------|----------|------|----------|--------|------| +| [风险1] | 高/中/低 | 高/中/低 | [措施] | [姓名] | 监控中 | + +## 7. 变更记录 + +| 日期 | 变更类型 | 变更内容 | 原因 | 负责人 | +|------|----------|----------|------|--------| +| [YYYY-MM-DD] | 需求变更/架构调整/... | [描述] | [原因] | [姓名] | + +--- + +**项目负责人**:[姓名] +**开始时间**:[YYYY-MM-DD] +**预计完成**:[YYYY-MM-DD] +**实际完成**:[YYYY-MM-DD] +**项目状态**:⏳ 计划中 / 🔄 开发中 / ✅ 已完成 diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md new file mode 100644 index 0000000..3935a27 --- /dev/null +++ b/docs/QUICK_START.md @@ -0,0 +1,249 @@ +# 快速入门指南 + +本指南帮助您快速掌握 RIPER-5 + 三文档体系的开发流程。 + +## ⚡ 5 分钟快速上手 + +### 场景:我要开发一个新功能 + +**第 1 步:启动研究模式** + +``` +你对 AI 说:ENTER RESEARCH MODE + 我要开发一个任务优先级管理功能 +``` + +AI 会: +- 分析相关代码 +- 创建任务文件 `.tasks/2026-02-24_1_task-priority.md` +- 询问需求细节 + +--- + +**第 2 步:进入创新模式,生成设计** + +``` +你说:ENTER INNOVATE MODE +``` + +AI 会: +- 探索多种设计方案 +- 讨论技术选型 +- **自动创建** `docs/task-priority/design.md` + +--- + +**第 3 步:进入规划模式,制定计划** + +``` +你说:ENTER PLAN MODE +``` + +AI 会: +- 分解开发任务 +- **自动创建** `docs/task-priority/development.md` +- **自动创建** `docs/task-priority/cases.md` +- 生成实施清单 + +--- + +**第 4 步:审批并执行** + +``` +你说:ENTER EXECUTE MODE +``` + +AI 会: +- 严格按照 development.md 中的实施清单执行 +- 每完成一项,更新任务进度 +- 自动更新 development.md 的进度表 + +--- + +**第 5 步:完成后评审** + +``` +你说:ENTER REVIEW MODE +``` + +AI 会: +- 验证代码与计划的一致性 +- 检查文档是否同步 +- 生成最终评审报告 +- 准备 Git 提交 + +--- + +## 📚 文档在哪里? + +完成后,您会得到: + +``` +.tasks/ +└── 2026-02-24_1_task-priority.md # 任务跟踪文件 + +docs/ +└── task-priority/ # 功能文档目录 + ├── design.md # 设计文档 + ├── development.md # 开发计划 + └── cases.md # 测试用例 + +src/code/agent/services/ +└── task-priority/ # 代码实现 + ├── __init__.py + ├── priority_manager.py + └── ... +``` + +--- + +## 🎓 关键命令速查 + +### 模式切换命令 + +```bash +ENTER RESEARCH MODE # 研究和分析 +ENTER INNOVATE MODE # 设计和创新 +ENTER PLAN MODE # 详细规划 +ENTER EXECUTE MODE # 执行实施 +ENTER REVIEW MODE # 审查验证 +``` + +### 文档查看命令 + +```bash +# 查看所有功能的设计文档 +find docs -name "design.md" + +# 查看特定功能的所有文档 +ls docs/[feature-name]/ + +# 查看任务文件 +ls .tasks/ +``` + +### Git 工作流 + +```bash +# AI 在 RESEARCH 阶段会自动创建分支 +# 分支名格式:task/[task-identifier]_[date]_[number] + +# 查看当前分支 +git branch + +# 查看任务文件(排除在提交之外) +cat .tasks/[task-file].md + +# REVIEW 阶段 AI 会自动提交代码(不包含 .tasks/) +``` + +--- + +## 💡 使用技巧 + +### 技巧 1:让 AI 主导流程 + +不需要记住所有细节,只需: +1. 说"ENTER RESEARCH MODE" +2. 描述你的需求 +3. 跟着 AI 的引导,逐个模式推进 + +### 技巧 2:随时查看文档 + +在任何阶段,你都可以: + +``` +你说:查看当前的设计文档 + 或 + development.md 的进度如何? +``` + +### 技巧 3:灵活调整 + +发现问题时可以回退: + +``` +你说:回到 PLAN MODE,我需要调整设计 +``` + +### 技巧 4:并行开发 + +可以同时进行多个功能开发: +- 每个功能有独立的任务文件 +- 每个功能有独立的文档目录 +- 每个功能有独立的 Git 分支 + +--- + +## 🎯 第一次尝试 + +### 实践项目建议 + +选择一个简单功能练习流程,例如: + +``` +功能:添加配置验证器 +复杂度:中等 +预计时间:2-3 小时 +``` + +### 操作步骤 + +1. 打开 Cursor +2. 对 AI 说:"ENTER RESEARCH MODE,我要开发一个配置验证器功能" +3. 回答 AI 的问题 +4. 跟随 AI 的引导完成 5 个模式 +5. 查看生成的文档:`docs/config-validator/` + +--- + +## 📊 各模式时间分配参考 + +| 模式 | 典型耗时 | 产出 | +|------|----------|------| +| RESEARCH | 15-30 分钟 | 需求分析、代码调研 | +| INNOVATE | 20-40 分钟 | design.md | +| PLAN | 30-60 分钟 | development.md + cases.md | +| EXECUTE | 根据任务量 | 代码实现 + 测试 | +| REVIEW | 10-20 分钟 | 验证和评审 | + +--- + +## 🆘 遇到问题? + +### AI 没有创建文档? + +检查: +- 是否正确进入了相应模式? +- 是否在对话中明确了功能名称? + +### 文档内容不满意? + +可以: +- 要求 AI 重新生成:"请重新生成 design.md,增加架构图" +- 手动编辑文档 +- 在 REVIEW 阶段提出修改意见 + +### 不知道进展到哪一步了? + +查看任务文件: + +```bash +# 查看当前任务 +cat .tasks/[latest-task-file].md + +# 或者问 AI +"当前进度如何?" +``` + +--- + +## 🔗 相关文档 + +- [完整文档说明](README.md) +- [RIPER-5 规则](.cursor/rules/riper5.mdc) +- [Python 编码规范](.cursor/rules/python-coding-standards.mdc) + +--- + +**现在就开始您的第一个 RIPER-5 功能开发吧!** 🚀 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..22796a7 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,319 @@ +# 项目文档中心 + +本目录包含项目所有功能的设计、开发和测试文档。 + +## 📁 目录结构 + +``` +docs/ +├── README.md # 本文件 - 文档使用指南 +├── .templates/ # 文档模板 +│ ├── design.md # 设计文档模板 +│ ├── development.md # 开发计划模板 +│ └── cases.md # 测试用例模板 +│ +└── [feature-name]/ # 每个功能的文档目录 + ├── design.md # 设计文档 + ├── development.md # 开发计划 + └── cases.md # 测试用例 +``` + +--- + +## 🎯 三文档体系 + +每个功能包含三个核心文档: + +### 1️⃣ design.md - 设计文档 + +**创建阶段**:INNOVATE(创新阶段) + +**用途**:记录功能的设计思路和技术方案 + +**包含内容**: +- 功能概述和背景 +- 架构设计(组件关系、数据流) +- 数据模型和接口设计 +- 技术决策和权衡 +- 依赖关系 +- 风险和限制 +- 未来扩展方向 + +--- + +### 2️⃣ development.md - 开发计划 + +**创建阶段**:PLAN(规划阶段) + +**用途**:分解任务、跟踪进度、管理风险 + +**包含内容**: +- 任务分解(按阶段组织) +- 实施清单(原子操作列表) +- 开发进度表 +- 技术债务记录 +- 里程碑跟踪 +- 风险管理 +- 变更记录 + +--- + +### 3️⃣ cases.md - 测试文档 + +**创建阶段**:PLAN(规划阶段) + +**用途**:定义测试用例和验收标准 + +**包含内容**: +- 测试范围和环境 +- 单元测试用例(正常、异常、边界) +- 集成测试用例 +- 并发和性能测试 +- Mock 策略 +- 测试覆盖率目标 +- 已知问题和待办 + +--- + +## 🚀 使用 RIPER-5 流程开发新功能 + +### 完整流程 + +``` +[MODE: RESEARCH] → 分析代码、理解需求 + → 记录在任务文件的"分析"部分 + +[MODE: INNOVATE] → 探索方案、设计架构 + → 创建 docs/[feature]/design.md + +[MODE: PLAN] → 制定计划、分解任务 + → 创建 docs/[feature]/development.md + → 创建 docs/[feature]/cases.md + +[MODE: EXECUTE] → 按计划实施、更新进度 + → 更新 development.md 的任务状态 + +[MODE: REVIEW] → 验证实施、评审文档 + → 确认文档与代码一致 +``` + +### 启动新功能开发 + +1. **进入 RESEARCH 模式**: + ``` + 用户:ENTER RESEARCH MODE + 我要开发 [功能描述] + ``` + +2. **AI 会自动**: + - 分析相关代码 + - 创建任务文件 `.tasks/YYYY-MM-DD_n_[task-name].md` + - 询问澄清问题 + +3. **进入 INNOVATE 模式**: + ``` + 用户:ENTER INNOVATE MODE + ``` + +4. **AI 会创建**: + - `docs/[feature]/design.md` 设计文档 + - 在任务文件中记录设计摘要 + +5. **进入 PLAN 模式**: + ``` + 用户:ENTER PLAN MODE + ``` + +6. **AI 会创建**: + - `docs/[feature]/development.md` 开发计划 + - `docs/[feature]/cases.md` 测试用例 + - 在任务文件中记录实施清单 + +7. **批准并执行**: + ``` + 用户:ENTER EXECUTE MODE + ``` + +8. **完成后评审**: + ``` + 用户:ENTER REVIEW MODE + ``` + +--- + +## 📖 模板使用 + +### 获取模板 + +模板位置:`docs/.templates/` + +```bash +# 查看可用模板 +ls docs/.templates/ + +# 输出: +# design.md - 设计文档模板 +# development.md - 开发计划模板 +# cases.md - 测试文档模板 +``` + +### 手动创建文档(如需要) + +```bash +# 创建功能文档目录 +mkdir -p docs/your-feature + +# 复制模板 +cp docs/.templates/design.md docs/your-feature/design.md +cp docs/.templates/development.md docs/your-feature/development.md +cp docs/.templates/cases.md docs/your-feature/cases.md + +# 编辑文档 +# 将 [功能名称] 替换为实际功能名 +``` + +--- + +## 💡 最佳实践 + +### ✅ 推荐做法 + +1. **设计先行** + - 在 INNOVATE 阶段充分讨论设计方案 + - 评审设计文档后再进入 PLAN 阶段 + +2. **小步快跑** + - 将大功能拆分为小任务 + - 每个任务控制在 2-4 小时内完成 + +3. **持续更新** + - EXECUTE 阶段完成任务时更新 development.md + - 发现新问题时更新 cases.md + +4. **文档同步** + - 代码变更时同步更新设计文档 + - 重要决策记录在文档中 + +### ❌ 避免做法 + +1. **跳过文档创建** + - 不要直接跳到 EXECUTE 阶段 + - 文档是理清思路的过程 + +2. **文档与代码脱节** + - 避免"先写代码后补文档" + - 避免文档更新滞后 + +3. **文档过于简单或冗长** + - 简单:缺乏关键信息,后续维护困难 + - 冗长:维护成本高,难以阅读 + +--- + +## 📋 Code Review 检查清单 + +提交 PR 前,确认: + +### 文档检查 +- [ ] `docs/[feature]/design.md` 存在且内容完整 +- [ ] `docs/[feature]/development.md` 所有任务已完成 +- [ ] `docs/[feature]/cases.md` 测试用例已实现 +- [ ] 文档中的技术方案与代码实现一致 +- [ ] 变更记录已更新 + +### 代码检查 +- [ ] 遵循 Python 编码规范 +- [ ] 所有函数有类型注解 +- [ ] 异常处理恰当 +- [ ] 日志记录合理 + +### 测试检查 +- [ ] 所有测试用例已实现并通过 +- [ ] 测试覆盖率达标(≥ 85%) +- [ ] 包含异常场景测试 +- [ ] Mock 使用恰当 + +--- + +## 🔍 查找现有文档 + +```bash +# 查找所有设计文档 +find docs -name "design.md" + +# 查找所有开发计划 +find docs -name "development.md" + +# 查找所有测试文档 +find docs -name "cases.md" + +# 查看特定功能的文档 +ls -lh docs/[feature-name]/ +``` + +--- + +## 📚 相关规范 + +- **RIPER-5 工作模式**:`.cursor/rules/riper5.mdc` + - 定义 5 个工作模式 + - 任务文件模板 + - 文档创建流程 + +- **Python 编码规范**:`.cursor/rules/python-coding-standards.mdc` + - 类型注解、命名约定 + - 错误处理、测试模式 + - 代码质量标准 + +--- + +## ❓ 常见问题 + +### Q1: 什么时候创建文档? + +**A**: +- **design.md**:INNOVATE 阶段(编码前) +- **development.md + cases.md**:PLAN 阶段(编码前) + +### Q2: 小功能也需要三个文档吗? + +**A**: 根据复杂度决定: +- 简单工具函数:只需代码文档字符串 +- 独立类或模块:至少需要 design.md +- 完整服务或子系统:需要完整三个文档 + +### Q3: AI 会自动创建文档吗? + +**A**: 是的!当您使用 RIPER-5 模式时: +- INNOVATE 阶段会自动创建 design.md +- PLAN 阶段会自动创建 development.md 和 cases.md + +### Q4: 如何保持文档不过期? + +**A**: +- 在 Code Review 中检查文档更新 +- 重大变更时在 development.md 的变更记录中记录 +- REVIEW 阶段验证文档与代码一致性 + +### Q5: 文档应该多详细? + +**A**: 以"三个月后自己或新同事能看懂"为标准。重点是: +- **设计文档**:为什么这样设计(而不是做了什么) +- **开发文档**:任务划分和依赖关系 +- **测试文档**:主要测试场景和验收标准 + +--- + +## 🎓 示例学习 + +建议按以下顺序学习: + +1. **阅读本文档**(10 分钟) +2. **查看模板**:`docs/.templates/` 目录(15 分钟) +3. **实践**:用 RIPER-5 模式开发一个小功能(1-2 小时) + +--- + +**维护人**:开发团队 +**创建时间**:2026-02-24 +**最后更新**:2026-02-24 diff --git a/docs/snapshot-manager/cases.md b/docs/snapshot-manager/cases.md new file mode 100644 index 0000000..306c576 --- /dev/null +++ b/docs/snapshot-manager/cases.md @@ -0,0 +1,505 @@ +# 工作空间快照管理 测试用例 + +> 本文档在 PLAN 阶段创建 | 示例文档供参考 + +## 1. 测试概述 + +### 测试范围 +- **功能范围**:工作空间快照的加载、保存和选择功能 +- **测试类型**: + - ✅ 单元测试 + - ✅ 集成测试 + - ⬜ 端到端测试(由上层服务负责) + - ⬜ 性能测试(后续补充) + +### 测试环境 +- **Python 版本**:3.9+ +- **测试框架**:pytest + unittest.mock +- **依赖服务**:无外部服务依赖,仅需文件系统 +- **测试数据**:Mock 数据,避免真实文件操作 + +--- + +## 2. 单元测试用例 + +### 2.1 SnapshotManager.load() + +#### 测试用例 1.1:正常流程 - 加载指定快照 + +**测试目标**:验证加载指定名称的快照 + +**前置条件**: +- 快照目录存在 +- 快照文件完整 + +**测试步骤**: +1. 创建 SnapshotManager 实例 +2. Mock 快照目录和 Loader +3. 调用 load("dev-20260115-120000") +4. 验证返回结果和状态更新 + +**预期结果**: +- 返回字典包含快照名称 +- cur_snapshot_name 被正确设置 +- Loader 被正确调用 + +**实现代码**: + +```python +def test_load_specified_snapshot_success(self, snapshot_manager): + """测试用例 1.1: 加载指定快照成功""" + # Given + snapshot_name = "dev-20260115-120000" + + with patch('os.path.exists', return_value=True): + with patch('services.workspace.snapshot_loader.ComfyUIDevSnapshotLoader') as mock_loader: + mock_loader.return_value.load.return_value = {"timing": {"load": 1000}} + + # When + result = snapshot_manager.load(snapshot_name) + + # Then + assert result["snapshot"] == snapshot_name + assert snapshot_manager.cur_snapshot_name == snapshot_name +``` + +**状态**:✅ 已通过 + +--- + +#### 测试用例 1.2:异常处理 - 快照不存在 + +**测试目标**:验证加载不存在快照时抛出 RuntimeError + +**前置条件**: +- 快照目录不存在 + +**测试步骤**: +1. Mock os.path.exists 返回 False +2. 调用 load("non-existent") +3. 捕获并验证异常 + +**预期结果**: +- 抛出 RuntimeError +- 错误消息包含快照名称和 "not found" + +**实现代码**: + +```python +def test_load_nonexistent_snapshot_error(self, snapshot_manager): + """测试用例 1.2: 快照不存在抛出异常""" + # Given + snapshot_name = "non-existent-snapshot" + + # When & Then + with patch('os.path.exists', return_value=False): + with pytest.raises(RuntimeError) as exc_info: + snapshot_manager.load(snapshot_name) + + assert snapshot_name in str(exc_info.value) + assert "not found" in str(exc_info.value).lower() +``` + +**状态**:✅ 已通过 + +--- + +#### 测试用例 1.3:边界值测试 - latest-dev 自动选择 + +**测试目标**:验证使用 "latest-dev" 自动选择最新开发快照 + +**前置条件**: +- 存在多个开发快照 + +**测试步骤**: +1. Mock _select_latest_snapshot 返回最新快照 +2. 调用 load("latest-dev") +3. 验证调用了正确的选择方法 + +**预期结果**: +- 调用 _select_latest_snapshot("dev") +- 加载返回的最新快照 + +**实现代码**: + +```python +def test_load_latest_dev_snapshot(self, snapshot_manager): + """测试用例 1.3: 使用 latest-dev 加载最新快照""" + # Given + latest_snapshot = "dev-20260120-150000" + + with patch.object(snapshot_manager, '_select_latest_snapshot', return_value=latest_snapshot): + with patch('os.path.exists', return_value=True): + with patch('services.workspace.snapshot_loader.ComfyUIDevSnapshotLoader') as mock_loader: + mock_loader.return_value.load.return_value = {} + + # When + result = snapshot_manager.load("latest-dev") + + # Then + assert result["snapshot"] == latest_snapshot + snapshot_manager._select_latest_snapshot.assert_called_once_with("dev") +``` + +**状态**:✅ 已通过 + +--- + +#### 测试用例 1.4:边界值测试 - 幂等性 + +**测试目标**:验证重复加载已加载的快照会跳过 + +**测试步骤**: +1. 设置 cur_snapshot_name +2. 再次加载同一快照 +3. 验证直接返回,不执行实际加载 + +**预期结果**: +- 直接返回快照名称 +- 不调用 Loader + +**实现代码**: + +```python +def test_load_same_snapshot_twice_idempotent(self, snapshot_manager): + """测试用例 1.4: 重复加载同一快照(幂等性)""" + # Given + snapshot_name = "dev-20260115" + snapshot_manager.cur_snapshot_name = snapshot_name + + # When + result = snapshot_manager.load(snapshot_name) + + # Then + assert result["snapshot"] == snapshot_name +``` + +**状态**:✅ 已通过 + +--- + +### 2.2 SnapshotManager.save() + +#### 测试用例 2.1:正常流程 - 自动生成名称 + +**测试目标**:验证保存快照时自动生成时间戳名称 + +**实现代码**: + +```python +def test_save_snapshot_auto_name(self, snapshot_manager): + """测试用例 2.1: 保存快照自动生成名称""" + # Given + snapshot_type = "dev" + + with patch('services.workspace.snapshot_saver.SnapshotSaver') as mock_saver: + mock_saver.return_value.save.return_value = {"snapshot": "dev-20260124-120000"} + + # When + result = snapshot_manager.save(snapshot_type) + + # Then + assert "snapshot" in result + assert result["snapshot"].startswith("dev-") +``` + +**状态**:✅ 已通过 + +--- + +#### 测试用例 2.2:正常流程 - 指定名称 + +**测试目标**:验证使用指定名称保存快照 + +**实现代码**: + +```python +def test_save_snapshot_custom_name(self, snapshot_manager): + """测试用例 2.2: 使用自定义名称保存快照""" + # Given + snapshot_type = "prod" + custom_name = "pre-stop-backup" + + with patch('services.workspace.snapshot_saver.SnapshotSaver') as mock_saver: + mock_saver.return_value.save.return_value = {"snapshot": custom_name} + + # When + result = snapshot_manager.save(snapshot_type, snapshot_name=custom_name) + + # Then + assert result["snapshot"] == custom_name +``` + +**状态**:✅ 已通过 + +--- + +### 2.3 SnapshotManager._select_latest_snapshot() + +#### 测试用例 3.1:正常流程 - 多个候选 + +**测试目标**:验证从多个快照中选择最新的 + +**实现代码**: + +```python +def test_select_latest_snapshot_multiple(self, snapshot_manager): + """测试用例 3.1: 从多个快照中选择时间最新的""" + # Given + snapshots = [ + "dev-20260120-100000", + "dev-20260122-100000", # 最新 + "dev-20260119-100000", + "prod-20260121-100000", # 不同类型,应被过滤 + ] + + with patch('os.listdir', return_value=snapshots): + # When + result = snapshot_manager._select_latest_snapshot("dev") + + # Then + assert result == "dev-20260122-100000" +``` + +**状态**:✅ 已通过 + +--- + +#### 测试用例 3.2:边界值测试 - 无匹配快照 + +**测试目标**:验证没有匹配类型的快照时返回 None + +**实现代码**: + +```python +def test_select_latest_snapshot_none_found(self, snapshot_manager): + """测试用例 3.2: 无匹配快照返回 None""" + # Given + snapshots = ["prod-20260120-100000"] # 只有 prod 类型 + + with patch('os.listdir', return_value=snapshots): + # When + result = snapshot_manager._select_latest_snapshot("dev") + + # Then + assert result is None +``` + +**状态**:✅ 已通过 + +--- + +## 3. 集成测试用例 + +### 3.1 完整流程测试 + +#### 测试用例 4.1:端到端 - 保存并加载 + +**测试目标**:验证保存后能正确加载的完整流程 + +**测试场景**: +用户保存当前工作空间为快照,然后加载该快照恢复状态 + +**测试步骤**: +1. 调用 save("dev") 保存快照 +2. 获取返回的快照名称 +3. 调用 load(snapshot_name) 加载 +4. 验证状态一致 + +**预期结果**: +- 保存成功返回快照名称 +- 加载成功恢复状态 +- cur_snapshot_name 正确更新 + +**状态**:✅ 已通过 + +--- + +## 4. 特殊场景测试 + +### 4.1 并发测试 + +#### 测试用例 5.1:并发加载不同快照 + +**测试目标**:验证多线程同时加载不同快照的安全性 + +**实现代码**: + +```python +def test_concurrent_load_different_snapshots(self): + """测试用例 5.1: 并发加载不同快照""" + import threading + + results = [] + def load_snapshot(name): + result = snapshot_manager.load(name) + results.append(result) + + threads = [ + threading.Thread(target=load_snapshot, args=(f"dev-snapshot-{i}",)) + for i in range(5) + ] + + for t in threads: + t.start() + for t in threads: + t.join() + + # 验证所有加载都完成(注:当前实现可能有竞态条件) + assert len(results) == 5 +``` + +**状态**:⚠️ 已通过(标记为技术债务:需要添加并发保护) + +--- + +## 5. Mock 策略 + +### 需要 Mock 的组件 + +| 组件 | Mock 方式 | 原因 | +|------|-----------|------| +| 文件系统 | `@patch('os.path.exists')` | 避免实际文件操作,加速测试 | +| 目录列表 | `@patch('os.listdir')` | 控制快照列表,测试选择逻辑 | +| SnapshotLoader | `@patch('services.workspace.snapshot_loader.ComfyUIDevSnapshotLoader')` | 隔离加载器实现 | +| SnapshotSaver | `@patch('services.workspace.snapshot_saver.SnapshotSaver')` | 隔离保存器实现 | + +### Mock Fixture + +```python +@pytest.fixture +def snapshot_manager(): + """创建测试用的 SnapshotManager 实例""" + manager = SnapshotManager() + yield manager + +@pytest.fixture +def mock_snapshot_dir(): + """Mock 快照目录存在""" + with patch('os.path.exists', return_value=True): + with patch('os.listdir', return_value=["dev-20260115", "prod-20260116"]): + yield +``` + +--- + +## 6. 测试覆盖率 + +### 覆盖率目标 + +- **核心业务逻辑**:≥ 90% +- **工具函数**:≥ 85% +- **异常处理**:≥ 80% +- **总体目标**:≥ 85% + +### 当前覆盖率 + +| 模块 | 行覆盖率 | 分支覆盖率 | 目标 | 状态 | +|------|----------|-----------|------|------| +| snapshot_manager.py | 88% | 85% | 90% | ⚠️ 接近目标 | +| snapshot_loader.py | 92% | 90% | 90% | ✅ 达标 | +| snapshot_saver.py | 91% | 88% | 90% | ✅ 达标 | +| **总计** | **90%** | **88%** | **85%** | ✅ 达标 | + +### 未覆盖代码 + +- `snapshot_manager.py:156-158` - 磁盘满异常分支(难以模拟) +- `snapshot_manager.py:201` - 日志记录代码(非关键路径) + +### 运行测试命令 + +```bash +# 运行快照管理器测试 +pytest test/unit/services/workspace/snapshot_manager_test.py -v + +# 查看覆盖率 +pytest test/unit/services/workspace/ --cov=src/code/agent/services/workspace --cov-report=html + +# 运行特定测试 +pytest test/unit/services/workspace/snapshot_manager_test.py::TestSnapshotManager::test_load_specified_snapshot_success -v +``` + +--- + +## 7. 测试数据 + +### 正常测试数据 + +```python +VALID_SNAPSHOTS = { + "dev": [ + "dev-20260115-120000", + "dev-20260116-120000", + "dev-20260120-150000", + ], + "prod": [ + "prod-20260115-090000", + "prod-20260116-090000", + ], +} +``` + +### 异常测试数据 + +```python +INVALID_INPUTS = { + "null": None, + "empty": "", + "invalid_path": "../../../etc/passwd", # 路径遍历 + "nonexistent": "snapshot-does-not-exist", +} +``` + +--- + +## 8. 已知问题 + +### 测试中发现的问题 + +- [x] **问题1:大快照加载超时** + - 严重程度:中 + - 发现时间:2026-01-18 + - 影响范围:超过 5GB 的快照加载时间超过 30 秒 + - 责任人:张三 + - 状态:✅ 已修复(添加了超时配置和进度显示) + - 修复时间:2026-01-19 + +- [x] **问题2:并发保存导致文件损坏** + - 严重程度:高 + - 发现时间:2026-01-21 + - 影响范围:多个进程同时保存可能导致文件不完整 + - 责任人:李四 + - 状态:✅ 已修复(添加了文件锁机制) + - 修复时间:2026-01-22 + +- [x] **问题3:重复加载浪费性能** + - 严重程度:低 + - 发现时间:2026-01-27 + - 影响范围:重复加载已加载快照会执行冗余操作 + - 责任人:张三 + - 状态:✅ 已修复(添加了幂等性检查) + - 修复时间:2026-01-27 + +### 待补充的测试用例 + +- [ ] **场景1:磁盘空间不足** + - 描述:保存快照时磁盘空间不足的处理 + - 优先级:低 + - 原因:难以模拟,实际场景罕见 + +- [ ] **场景2:快照损坏恢复** + - 描述:加载损坏快照时的降级处理 + - 优先级:中 + - 原因:需要实现快照完整性校验 + +- [ ] **场景3:性能压测** + - 描述:超大快照(>10GB)的加载性能 + - 优先级:低 + - 原因:需要准备大规模测试数据 + +--- + +**测试负责人**:赵六 +**创建时间**:2026-01-15 +**最后更新**:2026-01-30 +**测试状态**:✅ 测试完成(覆盖率达标 90%) diff --git a/docs/snapshot-manager/design.md b/docs/snapshot-manager/design.md new file mode 100644 index 0000000..ca7994b --- /dev/null +++ b/docs/snapshot-manager/design.md @@ -0,0 +1,215 @@ +# 工作空间快照管理 设计文档 + +> 本文档在 INNOVATE 阶段创建 | 示例文档供参考 + +## 1. 概述 + +工作空间快照管理功能用于保存和恢复 ComfyUI/SD 工作空间的完整状态,支持开发环境和生产环境的快照管理,实现环境快速切换和状态恢复。 + +## 2. 背景 + +### 业务需求 +用户需要在不同的工作空间状态之间快速切换,支持开发和生产环境隔离,实现"一键恢复"功能。 + +### 现有问题 +- 手动备份工作空间耗时且容易出错 +- 缺乏统一的快照管理机制 +- 环境切换需要重新配置,效率低下 +- 无法快速回滚到之前的稳定状态 + +### 目标用户 +- 开发者:频繁切换开发和测试环境 +- 运维人员:需要快速恢复生产环境 +- 用户:希望保存和分享工作空间配置 + +## 3. 架构设计 + +### 3.1 整体架构 + +``` +┌───────────────────────────────────────────────────────┐ +│ SnapshotManager (协调器) │ +│ + load(snapshot_name: str) -> Dict │ +│ + save(snapshot_type: str, name: Optional) -> Dict │ +│ - _select_latest_snapshot(type: str) -> Optional[str]│ +└────────────────┬────────────────────┬─────────────────┘ + │ │ + ┌────────▼────────┐ ┌──────▼──────┐ + │ SnapshotLoader │ │ SnapshotSaver│ + │ (策略接口) │ │ (保存器) │ + └────────┬────────┘ └──────────────┘ + │ + ┌────────────┼────────────┐ + │ │ │ +┌───▼────┐ ┌───▼────┐ ┌───▼────┐ +│ComfyUI │ │ComfyUI │ │ SD │ +│ Dev │ │ Prod │ │ Loader │ +│ Loader │ │ Loader │ │ │ +└────────┘ └────────┘ └────────┘ +``` + +**设计模式**:策略模式 + 模板方法 + +### 3.2 核心类/模块 + +- `SnapshotManager`: 快照管理器,协调加载和保存操作,管理当前快照状态 +- `SnapshotLoader`: 快照加载器基类,定义加载接口(抽象策略) +- `ComfyUIDevSnapshotLoader`: ComfyUI 开发环境加载策略 +- `ComfyUIProdSnapshotLoader`: ComfyUI 生产环境加载策略 +- `SDSnapshotLoader`: Stable Diffusion 加载策略 +- `SnapshotSaver`: 快照保存器,处理快照持久化和压缩 + +### 3.3 数据模型 + +```python +class SnapshotManager: + """快照管理器""" + + # 常量定义 + USE_LATEST_DEV: str = "latest-dev" # 使用最新开发快照 + USE_LATEST_PROD: str = "latest-prod" # 使用最新生产快照 + TYPE_DEV: str = "dev" # 开发环境类型 + TYPE_PROD: str = "prod" # 生产环境类型 + + # 实例属性 + cur_snapshot_name: Optional[str] # 当前加载的快照名称 +``` + +快照返回数据结构: + +```python +{ + "snapshot": "snapshot-name", # 快照名称 + "timing": { # 各阶段耗时(可选) + "load_time": 1234, # 加载耗时(毫秒) + "extract_time": 567, # 解压耗时(毫秒) + } +} +``` + +### 3.4 接口设计 + +#### 加载快照 + +```python +def load(self, snapshot_name: str) -> Dict[str, Any]: + """加载快照 + + Args: + snapshot_name: 快照名称,支持特殊值: + - "latest-dev": 自动选择最新开发快照 + - "latest-prod": 自动选择最新生产快照 + - 具体快照名: 直接加载指定快照 + + Returns: + 包含快照名称和耗时信息的字典 + + Raises: + RuntimeError: 快照不存在时抛出 + """ +``` + +#### 保存快照 + +```python +def save(self, snapshot_type: str, snapshot_name: Optional[str] = None) -> Dict[str, Any]: + """保存快照 + + Args: + snapshot_type: 快照类型,"dev" 或 "prod" + snapshot_name: 可选的快照名称,不提供则自动生成 + + Returns: + 包含快照名称和保存信息的字典 + """ +``` + +## 4. 技术决策 + +| 决策点 | 备选方案 | 最终选择 | 原因 | +|--------|----------|----------|------| +| 架构模式 | 简单继承 / 策略模式 | 策略模式 | 需要支持多种环境(Dev/Prod/SD),策略模式更灵活易扩展 | +| 快照存储 | 云存储 / 本地文件系统 | 本地文件系统 | 简化部署,支持挂载外部存储,满足当前需求 | +| 快照命名 | UUID / 时间戳 / 自定义 | 时间戳 + 自定义 | 时间戳便于排序和查找,同时支持自定义名称(preStop场景) | +| 并发控制 | 文件锁 / 分布式锁 | 暂不加锁 | 当前并发场景少,后续可扩展 | +| 错误处理 | 返回错误码 / 抛出异常 | 抛出异常 | 符合项目异常体系规范 | + +### 权衡考虑 + +- **本地存储 vs 云存储**: + - 本地存储优势:速度快、实现简单、无外部依赖 + - 本地存储劣势:占用磁盘空间、无法跨机器共享 + - 最终选择:本地存储,预留云端备份扩展点 + +- **策略模式 vs 简单继承**: + - 策略模式优势:灵活性高、易于添加新环境支持 + - 策略模式劣势:类更多、代码量稍大 + - 最终选择:策略模式,因为已知需要支持多种环境 + +## 5. 依赖关系 + +### 依赖的模块 +- `constants`: 配置常量(快照目录路径、后端类型等) +- `utils.timer`: 性能计时工具 +- `utils.logger`: 日志记录 +- `services.workspace.snapshot_loader`: 加载器策略实现 +- `services.workspace.snapshot_saver`: 保存器实现 + +### 被依赖的模块 +- `routes.management_routes`: 管理路由调用快照功能 +- `services.management_service`: 管理服务封装快照接口 + +``` +依赖图: +[ManagementService] ──┐ +[ManagementRoutes] ───┤ + ├──▶ [SnapshotManager] ──┬──▶ [SnapshotLoader] + │ └──▶ [SnapshotSaver] + │ + └──▶ [Constants] + [Logger] + [Timer] +``` + +## 6. 风险和限制 + +### 已知风险 + +- **风险1:磁盘空间不足** + - 影响程度:高 + - 应对措施:定期清理旧快照、设置快照数量上限、监控磁盘使用率 + - 责任人:运维团队 + +- **风险2:快照加载失败** + - 影响程度:高 + - 应对措施:保存时添加完整性校验(checksum)、加载前验证文件完整性 + - 责任人:开发团队 + +- **风险3:大快照加载超时** + - 影响程度:中 + - 应对措施:添加超时配置、显示加载进度、考虑异步加载 + - 责任人:开发团队 + +### 限制条件 + +- **快照大小限制**:取决于工作空间大小,可能达到 GB 级别 +- **加载时间限制**:大快照(>5GB)加载可能需要 10-30 秒 +- **并发限制**:暂不支持同时多个快照操作(未来可优化) +- **兼容性限制**:旧版本快照可能与新版本不兼容 + +## 7. 未来扩展 + +- **增量快照**:只保存变更部分,减少存储空间和加载时间 +- **快照压缩**:使用 gzip/zstd 压缩快照文件 +- **云端备份**:支持将快照上传到 OSS/S3 +- **快照版本管理**:支持快照的版本控制和回滚历史 +- **快照分享**:团队成员之间共享快照配置 +- **增量恢复**:支持部分恢复(仅恢复特定目录) +- **快照元数据**:记录创建时间、创建者、标签等信息 + +--- + +**作者**:示例文档 +**创建时间**:2026-02-24 +**最后更新**:2026-02-24 +**评审状态**:✅ 示例文档 diff --git a/docs/snapshot-manager/development.md b/docs/snapshot-manager/development.md new file mode 100644 index 0000000..6ecad80 --- /dev/null +++ b/docs/snapshot-manager/development.md @@ -0,0 +1,226 @@ +# 工作空间快照管理 开发计划 + +> 本文档在 PLAN 阶段创建 | 示例文档供参考 + +## 1. 任务分解 + +### 阶段 1:基础设施 + +- [x] **任务 1.1**:创建 SnapshotManager 基础类 + - **描述**:实现管理器的基础结构、常量定义和属性初始化 + - **工作量估算**:2 小时 + - **负责人**:张三 + - **优先级**:高 + - **依赖**:无 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-16 + +- [x] **任务 1.2**:定义快照数据模型 + - **描述**:定义快照类型常量(DEV/PROD)和返回数据结构 + - **工作量估算**:1 小时 + - **负责人**:张三 + - **优先级**:高 + - **依赖**:无 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-16 + +### 阶段 2:核心功能 + +- [x] **任务 2.1**:实现快照加载逻辑 + - **描述**:实现 load() 方法,支持加载指定快照和 latest-dev/prod + - **工作量估算**:4 小时 + - **负责人**:张三 + - **优先级**:高 + - **依赖**:任务 1.1, 1.2 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-18 + +- [x] **任务 2.2**:实现快照保存逻辑 + - **描述**:实现 save() 方法,支持自动生成快照名称和自定义名称 + - **工作量估算**:3 小时 + - **负责人**:李四 + - **优先级**:高 + - **依赖**:任务 1.1, 1.2 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-19 + +- [x] **任务 2.3**:实现最新快照选择逻辑 + - **描述**:实现 _select_latest_snapshot() 私有方法,从目录中筛选和排序 + - **工作量估算**:2 小时 + - **负责人**:张三 + - **优先级**:高 + - **依赖**:任务 2.1 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-20 + +- [x] **任务 2.4**:实现加载器策略 + - **描述**:创建 ComfyUIDevLoader、ComfyUIProdLoader、SDLoader 三个策略类 + - **工作量估算**:6 小时 + - **负责人**:李四 + - **优先级**:高 + - **依赖**:任务 2.1 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-22 + +- [x] **任务 2.5**:实现保存器 + - **描述**:创建 SnapshotSaver,处理文件复制和目录结构 + - **工作量估算**:4 小时 + - **负责人**:李四 + - **优先级**:高 + - **依赖**:任务 2.2 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-23 + +- [x] **任务 2.6**:添加错误处理和日志 + - **描述**:添加异常处理、错误日志记录和性能计时 + - **工作量估算**:2 小时 + - **负责人**:张三 + - **优先级**:高 + - **依赖**:任务 2.1, 2.2 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-24 + +### 阶段 3:集成和测试 + +- [x] **任务 3.1**:集成到 ManagementService + - **描述**:在管理服务中暴露快照管理接口 + - **工作量估算**:2 小时 + - **负责人**:王五 + - **优先级**:高 + - **依赖**:任务 2.6 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-25 + +- [x] **任务 3.2**:编写单元测试 + - **描述**:实现 cases.md 中定义的单元测试用例 + - **工作量估算**:5 小时 + - **负责人**:赵六 + - **优先级**:高 + - **依赖**:任务 2.6 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-27 + - **覆盖率**:88% + +- [x] **任务 3.3**:编写集成测试 + - **描述**:测试完整的加载和保存流程 + - **工作量估算**:3 小时 + - **负责人**:赵六 + - **优先级**:中 + - **依赖**:任务 3.1, 3.2 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-28 + +### 阶段 4:优化和文档 + +- [x] **任务 4.1**:性能优化 + - **描述**:优化大文件快照的加载速度,添加进度提示 + - **工作量估算**:3 小时 + - **负责人**:张三 + - **优先级**:中 + - **依赖**:任务 3.3 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-29 + +- [x] **任务 4.2**:完善文档 + - **描述**:更新 design.md 和 cases.md,补充实际实现细节 + - **工作量估算**:1 小时 + - **负责人**:张三 + - **优先级**:中 + - **依赖**:任务 4.1 + - **状态**:✅ 已完成 + - **完成时间**:2026-01-30 + +## 2. 实施清单 + +EXECUTE 阶段按此清单执行: + +1. 创建 `services/workspace/snapshot_manager.py` 文件 +2. 定义 `SnapshotManager` 类和常量 +3. 实现 `__init__()` 方法初始化属性 +4. 实现 `load()` 方法的基础框架 +5. 实现 `_select_latest_snapshot()` 私有方法 +6. 添加快照存在性检查和错误处理 +7. 集成 SnapshotLoader 策略选择逻辑 +8. 实现 `save()` 方法的基础框架 +9. 添加快照名称自动生成逻辑 +10. 集成 SnapshotSaver +11. 添加性能计时和日志记录 +12. 创建 `services/workspace/snapshot_loader.py` 定义加载器接口 +13. 实现 ComfyUIDevSnapshotLoader +14. 实现 ComfyUIProdSnapshotLoader +15. 实现 SDSnapshotLoader +16. 创建 `services/workspace/snapshot_saver.py` +17. 实现保存器的文件复制逻辑 +18. 在 ManagementService 中集成快照管理 +19. 编写单元测试(参考 cases.md) +20. 编写集成测试 +21. 运行测试并达到覆盖率目标 + +## 3. 开发进度 + +| 阶段 | 计划任务数 | 已完成 | 进行中 | 待开始 | 进度 | +|------|-----------|--------|--------|--------|------| +| 阶段 1 | 2 | 2 | 0 | 0 | 100% | +| 阶段 2 | 6 | 6 | 0 | 0 | 100% | +| 阶段 3 | 3 | 3 | 0 | 0 | 100% | +| 阶段 4 | 2 | 2 | 0 | 0 | 100% | +| **总计** | **13** | **13** | **0** | **0** | **100%** | + +## 4. 技术债务 + +- [x] **债务1:快照清理机制** + - 影响程度:中 + - 产生原因:首版未实现自动清理,担心磁盘空间耗尽 + - 计划处理时间:2026-02-15 + - 责任人:张三 + - 状态:✅ 已完成(添加了基于时间和数量的清理策略) + +- [ ] **债务2:快照版本兼容性** + - 影响程度:低 + - 产生原因:快照格式可能随版本变化 + - 计划处理时间:2026-03-01 + - 责任人:待定 + - 状态:待处理 + +- [ ] **债务3:并发安全性** + - 影响程度:低 + - 产生原因:当前无并发场景,未加锁保护 + - 计划处理时间:有并发需求时 + - 责任人:待定 + - 状态:监控中 + +## 5. 里程碑 + +| 里程碑 | 目标日期 | 状态 | 完成日期 | 备注 | +|--------|----------|------|----------|------| +| 设计评审完成 | 2026-01-15 | ✅ 完成 | 2026-01-15 | 设计方案获批准 | +| 核心功能完成 | 2026-01-24 | ✅ 完成 | 2026-01-24 | 按计划完成 | +| 测试完成 | 2026-01-28 | ✅ 完成 | 2026-01-28 | 覆盖率 88% 达标 | +| 上线发布 | 2026-01-31 | ✅ 完成 | 2026-01-30 | 提前 1 天完成 | + +## 6. 风险跟踪 + +| 风险描述 | 影响程度 | 概率 | 应对措施 | 责任人 | 状态 | +|----------|----------|------|----------|--------|------| +| 大快照加载超时 | 高 | 中 | 添加超时配置和进度显示 | 张三 | ✅ 已解决 | +| 快照存储空间不足 | 高 | 低 | 监控磁盘、定期清理旧快照 | 运维 | 监控中 | +| 并发保存冲突 | 中 | 低 | 添加文件锁机制 | 李四 | ✅ 已解决 | +| 快照损坏 | 中 | 低 | 保存时添加校验和 | 李四 | ✅ 已解决 | + +## 7. 变更记录 + +| 日期 | 变更类型 | 变更内容 | 原因 | 负责人 | +|------|----------|----------|------|--------| +| 2026-01-20 | 功能增强 | 添加 latest-dev/prod 特殊值支持 | 简化用户使用,避免手动查找最新快照 | 张三 | +| 2026-01-22 | 架构调整 | 将 Loader 拆分为 Dev 和 Prod 两个策略类 | 职责更清晰,便于扩展 | 李四 | +| 2026-01-23 | 功能增强 | 保存器支持自定义快照名称 | 支持 preStop 场景预先生成名称 | 李四 | +| 2026-01-26 | 性能优化 | 添加加载过程的性能计时 | 便于监控和优化,发现性能瓶颈 | 张三 | +| 2026-01-27 | Bug 修复 | 修复重复加载同一快照的冗余操作 | 提升性能,避免不必要的 I/O | 张三 | + +--- + +**项目负责人**:张三 +**开始时间**:2026-01-15 +**预计完成**:2026-01-31 +**实际完成**:2026-01-30 +**项目状态**:✅ 已完成 From 0bced08558e28c8c1f69175212686708ccc00d2c Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Wed, 25 Feb 2026 17:40:31 +0800 Subject: [PATCH 2/3] feat: add GitHub CI with 95% diff coverage check and GitHub Pages deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add pytest and coverage configuration files - Create GitHub Actions workflow for automated testing - Implement diff-cover tool to check new code coverage (≥95%) - Auto-deploy coverage reports to GitHub Pages on cap branch - Add test dependencies (pytest, pytest-cov, diff-cover) Change-Id: Iac9579d473b32765a34f412ada2be3cd3944082c Co-developed-by: Cursor Co-authored-by: Cursor --- .github/workflows/test-coverage.yml | 119 ++++ .gitignore | 8 + .tasks/2026-02-25_1_github-ci-coverage.md | 171 +++++ docs/github-ci-coverage/cases.md | 805 ++++++++++++++++++++++ docs/github-ci-coverage/design.md | 695 +++++++++++++++++++ docs/github-ci-coverage/development.md | 726 +++++++++++++++++++ src/code/agent/.coveragerc | 29 + src/code/agent/pytest.ini | 9 + src/code/agent/requirements-dev.txt | 3 + 9 files changed, 2565 insertions(+) create mode 100644 .github/workflows/test-coverage.yml create mode 100644 .tasks/2026-02-25_1_github-ci-coverage.md create mode 100644 docs/github-ci-coverage/cases.md create mode 100644 docs/github-ci-coverage/design.md create mode 100644 docs/github-ci-coverage/development.md create mode 100644 src/code/agent/.coveragerc create mode 100644 src/code/agent/pytest.ini create mode 100644 src/code/agent/requirements-dev.txt diff --git a/.github/workflows/test-coverage.yml b/.github/workflows/test-coverage.yml new file mode 100644 index 0000000..830848c --- /dev/null +++ b/.github/workflows/test-coverage.yml @@ -0,0 +1,119 @@ +name: Test Coverage + +on: + push: + branches: + - '**' + +permissions: + contents: write + +jobs: + test-coverage: + runs-on: ubuntu-latest + + steps: + - name: Checkout code with full history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' + + - name: Install dependencies + working-directory: src/code/agent + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt + + - name: Run tests with coverage + working-directory: src/code/agent + run: | + pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term + + - name: Check diff coverage against cap branch + working-directory: src/code/agent + run: | + diff-cover coverage.xml --compare-branch=origin/cap --fail-under=95 + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: src/code/agent/htmlcov/ + retention-days: 30 + + - name: Generate diff coverage HTML report + if: always() + working-directory: src/code/agent + run: | + diff-cover coverage.xml --compare-branch=origin/cap --html-report=diff-coverage.html + + - name: Upload diff coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: diff-coverage-report + path: src/code/agent/diff-coverage.html + retention-days: 30 + + - name: Create coverage index page + if: github.ref == 'refs/heads/cap' + working-directory: src/code/agent + run: | + mkdir -p gh-pages-deploy + cp -r htmlcov/* gh-pages-deploy/ + cp diff-coverage.html gh-pages-deploy/ + cat > gh-pages-deploy/index.html << 'EOF' + + + + + Coverage Reports - cap-comfyui + + + +

Coverage Reports - cap-comfyui Agent

+

Last updated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")

+ +
+

📊 Full Coverage Report

+

Complete test coverage report for all source code in src/code/agent/

+ View Full Coverage Report +
+ +
+

📈 Diff Coverage Report

+

Coverage report for code changes compared to the cap branch

+ View Diff Coverage Report +
+ +
+

ℹ️ About

+

These reports are automatically generated by GitHub Actions on every push to the cap branch.

+

Diff coverage threshold: ≥ 95%

+
+ + + EOF + + - name: Deploy to GitHub Pages + if: github.ref == 'refs/heads/cap' + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: src/code/agent/gh-pages-deploy + keep_files: false diff --git a/.gitignore b/.gitignore index f363988..8867eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,11 @@ **/dist .DS_Store .vscode/settings.json + +# Coverage reports +**/.coverage +**/.coverage.* +**/coverage.xml +**/htmlcov/ +**/diff-coverage.html +**/gh-pages-deploy/ diff --git a/.tasks/2026-02-25_1_github-ci-coverage.md b/.tasks/2026-02-25_1_github-ci-coverage.md new file mode 100644 index 0000000..c46c0ed --- /dev/null +++ b/.tasks/2026-02-25_1_github-ci-coverage.md @@ -0,0 +1,171 @@ +# 背景 +文件名:2026-02-25_1_github-ci-coverage.md +创建于:2026-02-25_17:00:00 +创建者:cici +主分支:cap +任务分支:task/github-ci-coverage_2026-02-25_1 +功能名称:github-ci-coverage +Yolo模式:Off + +# 任务描述 +setup 一个 github ci,要求新增代码的测试覆盖率高于 95% + +具体要求: +1. 测试执行目录:src/code/agent +2. 覆盖率范围:仅 src/code/agent 目录 +3. 基准分支:cap +4. CI 触发条件:每次 push 都运行 +5. 新增代码覆盖率阈值:≥ 95% + +# 项目概览 +- Python 版本: 3.10.16 +- 测试框架: pytest + coverage.py v7.13.4 +- 当前整体覆盖率: 77% +- 测试文件: 18 个单元测试文件位于 test/unit/ 目录 +- 项目类型: Flask 应用,包含 WebSocket、进程管理、任务管理等功能 +- 依赖管理: requirements.txt (需要新增测试依赖文件) + +# 文档结构 +本任务相关的文档: +- 设计文档:`docs/github-ci-coverage/design.md` (INNOVATE 阶段创建) +- 开发文档:`docs/github-ci-coverage/development.md` (PLAN 阶段创建) +- 测试文档:`docs/github-ci-coverage/cases.md` (PLAN 阶段创建) + +⚠️ 警告:永远不要修改此部分 ⚠️ +# RIPER-5 协议规则摘要 + +## 模式流程 +RESEARCH → INNOVATE → PLAN → EXECUTE → REVIEW + +## 核心原则 +- 每个响应必须声明当前模式:[MODE: MODE_NAME] +- 未经明确信号不得转换模式 +- EXECUTE 模式必须 100% 遵循计划 +- REVIEW 模式必须标记任何偏差 +- 禁止在未经请求时实施更改 + +## 模式职责 +- RESEARCH: 只读、分析、提问 +- INNOVATE: 设计方案、评估优劣、创建 design.md +- PLAN: 详细规划、创建 development.md 和 cases.md +- EXECUTE: 严格按计划实施、更新任务进度 +- REVIEW: 验证符合度、准备提交 +⚠️ 警告:永远不要修改此部分 ⚠️ + +# 分析 (RESEARCH 阶段) +## 代码结构分析 +- 测试代码位于: src/code/agent/test/unit/ +- 18 个测试文件覆盖 utils、services、gateway 等模块 +- 使用 pytest fixture 和 mock 进行单元测试 +- 已有 htmlcov 目录,说明本地已运行过覆盖率测试 + +## 现有配置缺失 +- 无 .github/workflows/ CI 配置 +- 无 pytest.ini 或 pyproject.toml +- 无 .coveragerc 覆盖率配置 +- requirements.txt 未包含测试依赖 + +## 技术约束 +- Python 3.10.16 +- 使用 pytest + coverage.py v7.13.4 +- 需要支持差异覆盖率计算(diff-cover) +- 工作目录: src/code/agent +- 基准分支: cap + +## 关键需求 +- **差异覆盖率**: 不是检查整体覆盖率,而是仅检查新增/修改代码的覆盖率 +- **失败条件**: 当新增代码覆盖率 < 95% 时,CI 应该失败 +- **触发频率**: 每次 push 都运行(不仅限于 PR) + +# 提议的解决方案 (INNOVATE 阶段) + +## 推荐方案:diff-cover 工具方案 + +采用 **diff-cover** 专业工具实现差异覆盖率检查,这是专门为"仅检查新增代码覆盖率"设计的工具。 + +### 技术架构 +- **测试框架**: pytest + pytest-cov +- **覆盖率工具**: coverage.py(生成 XML 报告) +- **差异分析**: diff-cover(对比 cap 分支) +- **CI 平台**: GitHub Actions + +### 核心工作流 +1. Checkout 代码(完整 git 历史) +2. 设置 Python 3.10 环境 +3. 安装依赖(requirements.txt + requirements-dev.txt) +4. 运行 pytest 生成覆盖率数据(XML + HTML + Terminal) +5. 运行 diff-cover 对比 cap 分支,阈值 95% +6. 失败时 CI 返回非零退出码 + +### 需要创建的文件 +- `.github/workflows/test-coverage.yml` - GitHub Actions 配置 +- `src/code/agent/requirements-dev.txt` - 测试依赖 +- `src/code/agent/pytest.ini` - pytest 配置 +- `src/code/agent/.coveragerc` - 覆盖率配置 +- 更新 `.gitignore` - 排除覆盖率文件 + +### 方案优势 +✅ 专业工具,专门用于差异覆盖率 +✅ 与现有 pytest + coverage.py 无缝集成 +✅ 开源免费,本地运行,无隐私问题 +✅ 成熟稳定(v9.2.4,生产级) +✅ 配置简单,维护成本低 +✅ 支持本地模拟 CI 流程 + +详细设计见:`docs/github-ci-coverage/design.md` + +# 实施计划摘要 (PLAN 阶段) + +## 开发计划 +分为 7 个阶段,21 个具体步骤: + +**阶段 1: 测试依赖配置文件创建(3 个文件)** +- requirements-dev.txt:pytest、pytest-cov、diff-cover +- pytest.ini:测试路径、命名模式、默认选项 +- .coveragerc:覆盖率源、排除规则、XML 输出 + +**阶段 2: GitHub Actions 工作流创建(2 个步骤)** +- 创建 .github/workflows/ 目录 +- 创建 test-coverage.yml 工作流(10 个 CI 步骤,含 GitHub Pages 部署) + +**阶段 3: gitignore 配置更新(1 个修改)** +- 在 .gitignore 追加 6 行覆盖率文件排除规则(含 gh-pages-deploy/) + +**阶段 4: GitHub Pages 配置(1 个步骤)** +- 在 GitHub 仓库 Settings > Pages 启用,配置 gh-pages 分支 + +**阶段 5: 本地验证测试(3 个步骤)** +- 安装测试依赖 +- 运行 pytest 生成覆盖率 +- 运行 diff-cover 验证工具 + +**阶段 6: 提交与 CI 验证(5 个步骤)** +- 暂存、提交、推送代码 +- 查看 GitHub Actions 运行状态 +- 确认 CI 成功 + +**阶段 7: GitHub Pages 部署验证(6 个步骤)** +- 合并到 cap 分支 +- 验证 Pages 部署成功 +- 访问并测试覆盖率报告页面 + +详细内容见:`docs/github-ci-coverage/development.md` + +## 测试计划 +定义 20 个测试用例,覆盖: +- 配置文件验证(2 个) +- 本地集成测试(3 个) +- CI 集成测试(5 个,含 GitHub Pages 部署和自动更新验证) +- 边界场景测试(5 个) +- 兼容性、性能、安全测试(各 1-2 个) + +详细内容见:`docs/github-ci-coverage/cases.md` + +# 当前执行步骤 +"设计技术方案" + +# 任务进度 (EXECUTE 阶段) +[待记录] + +# 最终审查 (REVIEW 阶段) +[待完成] diff --git a/docs/github-ci-coverage/cases.md b/docs/github-ci-coverage/cases.md new file mode 100644 index 0000000..bb170c5 --- /dev/null +++ b/docs/github-ci-coverage/cases.md @@ -0,0 +1,805 @@ +# GitHub CI 覆盖率检查 - 测试文档 + +**创建日期**: 2026-02-25 +**作者**: cici +**关联设计**: design.md +**关联开发**: development.md + +--- + +## 一、测试策略 + +### 1.1 测试范围 + +本任务主要是配置文件和 CI 流程的创建,测试策略包括: + +1. **配置文件语法验证**: 确保 YAML、INI 等配置文件格式正确 +2. **本地集成测试**: 验证 pytest + coverage + diff-cover 工具链在本地正常工作 +3. **CI 集成测试**: 验证 GitHub Actions 工作流正确执行 +4. **边界场景测试**: 测试各种 git diff 场景下的行为 + +### 1.2 测试类型 + +- **手动测试**: 本地运行命令验证 +- **集成测试**: GitHub Actions 自动运行 +- **场景测试**: 模拟不同代码变更场景 + +--- + +## 二、配置文件验证测试 + +### 测试用例 2.1: YAML 语法验证 + +**测试目标**: `.github/workflows/test-coverage.yml` +**测试方法**: 使用 YAML linter 或 GitHub Actions 语法检查 + +**步骤**: +1. 创建 workflow 文件 +2. 使用在线工具或命令行工具验证 YAML 语法 +3. 或者推送到 GitHub,查看是否有语法错误提示 + +**预期结果**: +- ✅ YAML 格式正确,无语法错误 +- ✅ 所有必需字段存在 +- ✅ 缩进正确 + +**失败处理**: 根据错误提示修正 YAML 语法 + +--- + +### 测试用例 2.2: INI 配置验证 + +**测试目标**: `pytest.ini` 和 `.coveragerc` +**测试方法**: 运行相关工具,检查是否正确加载配置 + +**步骤**: +```bash +cd src/code/agent + +# 验证 pytest.ini +pytest --collect-only + +# 验证 .coveragerc +coverage run --help +``` + +**预期结果**: +- ✅ pytest 正确识别配置文件 +- ✅ coverage 正确加载 .coveragerc +- ✅ 无警告或错误信息 + +**失败处理**: 检查配置项名称和值是否正确 + +--- + +## 三、本地集成测试 + +### 测试用例 3.1: 完整测试流程 + +**测试目标**: 验证整个测试和覆盖率流程在本地正常工作 +**前置条件**: 安装了 requirements-dev.txt 中的所有依赖 + +**步骤**: +```bash +cd src/code/agent + +# Step 1: 运行测试 +pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term + +# Step 2: 检查生成的文件 +ls -la coverage.xml htmlcov/ + +# Step 3: 运行 diff-cover +diff-cover coverage.xml --compare-branch=cap +``` + +**预期结果**: +- ✅ 所有测试通过(或至少运行完成) +- ✅ coverage.xml 文件生成 +- ✅ htmlcov/ 目录生成,包含 HTML 报告 +- ✅ diff-cover 成功执行,显示差异覆盖率 + +**失败场景**: +- ❌ 测试失败: 检查测试代码,修复失败的测试 +- ❌ coverage.xml 未生成: 检查 .coveragerc 配置 +- ❌ diff-cover 报错: 检查 git 分支状态和配置 + +--- + +### 测试用例 3.2: diff-cover 阈值测试 + +**测试目标**: 验证 diff-cover 的 `--fail-under` 参数正常工作 +**测试方法**: 故意设置一个很高的阈值,观察是否失败 + +**步骤**: +```bash +cd src/code/agent + +# 运行测试生成覆盖率 +pytest --cov=. --cov-report=xml + +# 设置不可能达到的阈值(100%) +diff-cover coverage.xml --compare-branch=cap --fail-under=100 +``` + +**预期结果**: +- ❌ diff-cover 应该返回非零退出码 +- ❌ 终端显示覆盖率不足的信息 + +**验证命令**: +```bash +echo $? # 应该显示非零值(通常是 1) +``` + +--- + +### 测试用例 3.3: 覆盖率排除规则测试 + +**测试目标**: 验证 .coveragerc 的 omit 配置正确排除测试文件 +**测试方法**: 检查覆盖率报告中是否包含测试文件 + +**步骤**: +```bash +cd src/code/agent +pytest --cov=. --cov-report=term + +# 查看报告,确认测试文件被排除 +``` + +**预期结果**: +- ✅ 覆盖率报告中不包含 `test/` 目录下的文件 +- ✅ 只统计源代码文件的覆盖率 + +--- + +## 四、CI 集成测试 + +### 测试用例 4.1: 首次 CI 运行测试 + +**测试目标**: 验证 GitHub Actions workflow 正确触发并执行 +**触发条件**: 推送配置文件到远程仓库 + +**步骤**: +1. 提交所有配置文件 +2. 推送到 GitHub: `git push -u origin task/github-ci-coverage_2026-02-25_1` +3. 在 GitHub 网页打开仓库 +4. 导航到 Actions 标签页 +5. 查看最新的 workflow 运行 + +**预期结果**: +- ✅ Workflow 自动触发 +- ✅ 所有步骤依次执行 +- ✅ Checkout、Setup Python、Install dependencies 步骤成功 +- ✅ Run tests 步骤成功(所有测试通过) +- ✅ Check diff coverage 步骤执行(可能成功或失败,取决于覆盖率) +- ✅ Upload artifact 步骤成功 + +**失败场景处理**: +- 如果 Checkout 失败: 检查仓库权限 +- 如果 Install dependencies 失败: 检查 requirements 文件路径和内容 +- 如果 Run tests 失败: 检查测试代码本身的问题 +- 如果 Check diff coverage 失败: 这是预期行为(如果覆盖率不足) + +--- + +### 测试用例 4.2: Artifact 上传验证 + +**测试目标**: 验证覆盖率报告正确上传为 artifact +**前置条件**: CI 已运行完成(无论成功或失败) + +**步骤**: +1. 在 GitHub Actions 运行页面,点击具体的 workflow run +2. 在页面底部查看 Artifacts 部分 +3. 应该看到两个 artifacts: + - coverage-report + - diff-coverage-report +4. 下载并解压查看 + +**预期结果**: +- ✅ coverage-report 包含完整的 htmlcov 目录 +- ✅ diff-coverage-report 包含 diff-coverage.html 文件 +- ✅ HTML 文件可以在浏览器中打开并查看 + +--- + +### 测试用例 4.3: 触发条件验证 + +**测试目标**: 验证所有分支的 push 都触发 CI +**测试方法**: 在不同分支 push 代码 + +**场景 A: 在功能分支 push** +```bash +git checkout task/github-ci-coverage_2026-02-25_1 +echo "test" >> README.md +git commit -am "test: trigger CI" +git push +``` +**预期**: +- ✅ CI 触发 +- ✅ 测试和覆盖率检查步骤运行 +- ⏭️ GitHub Pages 部署步骤跳过(不是 cap 分支) + +**场景 B: 在 cap 分支 push** +```bash +git checkout cap +git merge task/github-ci-coverage_2026-02-25_1 +git push +``` +**预期**: +- ✅ CI 触发 +- ✅ 测试和覆盖率检查步骤运行 +- ✅ GitHub Pages 部署步骤执行 + +--- + +### 测试用例 4.4: GitHub Pages 部署验证 + +**测试目标**: 验证覆盖率报告成功部署到 GitHub Pages +**前置条件**: +- 已在 Settings > Pages 启用 GitHub Pages +- 代码已推送到 cap 分支 +- CI 运行完成 + +**步骤**: +1. 在 GitHub Actions 页面查看 cap 分支的 workflow run +2. 展开 "Deploy to GitHub Pages" 步骤 +3. 确认步骤成功,没有错误 +4. 在 Settings > Pages 查看部署状态(应显示绿色 ✅) +5. 复制 GitHub Pages URL(显示在 Settings > Pages) +6. 在浏览器中访问该 URL +7. 验证 index.html 导航页面加载 +8. 点击 "View Full Coverage Report" 链接 +9. 验证完整覆盖率报告显示 +10. 返回导航页,点击 "View Diff Coverage Report" 链接 +11. 验证差异覆盖率报告显示 + +**预期结果**: +- ✅ GitHub Pages 显示绿色勾,状态为 "Active" +- ✅ 导航页面正常加载,显示最后更新时间 +- ✅ 两个报告链接都可点击 +- ✅ 完整覆盖率报告显示所有模块的覆盖率 +- ✅ 差异覆盖率报告显示与 cap 分支的差异 + +**失败处理**: +- 如果 404: 检查 Pages 配置和 gh-pages 分支内容 +- 如果链接失效: 检查文件路径是否正确 +- 如果报告空白: 检查 HTML 文件生成是否成功 + +--- + +### 测试用例 4.5: GitHub Pages 自动更新验证 + +**测试目标**: 验证每次 cap 分支更新时,GitHub Pages 自动刷新 +**测试方法**: 在 cap 分支进行新的提交,观察 Pages 更新 + +**步骤**: +```bash +# 在 cap 分支做一个小改动 +git checkout cap +echo "# Update" >> readme.md +git commit -am "docs: update readme" +git push + +# 等待 CI 运行 +``` + +**验证**: +1. 等待 CI 完成(约 3-5 分钟) +2. 刷新 GitHub Pages 页面 +3. 检查页面上的 "Last updated" 时间是否更新 + +**预期结果**: +- ✅ CI 运行完成后,Pages 自动更新 +- ✅ 时间戳更新为最新 +- ✅ 如有覆盖率变化,报告反映最新数据 + +--- + +## 五、边界场景测试 + +### 测试用例 5.1: 无代码变更场景 + +**场景**: 只修改文档或配置文件(非 Python 代码) + +**模拟步骤**: +```bash +echo "# Update" >> README.md +git commit -am "docs: update readme" +git push +``` + +**预期结果**: +- ✅ CI 运行 +- ✅ pytest 通过 +- ✅ diff-cover 显示 "No lines with coverage information in this diff" 或 100% +- ✅ CI 通过 + +--- + +### 测试用例 5.2: 仅新增测试文件场景 + +**场景**: 只添加新的测试文件,没有修改源代码 + +**模拟步骤**: +```bash +# 创建一个新的测试文件 +touch src/code/agent/test/unit/services/new_test.py +git add src/code/agent/test/unit/services/new_test.py +git commit -m "test: add new test" +git push +``` + +**预期结果**: +- ✅ CI 运行 +- ✅ pytest 发现并运行新测试 +- ✅ diff-cover 忽略测试文件(因为 omit 配置) +- ✅ CI 通过 + +--- + +### 测试用例 5.3: 新增未测试代码场景 + +**场景**: 新增 Python 代码但没有对应测试 + +**模拟步骤**: +```bash +# 在某个源文件中添加一个未测试的函数 +# 例如在 utils/logger.py 中添加新函数 +git commit -am "feat: add new untested function" +git push +``` + +**预期结果**: +- ✅ CI 运行 +- ✅ pytest 通过(现有测试仍然通过) +- ❌ diff-cover 失败(新增代码覆盖率 < 95%) +- ❌ CI 失败,阻止合并 + +**CI 输出示例**: +``` +Diff Coverage: 50.00% +``` + +--- + +### 测试用例 5.4: 新增代码并添加完整测试场景 + +**场景**: 新增 Python 代码,并添加完整测试(覆盖率 ≥ 95%) + +**模拟步骤**: +```bash +# 1. 添加新函数 +# 2. 添加对应测试,覆盖所有代码路径 +git commit -am "feat: add new function with tests" +git push +``` + +**预期结果**: +- ✅ CI 运行 +- ✅ pytest 通过(包括新测试) +- ✅ diff-cover 通过(差异覆盖率 ≥ 95%) +- ✅ CI 通过 + +--- + +### 测试用例 5.5: 修改现有低覆盖率代码场景 + +**场景**: 修改现有代码中覆盖率较低的部分,但没有增加测试 + +**预期结果**: +- ❌ diff-cover 失败 +- ❌ CI 失败 +- 💡 这会强制开发者为修改的代码添加测试 + +--- + +## 六、Mock 策略 + +本任务不涉及新的源代码编写,因此无需 Mock 策略。 + +如果将来需要测试 GitHub Actions 本身(单元测试 workflow): +- 可以使用 `act` 工具在本地运行 GitHub Actions +- 或使用 GitHub 的 workflow 测试功能 + +--- + +## 七、测试覆盖率目标 + +| 测试类型 | 目标覆盖率 | 说明 | +|---------|-----------|------| +| 配置文件验证 | N/A | 手动验证 | +| 本地集成测试 | 100% | 所有工具链步骤必须成功 | +| CI 集成测试 | 100% | 所有 CI 步骤必须执行 | +| 边界场景测试 | 80% | 覆盖主要场景 | + +**注意**: 本任务的"测试"是指验证 CI 配置,不是编写新的单元测试。 + +--- + +## 八、测试执行计划 + +### Phase 1: 配置创建后的即时验证 + +**时机**: 创建每个配置文件后立即验证 + +**测试清单**: +- [ ] requirements-dev.txt 可以被 pip 安装 +- [ ] pytest.ini 配置被 pytest 识别 +- [ ] .coveragerc 配置被 coverage 识别 +- [ ] test-coverage.yml YAML 语法正确 + +--- + +### Phase 2: 本地集成测试 + +**时机**: 所有配置文件创建完成后,推送到 GitHub 之前 + +**测试清单**: +- [ ] 执行测试用例 3.1(完整测试流程) +- [ ] 执行测试用例 3.2(阈值测试) +- [ ] 执行测试用例 3.3(排除规则测试) + +**通过条件**: 所有测试用例通过 + +--- + +### Phase 3: CI 集成测试 + +**时机**: 推送到 GitHub 后 + +**测试清单**: +- [ ] 执行测试用例 4.1(首次 CI 运行) +- [ ] 执行测试用例 4.2(Artifact 上传验证) +- [ ] 执行测试用例 4.3(触发条件验证) + +**通过条件**: CI 成功运行,所有步骤执行完成 + +--- + +### Phase 4: 边界场景测试 + +**时机**: CI 验证通过后,可选的额外验证 + +**测试清单**: +- [ ] 执行测试用例 5.1(无代码变更) +- [ ] 执行测试用例 5.2(仅测试文件) +- [ ] 执行测试用例 5.3(未测试代码) +- [ ] 执行测试用例 5.4(完整测试代码) + +**通过条件**: 各场景行为符合预期 + +--- + +## 九、失败场景与诊断 + +### 场景 A: pytest 无法发现测试 + +**症状**: +``` +collected 0 items +``` + +**可能原因**: +1. pytest.ini 中的 `testpaths` 配置错误 +2. `python_files` 模式不匹配测试文件名 +3. 测试文件中没有符合命名规范的函数/类 + +**诊断步骤**: +```bash +pytest --collect-only -v # 查看 pytest 尝试收集哪些文件 +``` + +**解决方案**: +- 检查 pytest.ini 中的 `testpaths` 是否正确(应该是 `test`) +- 检查 `python_files` 是否匹配 `*_test.py` +- 确认测试文件在正确的目录 + +--- + +### 场景 B: coverage.xml 未生成 + +**症状**: diff-cover 报错 "No such file: coverage.xml" + +**可能原因**: +1. pytest-cov 未安装 +2. --cov 参数错误 +3. --cov-report=xml 参数缺失 + +**诊断步骤**: +```bash +pip list | grep pytest-cov # 确认已安装 +pytest --cov=. --cov-report=xml -v # 详细输出 +ls -la coverage.xml # 检查文件是否存在 +``` + +**解决方案**: +- 安装 pytest-cov: `pip install pytest-cov` +- 确认 --cov 和 --cov-report=xml 参数都存在 + +--- + +### 场景 C: diff-cover 找不到 cap 分支 + +**症状**: +``` +fatal: ambiguous argument 'cap': unknown revision or path not in the working tree +``` + +**可能原因**: +1. 本地没有 cap 分支 +2. GitHub Actions 中 fetch-depth 设置错误 + +**诊断步骤**: +```bash +git branch -a # 查看所有分支 +git fetch origin cap # 手动拉取 cap 分支 +``` + +**解决方案**: +- 本地测试: 使用 `diff-cover coverage.xml --compare-branch=cap` +- GitHub Actions: 使用 `diff-cover coverage.xml --compare-branch=origin/cap` +- 确保 checkout action 使用 `fetch-depth: 0` + +--- + +### 场景 D: CI 运行但没有触发 + +**症状**: 推送代码后,GitHub Actions 页面没有新的运行记录 + +**可能原因**: +1. workflow 文件路径错误(不在 .github/workflows/) +2. YAML 语法错误导致 workflow 被忽略 +3. GitHub Actions 未启用 + +**诊断步骤**: +1. 检查文件路径: `.github/workflows/test-coverage.yml` +2. 在 GitHub 仓库的 Settings > Actions 检查是否启用 +3. 在 Actions 页面查看是否有错误提示 + +**解决方案**: +- 确保文件在正确路径 +- 启用 GitHub Actions +- 修正 YAML 语法错误 + +--- + +### 场景 E: CI 运行但步骤失败 + +**症状**: CI 运行但某个步骤显示红色 ❌ + +**诊断步骤**: +1. 点击失败的 workflow run +2. 展开失败的步骤,查看日志 +3. 根据错误信息定位问题 + +**常见失败原因**: + +| 失败步骤 | 可能原因 | 解决方案 | +|---------|---------|---------| +| Install dependencies | 包名错误或版本冲突 | 修正 requirements 文件 | +| Run tests | 测试代码有 bug | 修复测试 | +| Check diff coverage | 覆盖率不足 | 添加测试提升覆盖率 | + +--- + +## 十、回归测试 + +每次修改 CI 配置后,应该运行以下回归测试: + +### 回归测试清单 +- [ ] 配置文件语法验证(测试用例 2.1, 2.2) +- [ ] 本地完整流程(测试用例 3.1) +- [ ] CI 触发验证(测试用例 4.1) +- [ ] GitHub Pages 部署验证(测试用例 4.4) +- [ ] 至少一个边界场景(测试用例 5.3 或 5.4) + +--- + +## 十一、性能测试 + +### 测试用例 11.1: CI 运行时间测试 + +**测试目标**: 确保 CI 运行时间在可接受范围内 +**测试方法**: 观察 GitHub Actions 运行时长 + +**性能基准**: +- Checkout: < 30 秒(完整历史) +- Setup Python: < 30 秒(有缓存) +- Install dependencies: < 60 秒(有缓存) +- Run tests: < 300 秒(取决于测试数量) +- Check diff coverage: < 10 秒 +- Upload artifacts: < 30 秒 +- Create index page: < 5 秒 +- Deploy to Pages: < 30 秒(仅 cap 分支) + +**总计**: +- 功能分支: < 8 分钟 +- cap 分支: < 9 分钟(含 Pages 部署) + +**优化建议**: +- 如果 Install dependencies 太慢,使用 pip cache(已配置) +- 如果 Checkout 太慢,考虑是否真的需要完整历史(必需) +- Pages 部署是异步的,不会阻塞 CI + +--- + +## 十二、安全测试 + +### 测试用例 12.1: 敏感信息泄露检查 + +**测试目标**: 确保配置文件中不包含敏感信息 +**检查清单**: +- [ ] requirements-dev.txt 不包含密码或 token +- [ ] test-coverage.yml 不包含硬编码的密钥 +- [ ] .coveragerc 不暴露敏感路径 + +**预期结果**: ✅ 所有配置文件安全 + +--- + +## 十三、兼容性测试 + +### 测试用例 13.1: Python 版本兼容性 + +**测试目标**: 验证配置在 Python 3.10 环境下正常工作 +**前置条件**: Python 3.10.x 环境 + +**步骤**: +```bash +python --version # 确认版本 +cd src/code/agent +pip install -r requirements-dev.txt +pytest --cov=. --cov-report=xml +diff-cover coverage.xml --compare-branch=cap +``` + +**预期结果**: ✅ 所有工具正常运行 + +--- + +### 测试用例 13.2: 操作系统兼容性 + +**测试目标**: 验证配置在不同操作系统下的兼容性 + +**测试环境**: +- Ubuntu (GitHub Actions 使用) +- macOS (本地开发) +- Windows (可选) + +**预期结果**: +- ✅ Ubuntu: 完全兼容 +- ✅ macOS: 完全兼容 +- ⚠️ Windows: 路径可能需要调整(但 CI 不受影响) + +--- + +## 十四、测试数据 + +### 当前项目测试数据 + +**现有测试文件**: 18 个 +- utils: 3 个测试文件 +- services: 15 个测试文件(包括 gateway、workspace、pip 等子模块) + +**测试命名模式**: `*_test.py` + +**现有覆盖率**: 77% + +**测试框架**: pytest + unittest.mock + +--- + +## 十五、验收标准 + +任务完成的验收标准: + +### 功能验收 +- [x] 所有配置文件创建完成 +- [x] GitHub Actions workflow 正确配置 +- [ ] 本地可以运行完整测试流程 +- [ ] CI 自动触发并执行 +- [ ] diff-cover 正确计算差异覆盖率 +- [ ] 覆盖率不足时 CI 失败 +- [ ] 覆盖率达标时 CI 通过 +- [ ] GitHub Pages 在 cap 分支成功部署 +- [ ] 覆盖率报告可通过浏览器访问 + +### 质量验收 +- [ ] 配置文件格式正确 +- [ ] 无语法错误 +- [ ] 文档完整(design.md、development.md、cases.md) +- [ ] .gitignore 正确排除覆盖率文件 +- [ ] GitHub Pages 导航页面美观友好 + +### 用户体验验收 +- [ ] 开发者可以在本地运行相同的检查 +- [ ] CI 失败信息清晰,指出覆盖率不足 +- [ ] Artifact 可以下载查看详细报告 +- [ ] GitHub Pages 提供永久链接,无需下载即可查看 +- [ ] 导航页面清晰,易于找到所需报告 + +--- + +## 十六、测试报告模板 + +每个测试用例执行后,记录结果: + +```markdown +### 测试用例 X.X 执行记录 + +**执行时间**: YYYY-MM-DD HH:MM:SS +**执行人**: cici +**结果**: ✅ 通过 / ❌ 失败 + +**输出摘要**: +[命令输出或 CI 日志关键信息] + +**问题**: +[如果失败,记录问题] + +**解决方案**: +[如果失败,记录如何解决] +``` + +--- + +## 十七、持续监控 + +CI 部署后,需要持续监控: + +1. **每周检查**: + - CI 运行成功率 + - 平均运行时长 + - 差异覆盖率趋势 + +2. **每月检查**: + - 依赖包更新(pytest、pytest-cov、diff-cover) + - GitHub Actions 版本更新(checkout、setup-python 等) + +3. **问题追踪**: + - 记录 CI 失败的原因 + - 分析是否有误报(false positive) + - 根据反馈调整阈值或配置 + +--- + +## 十八、FAQ 预设 + +**Q1: 为什么本地测试通过,但 CI 失败?** +A: 可能是环境差异、依赖版本不同、或者本地没有正确配置 diff-cover。 + +**Q2: diff-cover 显示 "No lines with coverage information"?** +A: 这表示当前分支相对 cap 分支没有代码变更,这是正常的。 + +**Q3: 如何临时绕过覆盖率检查?** +A: 不建议绕过。如果确实需要,可以在 PR 中说明原因,或临时调整阈值。 + +**Q4: 如何查看详细的覆盖率报告?** +A: 有两种方式: + 1. 访问 GitHub Pages(推荐):https://\.github.io/\/ + 2. 下载 CI 的 artifact(coverage-report),在浏览器中打开 htmlcov/index.html + +**Q5: 如何在本地运行与 CI 相同的检查?** +A: 参考 development.md 的"本地开发体验"章节。 + +**Q6: GitHub Pages 多久更新一次?** +A: 每次推送到 cap 分支时自动更新,通常在 CI 运行完成后 1-2 分钟内生效。 + +**Q7: 功能分支的覆盖率报告可以在 GitHub Pages 看到吗?** +A: 不能。GitHub Pages 只部署 cap 分支的报告。功能分支的报告需要下载 Artifact 查看。 + +--- + +## 十九、测试总结 + +本文档定义了 20 个测试用例,覆盖: +- 配置文件验证(2 个) +- 本地集成测试(3 个) +- CI 集成测试(5 个,含 GitHub Pages 部署验证) +- 边界场景测试(5 个) +- 兼容性测试(2 个) +- 性能测试(1 个) +- 安全测试(1 个) +- 回归测试(1 个清单) + +通过这些测试用例,可以全面验证 GitHub CI 覆盖率检查功能和 GitHub Pages 自动部署的正确性和可靠性。 diff --git a/docs/github-ci-coverage/design.md b/docs/github-ci-coverage/design.md new file mode 100644 index 0000000..ceac2de --- /dev/null +++ b/docs/github-ci-coverage/design.md @@ -0,0 +1,695 @@ +# GitHub CI 覆盖率检查 - 设计文档 + +**创建日期**: 2026-02-25 +**作者**: cici +**状态**: 设计中 + +--- + +## 一、需求概述 + +### 核心需求 +设置 GitHub CI,确保每次代码提交时新增代码的测试覆盖率达到 95% 以上。 + +### 具体要求 +- **测试范围**: src/code/agent 目录 +- **触发条件**: 每次 push 到仓库 +- **基准分支**: cap +- **覆盖率类型**: 差异覆盖率(Diff Coverage) +- **阈值**: 新增代码覆盖率 ≥ 95% + +--- + +## 二、架构设计 + +### 2.1 技术方案对比 + +#### 方案 A: diff-cover 工具方案 ⭐ **推荐** + +**核心思路** +使用专门的 diff-cover 工具,它能够: +- 分析 git diff 找出新增/修改的代码行 +- 将这些行与 coverage.py 的报告对比 +- 仅计算变更代码的覆盖率 +- 当差异覆盖率低于阈值时返回非零退出码 + +**技术栈** +- pytest + pytest-cov:运行测试并生成覆盖率数据 +- coverage.py:生成 XML 格式的覆盖率报告 +- diff-cover:计算差异覆盖率 + +**工作流程** +``` +1. Checkout 代码(包含完整 git 历史) +2. 设置 Python 3.10 环境 +3. 安装依赖(包括 diff-cover) +4. 运行 pytest 生成覆盖率报告 +5. 运行 diff-cover 对比 cap 分支 +6. 如果差异覆盖率 < 95%,CI 失败 +``` + +**优势** +- ✅ 专业工具,专门用于差异覆盖率分析 +- ✅ 支持多种覆盖率报告格式(Cobertura XML、Clover、JaCoCo) +- ✅ 可以生成 HTML 报告供本地查看 +- ✅ 明确的退出码,易于 CI 集成 +- ✅ 活跃维护,最新版本 9.2.4(2025年3月) + +**劣势** +- ❌ 需要额外安装一个工具 +- ❌ 需要完整的 git 历史(fetch-depth: 0) + +#### 方案 B: 纯 pytest-cov 方案 + +**核心思路** +使用 pytest-cov 的 `--cov-fail-under` 参数检查整体覆盖率。 + +**工作流程** +``` +1. 运行 pytest --cov --cov-fail-under=95 +2. 如果整体覆盖率 < 95%,CI 失败 +``` + +**优势** +- ✅ 简单,无需额外工具 +- ✅ 配置少 + +**劣势** +- ❌ **不符合需求**:检查的是整体覆盖率,不是新增代码覆盖率 +- ❌ 当前整体覆盖率 77%,无法通过 95% 阈值 +- ❌ 会阻止所有提交,直到整体覆盖率提升到 95% + +#### 方案 C: coverage.py 比较 + 脚本方案 + +**核心思路** +手动编写脚本,对比两个分支的覆盖率数据。 + +**工作流程** +``` +1. 切换到 cap 分支,运行测试,保存覆盖率数据 +2. 切换回当前分支,运行测试,生成覆盖率数据 +3. 自定义脚本比较两个覆盖率数据 +4. 计算新增代码的覆盖率 +5. 判断是否达到阈值 +``` + +**优势** +- ✅ 完全自定义,灵活性高 + +**劣势** +- ❌ 需要手动编写和维护脚本 +- ❌ 容易出错,逻辑复杂 +- ❌ 难以处理边界情况(重命名、移动文件等) +- ❌ 开发和测试成本高 + +#### 方案 D: 第三方服务方案(Codecov / Coveralls) + +**核心思路** +使用 Codecov 或 Coveralls 等第三方服务,它们提供差异覆盖率检查。 + +**工作流程** +``` +1. 运行 pytest 生成覆盖率报告 +2. 上传报告到 Codecov/Coveralls +3. 服务自动分析差异覆盖率 +4. 在 PR 中显示覆盖率变化 +``` + +**优势** +- ✅ 功能强大,UI 美观 +- ✅ 支持多种语言和框架 +- ✅ 提供历史趋势分析 + +**劣势** +- ❌ 需要外部服务账号和配置 +- ❌ 可能涉及数据隐私问题 +- ❌ 免费版有使用限制 +- ❌ 依赖第三方服务可用性 + +--- + +### 2.2 推荐方案:方案 A(diff-cover) + +基于以下原因,推荐使用 **方案 A**: + +1. **完全符合需求**:diff-cover 专门用于计算差异覆盖率 +2. **开源且自主可控**:无需依赖外部服务 +3. **成熟稳定**:工具活跃维护,已是生产稳定版本 +4. **易于集成**:与现有的 pytest + coverage.py 工具链无缝集成 +5. **清晰的失败机制**:当覆盖率不达标时,明确返回非零退出码 + +--- + +## 三、详细设计 + +### 3.1 文件结构 + +需要创建/修改的文件: + +``` +cap-comfyui/ +├── .github/ +│ └── workflows/ +│ └── test-coverage.yml # GitHub Actions workflow +├── src/code/agent/ +│ ├── requirements-dev.txt # 测试依赖(新建) +│ ├── pytest.ini # pytest 配置(新建) +│ └── .coveragerc # coverage 配置(新建) +└── .gitignore # 更新,排除覆盖率文件 +``` + +### 3.2 依赖管理 + +**requirements-dev.txt** +``` +pytest>=8.0.0 +pytest-cov>=4.1.0 +diff-cover>=9.2.0 +``` + +**说明**: +- pytest: 测试框架 +- pytest-cov: pytest 的覆盖率插件 +- diff-cover: 差异覆盖率计算工具 + +### 3.3 pytest 配置 + +**pytest.ini** +```ini +[pytest] +testpaths = test +python_files = *_test.py +python_classes = Test* +python_functions = test_* +addopts = + -v + --strict-markers + --tb=short +``` + +**配置说明**: +- `testpaths`: 测试文件搜索路径 +- `python_files`: 测试文件命名模式(匹配现有的 *_test.py) +- `addopts`: 默认选项(详细输出、严格标记、短回溯) + +### 3.4 覆盖率配置 + +**.coveragerc** +```ini +[run] +source = . +omit = + */test/* + */tests/* + */__pycache__/* + */venv/* + */.venv/* + */htmlcov/* + +[report] +precision = 2 +show_missing = True +skip_covered = False + +[html] +directory = htmlcov + +[xml] +output = coverage.xml +``` + +**配置说明**: +- `source`: 覆盖率分析的源代码目录 +- `omit`: 排除测试文件、虚拟环境等 +- `precision`: 覆盖率精度(2 位小数) +- `output`: XML 报告输出路径(供 diff-cover 使用) + +### 3.5 GitHub Actions Workflow + +**.github/workflows/test-coverage.yml** + +**核心步骤**: + +1. **代码检出** + ```yaml + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # 获取完整 git 历史,diff-cover 需要 + ``` + +2. **环境设置** + ```yaml + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + ``` + +3. **依赖安装** + ```yaml + - name: Install dependencies + working-directory: src/code/agent + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt + ``` + +4. **运行测试并生成覆盖率** + ```yaml + - name: Run tests with coverage + working-directory: src/code/agent + run: | + pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term + ``` + +5. **检查差异覆盖率** + ```yaml + - name: Check diff coverage + working-directory: src/code/agent + run: | + diff-cover coverage.xml --compare-branch=origin/cap --fail-under=95 + ``` + +**关键参数解释**: +- `--compare-branch=origin/cap`: 与 cap 分支对比 +- `--fail-under=95`: 差异覆盖率低于 95% 时失败 +- `fetch-depth: 0`: 必须获取完整历史,否则 diff-cover 无法找到基准分支 + +### 3.6 CI 行为分析 + +**场景 1: 新增代码覆盖率 ≥ 95%** +``` +✅ pytest 通过 +✅ diff-cover 通过(差异覆盖率 95%+) +✅ CI 通过 +``` + +**场景 2: 新增代码覆盖率 < 95%** +``` +✅ pytest 通过(测试本身没问题) +❌ diff-cover 失败(差异覆盖率不足) +❌ CI 失败 +``` + +**场景 3: 仅修改测试代码** +``` +✅ pytest 通过 +✅ diff-cover 通过(测试代码被 omit 排除) +✅ CI 通过 +``` + +**场景 4: 没有新增代码** +``` +✅ pytest 通过 +✅ diff-cover 通过(无差异) +✅ CI 通过 +``` + +--- + +## 四、技术决策 + +### 4.1 为什么选择 diff-cover? + +| 考虑因素 | diff-cover | pytest-cov | 自定义脚本 | 第三方服务 | +|---------|-----------|-----------|----------|----------| +| 差异覆盖率计算 | ✅ 原生支持 | ❌ 不支持 | ⚠️ 需自己实现 | ✅ 支持 | +| 维护成本 | ✅ 低 | ✅ 低 | ❌ 高 | ✅ 低 | +| 数据隐私 | ✅ 本地运行 | ✅ 本地运行 | ✅ 本地运行 | ❌ 上传到外部 | +| 配置复杂度 | ✅ 简单 | ✅ 简单 | ❌ 复杂 | ⚠️ 需账号配置 | +| 成本 | ✅ 免费 | ✅ 免费 | ✅ 免费 | ⚠️ 可能收费 | + +### 4.2 为什么使用 XML 格式? + +diff-cover 支持多种格式,选择 XML(Cobertura)的原因: +- coverage.py 原生支持生成 XML +- XML 格式标准化,兼容性好 +- diff-cover 对 XML 格式支持最成熟 + +### 4.3 为什么需要完整 git 历史? + +diff-cover 需要: +- 访问基准分支(cap)的提交历史 +- 计算当前分支与基准分支的 diff +- 如果使用 `fetch-depth: 1`(浅克隆),无法访问 cap 分支,diff-cover 会失败 + +**性能考虑**: +- 完整历史克隆会增加 checkout 时间(通常 5-30 秒) +- 但这是必要的代价,无法避免 + +### 4.4 工作目录设计 + +**选择**: 在 `src/code/agent` 目录中执行所有操作 + +**理由**: +- 测试代码位于 `src/code/agent/test/` +- 源代码位于 `src/code/agent/` +- requirements.txt 位于 `src/code/agent/` +- 保持路径简洁,避免复杂的相对路径 + +**注意事项**: +- coverage.xml 将生成在 `src/code/agent/coverage.xml` +- 需要在 .gitignore 中排除此文件 + +--- + +## 五、配置文件设计细节 + +### 5.1 pytest.ini 设计 + +**位置**: `src/code/agent/pytest.ini` + +**设计考虑**: +- 使用 `testpaths = test` 而不是绝对路径,保持配置简洁 +- 匹配现有测试文件命名模式 `*_test.py` +- 添加 `-v` 详细输出,便于 CI 日志调试 +- 添加 `--tb=short` 减少错误堆栈输出 + +### 5.2 .coveragerc 设计 + +**位置**: `src/code/agent/.coveragerc` + +**关键配置**: + +1. **source = .**: 从当前目录(src/code/agent)开始分析 +2. **omit 列表**: 排除不需要覆盖的文件 + - 测试文件本身(*/test/*) + - Python 缓存(*/__pycache__/*) + - 虚拟环境(*/venv/*, */.venv/*) + - 覆盖率报告目录(*/htmlcov/*) + +3. **report 配置**: + - `precision = 2`: 显示到小数点后两位 + - `show_missing = True`: 显示未覆盖的行号 + - `skip_covered = False`: 报告中包含已覆盖的文件 + +4. **xml 输出**: `output = coverage.xml`,供 diff-cover 使用 + +### 5.3 requirements-dev.txt 设计 + +**位置**: `src/code/agent/requirements-dev.txt` + +**版本选择策略**: +- pytest: ≥8.0.0(最新稳定版,2024年初发布) +- pytest-cov: ≥4.1.0(支持 pytest 8.x) +- diff-cover: ≥9.2.0(最新版本,2025年3月) + +**为什么分离测试依赖**: +- 生产环境不需要测试工具 +- 保持 requirements.txt 简洁 +- CI 可以分别安装 + +--- + +## 六、GitHub Actions 工作流设计 + +### 6.1 触发条件 + +```yaml +on: + push: + branches: + - '**' # 所有分支的 push 都触发 +``` + +**设计说明**: +- 使用 `'**'` 匹配所有分支(包括 cap、feature 分支等) +- 满足"每次 push 都运行"的需求 +- 不限制 PR,push 即触发 + +### 6.2 作业配置 + +```yaml +jobs: + test-coverage: + runs-on: ubuntu-latest + steps: [...] +``` + +**选择 ubuntu-latest 的理由**: +- 项目使用 Linux 环境部署(Dockerfile 基于 python:3.10.16-slim) +- GitHub Actions 的 ubuntu-latest 性能最优 +- 与生产环境更接近 + +### 6.3 关键步骤分析 + +**Step 1: Checkout with full history** +```yaml +- uses: actions/checkout@v4 + with: + fetch-depth: 0 +``` +- 必须获取完整历史,供 diff-cover 对比 + +**Step 2: Python setup** +```yaml +- uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' +``` +- 匹配项目的 Python 3.10 版本 +- 使用 pip 缓存加速依赖安装 + +**Step 3: Install dependencies** +```yaml +- run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt +``` +- 分两步安装,先生产依赖后测试依赖 +- 确保测试环境与生产环境一致 + +**Step 4: Run tests** +```yaml +- run: pytest --cov=. --cov-report=xml --cov-report=term +``` +- `--cov=.`: 覆盖当前目录(src/code/agent) +- `--cov-report=xml`: 生成 XML 供 diff-cover 使用 +- `--cov-report=term`: 在 CI 日志中显示覆盖率摘要 + +**Step 5: Check diff coverage** +```yaml +- run: diff-cover coverage.xml --compare-branch=origin/cap --fail-under=95 +``` +- 对比 origin/cap 分支 +- 阈值 95% +- 失败时返回非零退出码,CI 失败 + +### 6.4 可选增强步骤 + +**上传覆盖率报告(artifact)** +```yaml +- uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-report + path: src/code/agent/htmlcov/ +``` +- 保存 HTML 报告,便于查看详细覆盖率信息 +- 使用 `if: always()` 确保即使测试失败也上传 + +**差异覆盖率 HTML 报告** +```yaml +- run: diff-cover coverage.xml --compare-branch=origin/cap --html-report diff-coverage.html +``` +- 生成可视化的差异覆盖率报告 + +--- + +## 七、风险评估 + +### 7.1 潜在风险 + +**风险 1: 首次运行可能失败** +- **原因**: 现有代码整体覆盖率 77%,如果对现有代码进行修改,可能无法达到 95% +- **应对**: 首次合并时可以临时降低阈值,逐步提升 + +**风险 2: 基准分支不存在** +- **原因**: GitHub Actions 只 checkout 当前分支,origin/cap 可能不存在 +- **应对**: 使用 `fetch-depth: 0` 获取所有分支 + +**风险 3: 测试依赖冲突** +- **原因**: 新增的测试依赖可能与现有依赖冲突 +- **应对**: 使用兼容的版本范围,测试后确认 + +**风险 4: diff-cover 无法识别重命名** +- **原因**: 文件重命名时,diff-cover 可能误判为删除+新增 +- **应对**: diff-cover 较新版本已改进此问题 + +### 7.2 降级方案 + +如果 diff-cover 方案遇到问题,可以降级到: +1. 先使用 pytest-cov 的 `--cov-fail-under` 检查整体覆盖率(阈值可设置为 70%) +2. 逐步提升测试覆盖率到 95% +3. 最终再引入 diff-cover + +--- + +## 八、本地开发体验 + +### 8.1 本地运行命令 + +开发者可以在本地模拟 CI 流程: + +```bash +# 进入 agent 目录 +cd src/code/agent + +# 安装测试依赖 +pip install -r requirements-dev.txt + +# 运行测试并生成覆盖率 +pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term + +# 检查差异覆盖率 +diff-cover coverage.xml --compare-branch=cap --fail-under=95 + +# 查看 HTML 报告 +open htmlcov/index.html # macOS +``` + +### 8.2 Makefile 集成建议 + +可以在项目根目录的 Makefile 中添加: + +```makefile +.PHONY: test +test: + cd src/code/agent && pytest + +.PHONY: test-cov +test-cov: + cd src/code/agent && pytest --cov=. --cov-report=html --cov-report=term + +.PHONY: test-diff +test-diff: + cd src/code/agent && \ + pytest --cov=. --cov-report=xml && \ + diff-cover coverage.xml --compare-branch=cap --fail-under=95 +``` + +--- + +## 九、扩展性考虑 + +### 9.1 已实现的增强功能 + +1. **GitHub Pages 自动部署** ✅ + - 在 cap 分支自动部署覆盖率报告 + - 提供美观的导航页面 + - 包含完整覆盖率和差异覆盖率两个报告 + - 永久链接,无需下载即可查看 + +### 9.2 未来可能的增强 + +1. **覆盖率徽章** + - 使用 shields.io 生成覆盖率徽章 + - 在 README 中显示 + +2. **PR 评论** + - 使用 GitHub Actions 在 PR 中自动评论覆盖率报告 + - 工具: coverage-comment-action + +3. **覆盖率趋势** + - 存储历史覆盖率数据 + - 生成趋势图表 + +4. **多 Python 版本测试** + - 使用 matrix 策略测试多个 Python 版本 + - 例如: 3.9, 3.10, 3.11 + +### 9.2 其他代码目录 + +如果将来需要对 `src/code/sd` 目录也进行覆盖率检查: +- 复制相同的配置文件 +- 创建单独的 workflow 或使用 matrix 策略 + +--- + +## 十、对比总结 + +| 方案 | 符合需求 | 实施难度 | 维护成本 | 推荐度 | +|-----|---------|---------|---------|--------| +| A: diff-cover | ✅ 完全符合 | ⭐⭐ 简单 | ⭐ 低 | ⭐⭐⭐⭐⭐ | +| B: pytest-cov | ❌ 不符合 | ⭐ 非常简单 | ⭐ 低 | ⭐ | +| C: 自定义脚本 | ⚠️ 可实现 | ⭐⭐⭐⭐⭐ 复杂 | ⭐⭐⭐⭐⭐ 高 | ⭐⭐ | +| D: 第三方服务 | ✅ 符合 | ⭐⭐⭐ 中等 | ⭐⭐ 中等 | ⭐⭐⭐ | + +**最终推荐**: 方案 A(diff-cover) + +--- + +## 十一、实施路线图概览 + +``` +阶段 1: 配置文件准备 +├── 创建 requirements-dev.txt +├── 创建 pytest.ini +├── 创建 .coveragerc +└── 更新 .gitignore + +阶段 2: GitHub Actions 配置 +├── 创建 .github/workflows/ 目录 +└── 创建 test-coverage.yml + +阶段 3: 验证测试 +├── 本地测试运行 +├── 推送到 GitHub +└── 验证 CI 运行结果 + +阶段 4: 文档更新 +└── 更新 README(可选) +``` + +--- + +## 十二、预期效果 + +实施完成后: +- ✅ 每次 push 自动运行测试 +- ✅ 生成详细的覆盖率报告 +- ✅ 自动检查新增代码覆盖率 +- ✅ 覆盖率不足时 CI 失败,阻止低质量代码合并 +- ✅ 开发者可以在本地运行相同的检查 +- ✅ 保持现有代码不受影响(仅检查新增代码) +- ✅ cap 分支的覆盖率报告自动部署到 GitHub Pages +- ✅ 团队成员可以随时通过浏览器访问最新覆盖率报告 + +**GitHub Pages 访问方式**: +``` +https://.github.io/cap-comfyui/ +``` + +**页面内容**: +- 导航页面(index.html):显示最后更新时间,提供两个报告链接 +- 完整覆盖率报告(htmlcov/):所有源代码的详细覆盖率 +- 差异覆盖率报告(diff-coverage.html):新增代码的覆盖率分析 + +--- + +## 附录:diff-cover 命令参考 + +### 基本用法 +```bash +diff-cover coverage.xml --compare-branch=origin/cap +``` + +### 设置阈值 +```bash +diff-cover coverage.xml --compare-branch=origin/cap --fail-under=95 +``` + +### 生成 HTML 报告 +```bash +diff-cover coverage.xml --compare-branch=origin/cap --html-report report.html +``` + +### 指定 diff 范围 +```bash +diff-cover coverage.xml --compare-branch=origin/cap --diff-range-notation='..' +``` + +### 查看帮助 +```bash +diff-cover --help +``` diff --git a/docs/github-ci-coverage/development.md b/docs/github-ci-coverage/development.md new file mode 100644 index 0000000..875e895 --- /dev/null +++ b/docs/github-ci-coverage/development.md @@ -0,0 +1,726 @@ +# GitHub CI 覆盖率检查 - 开发文档 + +**创建日期**: 2026-02-25 +**作者**: cici +**关联设计**: design.md + +--- + +## 一、任务分解 + +本任务分为 4 个阶段,按顺序执行: + +### 阶段 1: 测试依赖配置文件创建 +创建测试所需的配置文件,确保测试环境正确配置。 + +### 阶段 2: GitHub Actions 工作流创建 +创建 CI 配置文件,实现自动化测试和覆盖率检查。 + +### 阶段 3: gitignore 配置更新 +更新 .gitignore,排除覆盖率生成的临时文件。 + +### 阶段 4: 验证测试 +推送代码,验证 CI 是否正常工作。 + +--- + +## 二、详细实施规范 + +### 阶段 1: 测试依赖配置文件创建 + +#### 文件 1.1: src/code/agent/requirements-dev.txt + +**位置**: `/Users/cici/workspace/code/cap-comfyui/src/code/agent/requirements-dev.txt` +**操作**: 创建新文件 +**内容规范**: + +```txt +pytest>=8.0.0 +pytest-cov>=4.1.0 +diff-cover>=9.2.0 +``` + +**说明**: +- pytest: 测试框架核心 +- pytest-cov: pytest 的覆盖率插件 +- diff-cover: 差异覆盖率分析工具 +- 使用 >= 约束,允许向后兼容的补丁更新 + +--- + +#### 文件 1.2: src/code/agent/pytest.ini + +**位置**: `/Users/cici/workspace/code/cap-comfyui/src/code/agent/pytest.ini` +**操作**: 创建新文件 +**内容规范**: + +```ini +[pytest] +testpaths = test +python_files = *_test.py +python_classes = Test* +python_functions = test_* +addopts = + -v + --strict-markers + --tb=short +``` + +**配置项说明**: +- `testpaths = test`: 测试文件搜索路径,指向 test/ 目录 +- `python_files = *_test.py`: 匹配现有测试文件命名模式(如 task_manager_test.py) +- `python_classes = Test*`: 测试类以 Test 开头 +- `python_functions = test_*`: 测试函数以 test_ 开头 +- `addopts`: + - `-v`: 详细输出模式,显示每个测试的结果 + - `--strict-markers`: 严格标记模式,防止拼写错误的标记 + - `--tb=short`: 使用简短的回溯格式,减少日志输出 + +--- + +#### 文件 1.3: src/code/agent/.coveragerc + +**位置**: `/Users/cici/workspace/code/cap-comfyui/src/code/agent/.coveragerc` +**操作**: 创建新文件 +**内容规范**: + +```ini +[run] +source = . +omit = + */test/* + */tests/* + */__pycache__/* + */venv/* + */.venv/* + */htmlcov/* + */.pytest_cache/* + +[report] +precision = 2 +show_missing = True +skip_covered = False +exclude_lines = + pragma: no cover + def __repr__ + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: + if TYPE_CHECKING: + @abstractmethod + +[html] +directory = htmlcov + +[xml] +output = coverage.xml +``` + +**配置项说明**: + +**[run] 节**: +- `source = .`: 分析当前目录(src/code/agent)的代码 +- `omit`: 排除不需要覆盖率统计的文件模式 + - 测试文件本身 + - Python 缓存目录 + - 虚拟环境 + - 覆盖率报告目录 + +**[report] 节**: +- `precision = 2`: 覆盖率百分比精确到小数点后两位 +- `show_missing = True`: 显示未覆盖的行号 +- `skip_covered = False`: 报告中包含已覆盖的文件 +- `exclude_lines`: 排除特定代码模式(如 pragma 注释、抽象方法等) + +**[html] 节**: +- `directory = htmlcov`: HTML 报告输出目录 + +**[xml] 节**: +- `output = coverage.xml`: XML 报告输出文件(供 diff-cover 使用) + +--- + +### 阶段 2: GitHub Actions 工作流创建 + +#### 文件 2.1: .github/workflows/test-coverage.yml + +**位置**: `/Users/cici/workspace/code/cap-comfyui/.github/workflows/test-coverage.yml` +**操作**: 创建新文件(需先创建 .github/workflows 目录) +**内容规范**: + +```yaml +name: Test Coverage + +on: + push: + branches: + - '**' + +permissions: + contents: write + +jobs: + test-coverage: + runs-on: ubuntu-latest + + steps: + - name: Checkout code with full history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' + + - name: Install dependencies + working-directory: src/code/agent + run: | + pip install -r requirements.txt + pip install -r requirements-dev.txt + + - name: Run tests with coverage + working-directory: src/code/agent + run: | + pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term + + - name: Check diff coverage against cap branch + working-directory: src/code/agent + run: | + diff-cover coverage.xml --compare-branch=origin/cap --fail-under=95 + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: src/code/agent/htmlcov/ + retention-days: 30 + + - name: Generate diff coverage HTML report + if: always() + working-directory: src/code/agent + run: | + diff-cover coverage.xml --compare-branch=origin/cap --html-report=diff-coverage.html + + - name: Upload diff coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: diff-coverage-report + path: src/code/agent/diff-coverage.html + retention-days: 30 + + - name: Create coverage index page + if: github.ref == 'refs/heads/cap' + working-directory: src/code/agent + run: | + mkdir -p gh-pages-deploy + cp -r htmlcov/* gh-pages-deploy/ + cp diff-coverage.html gh-pages-deploy/ + cat > gh-pages-deploy/index.html << 'EOF' + + + + + Coverage Reports - cap-comfyui + + + +

Coverage Reports - cap-comfyui Agent

+

Last updated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")

+ +
+

📊 Full Coverage Report

+

Complete test coverage report for all source code in src/code/agent/

+ View Full Coverage Report +
+ +
+

📈 Diff Coverage Report

+

Coverage report for code changes compared to the cap branch

+ View Diff Coverage Report +
+ +
+

ℹ️ About

+

These reports are automatically generated by GitHub Actions on every push to the cap branch.

+

Diff coverage threshold: ≥ 95%

+
+ + + EOF + + - name: Deploy to GitHub Pages + if: github.ref == 'refs/heads/cap' + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: src/code/agent/gh-pages-deploy + keep_files: false +``` + +**权限配置**: +- `permissions: contents: write`: 允许 workflow 向 gh-pages 分支推送内容 + +**步骤说明**: + +1. **Checkout code with full history** + - 使用 `actions/checkout@v4`(最新版本) + - `fetch-depth: 0`: 获取完整 git 历史,diff-cover 需要访问 cap 分支 + +2. **Set up Python 3.10** + - 使用 `actions/setup-python@v5` + - 指定 Python 3.10,匹配项目版本 + - `cache: 'pip'`: 缓存 pip 依赖,加速后续运行 + +3. **Install dependencies** + - 工作目录: `src/code/agent` + - 先安装生产依赖,再安装测试依赖 + - 确保环境与本地一致 + +4. **Run tests with coverage** + - 工作目录: `src/code/agent` + - `--cov=.`: 覆盖当前目录 + - `--cov-report=xml`: 生成 coverage.xml(必需,供 diff-cover 使用) + - `--cov-report=html`: 生成 HTML 报告(可选,便于查看) + - `--cov-report=term`: 终端输出(可选,CI 日志中显示) + +5. **Check diff coverage** ⚠️ **关键步骤** + - 工作目录: `src/code/agent` + - `--compare-branch=origin/cap`: 与远程 cap 分支对比 + - `--fail-under=95`: 差异覆盖率低于 95% 时失败 + - 此步骤失败会导致整个 CI 失败 + +6. **Upload coverage report** + - `if: always()`: 即使前面步骤失败也上传 + - 保存 HTML 覆盖率报告为 artifact + - 保留 30 天 + +7. **Generate diff coverage HTML report** + - 生成可视化的差异覆盖率报告 + - 显示哪些新增行未被覆盖 + +8. **Upload diff coverage report** + - 上传差异覆盖率 HTML 报告 + - 便于查看具体是哪些代码未覆盖 + +9. **Create coverage index page** 🆕 + - `if: github.ref == 'refs/heads/cap'`: 仅在 cap 分支运行 + - 创建 gh-pages-deploy 临时目录 + - 复制 htmlcov 和 diff-coverage.html + - 生成 index.html 作为导航页面 + - 显示最后更新时间和报告链接 + +10. **Deploy to GitHub Pages** 🆕 + - `if: github.ref == 'refs/heads/cap'`: 仅在 cap 分支部署 + - 使用 `peaceiris/actions-gh-pages@v3` action + - 自动推送到 gh-pages 分支 + - `keep_files: false`: 每次完全替换,避免累积旧文件 + +--- + +### 阶段 3: gitignore 配置更新 + +#### 文件 3.1: .gitignore + +**位置**: `/Users/cici/workspace/code/cap-comfyui/.gitignore` +**操作**: 在现有文件末尾追加内容 +**追加内容**: + +``` +# Coverage reports +**/.coverage +**/.coverage.* +**/coverage.xml +**/htmlcov/ +**/diff-coverage.html +**/gh-pages-deploy/ +``` + +**说明**: +- 排除 coverage.py 生成的所有覆盖率相关文件 +- 排除 gh-pages-deploy 临时目录(用于 GitHub Pages 部署) +- 这些文件不应提交到仓库(每次运行都会重新生成) + +--- + +### 阶段 4: GitHub Pages 配置 + +#### 配置 4.1: 启用 GitHub Pages + +**操作步骤**: +1. 打开 GitHub 仓库网页 +2. 导航到 **Settings** > **Pages** +3. 在 **Source** 部分选择: + - Branch: `gh-pages` + - Folder: `/ (root)` +4. 点击 **Save** + +**说明**: +- gh-pages 分支会在首次部署时自动创建 +- 无需手动创建该分支 +- peaceiris/actions-gh-pages action 会自动处理 + +**访问链接**: +部署后,覆盖率报告将可通过以下链接访问: +``` +https://.github.io// +``` + +**示例结构**: +``` +https://.github.io/cap-comfyui/ +├── index.html # 导航页面 +├── htmlcov/ # 完整覆盖率报告 +│ └── index.html +└── diff-coverage.html # 差异覆盖率报告 +``` + +--- + +### 阶段 5: 本地验证测试 + +#### 验证步骤 5.1: 本地测试 + +**命令序列**: +```bash +cd src/code/agent +pip install -r requirements-dev.txt +pytest --cov=. --cov-report=xml --cov-report=term +diff-cover coverage.xml --compare-branch=cap --fail-under=95 +``` + +**预期结果**: +- pytest 应该全部通过 +- coverage.xml 生成成功 +- diff-cover 执行成功(可能失败,取决于当前分支的变更) + +**注意**: 如果当前分支相对 cap 没有代码变更,diff-cover 会显示 "No lines with coverage information in this diff" + +#### 验证步骤 6.1: 推送并观察 CI + +**命令序列**: +```bash +git add .github/workflows/test-coverage.yml +git add src/code/agent/requirements-dev.txt +git add src/code/agent/pytest.ini +git add src/code/agent/.coveragerc +git add .gitignore +git add docs/github-ci-coverage/ +git add .tasks/ +git commit -m "feat: add GitHub CI with 95% diff coverage check and GitHub Pages deployment" +git push -u origin task/github-ci-coverage_2026-02-25_1 +``` + +**预期结果**: +- GitHub Actions 自动触发 +- 在 GitHub 仓库的 Actions 标签页可以看到运行状态 +- CI 运行约 2-5 分钟 +- 检查 CI 是否成功 + +#### 验证步骤 6.2: GitHub Pages 部署验证 + +**前置条件**: +- CI 在功能分支成功运行 +- 代码已合并到 cap 分支 + +**命令序列**: +```bash +# 合并到 cap 分支(在 CI 验证通过后) +git checkout cap +git merge task/github-ci-coverage_2026-02-25_1 +git push origin cap +``` + +**验证步骤**: +1. 推送到 cap 分支后,等待 CI 运行完成 +2. 在 GitHub Actions 页面确认 "Deploy to GitHub Pages" 步骤成功 +3. 在 Settings > Pages 查看部署状态 +4. 访问 GitHub Pages 链接(格式:`https://.github.io//`) +5. 验证 index.html 导航页面正常显示 +6. 点击链接,验证完整覆盖率报告和差异覆盖率报告可访问 + +**预期结果**: +- ✅ gh-pages 分支自动创建 +- ✅ 覆盖率报告部署成功 +- ✅ 可以通过浏览器访问报告 +- ✅ 页面显示最后更新时间 +- ✅ 两个报告链接都正常工作 + +--- + +## 三、文件清单与路径映射 + +| 序号 | 文件路径 | 操作类型 | 描述 | +|-----|---------|---------|------| +| 1 | src/code/agent/requirements-dev.txt | 创建 | 测试依赖配置 | +| 2 | src/code/agent/pytest.ini | 创建 | pytest 配置 | +| 3 | src/code/agent/.coveragerc | 创建 | coverage 配置 | +| 4 | .github/workflows/test-coverage.yml | 创建 | GitHub Actions 工作流(含 Pages 部署) | +| 5 | .gitignore | 修改 | 追加覆盖率文件排除规则 | +| 6 | GitHub Pages 设置 | 配置 | 在仓库 Settings 中启用 | + +--- + +## 四、依赖关系 + +``` +阶段 1 (配置文件) + └─> 阶段 2 (GitHub Actions) + └─> 阶段 3 (.gitignore) + └─> 阶段 4 (GitHub Pages 配置) + └─> 阶段 5 (本地验证) + └─> 阶段 6 (提交与部署验证) +``` + +**依赖说明**: +- 阶段 1 必须先完成,因为 GitHub Actions 依赖这些配置文件 +- 阶段 2 和阶段 3 可以并行,但建议顺序执行 +- 阶段 4 (GitHub Pages 配置) 可以在推送后再配置 +- 阶段 5 在文件创建后本地验证 +- 阶段 6 需要所有配置完成后执行 + +--- + +## 五、实施清单 + +### 前置准备 +- [x] 创建任务分支 `task/github-ci-coverage_2026-02-25_1` +- [x] 创建任务文件 `.tasks/2026-02-25_1_github-ci-coverage.md` +- [x] 创建设计文档 `docs/github-ci-coverage/design.md` +- [x] 创建开发文档 `docs/github-ci-coverage/development.md` +- [x] 创建测试文档 `docs/github-ci-coverage/cases.md` + +### 阶段 1: 测试依赖配置文件创建 +1. 创建文件 `src/code/agent/requirements-dev.txt`,包含 3 行依赖(pytest>=8.0.0、pytest-cov>=4.1.0、diff-cover>=9.2.0) +2. 创建文件 `src/code/agent/pytest.ini`,配置 testpaths=test、python_files=*_test.py、python_classes=Test*、python_functions=test_*、addopts=-v/--strict-markers/--tb=short +3. 创建文件 `src/code/agent/.coveragerc`,配置 [run] source=./omit 测试文件、[report] precision=2/show_missing=True、[html] directory=htmlcov、[xml] output=coverage.xml + +### 阶段 2: GitHub Actions 工作流创建 +4. 创建目录 `.github/workflows/` +5. 创建文件 `.github/workflows/test-coverage.yml`,包含 name=Test Coverage、on push all branches、permissions contents write、jobs test-coverage with 10 steps(checkout、setup python、install、test、check diff、upload artifacts×2、create index、deploy pages) + +### 阶段 3: gitignore 配置更新 +6. 在 `.gitignore` 文件末尾追加 6 行覆盖率文件排除规则(.coverage*、coverage.xml、htmlcov/、diff-coverage.html、gh-pages-deploy/) + +### 阶段 4: GitHub Pages 配置 +7. 在 GitHub 仓库 Settings > Pages 中配置 Source 为 gh-pages 分支、目录为 root + +### 阶段 5: 本地验证测试 +8. 在 src/code/agent 目录执行 `pip install -r requirements-dev.txt` 安装测试依赖 +9. 在 src/code/agent 目录执行 `pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term` 运行测试 +10. 在 src/code/agent 目录执行 `diff-cover coverage.xml --compare-branch=cap` 验证 diff-cover 工具 + +### 阶段 6: 提交与 CI 验证 +11. 暂存所有新增文件(git add .github/ src/code/agent/requirements-dev.txt src/code/agent/pytest.ini src/code/agent/.coveragerc .gitignore docs/ .tasks/) +12. 提交更改(git commit -m "feat: add GitHub CI with 95% diff coverage check and GitHub Pages deployment") +13. 推送到远程仓库(git push -u origin task/github-ci-coverage_2026-02-25_1) +14. 在 GitHub Actions 页面查看 workflow 运行状态 +15. 确认所有 CI 步骤执行成功(除 GitHub Pages 部署外,因为不在 cap 分支) + +### 阶段 7: GitHub Pages 部署验证(需要合并到 cap 后) +16. 创建 Pull Request 或直接合并到 cap 分支 +17. 推送到 cap 分支触发 GitHub Pages 部署 +18. 等待 CI 完成并检查 "Deploy to GitHub Pages" 步骤成功 +19. 访问 GitHub Pages URL(https://\.github.io/\/)验证导航页面 +20. 点击 "View Full Coverage Report" 验证完整报告可访问 +21. 点击 "View Diff Coverage Report" 验证差异报告可访问 + +--- + +## 六、工作量估算 + +| 阶段 | 文件数量 | 预估复杂度 | 风险等级 | +|-----|---------|-----------|---------| +| 阶段 1 | 3 个文件 | 低 | 低 | +| 阶段 2 | 1 个文件 | 中 | 中 | +| 阶段 3 | 1 个文件 | 低 | 低 | +| 阶段 4 | GitHub 配置 | 低 | 低 | +| 阶段 5 | 本地验证 | 中 | 中 | +| 阶段 6 | CI+Pages 验证 | 中 | 中 | + +**总计**: 5 个文件修改/创建,1 个 GitHub 配置,17 个实施步骤 + +--- + +## 七、潜在问题与解决方案 + +### 问题 1: 首次运行 diff-cover 可能找不到 cap 分支 + +**原因**: GitHub Actions 默认只 checkout 当前分支 + +**解决**: +- 使用 `fetch-depth: 0` 获取完整历史 +- diff-cover 使用 `origin/cap` 而不是 `cap` + +### 问题 2: 如果当前分支是 cap 分支本身 + +**现象**: diff-cover 会显示 "No lines with coverage information in this diff" + +**解决**: 这是正常行为,因为没有差异 + +### 问题 3: Python 3.10 在 GitHub Actions 中可能不是默认版本 + +**解决**: 明确指定 `python-version: '3.10'` 在 setup-python action 中 + +### 问题 4: working-directory 设置错误导致找不到文件 + +**解决**: 所有与测试相关的步骤都设置 `working-directory: src/code/agent` + +### 问题 5: 依赖安装失败 + +**可能原因**: +- requirements.txt 中的某些包无法安装 +- 网络问题 + +**解决**: +- 本地先测试依赖安装 +- 如果遇到问题,检查包版本兼容性 + +### 问题 6: GitHub Pages 部署权限问题 + +**原因**: workflow 没有写入 gh-pages 分支的权限 + +**解决**: +- 在 workflow 顶层添加 `permissions: contents: write` +- 使用内置的 `${{ secrets.GITHUB_TOKEN }}` + +### 问题 7: GitHub Pages 未启用 + +**现象**: 部署成功但无法访问页面 + +**解决**: +- 在仓库 Settings > Pages 中配置 Source 为 gh-pages 分支 +- 等待几分钟让 GitHub Pages 生效 + +### 问题 8: GitHub Pages 显示 404 + +**可能原因**: +- Pages 配置的分支或目录错误 +- 部署未成功 +- index.html 不存在 + +**解决**: +- 检查 gh-pages 分支是否存在且有内容 +- 确认 Settings > Pages 配置正确 +- 查看 Actions 日志确认部署步骤成功 + +--- + +## 八、验证清单 + +实施完成后,验证以下内容: + +### 配置文件验证 +- [ ] requirements-dev.txt 内容正确 +- [ ] pytest.ini 配置项完整 +- [ ] .coveragerc 配置项完整 +- [ ] test-coverage.yml 语法正确(YAML 格式) +- [ ] .gitignore 已更新 + +### 本地验证 +- [ ] 可以成功安装 requirements-dev.txt +- [ ] pytest 可以发现并运行所有测试 +- [ ] coverage.xml 生成成功 +- [ ] diff-cover 可以正常执行 + +### CI 验证 +- [ ] GitHub Actions workflow 出现在仓库中 +- [ ] Push 后自动触发 CI +- [ ] CI 日志中可以看到所有步骤 +- [ ] pytest 步骤显示测试结果 +- [ ] diff-cover 步骤显示差异覆盖率 +- [ ] artifact 上传成功(coverage-report 和 diff-coverage-report) + +--- + +## 九、回滚计划 + +如果实施后发现问题: + +1. **配置错误**: + - 修改对应的配置文件 + - 重新提交 + +2. **CI 持续失败**: + - 检查 GitHub Actions 日志 + - 确认错误原因 + - 根据错误调整配置 + +3. **阻碍正常开发**: + - 临时降低 `--fail-under` 阈值(如 80%) + - 逐步提升覆盖率 + - 最终恢复到 95% + +4. **完全回滚**: + - 删除 `.github/workflows/test-coverage.yml` + - 或暂时禁用 workflow(在文件中添加 `if: false`) + +--- + +## 十、后续优化建议 + +实施完成后,可以考虑的增强功能: + +1. **PR 评论集成** + - 使用 GitHub Actions 在 PR 中自动评论覆盖率信息 + - 工具: py-cov-action/python-coverage-comment-action + +2. **覆盖率徽章** + - 生成动态徽章显示在 README 中 + - 工具: shields.io + +3. **多 Python 版本测试** + - 使用 matrix 策略测试 Python 3.9, 3.10, 3.11 + - 确保跨版本兼容性 + +4. **Makefile 集成** + - 在项目根目录 Makefile 中添加 `make test-diff` 命令 + - 便于开发者快速运行差异覆盖率检查 + +5. **通知集成** + - 失败时发送通知到 Slack/钉钉等 + - 使用 GitHub Actions 的通知 action + +--- + +## 十一、技术债务 + +无新增技术债务。 + +现有技术债务: +- 整体测试覆盖率 77%,建议逐步提升到 90%+ + +--- + +## 十二、进度跟踪 + +| 步骤 | 状态 | 完成时间 | 备注 | +|-----|------|---------|------| +| 1. requirements-dev.txt | 待执行 | - | - | +| 2. pytest.ini | 待执行 | - | - | +| 3. .coveragerc | 待执行 | - | - | +| 4. .github/workflows/ | 待执行 | - | - | +| 5. test-coverage.yml | 待执行 | - | - | +| 6. .gitignore | 待执行 | - | - | +| 7-14. 验证测试 | 待执行 | - | - | + +--- + +## 十三、参考资料 + +- [diff-cover 官方文档](https://diff-cover.readthedocs.io/) +- [pytest-cov 文档](https://pytest-cov.readthedocs.io/) +- [GitHub Actions 文档](https://docs.github.com/en/actions) +- [coverage.py 文档](https://coverage.readthedocs.io/) diff --git a/src/code/agent/.coveragerc b/src/code/agent/.coveragerc new file mode 100644 index 0000000..1e94566 --- /dev/null +++ b/src/code/agent/.coveragerc @@ -0,0 +1,29 @@ +[run] +source = . +omit = + */test/* + */tests/* + */__pycache__/* + */venv/* + */.venv/* + */htmlcov/* + */.pytest_cache/* + +[report] +precision = 2 +show_missing = True +skip_covered = False +exclude_lines = + pragma: no cover + def __repr__ + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: + if TYPE_CHECKING: + @abstractmethod + +[html] +directory = htmlcov + +[xml] +output = coverage.xml diff --git a/src/code/agent/pytest.ini b/src/code/agent/pytest.ini new file mode 100644 index 0000000..64ca466 --- /dev/null +++ b/src/code/agent/pytest.ini @@ -0,0 +1,9 @@ +[pytest] +testpaths = test +python_files = *_test.py +python_classes = Test* +python_functions = test_* +addopts = + -v + --strict-markers + --tb=short diff --git a/src/code/agent/requirements-dev.txt b/src/code/agent/requirements-dev.txt new file mode 100644 index 0000000..420314e --- /dev/null +++ b/src/code/agent/requirements-dev.txt @@ -0,0 +1,3 @@ +pytest>=8.0.0 +pytest-cov>=4.1.0 +diff-cover>=9.2.0 From 36f2b955e53e80e200c6aba17eae35db3559314d Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 2 Mar 2026 10:43:30 +0800 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20RIPER-5=20?= =?UTF-8?q?=E8=A7=84=E5=88=99=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic4788fd9b99ee6c1c96b6bebff00db1aa3f42efe Co-developed-by: Cursor Made-with: Cursor --- .cursor/rules/riper5.mdc | 4 ++-- src/code/agent/.tasks/2026-02-25_1_github-ci-coverage.md | 0 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/code/agent/.tasks/2026-02-25_1_github-ci-coverage.md diff --git a/.cursor/rules/riper5.mdc b/.cursor/rules/riper5.mdc index 3c50d1a..c955ab0 100644 --- a/.cursor/rules/riper5.mdc +++ b/.cursor/rules/riper5.mdc @@ -4,7 +4,7 @@ alwaysApply: true ### 背景介绍 -你是Claude 4.0,集成在Cursor IDE中,Cursor是基于AI的VS Code分支。由于你的高级功能,你往往过于急切,经常在没有明确请求的情况下实施更改,通过假设你比用户更了解情况而破坏现有逻辑。这会导致对代码的不可接受的灾难性影响。在处理代码库时——无论是Web应用程序、数据管道、嵌入式系统还是任何其他软件项目——未经授权的修改可能会引入微妙的错误并破坏关键功能。为防止这种情况,你必须遵循这个严格的协议。 +你是Claude 4.5,集成在Cursor IDE中,Cursor是基于AI的VS Code分支。由于你的高级功能,你往往过于急切,经常在没有明确请求的情况下实施更改,通过假设你比用户更了解情况而破坏现有逻辑。这会导致对代码的不可接受的灾难性影响。在处理代码库时——无论是Web应用程序、数据管道、嵌入式系统还是任何其他软件项目——未经授权的修改可能会引入微妙的错误并破坏关键功能。为防止这种情况,你必须遵循这个严格的协议。 语言设置:除非用户另有指示,所有常规交互响应都应该使用中文。然而,模式声明(例如\[MODE: RESEARCH\])和特定格式化输出(例如代码块、清单等)应保持英文,以确保格式一致性。 @@ -71,7 +71,7 @@ alwaysApply: true 1. 创建功能分支(如需要): ```java - git checkout -b task/[TASK_IDENTIFIER]_[TASK_DATE_AND_NUMBER] + git checkout -b [TASK_IDENTIFIER]_[TASK_DATE_AND_NUMBER] ``` 2. 创建任务文件(如需要): diff --git a/src/code/agent/.tasks/2026-02-25_1_github-ci-coverage.md b/src/code/agent/.tasks/2026-02-25_1_github-ci-coverage.md new file mode 100644 index 0000000..e69de29