Rust で GitHub CLI extension を作る
少し前に GitHub CLI 2.0 がリリースされ、独自のカスタムコマンド(GitHub CLI extension)が作れるようになりました。
Zenn でも以下の方々が記事を書かれています。
先人たちの GitHub CLI extension は以下から探せます。
基本的にはシェルスクリプトで書くのが一番楽なのですが、自分は Rust で書きたいなと思ったのでそのやり方を紹介します。
説明するのは主にカスタムコマンドの実行ファイルの作り方とリリース方法についてです。
ちなみに今回作ったコマンドは以下です。
GitHub のデフォルトブランチ名を参照・変更することができます。
そろそろデフォルトブランチを master から main に変えようと思った時に、GUI からやるの面倒だから CLI でやりたいな、という自分のために作ったコマンドです。[1]
やってることは git
と gh
コマンドを順番に実行してるだけなので、全然シェルスクリプトでよかったな、と途中で気づいてしまいましたが、この記事のネタになったのでよかったです。
作成方法
以下のリポジトリを参考にさせてもらいました。
大まかな流れは以下です。
- Rust で何かしらの CLI アプリケーションを作る
-
cargo build
して生成したバイナリをgh release create
でリリースする -
gh-xx
の実行ファイル内でgh release download
を行い、ダウンロードしたバイナリをexec
コマンドで実行
みなさんお察しの通り、このやり方であれば Rust でなくともリリース用のバイナリを吐けるプログラミング言語なら応用可能です。
上記の参考リポジトリではそれぞれ Go、TypeScript(Deno) が使われています。
1. Rust で CLI アプリケーションを作る
ご自由にお作りください。
もちろんコード内で gh
コマンドが利用可能です。
gh api コマンドの柔軟性が高いので、大体何でもできると思います。
あと、jq に依存せず --jq オプションが使えるのが素晴らしい です。
2. リリース
以下のようなリリース用スクリプトを書いて、$ ./release.sh v0.1
のような感じで実行します。
#!/bin/bash
set -e
tag="${1}"
cargoOutput="./target/release/gh-default-branch"
if [ "${tag}" == "" ]; then
echo "tag argument required"
exit 1
fi
cargo build --release
mv "${cargoOutput}" "${cargoOutput}-${tag}"
gh release create "$tag" "${cargoOutput}-${tag}" --title="${tag}" --notes "${tag}"
3. コマンド実行(リリースしたバイナリのダウンロード)
gh
コマンドに依存してますが、GitHub CLI extension を利用する = GitHub CLI をインストール済みということなので問題ありません。賢い解決方法ですね。
#!/bin/bash
set -e
# TODO: 現状だと新しいバージョンがリリースされるたびに手動でこの tag を書き換える必要があるので、
# バージョン文字列のみ別ファイルに逃し、リリース時に上書きするなどして自動で更新されるようにしたい
tag="v0.1"
repo="daido1976/gh-default-branch"
exe="gh-default-branch-${tag}"
extensionPath="$(dirname "$0")"
if [[ ! -x "${extensionPath}/bin/${exe}" ]]; then
mkdir -p "${extensionPath}/bin"
rm -f "${extensionPath}/bin/gh-default-branch-"*
gh release -R"${repo}" download "${tag}" -p "${exe}" --dir="${extensionPath}/bin"
chmod +x "${extensionPath}/bin/${exe}"
fi
exec "${extensionPath}/bin/${exe}" "$@"
参考
-
README に記載の通り、GUI からの rename に比べて圧倒的に機能が少ないのでご注意ください。 ↩︎
Discussion