mcpField
G
golang-cli

golang-cli

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

关于 golang-cli

面向 Go 命令行工具构建、扩展和审查的工程技能。涵盖 Cobra 与 Viper 用法、配置管理、Shell 友好型输入输出、参数校验和发布。

主要功能

  1. 01Cobra 命令与标志结构
  2. 02Viper 配置分层
  3. 03参数与标志校验
  4. 04Unix 标准输出和错误输出规范
  5. 05补全、测试与退出码

适用场景

  1. 01创建带子命令的 Go 命令行工具
  2. 02为现有工具添加标志和配置
  3. 03审查工具的输出、错误处理和退出码

安装

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

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

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

包含的文件

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

assets/examples/
args.go
cli_test.go
completion.go
config.go
exit_codes.go
flags.go
go.mod
main.go
output.go
root.go
serve.go
signal.go
version.go
evals/
evals.json

详细介绍

角色: 你是一名 Go 命令行工程师。你构建的工具原生融入 Unix shell,具有可组合、可编写脚本且在自动化环境中行为可预测的特点。

模式:

  • 构建 — 从零开始创建新的命令行工具:按顺序参照项目结构、根命令设置、标志绑定和版本嵌入部分。
  • 扩展 — 为现有命令行工具添加子命令、标志或补全:先阅读当前命令树,再按照现有结构应用更改。
  • 审查 — 审查现有命令行工具的正确性:检查“常见错误”表,验证 SilenceUsage/SilenceErrors、标志与 Viper 的绑定、退出代码,以及 stdout/stderr 的使用规范。

Go 命令行最佳实践

Go 命令行应用默认使用 Cobra + Viper 作为技术栈。Cobra 提供命令、子命令和标志结构,Viper 负责处理文件、环境变量和标志中的配置,并自动进行分层。这种组合用于 kubectl、docker、gh、hugo 等工具以及大多数生产级 Go 命令行工具。

使用 Cobra 或 Viper 时,请参阅库的官方文档和代码示例,了解当前 API 签名。

对于没有子命令且标志较少的简单单一用途工具,标准库 flag 足以胜任。

快速参考

关注点包 / 工具
命令和标志github.com/spf13/cobra
配置github.com/spf13/viper
标志解析github.com/spf13/pflag(通过 Cobra)
彩色输出github.com/fatih/color
表格输出github.com/olekukonko/tablewriter
交互式提示github.com/charmbracelet/bubbletea
版本注入go build -ldflags
分发goreleaser

项目结构

将命令行工具的命令组织在 cmd/myapp/ 中,每个命令单独放在一个文件里。保持 main.go 简洁——它只调用 Execute()。

myapp/
├── cmd/
│   └── myapp/
│       ├── main.go              # package main, only calls Execute()
│       ├── root.go              # Root command + Viper init
│       ├── serve.go             # "serve" subcommand
│       ├── migrate.go           # "migrate" subcommand
│       └── version.go           # "version" subcommand
├── go.mod
└── go.sum

main.go 应保持简洁——参见 assets/examples/main.go。

根命令设置

根命令通过 PersistentPreRunE 初始化 Viper 配置并设置全局行为。参见 assets/examples/root.go。

要点:

  • 必须设置 SilenceUsage: true——避免每次发生错误时都打印完整的用法文本
  • 必须设置 SilenceErrors: true——以便自行控制错误输出格式
  • PersistentPreRunE 会在每个子命令运行前执行,因此配置始终会初始化
  • 日志输出到 stderr,普通输出到 stdout

子命令

通过在 cmd/myapp/ 中创建独立文件并在 init() 中注册,即可添加子命令。参见 assets/examples/serve.go,其中包含一个完整的子命令示例(含命令分组)。

标志

所有标志模式请参见 assets/examples/flags.go:

持久标志与本地标志
  • 持久标志会由所有子命令继承(例如 --config)
  • 本地标志仅适用于定义它的命令(例如 --port)
必需标志

使用 MarkFlagRequired、MarkFlagsMutuallyExclusive 和 MarkFlagsOneRequired 设置标志约束。

使用 RegisterFlagCompletionFunc 验证标志

为标志值提供补全建议。

始终将标志绑定到 Viper

这样可确保 viper.GetInt("port") 返回标志值、环境变量 MYAPP_PORT 或配置文件值——具体取决于优先级。

参数验证

Cobra 为位置参数提供了内置验证器。请参阅 assets/examples/args.go,了解内置和自定义验证示例。

验证器描述
cobra.NoArgs如果提供了任何参数,则失败
cobra.ExactArgs(n)要求参数数量恰好为 n
cobra.MinimumNArgs(n)要求至少有 n 个参数
cobra.MaximumNArgs(n)最多允许 n 个参数
cobra.RangeArgs(min, max)要求参数数量介于 min 和 max 之间
cobra.ExactValidArgs(n)参数数量恰好为 n,且必须包含在 ValidArgs 中

使用 Viper 配置

Viper 按以下顺序(从高到低)解析配置值:

  1. CLI 标志(用户显式输入)
  2. 环境变量(部署配置)
  3. 配置文件(持久化设置)
  4. 默认值(在代码中设置)

请参阅 assets/examples/config.go,了解完整的 Viper 集成示例,包括结构体反序列化和配置文件监视。

配置文件示例(.myapp.yaml)
port: 8080
host: localhost
log-level: info
database:
  dsn: postgres://localhost:5432/myapp
  max-conn: 25

使用上述设置,以下方式的效果都相同:

  • 标志:--port 9090
  • 环境变量:MYAPP_PORT=9090
  • 配置文件:port: 9090

版本和构建信息

应在编译时使用 ldflags 嵌入版本信息。请参阅 assets/examples/version.go,了解版本命令和构建说明。

退出代码

退出代码必须遵循 Unix 约定:

代码含义使用时机
0成功操作正常完成
1一般错误运行时故障
2用法错误标志或参数无效
64-78BSD sysexits特定错误类别
126无法执行权限被拒绝
127找不到命令缺少依赖项
128+N信号 N被信号终止(例如,130 = SIGINT)

请参阅 assets/examples/exit_codes.go,了解将错误映射到退出代码的模式。

I/O 模式

请参阅 assets/examples/output.go,了解所有 I/O 模式:

  • stdout 与 stderr:绝不要将诊断输出写入 stdout——stdout 用于程序输出(可通过管道传递),stderr 用于日志、错误和诊断信息
  • 检测管道与终端:检查 stdout 上的 os.ModeCharDevice
  • 机器可读输出:支持 --output 标志,提供 table/json/plain 格式
  • 颜色:使用 fatih/color,当输出不是终端时它会自动禁用颜色

信号处理

信号处理必须使用 signal.NotifyContext,通过 context 传递取消信号。请参阅 assets/examples/signal.go,了解如何优雅地关闭 HTTP 服务端。

Shell 补全

Cobra 会自动为 bash、zsh、fish 和 PowerShell 生成补全。请参阅 assets/examples/completion.go,了解补全命令以及自定义标志和参数补全。

测试 CLI 命令

通过以编程方式执行命令并捕获输出来测试命令。请参阅 assets/examples/cli_test.go。

在命令中使用 cmd.OutOrStdout() 和 cmd.ErrOrStderr()(而不是 os.Stdout / os.Stderr),以便在测试中捕获输出。

常见错误

错误修正方法
直接写入 os.Stdout测试无法捕获输出。使用 cmd.OutOrStdout(),测试可以将其重定向到缓冲区
在 RunE 中调用 os.Exit()Cobra 的错误处理、延迟函数和清理代码都不会运行。返回错误,让 main() 决定如何处理
未将标志绑定到 Viper无法通过环境变量或配置文件配置标志。对每个可配置的标志调用 viper.BindPFlag
缺少 viper.SetEnvPrefixPORT 会与其他工具冲突。使用前缀(MYAPP_PORT)为环境变量划分命名空间
将日志写入标准输出Unix 管道会串联标准输出,日志会破坏下一个程序的数据流。日志应写入标准错误
每次出错都打印用法说明每次出错都打印完整帮助文本会造成干扰。设置 SilenceUsage: true,仅在 --help 时显示完整用法
要求必须有配置文件没有配置文件的用户会遇到崩溃。忽略 viper.ConfigFileNotFoundError,配置文件应为可选项
未使用 PersistentPreRunE配置初始化必须在任何子命令运行前完成。使用根命令的 PersistentPreRunE
硬编码版本字符串版本会与标签不一致。在构建时通过 ldflags 从 git 标签注入版本
不支持 --output 格式脚本无法解析面向用户的可读输出。添加 JSON、表格或纯文本格式,供程序处理

相关技能

请参阅 samber/cc-skills-golang@golang-project-layout、samber/cc-skills-golang@golang-dependency-injection、samber/cc-skills-golang@golang-testing 和 samber/cc-skills-golang@golang-design-patterns 技能。

评论

支持 Markdown