Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

Go でサクッと GitHub CLI の拡張機能を作る

この記事は Gunosy Advent Calendar 2022 の14日目の記事です。昨日の記事はサンドバーグさんの Rails Authentication・Authorization パターンでした。

はじめに

こんにちは。広告技術部の johnmanjiro です。普段は広告配信の API や管理画面を作っています。

早速ですが、みなさんは GitHub CLI をご存知でしょうか。

GitHub CLI brings GitHub to your terminal.

公式ページにある通り、GitHub を利用する上で便利な CLI です。 例として、Pull Request 一覧の取得や Release の作成などがターミナル上で行えます。

GitHub CLI は十分便利なのですが、実現したい内容によっては CLI そのものの機能だけではできないことも多々あります。たとえば、コミットに対してコメントしたい*1という場合には GitHub API を利用する必要があります。 シェルスクリプトを書くことで実現することもできますが、複雑なことをしようとすると煩雑になりがちです。

そこで利用できるのが、GitHub CLI の拡張機能です。これを利用することで、自作のシェルスクリプトや実行ファイルを GitHub CLI のコマンドとして実行することができるようになります。

今回は Go で実装した CLI を GitHub CLI の拡張機能として公開する方法をご紹介します。

参考までに、私が趣味で自作した拡張機能です。どちらも Go で実装しています。

  • gh-bump
    • Semantic Versioning に従って Release をインクリメントし作成する*2
  • gh-cmcm
    • 特定のコミットに対してコメントをつける

拡張機能の作成

GitHub CLI のコマンドを利用することで拡張機能の雛形を作成することができます。今回は Go を利用するので、--precompiled=go を指定します。

$ gh extension create --precompiled=go sample

このコマンドを実行すると、下記の gh-sample ディレクトリが作成されます。

│
├── .github
│   └── workflows
│       └── release.yml
├── .gitignore
├── gh-sample
├── go.mod
├── go.sum
└── main.go

ここで注意する必要があるのが、ディレクトリ名(リポジトリ名)は gh- というプレフィックスがついていなければいけないということです。これは、GitHub CLI が拡張機能をインストールする際、GitHub 上で gh- がついているリポジトリを探すためです。

また、基本的にはリポジトリに含まれる「リポジトリ名と同名の実行ファイル」がダウンロードされ実行されます。 今回は Go で実装するので、リポジトリに実行ファイルは置かずに Release にバイナリを添付します*3。この場合は Release のバイナリがダウンロードされ実行されます。

実際に上記の拡張機能を GitHub CLI にインストールして実行してみましょう。下記のコマンドは gh-sample ディレクトリ内で実行してください。

$ gh extension install .

$ gh extension list
gh sample

$ gh sample
hi world, this is the gh-sample extension!
running as johnmanjiro13

GitHub CLI のコマンドとして sample を実行することができました!

動作確認が済んだので、一度拡張をアンインストールしておきます。

$ gh extension remove gh-sample
✓ Removed extension sample

あとは Go で実現したい内容を実装し、GitHub 上で公開するだけです!

拡張機能の公開

拡張機能の実装ができたら、GitHub で公開しましょう。

実は gh-sample ディレクトリを作成した時点でリリースに必要なファイルの準備ができています。

自動生成されるファイルのなかにある release.yml というファイルに拡張機能のリリースを行うワークフローが定義されています。 タグを GitHub のリポジトリに push すると、Go のコードをコンパイルした後に Release を作成し、そこにバイナリを添付するところまで実行してくれます。

.github/workflows/release.yml

name: release
on:
  push:
    tags:
      - "v*"
permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: cli/gh-extension-precompile@v1 # これが拡張機能を公開してくれる

それでは実際に GitHub 上にリポジトリを作成し、公開してみましょう。 下記のコマンドは gh-sample ディレクトリ内で実行してください。

# リポジトリの作成
» gh repo create
? What would you like to do? Push an existing local repository to GitHub
? Path to local repository .
? Repository name gh-sample
? Description
? Visibility Public
✓ Created repository johnmanjiro13/gh-sample on GitHub
? Add a remote? Yes
? What should the new remote be called? origin
✓ Added remote [email protected]:johnmanjiro13/gh-sample.git
? Would you like to push commits from the current branch to "origin"? Yes
✓ Pushed commits to [email protected]:johnmanjiro13/gh-sample.git

$ git tag v0.0.1

$ git push --tags

これで下記のような Release が作成され、拡張機能が公開されます。

作成された Release

実際に GitHub CLI へインストールしてみましょう。

$ gh extension install johnmanjiro13/gh-sample
✓ Installed extension johnmanjiro13/gh-sample

$ gh extension list
gh sample  johnmanjiro13/gh-sample  v0.0.1

$ gh sample
hi world, this is the gh-sample extension!
running as johnmanjiro13

無事実行することができました!

まとめ

今回は Go 製の GitHub CLI 拡張を作成する方法についてご紹介しました。

コマンドで作成した雛形でリリースのワークフローまで準備できるので、拡張機能の実装に集中することができます。

また、Go でなくシェルスクリプトで公開する場合は、gh- プレフィックスをつけたリポジトリに同名のシェルスクリプトを置くだけで公開できるので、さらに簡単です!

みなさんもぜひ拡張機能を作って快適に GitHub を使ってみてください!

明日は hyamamoto さんの「社内で初めて Bazel を導入した話」です。お楽しみに!

*1:実行結果を PR にコメントする CI で、PR がない場合にはコミットにコメントするなど

*2:内部的に GitHub CLI を呼び出しています。Go から GitHub CLI のコマンドを呼び出す際は cli/go-gh が便利です

*3:このため、雛形に含まれる gh-sample は .gitignore に入っています