git

GitHub Copilot CLI で Git Hooks を作る

git
  1. はじめに
  2. GitHub Copilot CLI とは
  3. やりたいこと
  4. 問題
  5. GitHub Copilot CLI を試してみる
  6. コマンドの修正(手作業)
  7. まとめ

はじめに

新卒13期の@kromiiiです。 現在ペパボ13期は先月に引き続きサイクルOJTを実施中で、今月は minne 事業部にてOJTを行っています。

今回は minne 事業部で開発を行う中で、GitHub Copilot CLI を使って Git Hooks を作った話を紹介します。

GitHub Copilot CLI とは

GitHub Copilot CLI は GitHub Copilot の CLI 版で、2023年11月にリリースされたばかりの新しいツールです。

GitHub Copilot CLI

公式のドキュメントによると GitHub Copilot CLI でできることとしては

  1. コマンドの提案
  2. コマンドの説明

の2種類です。

今回は 1. コマンドの提案 を使ってローカルでコミット前に rubocop を動かす Git Hooks を作ったので話します。

やりたいこと

minne では PR を出す際に CI で Rubocop が動いています。 Rubocop は Ruby のコードをチェックしてコーディング規約に沿っているかをチェックしてくれるツールで、いわゆる Linter と呼ばれるものです。

RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. Out of the box it will enforce many of the guidelines outlined in the community Ruby Style Guide. Apart from reporting the problems discovered in your code, RuboCop can also automatically fix many of them for you. 引用: https://github.com/rubocop/rubocop

しかし毎回 GitHub に Push してから Rubocop の結果を待って修正するのは大変面倒です。 そこで Git Hooks を使ってリポートレポジトリにPushする前に Rubocop を動かしてあらかじめ警告に気づけるようにしたい、というのが今回の目的です。

問題

ところで Git Hooks とは Git のフック機能を使って特定のタイミングでコマンドを実行することができる機能で、中身はシェルスクリプトで書くのが一般的なのですが、一つ問題がありました。

それは私がシェルスクリプトを書くのが苦手ということです。今回やりたいこととしては

  1. git diff によって今回変更があったファイルを検知し
  2. 変更が検知されたファイルに対して rubocop を実行する

というものだったのですが、それぞれ個別に実行するコマンドを書くことはできても、それをパイプでまとめて書くにはどうしたらいいんだろう?というのが私が直面した問題でした。

GitHub Copilot CLI を試してみる

そんな私に救いの手を差し伸べてくれたのが最近ペパボにも導入された GitHub Copilot CLI でした。

まずはどういうコマンドを作りたいかをターミナルで Copilot に指示します。

gh copilot suggest "execute rubocop to files which are included in the results of git diff command"

例によってめちゃくちゃな英語ですが、これでも理解してコマンドを作ってくれるからすごいです、ほんと。

指示を入力した後はこのような対話的な画面が表示されるので、今回は generic shell command を選びます。

? What kind of command can I help you with?  [Use arrows to move, type to filter]
> generic shell command
  gh command
  git command

選択肢を選んだあとはものの数秒でコマンドを提案してくれます。

Suggestion:

  git diff --name-only | grep '.rb$' | xargs rubocop

? Select an option  [Use arrows to move, type to filter]
> Copy command to clipboard
  Explain command
  Revise command
  Rate response
  Exit

git diff --name-only | grep '.rb$' | xargs rubocop というのが生成されたコマンドで、その後、生成されたコマンドをクリップボードにコピーするのか、コマンドの説明を見るのか、コマンドを修正するのか、コマンドを評価するのか、終了するのかを選ぶことができます。

クリップボードへのコピーまでやってくれるとは、本当に至れりつくせりです。

今回は rubocop を docker の中で動かしたかったので下から3つ目の Revise command を選択してコマンドを修正します。

? How should this be revised?
> execute rubocop to files which are included in the results of git diff command, and the rubocop should be run in the docker container.

対話的に修正を進めていった結果、最終的にはこのようなコマンドが生成されました。

  git diff --name-only --cached | grep '\.rb$' | xargs docker run --rm -v "$(pwd)":/app -w /app container_name rubocop -a -c .rubocop.yml

コマンドの修正(手作業)

しかし、私の指示が悪かったのかこのコマンドはそのままでは動きませんでした。

というのも、私の開発環境では docker コマンドではなく docker compose exec でコンテナを動かしたかったのですが、その際に the input device is not a TTY というエラーが発生してしまいました。

原因を調査したところ、どうも xargs で引数を渡すときは docker compose exec-T オプションをつける必要があるらしく、最終的には Google で調べて手動で修正することになりました。

GitHub Copilot CLI はコマンドの大まかな構造を作ってくれるのは良いのですが、細かい部分についてはまだ自分で調べて修正する必要がありそうです。

Copilot CLI はまだベータ版なので、このあたりは今後のアップデートで改善されていくのかなと思います。

まとめ

今回は GitHub Copilot CLI を使って Git Hooks を作った話を紹介しました。このツールのおかげで今では CI の結果を待つことなく Rubocop の結果を確認することができるようになりました。

これは僕が Rubocop の機先を制してコードを修正しているときの様子です。

rubocop

結局別のテストで怒られてしまいました orz