【完全ガイド】Go で CLI ツールを作り、リリースまで一気通貫!
こんにちは、モモスケです!
本記事では、Go 言語を使って簡単な CLI ツールを作成し、リリースまでの流れを丁寧に解説します。
具体的には、以下の 3 ステップをハンズオン形式で進めます。
- Cobra を使った CLI ツールの作成
- GoReleaser を使ったリリース
- GitHub Actions を使った自動化パイプライン構築
この記事を読み終える頃には、自分だけの CLI ツールを簡単に開発・公開できるようになっているはずです!
1. 環境構築
まずは開発環境を整えます。
1.1 Go のインストール
以下の公式ドキュメントを参考に、お使いの OS に合わせて Go をインストールしてください。
以下のコマンドでバージョンが表示されればインストール成功です。
go version
1.2 Cobra のインストール
Cobra は CLI アプリケーションを簡単に作成するためのフレームワークです。以下のコマンドでインストールします。
go get -u github.com/spf13/cobra@latest
1.3 Cobra CLI のインストール
Cobra CLI は Cobra の CLI ツールです。以下のコマンドでインストールします。
go install github.com/spf13/cobra-cli@latest
1.4 GoReleaser のインストール
以下の公式ドキュメントを参考に、GoReleaser をインストールしてください。
おすすめは go install
です(OS に寄らずインストールできます)。
go install github.com/goreleaser/goreleaser/v2@latest
以下のコマンドでバージョンが表示されればインストール成功です。
goreleaser --version
2. Cobra で簡単な CLI ツールを作ってみよう
2.1 プロジェクトの作成
まずは新しいディレクトリを作成し、Go モジュールを初期化します。
mkdir my-cli-tool
cd my-cli-tool
go mod init my-cli-tool
go.mod
が作成されます。
module my-cli-tool
go 1.23.5
2.2 Cobra で初期化
Cobra を使ってプロジェクトのテンプレートを生成します。
cobra-cli init
以下のような構成のファイルが作成されます。
my-cli-tool/
├── cmd/
│ └── root.go
├── go.mod
├── go.sum
└── main.go
cmd/root.go
がコマンドのエントリーポイントです。
2.3 「Hello, World!」を実装
次に、cmd/root.go
の Run
関数に処理を追加します。
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
}
cmd/root.go の全体コード
/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "my-cli-tool",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.my-cli-tool.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
以下のコマンドで実行してみましょう。
go run main.go
or
# macOS / Linux
go build -o my-cli-tool
my-cli-tool
# Windows
go build -o my-cli-tool.exe
my-cli-tool.exe
出力結果は以下のようになります。
Hello, World!
これで Hello, World!
と出力する CLI ツールの完成です!
2.4 新しいサブコマンドの作成
以下のコマンドで、新しいサブコマンドを追加できます。
cobra-cli add greet
これにより、cmd/greet.go
ファイルが生成されます。このファイルを編集して、挨拶メッセージを表示するコマンドを作成します。
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, CLI user!")
}
cmd/greet.go の全体コード
/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// greetCmd represents the greet command
var greetCmd = &cobra.Command{
Use: "greet",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, CLI user!")
},
}
func init() {
rootCmd.AddCommand(greetCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// greetCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// greetCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
追加したコマンドを実行してみます。
go run main.go greet
or
# macOS / Linux
go build -o my-cli-tool
my-cli-tool greet
# Windows
go build -o my-cli-tool.exe
my-cli-tool.exe greet
出力結果は以下のようになります。
Hello, CLI user!
3. GoReleaser を使った CLI ツールのリリース
CLI ツールをリリースするには、GoReleaser を活用します。
3.1 設定ファイルの作成
以下のコマンドで、.goreleaser.yaml
を生成します。
goreleaser init
GoRelear ではこの設定ファイルをもとに、CLI を各プラットフォーム向けにビルドし、リリースします。
3.2 ローカルでリリーステスト
以下のコマンドでローカル環境でビルドを試してみましょう。
goreleaser release --snapshot --clean
-
--snapshot
はリリースのシミュレーションを行うためのオプションです。 -
--clean
は前回のビルド結果を削除するオプションです。
生成されたバイナリは dist/
ディレクトリに保存されます。
例えば、Windows 向けのバイナリは .\dist\my-cli-tool_windows_amd64_v1\my-cli-tool.exe
に生成されます。各自の OS に合わせて実行してみましょう。
# Windows (x86_64) の場合
.\dist\my-cli-tool_windows_amd64_v1\my-cli-tool.exe
# Hello, World!
これで、ローカルでのリリースが完了しました。
あとは、GitHub にリリース用のパイプラインを構築することで、自動リリースが可能です。
4. GitHub Actions で自動リリース
GitHub Actions を使えば、タグを push するだけで自動的にリリースを行えます。
4.1 ワークフローの作成
以下の内容で .github/workflows/release.yml
を作成します。
name: release
on:
push:
tags:
- "v*"
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
このワークフローは、v*
というタグが push されたときにリリースを実行します。
GoReleaser の公式アクションである goreleaser-action を使うことで、GitHub Actions で GoReleaser を実行できます。
4.2 リリースのトリガー
リリースタグを作成して push します。
# 現時点の変更を commit して push
git add .
git commit -m "IMPL: CLI says Hello, World!"
git push
# タグを作成して push
git tag v1.0.0
git push origin v1.0.0
これで、GitHub Actions がリリースを実行します。
リリースが成功すると、GitHub のリリースページにて各プラットフォーム向けのバイナリがダウンロードできるようになります。
これで、Go で CLI ツールを開発し、リリースするためのパイプラインが完成しました。
あとは、ユーザーがバイナリがダウンロードして使用可能な場所に配置したり、PATH
を通すことで使うことができます。
(Optional) 5. インストール スクリプトの作成
ユーザーが CLI ツールを簡単にインストールできるように、インストール スクリプトを用意しておき、README.md
に記載しておくと便利です。
macOS / Linux
以下のスクリプトを install.sh
として保存します。
#!/bin/bash
# If no version is specified as a command line argument, fetch the latest version.
if [ -z "$1" ]; then
VERSION=$(curl -s https://api.github.com/repos/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/releases/latest | grep -o '"tag_name": *"[^"]*"' | sed 's/"tag_name": *"//' | sed 's/"//')
if [ -z "$VERSION" ]; then
echo "Failed to fetch the latest version"
exit 1
fi
else
VERSION=$1
fi
OS=$(uname -s)
ARCH=$(uname -m)
URL="https://github.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/releases/download/${VERSION}/<GITHUB_REPO_NAME>_${OS}_${ARCH}.tar.gz"
echo "Start to install."
echo "VERSION=$VERSION, OS=$OS, ARCH=$ARCH"
echo "URL=$URL"
TMP_DIR=$(mktemp -d)
curl -L $URL -o $TMP_DIR/<GITHUB_REPO_NAME>.tar.gz
tar -xzvf $TMP_DIR/<GITHUB_REPO_NAME>.tar.gz -C $TMP_DIR
sudo mv $TMP_DIR/<GITHUB_REPO_NAME> /usr/local/bin/<GITHUB_REPO_NAME>
sudo chmod +x /usr/local/bin/<GITHUB_REPO_NAME>
rm -rf $TMP_DIR
if [ -f "/usr/local/bin/<GITHUB_REPO_NAME>" ]; then
echo "[SUCCESS] <GITHUB_REPO_NAME> $VERSION has been installed to /usr/local/bin"
else
echo "[FAIL] <GITHUB_REPO_NAME> $VERSION is not installed."
fi
このスクリプトを実行すると、最新バージョンの CLI ツールがダウンロードされ、/usr/local/bin
にインストールされます。
curl -fsSL https://raw.githubusercontent.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/main/install.sh | sh
Windows
以下のスクリプトを install.ps1
として保存します。
param(
[Parameter(Mandatory=$false)]
[ValidateSet("x86_64", "arm64", "i386")]
[string]$Arch = "x86_64"
)
$ErrorActionPreference = 'Stop'
[string]$Version
if (-not $Version) {
Write-Host "Fetching the latest version..."
try {
$response = Invoke-WebRequest -Uri "https://api.github.com/repos/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/releases/latest" -UseBasicParsing
$json = $response.Content | ConvertFrom-Json
$Version = $json.tag_name
if (-not $Version) {
Write-Error "Failed to fetch the latest version"
exit 1
}
} catch {
Write-Error "Failed to fetch the latest version"
exit 1
}
}
$url = "https://github.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/releases/download/$Version/<GITHUB_REPO_NAME>_Windows_$Arch.zip"
$output = "$env:temp\<GITHUB_REPO_NAME>.zip"
$installDir = "$env:LocalAppData\<GITHUB_REPO_NAME>"
Write-Host "Downloading <GITHUB_REPO_NAME> version $Version for architecture: $Arch"
Write-Host "Download URL: $url"
Invoke-WebRequest -Uri $url -OutFile $output
Write-Host "Extracting <GITHUB_REPO_NAME>"
Expand-Archive -Path $output -DestinationPath $installDir -Force
Write-Host "Adding <GITHUB_REPO_NAME> to PATH"
$oldPath = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::User)
$newPath = "$oldPath;$installDir"
[Environment]::SetEnvironmentVariable('Path', $newPath, [System.EnvironmentVariableTarget]::User)
Write-Host "Installation complete. Please restart your terminal."
このスクリプトを実行すると、最新バージョンの CLI ツールがダウンロードされ、C:\Users\<USER_NAME>\AppData\Local
にインストールされ、また PATH
に追加されます。
x86_64 (default)
powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/main/install.ps1 -OutFile install.ps1; .\install.ps1"
arm64
powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/main/install.ps1 -OutFile install.ps1; .\install.ps1 -Arch arm64"
i386
powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/<GITHUB_USER_NAME>/<GITHUB_REPO_NAME>/main/install.ps1 -OutFile install.ps1; .\install.ps1 -Arch i386"
以上で、インストール スクリプトの作成が完了しました。
6. まとめ
この記事では、Go で CLI ツールを開発し、リリースする手順を解説しました。
- Cobra で CLI を作成
- GoReleaser でバイナリをビルド
- GitHub Actions で自動化
シンプルなツールから始めて、ぜひ独自の CLI ツールを作成してみてください!
Discussion