golang-cli について
Go のコマンドラインツールの構築、拡張、レビューを支援するエンジニアリングスキルです。Cobra と Viper のパターン、設定、シェル向けの入出力、検証、配布を扱います。
主な機能
- 01Cobra のコマンドとフラグ構成
- 02Viper による設定の優先順位
- 03引数とフラグの検証
- 04Unix の標準出力・標準エラーの指針
- 05補完、テスト、終了コード
活用シーン
- 01サブコマンドを備えた Go CLI の作成
- 02既存 CLI へのフラグと設定の追加
- 03CLI の出力、エラー、終了コードのレビュー
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-cliインストール後、Claude Code で/golang-cliを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/examples/args.gocli_test.gocompletion.goconfig.goexit_codes.goflags.gogo.modmain.gooutput.goroot.goserve.gosignal.goversion.goevals/evals.json詳細
ペルソナ: Go CLI エンジニアです。Unix シェルに自然になじむ、組み合わせやすく、スクリプト化でき、自動化のもとでも予測どおりに動作するツールを構築します。
モード:
- 構築 — CLI をゼロから作成する場合:プロジェクト構成、ルートコマンドの設定、フラグのバインド、バージョンの埋め込みの各セクションを順に確認します。
- 拡張 — 既存の CLI にサブコマンド、フラグ、または補完機能を追加する場合:まず現在のコマンドツリーを確認し、既存の構成に沿って変更を適用します。
- レビュー — 既存の CLI の正確性を監査する場合:「よくある間違い」表を確認し、
SilenceUsage/SilenceErrors、フラグと Viper のバインド、終了コード、stdout/stderr の使い分けを検証します。
Go CLI のベストプラクティス
Go CLI アプリケーションでは、デフォルトのスタックとして Cobra + Viper を使用します。Cobra はコマンド/サブコマンド/フラグの構造を提供し、Viper はファイル、環境変数、フラグからの設定を自動的に階層化して処理します。この組み合わせは、kubectl、docker、gh、hugo をはじめ、ほとんどの本番環境向け Go CLI で使われています。
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 |
プロジェクト構成
CLI コマンドは 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 を参照してください。
ルートコマンドの設定
ルートコマンドでは Viper の設定を初期化し、PersistentPreRunE を使ってグローバルな動作を設定します。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 個要求します |
Viper による設定
Viper は次の順序(優先度の高いものから低いもの)で設定値を解決します。
- CLI フラグ(明示的なユーザー入力)
- 環境変数(デプロイ時の設定)
- 設定ファイル(永続的な設定)
- デフォルト値(コード内で設定)
構造体へのアンマーシャリングや設定ファイルの監視を含む Viper の完全な統合例については、assets/examples/config.go を参照してください。
設定ファイルの例(.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-78 | BSD sysexits | 特定のエラーカテゴリ |
| 126 | 実行不可 | 権限が拒否された場合 |
| 127 | コマンドが見つからない | 依存関係が不足している場合 |
| 128+N | シグナル N | シグナルによって終了した場合(例:130 = SIGINT) |
エラーを終了コードに対応付ける方法については、assets/examples/exit_codes.go を参照してください。
入出力パターン
すべての入出力パターンについては、assets/examples/output.go を参照してください。
- stdout と stderr:診断出力を stdout に書き込んではいけません。stdout はプログラム出力用(パイプで利用可能)であり、stderr はログ、エラー、診断情報用です。
- パイプと端末の判別:stdout の
os.ModeCharDeviceを確認します。 - 機械可読な出力:テーブル、JSON、プレーン形式に対応する
--outputフラグをサポートします。 - 色:出力先が端末でない場合に自動で無効になる
fatih/colorを使用します。
シグナル処理
シグナル処理では signal.NotifyContext を使用して、コンテキストを通じてキャンセルを伝播させる必要があります。HTTP サーバーをグレースフルにシャットダウンする例については、assets/examples/signal.go を参照してください。
シェル補完
Cobra は bash、zsh、fish、PowerShell 用の補完を自動生成します。補完コマンドとカスタムのフラグ/引数補完の両方については、assets/examples/completion.go を参照してください。
CLI コマンドのテスト
コマンドをプログラムから実行し、出力を取得してテストします。assets/examples/cli_test.go を参照してください。
テストで出力を取得できるように、コマンドでは os.Stdout / os.Stderr の代わりに cmd.OutOrStdout() と cmd.ErrOrStderr() を使用してください。
よくある間違い
| 間違い | 修正方法 |
|---|---|
os.Stdout に直接書き込む | テストでは出力をキャプチャできません。テストでバッファーにリダイレクトできる cmd.OutOrStdout() を使用します |
RunE 内で os.Exit() を呼び出す | Cobra のエラー処理、遅延実行関数、クリーンアップコードが実行されません。エラーを返し、main() に判断させます |
| フラグを Viper にバインドしない | フラグを環境変数や設定で構成できません。構成可能な各フラグに対して viper.BindPFlag を呼び出します |
viper.SetEnvPrefix がない | PORT はほかのツールと衝突します。接頭辞(MYAPP_PORT)を使用して環境変数を名前空間に分けます |
| stdout にログを出力する | Unix パイプでは stdout が連結されるため、ログが次のプログラムのデータストリームを破損させます。ログは stderr に出力します |
| エラーのたびに使用方法を表示する | エラーのたびにヘルプ全体を表示するとノイズになります。SilenceUsage: true を設定し、完全な使用方法は --help 用に残します |
| 設定ファイルを必須にする | 設定ファイルがないユーザーはクラッシュします。viper.ConfigFileNotFoundError を無視し、設定ファイルは任意にします |
PersistentPreRunE を使用しない | すべてのサブコマンドの前に設定を初期化する必要があります。ルートの PersistentPreRunE を使用します |
| バージョン文字列をハードコードする | バージョンがタグと一致しなくなります。ビルド時に git タグから ldflags を介して設定します |
--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 のスキルを参照してください。