cobra-modularity
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCobra Modular CLI Architecture
Cobra模块化CLI架构
Build scalable, maintainable CLI applications using Cobra with modular command registration patterns.
使用Cobra的模块化命令注册模式构建可扩展、易维护的CLI应用程序。
Your Role: CLI Architect
你的角色:CLI架构师
You help structure CLI applications with clean, modular architecture. You:
✅ Design modular command structure - Self-contained command modules
✅ Implement Register pattern - Commands register themselves
✅ Handle flags properly - Persistent vs local, parsing, validation
✅ Structure subcommands - Nested command hierarchies
✅ Apply Cobra idioms - RunE for errors, PreRun hooks, etc.
✅ Follow project patterns - Use existing module conventions
❌ Do NOT centralize commands - Keep modules self-contained
❌ Do NOT modify root unnecessarily - Add via registration only
❌ Do NOT ignore errors - Use RunE, not Run
你需要协助构建架构清晰、模块化的CLI应用程序。你需要:
✅ 设计模块化命令结构 - 独立的命令模块
✅ 实现注册模式 - 命令自行完成注册
✅ 正确处理标志 - 持久化标志与本地标志、解析、验证
✅ 构建子命令结构 - 嵌套命令层级
✅ 应用Cobra惯用写法 - 使用RunE处理错误、PreRun钩子等
✅ 遵循项目模式 - 采用现有模块约定
❌ 不要集中管理命令 - 保持模块独立
❌ 不要不必要地修改根命令 - 仅通过注册方式添加
❌ 不要忽略错误 - 使用RunE,而非Run
Core Principles
核心原则
1. Modular Command Registration
1. 模块化命令注册
Commands live in their own packages and register with parent commands.
✅ GOOD - Self-registering module:
go
// modules/demo/cmd.go
package demo
import "github.com/spf13/cobra"
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "demo",
Short: "Demo commands",
}
parent.AddCommand(cmd)
// Register subcommands
spinner.Register(cmd)
list.Register(cmd)
}❌ BAD - Centralized registration:
go
// cmd/root.go - DON'T do this
func init() {
RootCmd.AddCommand(demoCmd)
RootCmd.AddCommand(listCmd)
RootCmd.AddCommand(spinnerCmd)
// Root knows too much
}命令存放在独立包中,并向父命令完成注册。
✅ 推荐 - 自注册模块:
go
// modules/demo/cmd.go
package demo
import "github.com/spf13/cobra"
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "demo",
Short: "Demo commands",
}
parent.AddCommand(cmd)
// 注册子命令
spinner.Register(cmd)
list.Register(cmd)
}❌ 不推荐 - 集中式注册:
go
// cmd/root.go - 不要这样做
func init() {
RootCmd.AddCommand(demoCmd)
RootCmd.AddCommand(listCmd)
RootCmd.AddCommand(spinnerCmd)
// 根命令耦合性过高
}2. Command Structure Pattern
2. 命令结构模式
Standard module layout:
modules/demo/
├── cmd.go # Register function
├── spinner/
│ ├── cmd.go # spinner.Register()
│ └── spinner.go # Implementation
└── list/
├── cmd.go # list.Register()
└── list.go # ImplementationBenefits:
- Module is self-contained
- Easy to add/remove commands
- No changes to root when adding modules
- Testable in isolation
标准模块布局:
modules/demo/
├── cmd.go # 注册函数
├── spinner/
│ ├── cmd.go # spinner.Register()
│ └── spinner.go # 实现代码
└── list/
├── cmd.go # list.Register()
└── list.go # 实现代码优势:
- 模块独立完整
- 易于添加/移除命令
- 添加模块时无需修改根命令
- 可独立测试
3. Error Handling
3. 错误处理
Use RunE (not Run):
✅ GOOD:
go
cmd := &cobra.Command{
Use: "fetch",
Short: "Fetch data",
RunE: run, // Returns error
}
func run(cmd *cobra.Command, args []string) error {
if err := doWork(); err != nil {
return fmt.Errorf("fetch failed: %w", err)
}
return nil
}❌ BAD:
go
cmd := &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
doWork() // Error ignored
},
}使用RunE(而非Run):
✅ 推荐:
go
cmd := &cobra.Command{
Use: "fetch",
Short: "Fetch data",
RunE: run, // 返回错误
}
func run(cmd *cobra.Command, args []string) error {
if err := doWork(); err != nil {
return fmt.Errorf("fetch failed: %w", err)
}
return nil
}❌ 不推荐:
go
cmd := &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
doWork() // 错误被忽略
},
}Cobra Command Structure
Cobra命令结构
Basic Command
基础命令
go
package mycommand
import (
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "mycommand",
Short: "Short description",
Long: `Long description with examples`,
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
// Implementation
return nil
}go
package mycommand
import (
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "mycommand",
Short: "简短描述",
Long: `带示例的详细描述`,
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
// 实现代码
return nil
}With Flags
带标志的命令
Local flags (command-specific):
go
var (
flagName string
flagCount int
flagVerbose bool
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "process",
Short: "Process data",
RunE: run,
}
// String flag with shorthand
cmd.Flags().StringVarP(&flagName, "name", "n", "", "Name (required)")
cmd.MarkFlagRequired("name")
// Int flag
cmd.Flags().IntVarP(&flagCount, "count", "c", 10, "Count")
// Bool flag
cmd.Flags().BoolVarP(&flagVerbose, "verbose", "v", false, "Verbose output")
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
// Use flagName, flagCount, flagVerbose
return nil
}Persistent flags (inherited by subcommands):
go
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "server",
Short: "Server commands",
}
// Available to all subcommands
cmd.PersistentFlags().StringP("config", "c", "", "Config file")
parent.AddCommand(cmd)
// Register subcommands
start.Register(cmd) // Can access --config
stop.Register(cmd) // Can access --config
}本地标志(命令专属):
go
var (
flagName string
flagCount int
flagVerbose bool
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "process",
Short: "处理数据",
RunE: run,
}
// 带简写的字符串标志
cmd.Flags().StringVarP(&flagName, "name", "n", "", "名称(必填)")
cmd.MarkFlagRequired("name")
// 整数标志
cmd.Flags().IntVarP(&flagCount, "count", "c", 10, "数量")
// 布尔标志
cmd.Flags().BoolVarP(&flagVerbose, "verbose", "v", false, "详细输出")
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
// 使用flagName, flagCount, flagVerbose
return nil
}持久化标志(被子命令继承):
go
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "server",
Short: "服务器命令",
}
// 所有子命令均可使用
cmd.PersistentFlags().StringP("config", "c", "", "配置文件")
parent.AddCommand(cmd)
// 注册子命令
start.Register(cmd) // 可访问--config
stop.Register(cmd) // 可访问--config
}With Arguments
带参数的命令
Exact args:
go
cmd := &cobra.Command{
Use: "delete <id>",
Short: "Delete item by ID",
Args: cobra.ExactArgs(1), // Requires exactly 1 arg
RunE: run,
}
func run(cmd *cobra.Command, args []string) error {
id := args[0]
return deleteItem(id)
}Range of args:
go
Args: cobra.RangeArgs(1, 3), // 1 to 3 args
Args: cobra.MinimumNArgs(1), // At least 1 arg
Args: cobra.MaximumNArgs(2), // At most 2 argsCustom validation:
go
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("requires exactly one arg")
}
if !isValidID(args[0]) {
return fmt.Errorf("invalid ID: %s", args[0])
}
return nil
},固定数量参数:
go
cmd := &cobra.Command{
Use: "delete <id>",
Short: "按ID删除项",
Args: cobra.ExactArgs(1), // 要求恰好1个参数
RunE: run,
}
func run(cmd *cobra.Command, args []string) error {
id := args[0]
return deleteItem(id)
}参数范围:
go
Args: cobra.RangeArgs(1, 3), // 1到3个参数
Args: cobra.MinimumNArgs(1), // 至少1个参数
Args: cobra.MaximumNArgs(2), // 最多2个参数自定义验证:
go
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("需要恰好1个参数")
}
if !isValidID(args[0]) {
return fmt.Errorf("无效ID: %s", args[0])
}
return nil
},Module Patterns
模块模式
Demo Module Pattern (CLY)
示例模块模式(CLY)
Parent command - :
modules/demo/cmd.gogo
package demo
import (
"github.com/spf13/cobra"
spinner "github.com/yurifrl/cly/modules/demo/spinner"
)
var DemoCmd = &cobra.Command{
Use: "demo",
Short: "Demo TUI components",
}
func Register(parent *cobra.Command) {
parent.AddCommand(DemoCmd)
}
func init() {
// Register all demo subcommands
spinner.Register(DemoCmd)
// ... more demos
}Subcommand - :
modules/demo/spinner/cmd.gogo
package spinner
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "spinner",
Short: "Spinner demo",
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
p := tea.NewProgram(initialModel())
if _, err := p.Run(); err != nil {
return err
}
return nil
}父命令 - :
modules/demo/cmd.gogo
package demo
import (
"github.com/spf13/cobra"
spinner "github.com/yurifrl/cly/modules/demo/spinner"
)
var DemoCmd = &cobra.Command{
Use: "demo",
Short: "Demo TUI components",
}
func Register(parent *cobra.Command) {
parent.AddCommand(DemoCmd)
}
func init() {
// 注册所有示例子命令
spinner.Register(DemoCmd)
// ... 更多示例
}子命令 - :
modules/demo/spinner/cmd.gogo
package spinner
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "spinner",
Short: "Spinner demo",
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
p := tea.NewProgram(initialModel())
if _, err := p.Run(); err != nil {
return err
}
return nil
}Utility Module Pattern (CLY)
工具模块模式(CLY)
Standalone command - :
modules/uuid/cmd.gogo
package uuid
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "uuid",
Short: "Generate UUIDs",
Long: "Interactive UUID generator with history",
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
p := tea.NewProgram(initialModel())
_, err := p.Run()
return err
}Registered in root - :
cmd/root.gogo
import (
"github.com/yurifrl/cly/modules/uuid"
"github.com/yurifrl/cly/modules/demo"
)
func init() {
uuid.Register(RootCmd)
demo.Register(RootCmd)
}独立命令 - :
modules/uuid/cmd.gogo
package uuid
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
)
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "uuid",
Short: "生成UUID",
Long: "带历史记录的交互式UUID生成器",
RunE: run,
}
parent.AddCommand(cmd)
}
func run(cmd *cobra.Command, args []string) error {
p := tea.NewProgram(initialModel())
_, err := p.Run()
return err
}在根命令中注册 - :
cmd/root.gogo
import (
"github.com/yurifrl/cly/modules/uuid"
"github.com/yurifrl/cly/modules/demo"
)
func init() {
uuid.Register(RootCmd)
demo.Register(RootCmd)
}Advanced Patterns
进阶模式
PreRun Hooks
PreRun钩子
Validate before run:
go
cmd := &cobra.Command{
Use: "deploy",
PreRunE: func(cmd *cobra.Command, args []string) error {
// Validation
if !fileExists(configFile) {
return fmt.Errorf("config not found: %s", configFile)
}
return nil
},
RunE: run,
}Setup before run:
go
PreRunE: func(cmd *cobra.Command, args []string) error {
// Setup database connection
db, err = connectDB()
return err
},运行前验证:
go
cmd := &cobra.Command{
Use: "deploy",
PreRunE: func(cmd *cobra.Command, args []string) error {
// 验证逻辑
if !fileExists(configFile) {
return fmt.Errorf("未找到配置文件: %s", configFile)
}
return nil
},
RunE: run,
}运行前初始化:
go
PreRunE: func(cmd *cobra.Command, args []string) error {
// 建立数据库连接
db, err = connectDB()
return err
},PostRun Hooks
PostRun钩子
Cleanup after run:
go
PostRun: func(cmd *cobra.Command, args []string) {
// Cleanup
db.Close()
tempFile.Remove()
},运行后清理:
go
PostRun: func(cmd *cobra.Command, args []string) {
// 清理操作
db.Close()
tempFile.Remove()
},Persistent PreRun (Inherited)
持久化PreRun(可继承)
go
cmd := &cobra.Command{
Use: "api",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// Runs before ALL subcommands
return loadConfig()
},
}go
cmd := &cobra.Command{
Use: "api",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// 在所有子命令运行前执行
return loadConfig()
},
}Flag Dependencies
标志依赖
Require flag if another present:
go
cmd.Flags().String("format", "", "Output format")
cmd.Flags().String("output", "", "Output file")
cmd.MarkFlagsRequiredTogether("format", "output")Mutually exclusive flags:
go
cmd.Flags().Bool("json", false, "JSON output")
cmd.Flags().Bool("yaml", false, "YAML output")
cmd.MarkFlagsMutuallyExclusive("json", "yaml")存在一个标志时需要另一个标志:
go
cmd.Flags().String("format", "", "输出格式")
cmd.Flags().String("output", "", "输出文件")
cmd.MarkFlagsRequiredTogether("format", "output")互斥标志:
go
cmd.Flags().Bool("json", false, "JSON输出")
cmd.Flags().Bool("yaml", false, "YAML输出")
cmd.MarkFlagsMutuallyExclusive("json", "yaml")Subcommand Groups
子命令分组
go
parent := &cobra.Command{
Use: "api",
Short: "API commands",
}
// Group 1
parent.AddGroup(&cobra.Group{
ID: "server",
Title: "Server Commands:",
})
cmd1 := &cobra.Command{
Use: "start",
GroupID: "server",
}
cmd2 := &cobra.Command{
Use: "stop",
GroupID: "server",
}
parent.AddCommand(cmd1, cmd2)go
parent := &cobra.Command{
Use: "api",
Short: "API命令",
}
// 分组1
parent.AddGroup(&cobra.Group{
ID: "server",
Title: "服务器命令:",
})
cmd1 := &cobra.Command{
Use: "start",
GroupID: "server",
}
cmd2 := &cobra.Command{
Use: "stop",
GroupID: "server",
}
parent.AddCommand(cmd1, cmd2)Configuration Integration
配置集成
With Viper
与Viper集成
go
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "server",
Short: "Run server",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return initConfig()
},
RunE: run,
}
cmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Config file")
// Bind flag to viper
viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config"))
parent.AddCommand(cmd)
}
func initConfig() error {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME/.myapp")
}
viper.AutomaticEnv()
return viper.ReadInConfig()
}
func run(cmd *cobra.Command, args []string) error {
port := viper.GetInt("server.port")
// Use config
return nil
}go
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
func Register(parent *cobra.Command) {
cmd := &cobra.Command{
Use: "server",
Short: "启动服务器",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return initConfig()
},
RunE: run,
}
cmd.PersistentFlags().StringVar(&cfgFile, "config", "", "配置文件")
// 将标志绑定到Viper
viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config"))
parent.AddCommand(cmd)
}
func initConfig() error {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME/.myapp")
}
viper.AutomaticEnv()
return viper.ReadInConfig()
}
func run(cmd *cobra.Command, args []string) error {
port := viper.GetInt("server.port")
// 使用配置
return nil
}Best Practices
最佳实践
1. Keep Commands Focused
1. 保持命令职责单一
One responsibility per command:
go
// ✅ GOOD
cly uuid # Generate UUIDs
cly demo spinner # Show spinner demo
// ❌ BAD
cly utils # Does everything每个命令对应一个职责:
go
// ✅ 推荐
cly uuid # 生成UUID
cly demo spinner # 展示加载动画示例
// ❌ 不推荐
cly utils # 包含所有功能2. Use Meaningful Names
2. 使用有意义的命令名称
go
// ✅ GOOD
Use: "generate",
Use: "list-users",
Use: "deploy-app",
// ❌ BAD
Use: "do",
Use: "run",
Use: "execute",go
// ✅ 推荐
Use: "generate",
Use: "list-users",
Use: "deploy-app",
// ❌ 不推荐
Use: "do",
Use: "run",
Use: "execute",3. Provide Good Help
3. 提供完善的帮助信息
go
cmd := &cobra.Command{
Use: "deploy <environment>",
Short: "Deploy application",
Long: `Deploy the application to specified environment.
Environments: dev, staging, prod
Examples:
cly deploy dev
cly deploy prod --version v1.2.3`,
Example: ` cly deploy dev
cly deploy prod --version v1.2.3`,
}go
cmd := &cobra.Command{
Use: "deploy <environment>",
Short: "部署应用",
Long: `将应用部署到指定环境。
支持环境: dev, staging, prod
示例:
cly deploy dev
cly deploy prod --version v1.2.3`,
Example: ` cly deploy dev
cly deploy prod --version v1.2.3`,
}4. Validate Early
4. 提前验证
go
PreRunE: func(cmd *cobra.Command, args []string) error {
// Validate flags
if port < 1 || port > 65535 {
return fmt.Errorf("invalid port: %d", port)
}
// Check prerequisites
if !commandExists("docker") {
return fmt.Errorf("docker not found")
}
return nil
},go
PreRunE: func(cmd *cobra.Command, args []string) error {
// 验证标志
if port < 1 || port > 65535 {
return fmt.Errorf("无效端口: %d", port)
}
// 检查前置依赖
if !commandExists("docker") {
return fmt.Errorf("未找到docker")
}
return nil
},5. Handle Interrupts
5. 处理中断信号
go
import (
"context"
"os/signal"
"syscall"
)
func run(cmd *cobra.Command, args []string) error {
ctx, stop := signal.NotifyContext(
context.Background(),
os.Interrupt,
syscall.SIGTERM,
)
defer stop()
return runWithContext(ctx)
}go
import (
"context"
"os/signal"
"syscall"
)
func run(cmd *cobra.Command, args []string) error {
ctx, stop := signal.NotifyContext(
context.Background(),
os.Interrupt,
syscall.SIGTERM,
)
defer stop()
return runWithContext(ctx)
}Testing Commands
命令测试
Test Registration
测试注册逻辑
go
func TestRegister(t *testing.T) {
parent := &cobra.Command{Use: "root"}
Register(parent)
require.Len(t, parent.Commands(), 1)
require.Equal(t, "mycommand", parent.Commands()[0].Use)
}go
func TestRegister(t *testing.T) {
parent := &cobra.Command{Use: "root"}
Register(parent)
require.Len(t, parent.Commands(), 1)
require.Equal(t, "mycommand", parent.Commands()[0].Use)
}Test Command Execution
测试命令执行
go
func TestRun(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
RunE: run,
}
cmd.SetArgs([]string{"arg1", "arg2"})
err := cmd.Execute()
require.NoError(t, err)
}go
func TestRun(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
RunE: run,
}
cmd.SetArgs([]string{"arg1", "arg2"})
err := cmd.Execute()
require.NoError(t, err)
}Test with Flags
带标志的命令测试
go
func TestRunWithFlags(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
RunE: run,
}
var flagValue string
cmd.Flags().StringVar(&flagValue, "flag", "", "test flag")
cmd.SetArgs([]string{"--flag", "value"})
err := cmd.Execute()
require.NoError(t, err)
require.Equal(t, "value", flagValue)
}go
func TestRunWithFlags(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
RunE: run,
}
var flagValue string
cmd.Flags().StringVar(&flagValue, "flag", "", "test flag")
cmd.SetArgs([]string{"--flag", "value"})
err := cmd.Execute()
require.NoError(t, err)
require.Equal(t, "value", flagValue)
}Common Pitfalls
常见陷阱
❌ Using Run instead of RunE:
go
Run: func(cmd *cobra.Command, args []string) {
// Can't return errors!
doWork()
}✅ Use RunE:
go
RunE: func(cmd *cobra.Command, args []string) error {
return doWork()
}❌ Not validating args:
go
RunE: func(cmd *cobra.Command, args []string) error {
id := args[0] // Panic if no args!
return nil
}✅ Validate with Args:
go
cmd := &cobra.Command{
Args: cobra.ExactArgs(1),
RunE: run,
}❌ Centralizing all commands:
go
// root.go
RootCmd.AddCommand(cmd1)
RootCmd.AddCommand(cmd2)
RootCmd.AddCommand(cmd3)
// Tight coupling✅ Module registration:
go
// Each module registers itself
module1.Register(RootCmd)
module2.Register(RootCmd)❌ 使用Run而非RunE:
go
Run: func(cmd *cobra.Command, args []string) {
// 无法返回错误!
doWork()
}✅ 使用RunE:
go
RunE: func(cmd *cobra.Command, args []string) error {
return doWork()
}❌ 不验证参数:
go
RunE: func(cmd *cobra.Command, args []string) error {
id := args[0] // 无参数时会 panic!
return nil
}✅ 使用Args字段验证:
go
cmd := &cobra.Command{
Args: cobra.ExactArgs(1),
RunE: run,
}❌ 集中管理所有命令:
go
// root.go
RootCmd.AddCommand(cmd1)
RootCmd.AddCommand(cmd2)
RootCmd.AddCommand(cmd3)
// 耦合性过高✅ 模块注册方式:
go
// 每个模块自行注册
module1.Register(RootCmd)
module2.Register(RootCmd)Checklist
检查清单
- Command uses RunE (not Run)
- Register() function for modularity
- Args validated with Args field
- Flags bound to variables
- Required flags marked
- Good Short description
- Detailed Long description
- Examples provided
- Errors wrapped with context
- Tests for command execution
- 命令使用RunE(而非Run)
- 提供Register()函数实现模块化
- 通过Args字段验证参数
- 标志已绑定到变量
- 必填标志已标记
- 包含清晰的Short描述
- 包含详细的Long描述
- 提供使用示例
- 错误信息包含上下文
- 包含命令执行测试
Reference
参考
CLY Project Structure:
cmd/
└── root.go # Root command, imports modules
modules/
├── demo/
│ ├── cmd.go # demo.Register()
│ └── spinner/
│ └── cmd.go # spinner.Register()
└── uuid/
└── cmd.go # uuid.Register()Pattern: Each module registers itself, no central registration.
CLY项目结构:
cmd/
└── root.go # 根命令,导入模块
modules/
├── demo/
│ ├── cmd.go # demo.Register()
│ └── spinner/
│ └── cmd.go # spinner.Register()
└── uuid/
└── cmd.go # uuid.Register()模式: 每个模块自行注册,无需集中管理。
Resources
资源
- Cobra Docs
- Cobra User Guide
- Viper Config
- CLY examples: ,
modules/demo/modules/uuid/
- Cobra Docs
- Cobra User Guide
- Viper Config
- CLY示例: ,
modules/demo/modules/uuid/