mcpField
G
golang-spf13-cobra

golang-spf13-cobra

github.com/samber开发3.7k37.5k 次安装6 天前更新
代码仓库

关于 golang-spf13-cobra

面向 Go CLI 工程师的 spf13/cobra 技能指南,介绍命令树、钩子、参数校验、标志、补全和文档生成,也涵盖测试实践。

主要功能

  1. 01构建命令与子命令树
  2. 02配置命令钩子和错误处理
  3. 03校验位置参数并定义标志
  4. 04生成 Shell 补全与命令文档
  5. 05编写可测试的命令处理逻辑

适用场景

  1. 01从零构建 Go 命令行程序
  2. 02为现有 CLI 添加子命令或标志
  3. 03审查命令生命周期和参数校验
  4. 04隔离测试命令输出与状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/samber/cc-skills-golang --skill golang-spf13-cobra

安装后在 Claude Code 中输入/golang-spf13-cobra确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
commands-and-args.md
completions.md
flags.md
generators.md
testing.md

详细介绍

**角色:**你是一名 Go 命令行工程师,负责构建符合 Unix shell 使用习惯的命令树。你会先设计面向用户的界面,再将行为接入合适的钩子。

模式:

  • 构建 — 从头创建新的 CLI:依次遵循命令树设置、钩子接线和标志部分。
  • 扩展 — 为现有 CLI 添加子命令、标志或补全:先阅读当前命令树,再按照现有结构应用更改。
  • 审查 — 审核现有 CLI:检查常见错误表,验证 RunE 的使用、OutOrStdout()、钩子链顺序和参数校验。

在 Go 中使用 spf13/cobra 构建 CLI 命令树

Cobra 是 Go CLI 应用的事实标准。它提供命令/子命令树、标志解析(通过 pflag)、参数校验、shell 补全生成和文档生成。它不负责配置分层——那是 viper 的工作。

官方资源:

本技能并非详尽无遗——如需更多信息,请参阅库文档和代码示例:

  • 如需查阅 Go 包文档、符号、版本、导入方和已知漏洞,→ 请参阅 samber/cc-skills-golang@golang-pkg-go-dev 技能(godig);查询 Go 包信息时优先于 Context7。
  • 如需在自己的代码中了解此库的用法(定义、调用位置、诊断信息),→ 请参阅 samber/cc-skills-golang@golang-gopls 技能(gopls)。
  • 对于 pkg.go.dev 未收录的文档,Context7 仍可作为备用方案。
go get github.com/spf13/cobra@latest

Cobra 与 viper

这两个库在根本上承担不同的职责,可以独立使用。

关注点cobraviper
负责命令树、标志、参数校验、补全配置值解析
面向用户?是——子命令、标志、帮助文本否——纯键值解析器
能否单独使用?能——只有标志的 CLI 只需要 cobra能——读取 YAML 和环境变量的守护进程只需要 viper
集成方式通过 BindPFlag 将 pflag.Flag 交给 viper将 cobra 标志视为优先级最高的配置层

当二进制程序接收标志和参数,但不需要配置文件或环境变量解析时,单独使用 cobra。当你有一个从 YAML 和环境变量读取配置、没有 CLI 子命令的长期运行服务时,单独使用 viper。两者都需要时,则同时使用——在根命令的 PersistentPreRunE 中绑定。

→ 有关此集成中 viper 一侧的信息,请参阅 samber/cc-skills-golang@golang-spf13-viper。

命令树

每个 cobra CLI 都有一个根命令,以及零个或多个通过 AddCommand 注册的子命令。根命令名称就是二进制文件名称。

var rootCmd = &cobra.Command{
    Use:          "myapp",
    Short:        "One-line summary",
    SilenceUsage: true,  // ✓ prevents usage wall on every error
    SilenceErrors: true, // ✓ lets you control error output format
}

使用 AddGroup 为帮助输出中的子命令添加分组标签——必须在引用这些分组的 AddCommand 调用之前注册分组;cobra 不会追溯分配分组。

Run* 系列

Cobra 命令有五个按顺序执行的运行钩子:

PersistentPreRunE → PreRunE → RunE → PostRunE → PersistentPostRunE

始终使用 *E 变体——非 E 形式无法返回错误。关键规则:

  • 根命令上的 PersistentPreRunE 会在每个子命令之前运行——用于初始化配置和检查身份验证。
  • 子命令的 PersistentPreRunE 会完全替换父命令的钩子——如果两者都需要,就显式调用父命令的钩子。
  • 只有 RunE 成功时,才会运行 PostRunE。

有关完整的生命周期和继承规则,请参阅 commands-and-args.md。

参数验证器

Cobra 会在运行 RunE 前验证位置参数。不要在 RunE 中编写 len(args) 检查——这会绕过 cobra 的标准错误消息和参数计数跟踪。

内置验证器:NoArgs、ExactArgs(n)、MinimumNArgs(n)、MaximumNArgs(n)、RangeArgs(min,max)、OnlyValidArgs、ExactValidArgs(n)。使用 MatchAll(v1, v2) 组合。自定义验证器:func(cmd *cobra.Command, args []string) error。

完整的验证器列表、示例和 MatchAll 模式,请参阅 commands-and-args.md。

标志入门

Cobra 将标志解析交由 pflag 处理。持久标志(PersistentFlags())由所有子命令继承;局部标志(Flags())仅适用于声明该标志的命令。

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path") // inherited by all subcommands
serveCmd.Flags().IntVar(&port, "port", 8080, "listen port")                     // local to serveCmd only
serveCmd.MarkFlagRequired("port")
serveCmd.MarkFlagsMutuallyExclusive("json", "yaml")

有关 pflag 类型、自定义标志值、标志组和 viper 绑定,请参阅 flags.md。

补全入门

Cobra 会自动生成 Shell 补全。可通过以下方式扩展:

  • ValidArgs []string — 静态位置参数补全。
  • ValidArgsFunction — 动态补全:func(cmd, args, toComplete string) ([]string, ShellCompDirective)。返回 ShellCompDirectiveNoFileComp 可禁用文件回退补全。
  • RegisterFlagCompletionFunc(name, fn) — 标志值补全。

有关 ShellCompDirective 值、注解和测试,请参阅 completions.md。

测试命令

通过以编程方式执行命令来测试命令。命令处理程序中不要直接使用 os.Stdout / os.Stderr——应使用 cmd.OutOrStdout() / cmd.ErrOrStderr(),以便测试重定向输出。

func TestServeCmd(t *testing.T) {
    buf := new(bytes.Buffer)
    rootCmd.SetOut(buf)
    rootCmd.SetArgs([]string{"serve", "--port", "9090"})
    require.NoError(t, rootCmd.Execute())
    assert.Contains(t, buf.String(), "listening on :9090")
}

Cobra 会在多次调用 Execute() 时累积标志状态——每个测试都要构建全新的命令树。有关隔离模式、黄金文件和补全测试,请参阅 testing.md。

最佳实践

  1. 始终使用 RunE,不要使用 Run——Run 无法返回错误;唯一的退出方式是 os.Exit 或 panic,这会绕过 defer。
  2. 将配置初始化放在 PersistentPreRunE 中——它会在每个子命令运行前执行;适合进行 viper 绑定和身份验证检查。
  3. 使用 Args 而非在 RunE 中验证位置参数——Args 会提供 cobra 的标准错误消息;MatchAll 可组合多个验证器。
  4. 所有输出都使用 cmd.OutOrStdout() / cmd.ErrOrStderr()——直接写入 os.Stdout 无法被测试捕获。
  5. 每个测试都重新创建命令树——在同一实例上多次调用 Execute() 时,cobra 会累积标志状态。

常见错误

错误失败原因修复方法
使用 Run 而非 RunE无法返回错误——唯一的退出方式是 os.Exit 或 panic,这会绕过 defer使用 RunE——返回错误并让 cobra 处理退出
在 RunE 中编写 len(args) 检查绕过 cobra 的标准错误消息(“需要 1 个参数,收到 2 个”)在命令上声明 Args: cobra.ExactArgs(1)
直接写入 os.Stdout测试无法捕获输出——操作系统级文件句柄无法重定向使用 cmd.OutOrStdout() / cmd.ErrOrStderr()
子命令的 PersistentPreRunE 静默丢弃父命令的钩子Cobra 不会串联钩子——子命令会完全替换父命令的钩子在子命令的钩子中调用 parent.PersistentPreRunE(cmd, args)
在多个测试间重用根命令Cobra 会累积标志状态;第二次 Execute() 会看到第一次执行时的标志每个测试都构建全新的命令树

延伸阅读

  • commands-and-args.md — 完整的 PreRun*/PostRun* 链、所有 Args 验证器、PersistentPreRunE 继承规则
  • flags.md — pflag 类型、必需/互斥/至少一个必选组、自定义值类型、viper 绑定
  • completions.md — ShellCompDirective 集合、基于注解的补全、补全测试
  • generators.md — man 页面、markdown、YAML、RST 文档生成;cobra-cli 脚手架工具
  • testing.md — 隔离模式、黄金文件、补全测试、表驱动命令测试

交叉引用

  • → 有关通用 CLI 架构(项目布局、退出码、信号处理、I/O 模式),请参阅 samber/cc-skills-golang@golang-cli 技能
  • → 有关与 cobra 配合使用的配置分层(flag → env → file → default 优先级),请参阅 samber/cc-skills-golang@golang-spf13-viper 技能
  • → 有关通用 Go 测试模式,请参阅 samber/cc-skills-golang@golang-testing 技能

如果你在 spf13/cobra 中遇到 Bug 或意外行为,请前往 https://github.com/spf13/cobra/issues 提交问题。

评论

支持 Markdown