目次

    Go製CLI開発の決定版:CobraとViperによるモダンなコマンドラインツール実践入門
    GoCLICobraViperコマンドラインツール設定管理
    202507-08
    CobraとViperを組み合わせたGo製CLIツールのアーキテクチャ図

    Go製CLI開発の決定版:CobraとViperによるモダンなコマンドラインツール実践入門

    はじめに:あなたのCLIツール、"ただ動く"だけで満足ですか?

    GoでのCLIツール開発は手軽ですが、機能が増えるとフラグ管理が煩雑になります。プロフェッショナルなCLIツールには、サブコマンド、柔軟な設定、分かりやすいヘルプ機能が不可欠です。この課題を解決するのが、CobraViperの組み合わせです。


    なぜCobraViperなのか?

    • Cobra: サブコマンド構造、フラグ管理、ヘルプ自動生成
    • Viper: 設定ファイル、環境変数、フラグの統合管理

    Go Cobra Viper チュートリアル:設定ファイル対応のCLIを作る

    ステップ①:プロジェクト初期化

    bash
    1go install github.com/spf13/[email protected]
    2mkdir myapp && cd myapp
    3go mod init myapp
    4cobra-cli init

    ステップ②:ルートコマンド定義

    go
    1// cmd/root.go
    2package cmd
    3
    4import (
    5    "fmt"
    6    "log"
    7    "os"
    8    "github.com/spf13/cobra"
    9    "github.com/spf13/viper"
    10)
    11
    12var cfgFile string
    13
    14var rootCmd = &cobra.Command{
    15    Use: "myapp",
    16    Run: func(cmd *cobra.Command, args []string) {
    17        fmt.Printf("Host: %s, Port: %d\n", 
    18            viper.GetString("host"), viper.GetInt("port"))
    19    },
    20}
    21
    22func Execute() {
    23    if err := rootCmd.Execute(); err != nil {
    24        os.Exit(1)
    25    }
    26}
    27
    28func init() {
    29    cobra.OnInitialize(initConfig)
    30    rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
    31    rootCmd.PersistentFlags().String("host", "localhost", "server host")
    32    rootCmd.PersistentFlags().Int("port", 8080, "server port")
    33    
    34    viper.BindPFlag("host", rootCmd.PersistentFlags().Lookup("host"))
    35    viper.BindPFlag("port", rootCmd.PersistentFlags().Lookup("port"))
    36}

    ステップ③:Viper設定

    go
    1func initConfig() {
    2    if cfgFile != "" {
    3        viper.SetConfigFile(cfgFile)
    4    } else {
    5        home, _ := os.UserHomeDir()
    6        viper.AddConfigPath(home)
    7        viper.SetConfigName(".myapp")
    8        viper.SetConfigType("yaml")
    9    }
    10    
    11    viper.SetEnvPrefix("MYAPP")
    12    viper.AutomaticEnv()
    13    
    14    if err := viper.ReadInConfig(); err != nil {
    15        if _, ok := err.(viper.ConfigFileNotFoundError); ok {
    16            fmt.Println("No config file found")
    17        } else {
    18            log.Fatalf("Config error: %v", err)
    19        }
    20    }
    21}

    設定ファイル例(~/.myapp.yaml):

    yaml
    1host: "0.0.0.0"
    2port: 9090

    ステップ④:設定値の優先順位

    設定値は以下の優先順位で決定されます:

    1. コマンドラインフラグ(最優先)
    2. 環境変数(MYAPP_HOST=localhost
    3. 設定ファイル
    4. デフォルト値

    応用編:サブコマンド追加

    bash
    1cobra-cli add version
    2cobra-cli add server

    これでmyapp versionmyapp serverコマンドが追加できます。


    本格運用:goreleaser × GitHub Actions

    プロダクションレベルのCLIツールには、自動ビルド・配布が不可欠です。

    goreleaser × GitHub Actions(一例)

    yaml
    1# .github/workflows/release.yml
    2name: Release
    3on: 
    4  push: 
    5    tags: ["v*"]
    6jobs:
    7  release:
    8    runs-on: ubuntu-latest
    9    steps:
    10      - uses: actions/checkout@v4
    11      - uses: actions/setup-go@v4
    12        with:
    13          go-version: '1.21'
    14      - uses: goreleaser/goreleaser-action@v5
    15        with: 
    16          version: latest
    17          args: release --rm-dist
    18        env:
    19          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    goreleaser設定例(.goreleaser.yaml):

    yaml
    1builds:
    2  - env: [CGO_ENABLED=0]
    3    goos: [linux, windows, darwin]
    4    goarch: [amd64, arm64]
    5
    6archives:
    7  - format: tar.gz
    8    name_template: >-
    9      {{ .ProjectName }}_
    10      {{- title .Os }}_
    11      {{- if eq .Arch "amd64" }}x86_64
    12      {{- else if eq .Arch "386" }}i386
    13      {{- else }}{{ .Arch }}{{ end }}
    14
    15release:
    16  github:
    17    owner: your-username
    18    name: your-repo

    テストコード例

    go
    1// cmd/root_test.go
    2package cmd
    3
    4import (
    5    "bytes"
    6    "testing"
    7    "github.com/spf13/viper"
    8)
    9
    10func TestRootCommand(t *testing.T) {
    11    viper.Set("host", "testhost")
    12    viper.Set("port", 3000)
    13    
    14    buf := new(bytes.Buffer)
    15    rootCmd.SetOut(buf)
    16    rootCmd.SetArgs([]string{})
    17    
    18    if err := rootCmd.Execute(); err != nil {
    19        t.Fatalf("Execute failed: %v", err)
    20    }
    21    
    22    output := buf.String()
    23    if !strings.Contains(output, "testhost") {
    24        t.Errorf("Expected output to contain 'testhost', got: %s", output)
    25    }
    26}

    まとめ

    CobraとViperの組み合わせにより、保守性が高く、ユーザーフレンドリーなCLIツールを効率的に開発できます。サブコマンド、設定ファイル、環境変数を統合的に管理し、プロフェッショナルなツール開発を実現しましょう。

    私たちGoForceは、Goのコーディングスキルだけでなく、CobraやViperといったエコシステムのベストプラクティスを熟知し、プロフェッショナルなツールを開発できるエンジニアを高く評価しています。あなたのその「作る力」を、多くのユーザーに影響を与えるプロジェクトで活かしませんか?ぜひ一度、ご相談ください。

    会員登録はこちら

    最適なGo案件を今すぐチェック!

    会員登録

    生年月日 *

    /

    /

    Go経験年数 *

    /

    利用規約プライバシーポリシーに同意してお申し込みください。