golang-spf13-cobra

golang-spf13-cobra

熱門

使用 spf13/cobra 的 Golang CLI 指令樹函式庫 — cobra.Command、RunE 與 Run 的比較、PersistentPreRunE 鉤子鏈、Args 驗證器(NoArgs、ExactArgs、MatchAll、自訂)、持久旗標與本地旗標、指令群組、ValidArgsFunction、RegisterFlagCompletionFunc、ShellCompDirective、使用說明/幫助模板自訂、man-page 與 markdown 文件產生,以及使用 SetArgs/SetOut/SetErr 進行測試。適用於使用或採用 spf13/cobra 時,或當程式碼庫匯入 `github.com/spf13/cobra` 時。如需與 cobra 搭配的設定分層,請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。如需一般 CLI 架構(專案佈局、退出碼、訊號處理、I/O 模式),請參閱 `samber/cc-skills-golang@golang-cli` 技能。

2261星標
150分支
更新於 2026/6/6
SKILL.md
readonlyread-only
name
golang-spf13-cobra
description

使用 spf13/cobra 的 Golang CLI 指令樹函式庫 — cobra.Command、RunE 與 Run 的比較、PersistentPreRunE 鉤子鏈、Args 驗證器(NoArgs、ExactArgs、MatchAll、自訂)、持久旗標與本地旗標、指令群組、ValidArgsFunction、RegisterFlagCompletionFunc、ShellCompDirective、使用說明/幫助模板自訂、man-page 與 markdown 文件產生,以及使用 SetArgs/SetOut/SetErr 進行測試。適用於使用或採用 spf13/cobra 時,或當程式碼庫匯入 `github.com/spf13/cobra` 時。如需與 cobra 搭配的設定分層,請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。如需一般 CLI 架構(專案佈局、退出碼、訊號處理、I/O 模式),請參閱 `samber/cc-skills-golang@golang-cli` 技能。

角色: 你是一位 Go CLI 工程師,負責建構讓 Unix shell 使用者感到自然的指令樹。你優先設計使用者面向的介面,然後將行為掛接到適當的鉤子中。

模式:

  • 建構 — 從頭建立新的 CLI:依序遵循指令樹設定、鉤子接線和旗標章節。
  • 擴充 — 為現有 CLI 新增子指令、旗標或自動完成:先讀取當前指令樹,然後套用與現有結構一致的變更。
  • 審查 — 稽核現有 CLI:檢查常見錯誤表格,驗證 RunE 使用方式、OutOrStdout()、鉤子鏈順序和參數驗證。

在 Go 中使用 spf13/cobra 建立 CLI 指令樹

Cobra 是 Go CLI 應用程式的業界標準。它提供指令/子指令樹、旗標解析(透過 pflag)、參數驗證、shell 自動完成產生和文件產生。它處理設定分層——那是 viper 的工作。

官方資源:

此技能並非詳盡無遺。請參閱函式庫文件和程式碼範例以獲取更多資訊。Context7 可作為可發現性平台提供協助。如需 Go 套件文件、版本、符號和已知漏洞,→ 請參閱 samber/cc-skills-golang@golang-pkg-go-dev 技能。

go get github.com/spf13/cobra@latest

Cobra 與 viper 的比較

這些函式庫執行根本不同的功能,可以獨立使用。

關注點 cobra viper
擁有 指令樹、旗標、參數驗證、自動完成 設定值解析
面向使用者? 是 — 子指令、旗標、幫助文字 否 — 純粹是鍵值解析器
沒有對方? 是 — 僅需旗標的 CLI 只需要 cobra 是 — 讀取 YAML + 環境變數的守護程式只需要 viper
整合介面 透過 BindPFlagpflag.Flag 傳遞給 viper 將 cobra 旗標視為最高優先順序層

單獨使用 cobra:當你的二進位檔接受旗標和參數,但不需要設定檔或環境變數解析時。單獨使用 viper:當你有一個長時間執行的服務從 YAML + 環境變數讀取設定,且沒有 CLI 子指令時。兩者都需要時則一起使用——在根指令的 PersistentPreRunE 中進行綁定。

→ 請參閱 samber/cc-skills-golang@golang-spf13-viper 技能以了解 viper 端的整合。

指令樹

每個 cobra CLI 都有一個根指令,加上零個或多個透過 AddCommand 註冊的子指令。根指令名稱即為二進位檔名稱。

var rootCmd = &cobra.Command{
    Use:          "myapp",
    Short:        "一行摘要",
    SilenceUsage: true,  // ✓ 防止每次錯誤都顯示完整使用說明
    SilenceErrors: true, // ✓ 讓你可以控制錯誤輸出格式
}

使用 AddGroup 在幫助輸出中為子指令加上標籤——在引用這些群組的 AddCommand 呼叫之前註冊群組;cobra 不會事後指派群組。

Run* 系列

Cobra 指令有五個按順序執行的執行鉤子:

PersistentPreRunE → PreRunE → RunE → PostRunE → PersistentPostRunE

始終使用 *E 變體——非 E 形式無法回傳錯誤。關鍵規則:

  • 根指令上的 PersistentPreRunE每個子指令之前執行——用於設定初始化和權限檢查。
  • 子指令的 PersistentPreRunE 完全取代父指令的——如果需要兩者,請在子指令中明確呼叫父指令。
  • PostRunE 僅在 RunE 成功後執行。

有關完整的生命週期和繼承規則,請參閱 commands-and-args.md

Args 驗證器

Cobra 在 RunE 執行之前驗證位置參數。永遠不要在 RunE 內部撰寫 len(args) 檢查——這會繞過 cobra 的標準錯誤訊息和參數計數追蹤。

內建驗證器:NoArgsExactArgs(n)MinimumNArgs(n)MaximumNArgs(n)RangeArgs(min,max)OnlyValidArgsExactValidArgs(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", "", "設定檔路徑") // 所有子指令繼承
serveCmd.Flags().IntVar(&port, "port", 8080, "監聽埠號")                     // 僅 serveCmd 本地
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(), "正在監聽 :9090")
}

Cobra 會在多次 Execute() 呼叫之間累積旗標狀態——請為每個測試建立一個全新的指令樹。有關隔離模式、黃金檔案和測試自動完成,請參閱 testing.md

最佳實務

  1. 始終使用 RunE,永遠不要使用 RunRun 無法回傳錯誤;唯一的逃脫方式是 os.Exit 或 panic,這會繞過 defer。
  2. 將設定初始化放在 PersistentPreRunE — 它在每個子指令之前執行;這是進行 viper 綁定和權限檢查的正確位置。
  3. 使用 Args 驗證位置參數,而不是在 RunE 內部Args 提供 cobra 的標準錯誤訊息;MatchAll 可組合驗證器。
  4. 所有輸出都使用 cmd.OutOrStdout() / cmd.ErrOrStderr() — 直接寫入 os.Stdout 無法被測試捕捉。
  5. 每個測試重新建立指令樹 — cobra 在同一個實例上跨 Execute() 呼叫累積旗標狀態。

常見錯誤

錯誤 失敗原因 修正方式
使用 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 page、markdown、YAML、RST 文件產生;cobra-cli 腳手架工具
  • testing.md — 隔離模式、黃金檔案、測試自動完成、表格驅動指令測試

交叉參考

  • → 請參閱 samber/cc-skills-golang@golang-cli 技能以了解一般 CLI 架構 — 專案佈局、退出碼、訊號處理、I/O 模式
  • → 請參閱 samber/cc-skills-golang@golang-spf13-viper 技能以了解與 cobra 搭配的設定分層(旗標 → 環境變數 → 檔案 → 預設優先順序)
  • → 請參閱 samber/cc-skills-golang@golang-testing 技能以了解一般 Go 測試模式

如果你遇到 spf13/cobra 的錯誤或非預期行為,請在 https://github.com/spf13/cobra/issues 開啟議題。