UNPKG

git-yike-logger-hook

Version:

A TypeScript Git hook plugin for automatically generating commit logs with TODO/WIP comment scanning

468 lines (359 loc) 10.9 kB
# 开发指南 ## 项目结构详解 ``` git-logger-hook/ ├── src/ # 源代码目录 │ ├── types.ts # 类型定义 │ ├── git-utils.ts # Git 操作工具 │ ├── comment-scanner.ts # 注释扫描器 │ ├── logger.ts # 日志生成器(核心) │ ├── hook.ts # Git hook 入口 │ ├── install.ts # Hook 安装器 │ └── index.ts # 模块导出 ├── dist/ # 编译输出目录 ├── .git-logs/ # 日志文件目录 ├── package.json # 项目配置 ├── tsconfig.json # TypeScript 配置 ├── .gitignore # Git 忽略文件 ├── README.md # 项目文档 ├── DEVELOPMENT.md # 开发指南 └── example.js # 使用示例 ``` ## 核心设计模式 ### 1. 组合模式 (Composition Pattern) ```typescript export class GitLogger { private gitUtils: GitUtils; private commentScanner: CommentScanner; constructor() { this.gitUtils = new GitUtils(); this.commentScanner = new CommentScanner(); } } ``` **优势:** - 职责分离,每个类只负责特定功能 - 易于测试和维护 - 支持独立扩展各个组件 ### 2. 策略模式 (Strategy Pattern) ```typescript // 不同的注释扫描策略 private todoPatterns = [ /\/\/\s*TODO\s*:?\s*(.+)/gi, /\/\*\s*TODO\s*:?\s*(.+?)\s*\*\//gi, // ... ]; ``` **优势:** - 易于添加新的注释格式 - 扫描逻辑与业务逻辑分离 - 支持运行时切换策略 ### 3. 工厂模式 (Factory Pattern) ```typescript // 根据文件类型创建不同的处理器 private isJavaScriptFile(filePath: string): boolean { const ext = path.extname(filePath).toLowerCase(); return this.supportedExtensions.includes(ext); } ``` ## 关键实现细节 ### 1. 异步处理 ```typescript async generateLog(): Promise<void> { try { // 并行执行多个异步操作 const [commitInfo, branch, remote, fileChanges] = await Promise.all([ this.gitUtils.getCurrentCommitInfo(), this.gitUtils.getCurrentBranch(), this.gitUtils.getRemoteInfo(), this.gitUtils.getFileChanges() ]); // 顺序执行依赖操作 const comments = await this.commentScanner.scanChangedFiles(fileChanges); } catch (error) { // 统一错误处理 } } ``` **关键点:** - 使用 `Promise.all()` 并行执行独立操作 - 使用 `await` 顺序执行依赖操作 - 统一的错误处理机制 ### 2. 错误处理策略 ```typescript // 分级错误处理 try { const result = await riskyOperation(); return result; } catch (error) { if (error instanceof SpecificError) { // 特定错误处理 console.warn('特定错误:', error.message); return defaultValue; } else { // 通用错误处理 throw new Error(`操作失败: ${error}`); } } ``` **策略:** - 可恢复错误:记录警告,使用默认值 - 致命错误:抛出异常,终止执行 - 用户友好:提供清晰的错误信息 ### 3. 文件系统操作 ```typescript // 安全的文件操作 private async ensureLogDirectory(): Promise<void> { if (!fs.existsSync(this.config.logDir)) { fs.mkdirSync(this.config.logDir, { recursive: true }); } } // 原子性写入 private async writeLogFile(filePath: string, content: string): Promise<void> { const tempFile = filePath + '.tmp'; fs.writeFileSync(tempFile, content, 'utf8'); fs.renameSync(tempFile, filePath); } ``` **关键点:** - 使用 `recursive: true` 创建嵌套目录 - 使用临时文件确保原子性写入 - 检查文件存在性避免重复操作 ## 性能优化技巧 ### 1. 文件扫描优化 ```typescript // 只扫描变更的文件 async scanChangedFiles(changedFiles: FileChanges): Promise<Comments> { const filesToScan = [...changedFiles.added, ...changedFiles.modified] .filter(file => this.isJavaScriptFile(file)); // 并行扫描多个文件 const results = await Promise.all( filesToScan.map(file => this.scanFile(file)) ); return this.mergeResults(results); } ``` ### 2. 内存管理 ```typescript // 流式处理大文件 private async scanLargeFile(filePath: string): Promise<Comments> { return new Promise((resolve, reject) => { const stream = fs.createReadStream(filePath, { encoding: 'utf8' }); let lineNumber = 0; const comments: CodeComment[] = []; stream.on('line', (line) => { lineNumber++; const found = this.extractComments(line, lineNumber); comments.push(...found); }); stream.on('end', () => resolve({ todos: comments, wips: [] })); stream.on('error', reject); }); } ``` ### 3. 缓存机制 ```typescript // 简单的内存缓存 private fileCache = new Map<string, { content: string; mtime: number }>(); private async getFileContent(filePath: string): Promise<string> { const stat = fs.statSync(filePath); const cac hed = this.fileCache.get(filePath); if (cached && cached.mtime === stat.mtime.getTime()) { return cached.content; } const content = fs.readFileSync(filePath, 'utf8'); this.fileCache.set(filePath, { content, mtime: stat.mtime.getTime() }); return content; } ``` ## 测试策略 ### 1. 单元测试 ```typescript // 使用 Jest 进行单元测试 describe('CommentScanner', () => { test('应该正确提取 TODO 注释', async () => { const scanner = new CommentScanner(); const result = await scanner.scanFile('test.js'); expect(result.todos).toHaveLength(2); expect(result.todos[0].content).toBe('实现这个功能'); }); }); ``` ### 2. 集成测试 ```typescript // 测试完整的日志生成流程 describe('GitLogger 集成测试', () => { test('应该生成完整的日志', async () => { const logger = new GitLogger(); await logger.generateLog(); const logs = await logger.getAllLogs(); expect(logs).toHaveLength(1); expect(logs[0].comments.todos).toBeDefined(); }); }); ``` ### 3. 端到端测试 ```bash #!/bin/bash # 端到端测试脚本 # 1. 创建测试仓库 git init test-repo cd test-repo # 2. 安装插件 npm install ../git-logger-hook node dist/install.js install # 3. 创建测试文件 echo "// TODO: 测试注释" > test.js git add test.js # 4. 提交并验证 git commit -m "测试提交" ls -la .git-logs/ # 5. 验证日志内容 cat .git-logs/*.json | jq '.comments.todos' ``` ## 调试技巧 ### 1. 日志级别 ```typescript enum LogLevel { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, } class Logger { private level: LogLevel = LogLevel.INFO; debug(message: string, ...args: any[]) { if (this.level <= LogLevel.DEBUG) { console.log(`[DEBUG] ${message}`, ...args); } } } ``` ### 2. 性能监控 ```typescript // 性能计时器 class PerformanceTimer { private timers = new Map<string, number>(); start(label: string) { this.timers.set(label, Date.now()); } end(label: string): number { const start = this.timers.get(label); if (!start) return 0; const duration = Date.now() - start; console.log(`${label}: ${duration}ms`); return duration; } } ``` ### 3. 错误追踪 ```typescript // 详细的错误信息 try { await riskyOperation(); } catch (error) { console.error('操作失败:', { error: error.message, stack: error.stack, timestamp: new Date().toISOString(), context: { file: __filename, line: __line }, }); } ``` ## 扩展指南 ### 1. 添加新的注释类型 ```typescript // 1. 在 types.ts 中定义新类型 export type CommentType = 'TODO' | 'WIP' | 'FIXME' | 'NOTE'; // 2. 在 comment-scanner.ts 中添加模式 private fixmePatterns = [ /\/\/\s*FIXME\s*:?\s*(.+)/gi, /\/\*\s*FIXME\s*:?\s*(.+?)\s*\*\//gi ]; // 3. 更新扫描逻辑 private extractMatches(text: string, pattern: RegExp, type: CommentType) { // 实现新的提取逻辑 } ``` ### 2. 添加新的文件类型 ```typescript // 在 comment-scanner.ts 中扩展支持的文件类型 private supportedExtensions = [ '.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte', '.py', '.java' // 新增支持 ]; ``` ### 3. 添加新的 Git 操作 ```typescript // 在 git-utils.ts 中添加新方法 async getCommitStats(): Promise<{ insertions: number; deletions: number; filesChanged: number; }> { const diff = await this.git.diff(['--stat']); // 解析 diff 统计信息 return this.parseDiffStats(diff); } ``` ## 部署指南 ### 1. 本地开发 ```bash # 克隆项目 git clone <repository-url> cd git-logger-hook # 安装依赖 npm install # 开发模式 npm run dev # 测试 npm test ``` ### 2. 生产部署 ```bash # 编译项目 npm run build # 安装到目标仓库 cd /path/to/target/repo npm install /path/to/git-logger-hook node node_modules/git-logger-hook/dist/install.js install ``` ### 3. 全局安装 ```bash # 发布到 npm npm publish # 全局安装 npm install -g git-logger-hook # 在任何仓库中使用 git-logger-hook install ``` ## 贡献指南 ### 1. 代码规范 - 使用 TypeScript 严格模式 - 遵循 ESLint 规则 - 添加完整的 JSDoc 注释 - 保持 80% 以上的测试覆盖率 ### 2. 提交规范 ```bash # 使用约定式提交 git commit -m "feat: 添加新的注释类型支持" git commit -m "fix: 修复文件扫描性能问题" git commit -m "docs: 更新 API 文档" ``` ### 3. 拉取请求 - 提供详细的变更说明 - 包含相关的测试用例 - 更新文档和示例 - 确保所有测试通过 ## 常见问题 ### Q: 为什么选择 TypeScript? A: TypeScript 提供类型安全、更好的 IDE 支持、编译时错误检查,特别适合构建工具类项目。 ### Q: 为什么不直接使用 Git 命令? A: simple-git 提供了统一的 Promise 接口,简化了异步操作,并且内置了错误处理机制。 ### Q: 如何提高扫描性能? A: 只扫描变更的文件、使用并行处理、实现文件缓存、跳过大型目录。 ### Q: 如何扩展支持更多文件类型? A: 在 `comment-scanner.ts` 中添加新的文件扩展名和对应的注释模式。 ### Q: 如何处理大型项目? A: 实现增量扫描、文件缓存、并行处理,并考虑添加配置文件来排除特定目录。