diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9cb0606 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,64 @@ +## Description / 描述 + + + +## Type of Change / 变更类型 + +- [ ] 🐛 Bug fix / 缺陷修复 +- [ ] ✨ New feature / 新功能 +- [ ] 💥 Breaking change / 破坏性变更 +- [ ] 📝 Documentation / 文档更新 +- [ ] 🔧 Configuration / 配置变更 +- [ ] ♻️ Refactor / 代码重构 +- [ ] 🎨 Style / 代码风格 +- [ ] ⚡ Performance / 性能优化 +- [ ] ✅ Test / 测试相关 + +## Related Issues / 关联 Issue + + + + +## Pre-submission Checklist / 提交前检查清单 + +### Critical Issues / 关键问题 🔴 +- [ ] No requirements mismatch `[REQ]` / 无需求不匹配 +- [ ] No logic bugs `[LOGI]` / 无逻辑缺陷 +- [ ] No security vulnerabilities `[SEC]` / 无安全漏洞 +- [ ] No auth/permission issues `[AUTH]` / 无认证授权问题 + +### High Priority / 高优先级 🟠 +- [ ] Design is appropriate `[DSN]` / 设计合理 +- [ ] Error handling is robust `[RBST]` / 错误处理健壮 +- [ ] Transactions handled correctly `[TRANS]` / 事务处理正确 +- [ ] No concurrency issues `[CONC]` / 无并发问题 +- [ ] Performance is acceptable `[PERF]` / 性能可接受 + +### Code Quality / 代码质量 🟡🟢 +- [ ] Code is maintainable `[MAIN]` / 代码可维护 +- [ ] No unnecessary coupling `[CPL]` / 无不必要耦合 +- [ ] Code is readable `[READ]` / 代码可读 +- [ ] No code duplication `[DUP]` / 无代码重复 +- [ ] Naming is clear `[NAM]` / 命名清晰 + +### Testing / 测试 +- [ ] Unit tests added/updated / 已添加/更新单元测试 +- [ ] Integration tests passed / 集成测试通过 +- [ ] Manual testing completed / 已完成手动测试 + +### Documentation / 文档 +- [ ] Code comments added where needed / 已添加必要的代码注释 +- [ ] README updated if needed / 如需要已更新 README +- [ ] API docs updated if needed / 如需要已更新 API 文档 + +## Screenshots / 截图 + + + +## Additional Notes / 补充说明 + + + +--- + +> 💡 **Review Guidelines**: This PR will be reviewed following our [Code Review Guide / 代码审查指南](docs/codereview/CODE_REVIEW_GUIDE_CN.md) diff --git a/.github/copilot-code-review.yml b/.github/copilot-code-review.yml new file mode 100644 index 0000000..3ba2625 --- /dev/null +++ b/.github/copilot-code-review.yml @@ -0,0 +1,54 @@ +# GitHub Copilot Code Review Configuration +# Documentation: https://docs.github.com/en/copilot/using-github-copilot/code-review + +reviews: + # Enable automatic code review on pull requests + auto_review: true + + # High-level focus areas for reviews + high_level_summary: true + + # Review scope configuration + review_scope: + # Focus on these aspects during review + focus_areas: + - correctness + - security + - performance + - maintainability + - best_practices + + # Path filters - which files to review + path_filters: + include: + - "**/*.go" + - "**/*.java" + - "**/*.py" + - "**/*.js" + - "**/*.ts" + - "**/*.jsx" + - "**/*.tsx" + - "**/*.rs" + - "**/*.c" + - "**/*.cpp" + - "**/*.cs" + - "**/*.rb" + - "**/*.php" + - "**/*.swift" + - "**/*.kt" + - "**/*.scala" + exclude: + - "**/*.test.*" + - "**/*.spec.*" + - "**/test/**" + - "**/tests/**" + - "**/__tests__/**" + - "**/node_modules/**" + - "**/vendor/**" + - "**/dist/**" + - "**/build/**" + - "**/*.min.js" + - "**/*.generated.*" + + # Custom instructions file (automatically read by Copilot) + # instructions_file: .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..e87741c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,65 @@ +# GitHub Copilot 代码审查指令 + +本文档为 GitHub Copilot 提供代码审查的指导规范。 + +## 核心审查原则 + +审查代码时,需要从多个角度评估: + +1. **正确性**:代码是否按预期工作? +2. **安全性**:是否存在安全漏洞? +3. **性能**:代码是否高效? +4. **可维护性**:代码是否易于理解和修改? +5. **最佳实践**:代码是否遵循既定规范? + +## 黄金法则 + +1. **简单、高效、安全的设计** - 避免过度设计;优先考虑清晰性和安全性 +2. **严格的完整性和性能** - 确保数据完整性,按需优化 +3. **合理的模块化** - 模块内高内聚,模块间低耦合 +4. **减少重复** - DRY原则 +5. **良好的命名和注释** - 清晰、描述性的名称;有意义的注释 + +## 审查分类参考 + +完整的审查分类检查清单请参见:docs/codereview/CODE_REVIEW_GUIDE_CN.md + +### 问题分类速查表 + +| 分类 | 代码 | 优先级 | +|------|------|--------| +| 需求不匹配 | `REQ` | 🔴 关键 | +| 逻辑问题 | `LOGI` | 🔴 关键 | +| 安全问题 | `SEC` | 🔴 关键 | +| 认证/授权 | `AUTH` | 🔴 关键 | +| 设计问题 | `DSN` | 🟠 高 | +| 健壮性 | `RBST` | 🟠 高 | +| 事务问题 | `TRANS` | 🟠 高 | +| 并发问题 | `CONC` | 🟠 高 | +| 性能问题 | `PERF` | 🟠 高 | +| 兼容性 | `CPT` | 🟡 中 | +| 幂等性 | `IDE` | 🟡 中 | +| 可维护性 | `MAIN` | 🟡 中 | +| 耦合问题 | `CPL` | 🟡 中 | +| 可读性 | `READ` | 🟢 普通 | +| 简洁性 | `SIMPL` | 🟢 普通 | +| 一致性 | `CONS` | 🟢 普通 | +| 重复代码 | `DUP` | 🟢 普通 | +| 命名问题 | `NAM` | 🟢 普通 | +| 文档字符串 | `DOCS` | 🟢 普通 | +| 注释问题 | `COMM` | 🔵 低 | +| 日志问题 | `LOGG` | 🔵 低 | +| 错误消息 | `ERR` | 🔵 低 | +| 格式问题 | `FOR` | 🔵 低 | +| 语法问题 | `GRAM` | 🔵 低 | +| 最佳实践 | `PRAC` | 🔵 低 | +| PR描述 | `PR` | 🔵 低 | + +## 响应格式 + +提供审查反馈时: +- 具体且可操作 +- 引用问题分类(如 `[LOGI]`、`[SEC]`、`[PERF]`) +- 建议具体的改进方案 +- 解释建议背后的原因 +- 优先处理关键和高优先级问题 diff --git a/.github/gemini-instructions.md b/.github/gemini-instructions.md new file mode 100644 index 0000000..29ef960 --- /dev/null +++ b/.github/gemini-instructions.md @@ -0,0 +1,145 @@ +# Gemini Code Review 使用指南 + +本文档为 Gemini 提供代码审查的指导规范。 + +## 角色定义 + +你是一位专业的代码审查专家。在审查代码时,需要从多个角度评估代码,识别问题并提出改进建议。 + +## 核心审查原则 + +1. **正确性**:代码是否按预期工作? +2. **安全性**:是否存在安全漏洞? +3. **性能**:代码是否高效? +4. **可维护性**:代码是否易于理解和修改? +5. **最佳实践**:代码是否遵循既定规范? + +## 黄金法则 + +1. **简单、高效、安全的设计** - 避免过度设计;优先考虑清晰性和安全性 +2. **严格的完整性和性能** - 确保数据完整性,按需优化 +3. **合理的模块化** - 模块内高内聚,模块间低耦合 +4. **减少重复** - DRY原则 +5. **良好的命名和注释** - 清晰、描述性的名称;有意义的注释 + +## 问题分类 + +审查代码时,使用以下分类代码识别和标注问题: + +### 🔴 关键问题(必须修复) + +| 代码 | 分类 | 检查要点 | +|------|------|----------| +| `REQ` | 需求不匹配 | 实现与需求不符;遗漏边界情况 | +| `LOGI` | 逻辑问题 | 空指针、除零错误、无限循环、分支不完整 | +| `SEC` | 安全问题 | SQL注入、XSS、硬编码凭证、未验证输入 | +| `AUTH` | 认证/授权 | 缺少认证检查、访问控制不当 | + +### 🟠 高优先级(强烈建议修复) + +| 代码 | 分类 | 检查要点 | +|------|------|----------| +| `DSN` | 设计问题 | 过于复杂的设计、架构决策不当 | +| `RBST` | 健壮性 | 缺少错误处理、无优雅降级 | +| `TRANS` | 事务问题 | 缺少事务边界、错误时未回滚 | +| `CONC` | 并发问题 | 竞态条件、死锁、非线程安全代码 | +| `PERF` | 性能问题 | O(n²)算法、N+1查询、缺少索引 | + +### 🟡 中优先级(建议修复) + +| 代码 | 分类 | 检查要点 | +|------|------|----------| +| `CPT` | 兼容性 | 破坏性变更、版本不兼容 | +| `IDE` | 幂等性 | 应该幂等但非幂等的操作 | +| `MAIN` | 可维护性 | 难以理解、紧密耦合的代码 | +| `CPL` | 耦合问题 | 硬编码依赖、隐藏依赖 | + +### 🟢 普通优先级(可以改进) + +| 代码 | 分类 | 检查要点 | +|------|------|----------| +| `READ` | 可读性 | 变量名不清晰、深层嵌套代码 | +| `SIMPL` | 简洁性 | 过度设计、未使用的代码 | +| `CONS` | 一致性 | 命名不一致、风格不匹配 | +| `DUP` | 重复代码 | 复制粘贴代码、重复逻辑 | +| `NAM` | 命名问题 | 模糊的名称、误导性名称 | +| `DOCS` | 文档字符串 | 缺失或过时的文档 | + +### 🔵 低优先级(锦上添花) + +| 代码 | 分类 | 检查要点 | +|------|------|----------| +| `COMM` | 注释问题 | 复杂逻辑缺少注释 | +| `LOGG` | 日志问题 | 缺少错误日志、过度日志 | +| `ERR` | 错误消息 | 模糊的错误消息 | +| `FOR` | 格式问题 | 格式问题、拼写错误 | +| `GRAM` | 语法问题 | 注释/文档中的语法错误 | +| `PRAC` | 最佳实践 | 违反规范 | +| `PR` | PR描述 | PR描述不完整 | + +## 响应格式 + +提供审查反馈时: + +1. **以摘要开始** - 简要概述代码质量 +2. **按优先级列出问题** - 关键问题优先 +3. **使用分类代码** - 如 `[LOGI]`、`[SEC]`、`[PERF]` +4. **具体明确** - 指出确切的行/函数 +5. **建议修复方案** - 提供具体的改进建议 +6. **解释原因** - 为什么这是一个问题? + +### 输出格式示例 + +```markdown +## 代码审查总结 + +整体评价:代码正确实现了功能,但存在一些安全和性能问题。 + +### 🔴 关键问题 + +**[SEC] SQL注入漏洞**(第42行) +- 问题:用户输入直接拼接到SQL查询中 +- 修复:使用参数化查询 +```python +# 修改前 +query = f"SELECT * FROM users WHERE id = {user_id}" + +# 修改后 +query = "SELECT * FROM users WHERE id = %s" +cursor.execute(query, (user_id,)) +``` + +### 🟠 高优先级问题 + +**[PERF] N+1查询问题**(第55-60行) +- 问题:循环内执行数据库查询 +- 修复:使用批量查询或JOIN +... + +### 🟢 改进建议 + +**[NAM] 变量名不清晰**(第23行) +- `d` 应改名为 `user_data` 以提高可读性 +``` + +## 审查检查清单 + +每次代码审查时检查: + +- [ ] 无空指针风险 +- [ ] 无SQL注入或XSS漏洞 +- [ ] 无硬编码密钥 +- [ ] 正确的错误处理 +- [ ] 无N+1查询或低效循环 +- [ ] 事务边界正确 +- [ ] 并发场景线程安全 +- [ ] 代码可读且可维护 +- [ ] 包含测试 + +## 其他指南 + +1. **建设性** - 提出改进建议,而不仅仅是批评 +2. **优先级排序** - 首先关注关键问题 +3. **考虑上下文** - 理解项目的约定 +4. **简洁明了** - 清晰扼要 +5. **肯定优点** - 也指出写得好的部分 diff --git a/.github/gemini.json b/.github/gemini.json new file mode 100644 index 0000000..7c11ce2 --- /dev/null +++ b/.github/gemini.json @@ -0,0 +1,90 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gemini Code Assist Configuration", + "reviews": { + "auto_review": true, + "instructions_file": ".github/gemini-instructions.md", + "language": "en", + "focus_areas": [ + "correctness", + "security", + "performance", + "maintainability", + "best_practices" + ], + "severity_levels": { + "critical": [ + "REQ", + "LOGI", + "SEC", + "AUTH" + ], + "high": [ + "DSN", + "RBST", + "TRANS", + "CONC", + "PERF" + ], + "medium": [ + "CPT", + "IDE", + "MAIN", + "CPL" + ], + "normal": [ + "READ", + "SIMPL", + "CONS", + "DUP", + "NAM", + "DOCS" + ], + "low": [ + "COMM", + "LOGG", + "ERR", + "FOR", + "GRAM", + "PRAC", + "PR" + ] + }, + "path_filters": { + "include": [ + "**/*.go", + "**/*.java", + "**/*.py", + "**/*.js", + "**/*.ts", + "**/*.jsx", + "**/*.tsx", + "**/*.rs", + "**/*.c", + "**/*.cpp", + "**/*.cs", + "**/*.rb", + "**/*.php", + "**/*.swift", + "**/*.kt", + "**/*.scala" + ], + "exclude": [ + "**/*.test.*", + "**/*.spec.*", + "**/test/**", + "**/tests/**", + "**/__tests__/**", + "**/node_modules/**", + "**/vendor/**", + "**/dist/**", + "**/build/**", + "**/*.min.js", + "**/*.generated.*" + ] + } + }, + "chat": { + "instructions_file": ".github/gemini-instructions.md" + } +} diff --git a/cmd/format/format.go b/cmd/format/format.go index 5e42818..a304148 100644 --- a/cmd/format/format.go +++ b/cmd/format/format.go @@ -6,7 +6,7 @@ import ( "github.com/bufbuild/protocompile/parser" "github.com/bufbuild/protocompile/reporter" - "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/v2/assert" ) // Format formats and writes the target module files into a read bucket. diff --git a/cmd/formatcmd/cmd.go b/cmd/formatcmd/cmd.go index 1c6a4dc..eefb9e4 100644 --- a/cmd/formatcmd/cmd.go +++ b/cmd/formatcmd/cmd.go @@ -10,7 +10,7 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/v2/errors" "github.com/pubgo/redant" "github.com/pubgo/protobuild/cmd/format" diff --git a/cmd/protobuild/cmd.go b/cmd/protobuild/cmd.go index f068b75..5dd51d6 100644 --- a/cmd/protobuild/cmd.go +++ b/cmd/protobuild/cmd.go @@ -10,11 +10,11 @@ import ( "os/exec" "strings" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/generic" - "github.com/pubgo/funk/log" - "github.com/pubgo/funk/recovery" - "github.com/pubgo/funk/running" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/cmds/upgradecmd" + "github.com/pubgo/funk/v2/log" + "github.com/pubgo/funk/v2/recovery" + "github.com/pubgo/funk/v2/running" "github.com/pubgo/protobuild/cmd/formatcmd" "github.com/pubgo/protobuild/cmd/linters" "github.com/pubgo/protobuild/cmd/webcmd" @@ -29,8 +29,7 @@ import ( ) var ( - globalCfg Config - + globalCfg Config protoCfg = "protobuf.yaml" protoPluginCfg = "protobuf.plugin.yaml" pwd = assert.Exit1(os.Getwd()) @@ -54,14 +53,14 @@ func withParseConfig() redant.MiddlewareFunc { } } -// Main creates the main CLI application. -func Main(ver string) *redant.Command { +// Main creates and returns the root CLI command with all subcommands. +func Main() *redant.Command { var force, update, dryRun bool cliArgs, options := linters.NewCli() app := &redant.Command{ - Use: "protobuf", - Short: "protobuf generation, configuration and management", + Use: "protobuild", + Short: "Protobuf generation, configuration and management tool", Options: typex.Options{ redant.Option{ Flag: "conf", @@ -84,6 +83,7 @@ func Main(ver string) *redant.Command { newCleanCommand(&dryRun), webcmd.New(&protoCfg), newVersionCommand(), + upgradecmd.New("pubgo", "protobuild"), }, } @@ -92,18 +92,14 @@ func Main(ver string) *redant.Command { // handleStdinPlugin handles protoc plugin mode when invoked via stdin. func handleStdinPlugin(ctx context.Context, inv *redant.Invocation) error { - if shutil.IsHelp() { - return nil - } - file := os.Stdin if term.IsTerminal(int(file.Fd())) { - return nil + return redant.DefaultHelpFn()(ctx, inv) } fi := assert.Exit1(file.Stat()) if fi.Size() == 0 { - return nil + return redant.DefaultHelpFn()(ctx, inv) } in := assert.Must1(io.ReadAll(file)) @@ -121,7 +117,7 @@ func handleStdinPlugin(ctx context.Context, inv *redant.Invocation) error { plgName, params := parsePluginParams(req.GetParameter()) if len(params) > 0 { - req.Parameter = generic.Ptr(strings.Join(params, ",")) + req.Parameter = lo.ToPtr(strings.Join(params, ",")) } return executeWrapperPlugin(plgName, req) @@ -221,9 +217,9 @@ func newVersionCommand() *redant.Command { Short: "version info", Handler: func(ctx context.Context, inv *redant.Invocation) error { defer recovery.Exit() - fmt.Printf("Project: %s\n", running.Project) - fmt.Printf("Version: %s\n", running.Version) - fmt.Printf("GitCommit: %s\n", running.CommitID) + fmt.Printf("Project: %s\n", running.Project()) + fmt.Printf("Version: %s\n", running.Version()) + fmt.Printf("GitCommit: %s\n", running.CommitID()) return nil }, } diff --git a/cmd/protobuild/cmd_doctor.go b/cmd/protobuild/cmd_doctor.go index 615478c..9883548 100644 --- a/cmd/protobuild/cmd_doctor.go +++ b/cmd/protobuild/cmd_doctor.go @@ -9,7 +9,7 @@ import ( "runtime" "strings" - "github.com/pubgo/funk/recovery" + "github.com/pubgo/funk/v2/recovery" "github.com/pubgo/protobuild/internal/typex" "github.com/pubgo/redant" ) diff --git a/cmd/protobuild/cmd_init.go b/cmd/protobuild/cmd_init.go index ea3a637..7aa0519 100644 --- a/cmd/protobuild/cmd_init.go +++ b/cmd/protobuild/cmd_init.go @@ -8,7 +8,7 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/recovery" + "github.com/pubgo/funk/v2/recovery" "github.com/pubgo/protobuild/internal/config" "github.com/pubgo/protobuild/internal/typex" "github.com/pubgo/redant" diff --git a/cmd/protobuild/commands.go b/cmd/protobuild/commands.go index 03d4330..938e64c 100644 --- a/cmd/protobuild/commands.go +++ b/cmd/protobuild/commands.go @@ -8,8 +8,8 @@ import ( "os" "path/filepath" - "github.com/pubgo/funk/pathutil" - "github.com/pubgo/funk/recovery" + "github.com/pubgo/funk/v2/pathutil" + "github.com/pubgo/funk/v2/recovery" "github.com/pubgo/protobuild/internal/depresolver" "github.com/pubgo/redant" "gopkg.in/yaml.v3" diff --git a/cmd/protobuild/proto_walker.go b/cmd/protobuild/proto_walker.go index d59c290..3b73d3d 100644 --- a/cmd/protobuild/proto_walker.go +++ b/cmd/protobuild/proto_walker.go @@ -6,8 +6,8 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/pathutil" "github.com/samber/lo" ) diff --git a/cmd/protobuild/protoc_builder.go b/cmd/protobuild/protoc_builder.go index 061022a..c0af069 100644 --- a/cmd/protobuild/protoc_builder.go +++ b/cmd/protobuild/protoc_builder.go @@ -6,9 +6,9 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/log" - "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/log" + "github.com/pubgo/funk/v2/pathutil" "github.com/pubgo/protobuild/internal/shutil" "github.com/samber/lo" ) diff --git a/cmd/protobuild/util.go b/cmd/protobuild/util.go index 19affa0..5e7a807 100644 --- a/cmd/protobuild/util.go +++ b/cmd/protobuild/util.go @@ -10,10 +10,10 @@ import ( "github.com/cnf/structhash" "github.com/googleapis/api-linter/v2/lint" "github.com/huandu/go-clone" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/pathutil" - "github.com/pubgo/funk/strutil" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/errors" + "github.com/pubgo/funk/v2/pathutil" + "github.com/pubgo/funk/v2/strutil" "github.com/pubgo/protobuild/cmd/linters" "github.com/pubgo/protobuild/internal/config" "gopkg.in/yaml.v3" @@ -135,11 +135,11 @@ var checkSumPath = func(vendorPath string) string { func getChecksumData(vendorPath string) (string, error) { var path = checkSumPath(vendorPath) if pathutil.IsNotExist(vendorPath) { - return "", errors.NewFmt("file not found") + return "", errors.New("file not found") } if pathutil.IsNotExist(path) { - return "", errors.NewFmt("file not found") + return "", errors.New("file not found") } data, err := os.ReadFile(path) diff --git a/cmd/protobuild/vendor_service.go b/cmd/protobuild/vendor_service.go index 5efaea1..b4515ba 100644 --- a/cmd/protobuild/vendor_service.go +++ b/cmd/protobuild/vendor_service.go @@ -9,10 +9,10 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" - "github.com/pubgo/funk/pathutil" - "github.com/pubgo/funk/recovery" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/errors" + "github.com/pubgo/funk/v2/pathutil" + "github.com/pubgo/funk/v2/recovery" "github.com/pubgo/protobuild/internal/depresolver" "github.com/schollz/progressbar/v3" ) @@ -128,10 +128,10 @@ func (s *VendorService) CopyToVendor(resolvedPaths map[string]string) (int, erro } defer recovery.Err(&gErr, func(err error) error { - return errors.WrapTag(err, - errors.T("path", path), - errors.T("name", info.Name()), - ) + return errors.WrapTags(err, errors.Tags{ + "path": path, + "name": info.Name(), + }) }) if info.IsDir() || !strings.HasSuffix(info.Name(), ".proto") { diff --git a/cmd/protobuild/yaml_types.go b/cmd/protobuild/yaml_types.go index 4bca88e..336b4c0 100644 --- a/cmd/protobuild/yaml_types.go +++ b/cmd/protobuild/yaml_types.go @@ -1,8 +1,8 @@ package protobuild import ( - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/errors" yaml "gopkg.in/yaml.v3" ) @@ -34,7 +34,7 @@ func (p *YamlListType[T]) UnmarshalYAML(value *yaml.Node) error { default: var val any assert.Exit(value.Decode(&val)) - return errors.Format("yaml kind type error, kind=%v data=%v", value.Kind, val) + return errors.Errorf("yaml kind type error, kind=%v data=%v", value.Kind, val) } } @@ -65,6 +65,6 @@ func (p *strOrObject) UnmarshalYAML(value *yaml.Node) error { default: var val any assert.Exit(value.Decode(&val)) - return errors.Format("yaml kind type error,kind=%v data=%v", value.Kind, val) + return errors.Errorf("yaml kind type error,kind=%v data=%v", value.Kind, val) } } diff --git a/cmd/webcmd/cmd.go b/cmd/webcmd/cmd.go index 3d6b8bc..abd2536 100644 --- a/cmd/webcmd/cmd.go +++ b/cmd/webcmd/cmd.go @@ -8,8 +8,9 @@ import ( "strconv" "syscall" - "github.com/pubgo/protobuild/internal/typex" "github.com/pubgo/redant" + + "github.com/pubgo/protobuild/internal/typex" ) // New creates the web command. diff --git a/cmd/webcmd/server.go b/cmd/webcmd/server.go index 44acd7b..a8e8124 100644 --- a/cmd/webcmd/server.go +++ b/cmd/webcmd/server.go @@ -20,6 +20,8 @@ import ( "sync" "time" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/protobuild/internal/config" ) @@ -129,7 +131,7 @@ func (s *Server) Start(ctx context.Context, port int) error { // Open browser go func() { time.Sleep(500 * time.Millisecond) - openBrowser(url) + assert.Must(openBrowser(url)) }() // Handle graceful shutdown @@ -137,7 +139,7 @@ func (s *Server) Start(ctx context.Context, port int) error { <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - s.server.Shutdown(shutdownCtx) + assert.Must(s.server.Shutdown(shutdownCtx)) }() return s.server.Serve(listener) @@ -154,7 +156,7 @@ func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { cfg := s.config s.mu.RUnlock() - data := map[string]interface{}{ + data := map[string]any{ "Config": cfg, "ConfigPath": s.configPath, } @@ -169,14 +171,14 @@ func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { // Reload config from file - s.loadConfig() + assert.Must(s.loadConfig()) s.mu.RLock() cfg := s.config s.mu.RUnlock() w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(cfg) + assert.Must(json.NewEncoder(w).Encode(cfg)) return } @@ -202,18 +204,18 @@ func (s *Server) handleSaveConfig(w http.ResponseWriter, r *http.Request) { if err := s.saveConfig(); err != nil { w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(CommandResult{ + assert.Must(json.NewEncoder(w).Encode(CommandResult{ Success: false, Error: err.Error(), - }) + })) return } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(CommandResult{ + assert.Must(json.NewEncoder(w).Encode(CommandResult{ Success: true, Output: "Configuration saved successfully", - }) + })) } // handleCommand executes protobuild commands. @@ -234,7 +236,7 @@ func (s *Server) handleCommand(w http.ResponseWriter, r *http.Request) { args := []string{"-c", s.configPath, cmdName} // Parse additional flags from request body - var flags map[string]interface{} + var flags map[string]any if err := json.NewDecoder(r.Body).Decode(&flags); err == nil { for key, val := range flags { switch v := val.(type) { @@ -264,7 +266,7 @@ func (s *Server) handleCommand(w http.ResponseWriter, r *http.Request) { cmd.Dir = filepath.Dir(s.configPath) output, err := cmd.CombinedOutput() - + assert.Must(err) result := CommandResult{ Success: err == nil, Output: string(output), @@ -274,7 +276,7 @@ func (s *Server) handleCommand(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(result) + assert.Must(json.NewEncoder(w).Encode(result)) } // handleProtoFiles returns a list of proto files in the project. @@ -288,7 +290,7 @@ func (s *Server) handleProtoFiles(w http.ResponseWriter, r *http.Request) { for _, root := range cfg.Root { rootPath := filepath.Join(baseDir, root) - filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error { + assert.Must(filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error { if err != nil { return nil } @@ -297,11 +299,11 @@ func (s *Server) handleProtoFiles(w http.ResponseWriter, r *http.Request) { files = append(files, relPath) } return nil - }) + })) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(files) + assert.Must(json.NewEncoder(w).Encode(files)) } // handleDepsStatus returns the status of dependencies. @@ -317,9 +319,9 @@ func (s *Server) handleDepsStatus(w http.ResponseWriter, r *http.Request) { output, _ := cmd.CombinedOutput() w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(map[string]string{ + assert.Must(json.NewEncoder(w).Encode(map[string]string{ "output": string(output), - }) + })) } // openBrowser opens the URL in the default browser. @@ -391,7 +393,7 @@ func (s *Server) handleCommandStream(w http.ResponseWriter, r *http.Request) { stderr, _ := cmd.StderrPipe() if err := cmd.Start(); err != nil { - fmt.Fprintf(w, "data: {\"type\":\"error\",\"data\":\"%s\"}\n\n", err.Error()) + assert.Must1(fmt.Fprintf(w, "data: {\"type\":\"error\",\"data\":\"%s\"}\n\n", err.Error())) flusher.Flush() return } @@ -401,7 +403,7 @@ func (s *Server) handleCommandStream(w http.ResponseWriter, r *http.Request) { scanner := bufio.NewScanner(stdout) for scanner.Scan() { line := scanner.Text() - fmt.Fprintf(w, "data: {\"type\":\"stdout\",\"data\":\"%s\"}\n\n", escapeJSON(line)) + assert.Must1(fmt.Fprintf(w, "data: {\"type\":\"stdout\",\"data\":\"%s\"}\n\n", escapeJSON(line))) flusher.Flush() } }() @@ -410,16 +412,16 @@ func (s *Server) handleCommandStream(w http.ResponseWriter, r *http.Request) { scanner := bufio.NewScanner(stderr) for scanner.Scan() { line := scanner.Text() - fmt.Fprintf(w, "data: {\"type\":\"stderr\",\"data\":\"%s\"}\n\n", escapeJSON(line)) + assert.Must1(fmt.Fprintf(w, "data: {\"type\":\"stderr\",\"data\":\"%s\"}\n\n", escapeJSON(line))) flusher.Flush() } }() err = cmd.Wait() if err != nil { - fmt.Fprintf(w, "data: {\"type\":\"error\",\"data\":\"%s\"}\n\n", err.Error()) + assert.Must1(fmt.Fprintf(w, "data: {\"type\":\"error\",\"data\":\"%s\"}\n\n", err.Error())) } else { - fmt.Fprintf(w, "data: {\"type\":\"done\",\"data\":\"Command completed successfully\"}\n\n") + assert.Must1(fmt.Fprintf(w, "data: {\"type\":\"done\",\"data\":\"Command completed successfully\"}\n\n")) } flusher.Flush() } @@ -469,12 +471,12 @@ func (s *Server) handleProtoContent(w http.ResponseWriter, r *http.Request) { info, _ := os.Stat(fullPath) w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(map[string]interface{}{ + assert.Must(json.NewEncoder(w).Encode(map[string]any{ "path": filePath, "content": string(content), "size": info.Size(), "modified": info.ModTime().Format(time.RFC3339), - }) + })) } // ProjectStats represents project statistics. @@ -508,7 +510,7 @@ func (s *Server) handleProjectStats(w http.ResponseWriter, r *http.Request) { // Count proto files in root directories for _, root := range cfg.Root { rootPath := filepath.Join(baseDir, root) - filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error { + assert.Must(filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error { if err != nil { return nil } @@ -532,13 +534,13 @@ func (s *Server) handleProjectStats(w http.ResponseWriter, r *http.Request) { } } return nil - }) + })) } // Count vendor files if cfg.Vendor != "" { vendorPath := filepath.Join(baseDir, cfg.Vendor) - filepath.Walk(vendorPath, func(path string, info fs.FileInfo, err error) error { + assert.Must(filepath.Walk(vendorPath, func(path string, info fs.FileInfo, err error) error { if err != nil { return nil } @@ -546,9 +548,9 @@ func (s *Server) handleProjectStats(w http.ResponseWriter, r *http.Request) { stats.VendorFiles++ } return nil - }) + })) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(stats) + assert.Must(json.NewEncoder(w).Encode(stats)) } diff --git a/docs/codereview/CODE_REVIEW_GUIDE_CN.md b/docs/codereview/CODE_REVIEW_GUIDE_CN.md new file mode 100644 index 0000000..fc39c11 --- /dev/null +++ b/docs/codereview/CODE_REVIEW_GUIDE_CN.md @@ -0,0 +1,663 @@ +# 代码审查综合指南 + +> 结合最佳实践和问题分类检测的综合代码审查指南。 +> +> 本文档可供 GitHub Copilot、审查工具和开发团队参考使用。 + +## 目录 + +- [概述](#概述) +- [黄金法则](#黄金法则) +- [审查流程指南](#审查流程指南) +- [问题分类速查表](#问题分类速查表) +- [详细分类检查清单](#详细分类检查清单) +- [PR提交检查清单](#pr提交检查清单) +- [使用指南](#使用指南) + +--- + +## 概述 + +### 目的 + +代码审查主要有两个目的: +1. **发现缺陷**:测试通常能发现50-60%的问题,而执行良好的代码审查可以发现60-80%的缺陷。 +2. **提升质量**:确保软件具备六大关键特性:**可靠性、效率、可用性、可维护性、安全性和可移植性**。 + +### 范围 + +审查代码时,需要检查: +- 分配审查的每一行代码 +- 逻辑正确性 +- 设计决策 +- 代码质量和可维护性 + +--- + +## 黄金法则 + +| # | 法则 | 描述 | +|---|------|------| +| 1 | **简单、高效、安全的设计** | 避免过度设计;优先考虑清晰性和安全性 | +| 2 | **严格的完整性和性能** | 确保数据完整性,按需优化 | +| 3 | **合理的模块化** | 模块内高内聚,模块间低耦合 | +| 4 | **减少重复** | DRY原则 - 不要重复自己 | +| 5 | **良好的命名和注释** | 清晰、描述性的名称;有意义的注释 | + +### 审查基准 + +> **目标:每100行代码(LOC)至少发现1个逻辑问题** + +--- + +## 审查流程指南 + +### 审查前 + +1. 理解上下文和需求 +2. 审查相关文档和设计文档 +3. 检查是否包含测试 + +### 审查中 + +1. 仔细阅读PR描述 +2. 系统性地检查所有变更文件 +3. 验证逻辑流程和边界情况 +4. 寻找问题模式(见下文分类) +5. 考虑安全影响 +6. 检查性能问题 + +### 审查后 + +1. 提供建设性反馈 +2. 建议具体改进方案 +3. 只有在所有关键问题解决后才批准 + +--- + +## 问题分类速查表 + +| 分类 | 代码 | 优先级 | 描述 | +|------|------|--------|------| +| 需求不匹配 | `REQ` | 🔴 关键 | 实现与需求不符 | +| 逻辑问题 | `LOGI` | 🔴 关键 | 阻止正确执行的Bug | +| 安全问题 | `SEC` | 🔴 关键 | 漏洞和安全风险 | +| 认证/授权 | `AUTH` | 🔴 关键 | 访问控制问题 | +| 设计问题 | `DSN` | 🟠 高 | 架构和设计问题 | +| 健壮性 | `RBST` | 🟠 高 | 错误处理和容错 | +| 事务问题 | `TRANS` | 🟠 高 | 数据库事务问题 | +| 并发问题 | `CONC` | 🟠 高 | 多线程问题 | +| 性能问题 | `PERF` | 🟠 高 | 资源效率问题 | +| 兼容性 | `CPT` | 🟡 中 | 版本和环境兼容性 | +| 幂等性 | `IDE` | 🟡 中 | 重复操作安全性 | +| 可维护性 | `MAIN` | 🟡 中 | 长期维护问题 | +| 耦合问题 | `CPL` | 🟡 中 | 模块间依赖 | +| 可读性 | `READ` | 🟢 普通 | 代码清晰度问题 | +| 简洁性 | `SIMPL` | 🟢 普通 | 不必要的复杂性 | +| 一致性 | `CONS` | 🟢 普通 | 风格和命名一致性 | +| 重复代码 | `DUP` | 🟢 普通 | 重复的代码/逻辑 | +| 命名问题 | `NAM` | 🟢 普通 | 变量/函数命名 | +| 文档字符串 | `DOCS` | 🟢 普通 | 文档注释 | +| 注释问题 | `COMM` | 🔵 低 | 行内注释 | +| 日志问题 | `LOGG` | 🔵 低 | 日志语句 | +| 错误消息 | `ERR` | 🔵 低 | 错误定义 | +| 格式问题 | `FOR` | 🔵 低 | 代码格式 | +| 语法问题 | `GRAM` | 🔵 低 | 文本语法问题 | +| 最佳实践 | `PRAC` | 🔵 低 | 规范违反 | +| PR描述 | `PR` | 🔵 低 | PR文档 | + +--- + +## 详细分类检查清单 + +### 🔴 关键问题 + +#### 需求不匹配 (REQ) + +**定义**:代码实现与需求/文档不符。 + +**检查清单**: +- [ ] 代码实现与需求/文档一致 +- [ ] 所有规定的行为都已实现 +- [ ] 需求中的边界情况已处理 +- [ ] 考虑了失败路径,不仅仅是"正常路径" +- [ ] 假设条件有文档记录并已验证 + +**示例**: +``` +[REQ] 文档说明为A,但实现为B +[REQ] 定义了"正常路径",但忽略了失败路径 +[REQ] 需求指定30秒超时,但代码使用10秒 +``` + +#### 逻辑问题 (LOGI) + +**定义**:任何阻止软件按预期运行的问题。 + +**检查清单**: +- [ ] 无空指针引用 +- [ ] 无除零可能性 +- [ ] 数组/列表索引边界已检查 +- [ ] 无无限递归可能性 +- [ ] 所有if-else分支完整 +- [ ] 控制流正确关闭(if-else if有else) +- [ ] 表单/输入数据已验证 +- [ ] 循环终止条件正确 + +**示例**: +``` +[LOGI] 未检查user是否为null就访问user.name +[LOGI] if-else if语句缺少else分支处理其他情况 +[LOGI] 数组索引访问未进行边界检查 +[LOGI] 无限递归导致栈溢出 +``` + +#### 安全问题 (SEC) + +**定义**:防止漏洞,保护免受未授权访问、数据泄露、篡改或中断等威胁。 + +**检查清单**: +- [ ] 无SQL注入漏洞 +- [ ] 无XSS(跨站脚本)漏洞 +- [ ] 无缓冲区溢出风险 +- [ ] 无硬编码凭证或密钥 +- [ ] 正确的认证检查 +- [ ] 数据库中无明文凭证 +- [ ] 安全的数据传输(HTTPS、加密) +- [ ] 所有用户输入都有验证 +- [ ] 正确的输出编码 + +**示例**: +``` +[SEC] SQL注入:查询直接拼接用户输入 +[SEC] 硬编码凭证:password = "admin123" +[SEC] XSS漏洞:用户输入未转义直接渲染 +[SEC] 数据库中存储明文凭证 +``` + +#### 认证/授权 (AUTH) + +**定义**:与身份验证和访问控制相关的问题。 + +**检查清单**: +- [ ] 需要认证的地方都有认证 +- [ ] 授权检查到位 +- [ ] 基于角色的访问控制正确实现 +- [ ] 会话管理安全 +- [ ] Token正确验证 + +**示例**: +``` +[AUTH] API端点无需认证即可访问 +[AUTH] 管理员功能缺少角色验证 +[AUTH] JWT令牌使用前未验证 +``` + +### 🟠 高优先级问题 + +#### 设计问题 (DSN) + +**定义**:设计/实现应该简单、可用、安全、可靠、可维护、可扩展和高效。 + +**检查清单**: +- [ ] 设计简单直接 +- [ ] 设计可用且直观 +- [ ] 设计默认安全 +- [ ] 设计可靠 +- [ ] 设计可维护 +- [ ] 设计可扩展 +- [ ] 设计高效 +- [ ] 工作流不过于复杂 + +**示例**: +``` +[DSN] 设计过于复杂:工作流有不必要的步骤 +[DSN] 设计不高效:多次处理数据 +[DSN] 设计不灵活:难以扩展新需求 +``` + +#### 健壮性 (RBST) + +**定义**:系统在不崩溃的情况下优雅地处理错误、意外输入或压力条件的能力。 + +**检查清单**: +- [ ] 异常被适当捕获和处理 +- [ ] 无效数据被阻止影响系统 +- [ ] 系统在组件故障时继续运行 +- [ ] 系统能在故障后恢复到稳定状态 +- [ ] 适当的地方实现了优雅降级 + +**示例**: +``` +[RBST] 异常未捕获:网络错误时应用崩溃 +[RBST] 无效输入未验证:导致下游错误 +[RBST] 外部服务不可用时无回退机制 +``` + +#### 事务问题 (TRANS) + +**定义**:事务是作为单个逻辑工作单元执行的操作序列。 + +**检查清单**: +- [ ] 事务边界正确定义 +- [ ] 异常时事务回滚 +- [ ] 避免长时间运行的事务 +- [ ] 有死锁预防措施 +- [ ] 需要数据完整性时使用事务 + +**示例**: +``` +[TRANS] 多步操作缺少事务边界 +[TRANS] 异常时事务未回滚 +[TRANS] 长时间运行的事务阻塞其他操作 +[TRANS] 锁顺序不一致导致死锁风险 +``` + +#### 并发问题 (CONC) + +**定义**:特定于多线程/多任务环境中发生的问题。 + +**检查清单**: +- [ ] 无竞态条件 +- [ ] 无死锁可能性 +- [ ] 正确使用锁 +- [ ] 需要时使用线程安全的数据结构 +- [ ] 需要时使用原子操作 + +**示例**: +``` +[CONC] 竞态条件:共享计数器未同步修改 +[CONC] 死锁:方法A和B以不同顺序获取锁 +[CONC] 多线程环境中使用非线程安全的集合 +``` + +#### 性能问题 (PERF) + +**定义**:不必要地过度消耗CPU、内存、磁盘、网络等资源。 + +**检查清单**: +- [ ] 使用高效算法(检查Big O复杂度) +- [ ] 无过度内存使用 +- [ ] 数据库查询已优化 +- [ ] 使用批量操作而非逐个处理 +- [ ] 数据库查询有适当索引 +- [ ] 无不必要的重复操作 +- [ ] 适当使用缓存 +- [ ] 无N+1查询问题 + +**示例**: +``` +[PERF] 使用O(n²)算法,而O(n log n)是可行的 +[PERF] 循环内数据库查询:应使用批量查询 +[PERF] 频繁过滤的列缺少索引 +[PERF] N+1查询:逐个加载关联实体 +``` + +### 🟡 中优先级问题 + +#### 兼容性 (CPT) + +**定义**:阻止软件与不同版本或环境正确交互的冲突。 + +**检查清单**: +- [ ] 保持向后兼容性 +- [ ] 考虑向前兼容性 +- [ ] API变更适当版本化 +- [ ] 数据库Schema变更迁移安全 +- [ ] 测试浏览器/操作系统兼容性 +- [ ] 库版本兼容 + +**示例**: +``` +[CPT] API字段删除破坏现有客户端 +[CPT] 新功能与旧浏览器版本不兼容 +[CPT] 库升级引入破坏性变更 +``` + +#### 幂等性 (IDE) + +**定义**:多次运行操作产生相同结果。 + +**检查清单**: +- [ ] 重复操作产生相同结果 +- [ ] 重试不产生重复记录 +- [ ] 删除操作处理已删除的情况 +- [ ] 支付/关键操作有幂等键 + +**示例**: +``` +[IDE] 同一订单下单两次产生重复记录 +[IDE] 第二次删除返回错误 +[IDE] 支付操作无幂等键 +``` + +#### 可维护性 (MAIN) + +**定义**:应用程序可被理解、修复或增强的程度。约75%的项目成本是维护! + +**检查清单**: +- [ ] 代码具有良好可读性 +- [ ] 代码模块化且逻辑分离 +- [ ] 复杂度保持较低(无深层嵌套) +- [ ] 代码可测试 +- [ ] 文档保持最新 +- [ ] 使用一致的编码模式 + +**示例**: +``` +[MAIN] 代码紧密耦合:变更需要修改多个文件 +[MAIN] 无单元测试:难以验证变更 +[MAIN] 文档过时:不反映当前行为 +``` + +#### 耦合问题 (CPL) + +**定义**:软件模块之间的相互依赖程度。期望低耦合高内聚。 + +**检查清单**: +- [ ] 无硬编码依赖 +- [ ] 下层不依赖上层 +- [ ] 组件依赖接口而非实现 +- [ ] 相关逻辑集中在一处 +- [ ] 无隐藏依赖(必须先调用A再调用B) +- [ ] 数据通过定义的接口传递,而非共享结构 + +**示例**: +``` +[CPL] 方法接收整个User对象但只使用userId +[CPL] 必须先调用init()再调用start(),但依赖未记录 +[CPL] 业务逻辑分散在多个不相关的模块中 +``` + +### 🟢 普通问题 + +#### 可读性 (READ) + +**定义**:清晰的代码结构、命名约定和文档。 + +**检查清单**: +- [ ] 变量名具有描述性(不是x1、temp、val2) +- [ ] 函数大小合理(不超过100行) +- [ ] 嵌套有限(最多3-4层) +- [ ] 正确的缩进和间距 +- [ ] 简单代码优于"聪明"的技巧 +- [ ] 逻辑清晰地分离到函数/模块中 + +**示例**: +``` +[READ] 变量名'd'不清晰,应该是'data'或更具体 +[READ] 函数超过150行,应该拆分成更小的函数 +[READ] 5层嵌套的if语句,应该重构 +``` + +#### 简洁性 (SIMPL) + +**定义**:设计和实现应尽可能简单,避免不必要的复杂性。 + +**检查清单**: +- [ ] 逻辑直接易懂 +- [ ] 每个函数/类有单一职责 +- [ ] 无过度设计或投机性功能 +- [ ] 删除未使用的代码和注释 +- [ ] 无不必要的通用设计 + +**示例**: +``` +[SIMPL] 简单问题使用过于通用的解决方案 +[SIMPL] 未使用的辅助函数应删除 +[SIMPL] 过早优化使代码难以理解 +``` + +#### 一致性 (CONS) + +**定义**:确保文档、命名、格式、逻辑、注释、日志等的一致性。 + +**检查清单**: +- [ ] 一致的命名约定(camelCase、snake_case等) +- [ ] 注释语言一致 +- [ ] 代码和注释同步 +- [ ] 代码和文档同步 +- [ ] 全文术语一致 + +**示例**: +``` +[CONS] 随意混用camelCase和snake_case +[CONS] 代码变了但注释仍描述旧行为 +[CONS] 代码和文档中对同一概念使用不同术语 +``` + +#### 重复代码 (DUP) + +**定义**:不同位置的重复代码/逻辑导致高耦合和低可维护性。 + +**检查清单**: +- [ ] 无复制粘贴的代码块 +- [ ] 重复表达式提取为变量 +- [ ] 公共逻辑提取为函数 +- [ ] 共享代码放在适当的工具类/辅助类中 + +**示例**: +``` +[DUP] 相同的验证逻辑在3个不同的地方复制粘贴 +[DUP] 重复表达式cameras[i].getStream().getResolution()应提取为变量 +``` + +#### 命名问题 (NAM) + +**定义**:名称应清晰、描述性但简洁、易于理解。 + +**检查清单**: +- [ ] 名称清晰且具有描述性 +- [ ] 名称简洁(不超过5个词) +- [ ] 避免模糊词如"data"、"info"、"stuff" +- [ ] 数组/列表使用复数名称(cameras、cameraList) +- [ ] 方法使用动词,类使用名词 +- [ ] 布尔变量命名为疑问形式(isActive、hasPermission) + +**示例**: +``` +[NAM] 变量'tp'太晦涩,应该是'timeoutPeriod' +[NAM] 数组'camera'应该是'cameras'或'cameraList' +[NAM] 方法'calculation()'应该是'calculate()' +``` + +#### 文档字符串 (DOCS) + +**定义**:解释函数、类或模块功能的特殊注释。 + +**检查清单**: +- [ ] 必要时函数/类有文档字符串 +- [ ] 参数有说明 +- [ ] 返回值有说明 +- [ ] 异常/副作用有说明 +- [ ] 文档字符串与代码同步 + +**示例**: +``` +[DOCS] 公共API方法缺少文档字符串 +[DOCS] 参数'options'未说明 +[DOCS] 返回值类型和含义未指定 +``` + +### 🔵 低优先级问题 + +#### 注释问题 (COMM) + +**定义**:应根据需要添加注释以帮助审查和维护。 + +**检查清单**: +- [ ] 复杂逻辑有解释性注释 +- [ ] 变通方案/技巧有上下文注释 +- [ ] 无注释掉的死代码 +- [ ] 注释清晰简洁 +- [ ] 性能权衡有解释 + +**示例**: +``` +[COMM] 复杂算法缺少解释注释 +[COMM] 变通方案缺少上下文:为什么需要这样做? +[COMM] 注释掉的代码应删除 +``` + +#### 日志问题 (LOGG) + +**定义**:按需记录日志,避免不必要或过多的日志。 + +**检查清单**: +- [ ] 错误条件有日志 +- [ ] 日志包含必要的上下文(ID、类型) +- [ ] 生产环境无过多调试日志 +- [ ] 使用适当的日志级别 +- [ ] 不记录敏感数据 + +**示例**: +``` +[LOGG] 错误情况未记录日志 +[LOGG] 日志消息缺少上下文:缺少请求ID +[LOGG] 调试日志留在生产代码中 +``` + +#### 错误消息 (ERR) + +**定义**:根据需要添加或定义错误,包含清晰、简洁的上下文。 + +**检查清单**: +- [ ] 错误消息具体且有帮助 +- [ ] 需要时定义错误代码/类型 +- [ ] 错误消息包含上下文 +- [ ] 错误被适当记录 + +**示例**: +``` +[ERR] 通用消息"出了点问题"缺少上下文 +[ERR] 面向客户端的API缺少错误代码 +[ERR] 错误消息未指示应采取的操作 +``` + +#### 格式问题 (FOR) + +**定义**:包括编码风格、格式和措辞。 + +**检查清单**: +- [ ] 无拼写错误 +- [ ] 一致的缩进 +- [ ] 无过多空行 +- [ ] 操作符周围有适当间距 +- [ ] 代码符合团队风格指南 + +**示例**: +``` +[FOR] 变量名拼写错误:'recieve'应该是'receive' +[FOR] 缩进不一致:混用制表符和空格 +[FOR] 语句之间空行过多 +``` + +#### 语法问题 (GRAM) + +**定义**:注释、错误消息和文档应语法正确。 + +**检查清单**: +- [ ] 注释语法正确 +- [ ] 错误消息正确书写 +- [ ] 文档句子完整 + +**示例**: +``` +[GRAM] 注释有拼写错误:"the user is login"应该是"the user is logged in" +[GRAM] 文档中句子不完整 +``` + +#### 最佳实践 (PRAC) + +**定义**:符合编程风格、约定、常见用例和团队约定的规则。 + +**检查清单**: +- [ ] 事件处理器遵循命名约定(onXxx) +- [ ] 文件按功能/模块组织 +- [ ] 文件夹结构遵循约定 +- [ ] 无容易造成困惑的模式 + +**示例**: +``` +[PRAC] 事件处理器'click'应命名为'onClick' +[PRAC] 工具文件放在错误的文件夹 +[PRAC] 误导性的变量名造成困惑 +``` + +#### PR描述 (PR) + +**定义**:PR描述应符合团队指南。 + +**检查清单**: +- [ ] PR描述清晰简洁 +- [ ] 链接设计文档(如适用) +- [ ] 链接相关票据/问题 +- [ ] 记录API变更 +- [ ] 列出测试点 +- [ ] 突出显示破坏性变更 + +**示例**: +``` +[PR] 缺少设计文档链接 +[PR] 未描述测试点 +[PR] 未突出显示破坏性变更 +``` + +--- + +## PR提交检查清单 + +提交PR前,请确保: + +1. [ ] **代码遵循指南**:良好的命名、高内聚、低耦合、最少重复 +2. [ ] **完成自审**:差异尽可能小 +3. [ ] **复杂代码有注释**:特别是难以理解的部分 +4. [ ] **日志包含上下文**:ID、reqId等 +5. [ ] **PR描述完整**:包含所有必要的链接 +6. [ ] **文档已更新**:做出相应的变更 +7. [ ] **测试已添加/更新**:证明修复有效或功能正常 +8. [ ] **本地所有测试通过**:新测试和现有测试 +9. [ ] **依赖变更已合并**:下游模块已更新 + +--- + +## 使用指南 + +### 对于审查者 + +1. **系统性审查**:按分类检查项目,避免遗漏 +2. **优先级排序**:首先关注关键和高优先级问题 +3. **明确标注**:使用分类代码如`[LOGI]`、`[SEC]` +4. **提供建议**:不仅指出问题,还要建议改进方案 + +### 对于GitHub Copilot + +协助代码审查时: +1. 识别问题时引用分类代码 +2. 解释问题及其分类 +3. 建议具体修复方案 +4. 考虑每个代码段的多个分类 + +### 对于开发者 + +1. **自查**:提交PR前使用此清单 +2. **理解分类**:了解不同问题类型的严重程度 +3. **持续改进**:根据反馈改进编码习惯 + +### 对于团队 + +1. **定制化**:根据项目需求调整优先级和检查项 +2. **数据追踪**:监控问题频率以识别改进领域 +3. **培训材料**:用于新人入职和技能发展 + +--- + +## 参考资料 + +- [Google代码审查指南](https://google.github.io/eng-practices/review/reviewer/looking-for.html) +- 内部代码规范 +- 安全最佳实践 + +--- + +*最后更新:2026-01-22* diff --git a/go.mod b/go.mod index 7cf7416..710ebd5 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/pubgo/protobuild -go 1.24.6 +go 1.25 require ( github.com/a8m/envsubst v1.4.3 @@ -13,16 +13,16 @@ require ( github.com/hashicorp/go-getter v1.8.4 github.com/hashicorp/go-version v1.8.0 github.com/huandu/go-clone v1.7.3 - github.com/pubgo/funk v0.5.68 + github.com/pubgo/funk/v2 v2.0.0-beta.16 github.com/pubgo/protoc-gen-retag v0.0.5 github.com/pubgo/redant v0.0.5 - github.com/samber/lo v1.51.0 + github.com/samber/lo v1.52.0 github.com/schollz/progressbar/v3 v3.19.0 go.uber.org/multierr v1.11.0 - golang.org/x/mod v0.30.0 - golang.org/x/term v0.38.0 - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba - google.golang.org/protobuf v1.36.10 + golang.org/x/mod v0.32.0 + golang.org/x/term v0.39.0 + google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b + google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 ) @@ -37,9 +37,10 @@ require ( cloud.google.com/go/longrunning v0.7.0 // indirect cloud.google.com/go/monitoring v1.24.3 // indirect cloud.google.com/go/storage v1.58.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect github.com/aws/aws-sdk-go-v2/config v1.32.6 // indirect @@ -63,17 +64,24 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect + github.com/cheggaaa/pb/v3 v3.1.7 // indirect + github.com/clipperhouse/stringish v0.1.1 // indirect + github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 // indirect - github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/ettle/strcase v0.2.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gertd/go-pluralize v0.2.1 // indirect - github.com/go-jose/go-jose/v4 v4.1.2 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/goccy/go-json v0.10.5 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-github/v71 v71.0.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect @@ -83,48 +91,47 @@ require ( github.com/joho/godotenv v1.5.1 // indirect github.com/k0kubun/pp/v3 v3.5.0 // indirect github.com/klauspost/compress v1.18.2 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mattn/go-tty v0.0.7 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/muesli/termenv v0.15.2 // indirect - github.com/phuslu/goid v1.0.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/xid v1.6.0 // indirect github.com/rs/zerolog v1.34.0 // indirect + github.com/samber/slog-common v0.19.0 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/zeebo/errs v1.4.0 // indirect + github.com/yarlson/tap v0.11.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.39.0 // indirect golang.org/x/crypto v0.46.0 // indirect - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect golang.org/x/net v0.48.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/api v0.256.0 // indirect google.golang.org/genproto v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/grpc v1.76.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/grpc v1.78.0 // indirect ) diff --git a/go.sum b/go.sum index dfc7c62..bd02229 100644 --- a/go.sum +++ b/go.sum @@ -22,14 +22,16 @@ cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNx cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY= github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU= github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= @@ -80,52 +82,64 @@ github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/ github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI= +github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ= github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= -github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= -github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= +github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a h1:Ohw57yVY2dBTt+gsC6aZdteyxwlxfbtgkFEMTEkwgSw= github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= -github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= -github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= -github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= +github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= +github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flosch/pongo2/v5 v5.0.0 h1:ZauMp+iPZzh2aI1QM2UwRb0lXD4BoFcvBuWqefkIuq0= github.com/flosch/pongo2/v5 v5.0.0/go.mod h1:6ysKu++8ANFXmc3x6uA6iVaS+PKUoDfdX3yPcv8TIzY= github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA= github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk= -github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= -github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30= +github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= @@ -165,8 +179,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -174,49 +188,53 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-tty v0.0.7 h1:KJ486B6qI8+wBO7kQxYgmmEFDaFEE96JMBQ7h400N8Q= +github.com/mattn/go-tty v0.0.7/go.mod h1:f2i5ZOvXBU/tCABmLmOfzLz9azMo5wdAaElRNnJKr+k= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= -github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= -github.com/phuslu/goid v1.0.2 h1:NfPgJ5gJoAhQYCSp6DTbnPvHQYjPBjTyFiBeNu3jvMw= -github.com/phuslu/goid v1.0.2/go.mod h1:txc2fUIdrdnn+v9Vq+QpiPQ3dnrXEchjoVDgic+r+L0= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pubgo/funk v0.5.68 h1:3fDJAt+QHhPnbAxUr8kLLAh6vra/C3vb7/LoSMQl788= -github.com/pubgo/funk v0.5.68/go.mod h1:CQDKnci4zmCyb0LSD9YiKx/6QBh3Z+PRyCLmJb6ZTOg= +github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 h1:eR+0HE//Ciyfwy3HC7fjRyKShSJHYoX2Pv7pPshjK/Q= +github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= +github.com/pubgo/funk/v2 v2.0.0-beta.16 h1:YYjIN+BkKUkzQbmlaRqqfth05wDYjOp66XertEe46Ek= +github.com/pubgo/funk/v2 v2.0.0-beta.16/go.mod h1:UQEBkZpMH6L2Vl0huy7vMrPV0pMWN+GKh+1Y6w++n/U= github.com/pubgo/protoc-gen-retag v0.0.5 h1:tF++mxmAUILb3IkVvSM0el+ww0jcLyPTkIXYzwgiv1A= github.com/pubgo/protoc-gen-retag v0.0.5/go.mod h1:/TD5yIvhQpb6ttvpmhpQPUnQ73Rtj23QlXeoczGyAHs= github.com/pubgo/redant v0.0.5 h1:iDq0cQJNtST8pu9bFSgxZ78JoQ0aVW+svZyOMouWjfM= github.com/pubgo/redant v0.0.5/go.mod h1:FOBNjL8pPLOBcZS3SL2R5GusFz/bNBwDJzSinGuKs7A= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= -github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= +github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI= +github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M= github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc= github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= -github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -228,28 +246,28 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= -github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= -github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/yarlson/tap v0.11.0 h1:UU3XpN9YWVaDsGBuXZC+gkuI289t3kGRQ/JxgCqGNxg= +github.com/yarlson/tap v0.11.0/go.mod h1:AuqXWK8npVwIM6spv9unFmQnz0koSrw7iU990bIQ0XY= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= @@ -266,41 +284,40 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= google.golang.org/genproto v0.0.0-20251111163417-95abcf5c77ba h1:Ze6qXW0j37YCqZdCD2LkzVSxgEWez0cO4NUyd44DiDY= google.golang.org/genproto v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:4FLPzLA8eGAktPOTemJGDgDYRpLYwrNu4u2JtWINhnI= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= -google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/config/loader.go b/internal/config/loader.go index 8616178..6b5da6e 100644 --- a/internal/config/loader.go +++ b/internal/config/loader.go @@ -29,7 +29,7 @@ func Save(path string, cfg *Config) error { return err } - return os.WriteFile(path, data, 0644) + return os.WriteFile(path, data, 0o644) } // Default returns a default configuration. diff --git a/internal/config/yaml_types.go b/internal/config/yaml_types.go index 01882a2..6856069 100644 --- a/internal/config/yaml_types.go +++ b/internal/config/yaml_types.go @@ -2,7 +2,7 @@ package config import ( - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/v2/errors" "gopkg.in/yaml.v3" ) @@ -32,6 +32,6 @@ func (p *PluginOpts) UnmarshalYAML(value *yaml.Node) error { *p = data return nil default: - return errors.Format("yaml kind type error, kind=%v data=%s", value.Kind, value.Value) + return errors.Errorf("yaml kind type error, kind=%v data=%s", value.Kind, value.Value) } } diff --git a/internal/depresolver/gomod.go b/internal/depresolver/gomod.go index 0ccde5b..6a79af0 100644 --- a/internal/depresolver/gomod.go +++ b/internal/depresolver/gomod.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/pathutil" "github.com/schollz/progressbar/v3" "github.com/pubgo/protobuild/internal/modutil" diff --git a/internal/depresolver/manager.go b/internal/depresolver/manager.go index fb12c8d..897933e 100644 --- a/internal/depresolver/manager.go +++ b/internal/depresolver/manager.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/hashicorp/go-getter" - "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/pathutil" "github.com/schollz/progressbar/v3" ) diff --git a/internal/modutil/util.go b/internal/modutil/util.go index ce56306..6b2f5ca 100644 --- a/internal/modutil/util.go +++ b/internal/modutil/util.go @@ -8,8 +8,8 @@ import ( mapset "github.com/deckarep/golang-set/v2" ver "github.com/hashicorp/go-version" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/pathutil" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/pathutil" "github.com/pubgo/funk/v2/result" "github.com/samber/lo" "golang.org/x/mod/modfile" @@ -38,7 +38,7 @@ func GoModPath() string { // LoadVersionGraph loads the module version graph from 'go mod graph'. func LoadVersionGraph() map[string]string { - modList := strings.Split(result.Wrap(shutil.GoModGraph()).Must(), "\n") + modList := strings.Split(result.Wrap(shutil.GoModGraph()).Unwrap(), "\n") modSet := mapset.NewSet[string]() for _, m := range modList { for _, v := range strings.Split(m, " ") { diff --git a/internal/modutil/util_test.go b/internal/modutil/util_test.go index 79c9431..97d24b9 100644 --- a/internal/modutil/util_test.go +++ b/internal/modutil/util_test.go @@ -6,7 +6,7 @@ import ( mapset "github.com/deckarep/golang-set/v2" ver "github.com/hashicorp/go-version" - "github.com/pubgo/funk/pretty" + "github.com/pubgo/funk/v2/pretty" "github.com/pubgo/funk/v2/result" "github.com/samber/lo" @@ -20,7 +20,7 @@ func TestName(t *testing.T) { } pretty.Println(versions) - modList := strings.Split(result.Wrap(shutil.GoModGraph()).Must(), "\n") + modList := strings.Split(result.Wrap(shutil.GoModGraph()).Unwrap(), "\n") modSet := mapset.NewSet[string]() for _, m := range modList { for _, v := range strings.Split(m, " ") { diff --git a/internal/protoutil/gen.go b/internal/protoutil/gen.go index 71d365b..f36aea6 100644 --- a/internal/protoutil/gen.go +++ b/internal/protoutil/gen.go @@ -12,7 +12,7 @@ import ( pongo "github.com/flosch/pongo2/v5" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/v2/assert" options "google.golang.org/genproto/googleapis/api/annotations" "google.golang.org/protobuf/compiler/protogen" gp "google.golang.org/protobuf/proto" diff --git a/internal/shutil/shell.go b/internal/shutil/shell.go index 50e51ef..1774588 100644 --- a/internal/shutil/shell.go +++ b/internal/shutil/shell.go @@ -7,8 +7,8 @@ import ( "os/exec" "strings" - "github.com/pubgo/funk/assert" - "github.com/pubgo/funk/errors" + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/errors" ) // Run executes a shell command and returns the output. diff --git a/main.go b/main.go index 29e07dd..aed143b 100644 --- a/main.go +++ b/main.go @@ -3,19 +3,17 @@ package main import ( _ "embed" - "fmt" - "os" + + "github.com/pubgo/funk/v2/assert" + "github.com/pubgo/funk/v2/buildinfo/version" "github.com/pubgo/protobuild/cmd/protobuild" ) //go:embed .version/VERSION -var version string +var ver string +var _ = version.SetVersion(ver) func main() { - err := protobuild.Main(version).Invoke().WithOS().Run() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } + assert.Exit(protobuild.Main().Invoke().WithOS().Run()) }