運用コマンドの新時代到来か？GPT-4 ベースの GitHub Copilot for CLI（technical preview）を今すぐ体験しよう！

# 0. はじめに
先日発表されました OpenAI の GPT-4 モデルを採用した GitHub Copilot X

https://github.blog/jp/2023-03-23-github-copilot-x-the-ai-powered-developer-experience/

その中でも、気になっていた GitHub Copilot for CLI 

https://githubnext.com/projects/copilot-cli/

ウェイティングリストへ登録していたところ、
`GitHub Next <noreply@githubnext.com>` より、`You're in for Copilot for CLI!`というタイトルでメールが来て使えるようになりましたので、早速ためしてみました！

:::note 
GitHub Copilot for CLI は、現在ブレピュー中の機能のため、以下よりウェイティングリストの登録が必要です
https://githubnext.com/projects/copilot-cli/
:::

:::note 
実行結果などは執筆時点（2023/03/30）の内容です
:::

# 1. インストールとセットアップ
GitHub Next からのメールに記載されていた以下ページの内容に従いインストールとセットアップをします

https://www.npmjs.com/package/@githubnext/github-copilot-cli

1. GitHub Copilot for CLI のインストール
2. Device Activation
3. エイリアスの設定

## 1.1. GitHub Copilot for CLI のインストール
手元の intel Mac (Monterey) へ 以下コマンドでインストールします

```
npm install -g @githubnext/github-copilot-cli
```

## 1.2. Device Activation 
インストールが完了したら、Device Activation を行います
```
github-copilot-cli auth
```

``` bash:実行結果例
Copy this code: XXX-XXXX

Then go to https://github.com/login/device, paste the code in and approve the access.
⠙ It will take up to 5 seconds after approval for the token to be retrieved.
```

ブラウザより GitHub の Device Activation ページへアクセスし

https://github.com/login/device

![gh-device-activation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/8f7658be-bdbf-6418-32e6-1af400810b55.png)
さきほどの認証用コードを入力 or ペーストして`Continue`をクリック

![gh-copilot-plugin-permission.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/ab93f0d8-aa4d-7c70-163d-2a11322a7f48.png)

`Authorize GitHub Copilot Plugin`をクリックして完了させます
![gh-device-set.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/7f4492ab-b0ce-3008-d06f-aeb434eb90f5.png)

## 1.3. エイリアスの設定
`??`や`git?`、`gh?`より利用可能にするためにエイリアスの設定をします

今回はbash なので `~/.bash_profile`の末尾に以下を追記して、`source ~/.bash_profile`します

```
eval "$(github-copilot-cli alias -- "$0")"
```

# 2.　GitHub Copilot for CLI をためす
準備が整いましたので、早速ためしてみます

GitHub Copilot CLI では、自然言語（入力した文章を）をシェル コマンドに翻訳し変換、実行することが可能です

次の3つのコマンドを使用可能です

* ??: 自然言語（入力した文章）を任意のシェルコマンドに翻訳し変換する
* git?: 自然言語（入力した文章） Git コマンドに翻訳し変換する
* gh?: 自然言語（入力した文章）を GitHub CLI コマンドに翻訳し変換する

今回は上記の中から、とても汎用性の高い
**??: 自然言語（入力した文章）を任意のシェルコマンドに翻訳し変換する**
を試してみます

## 2.1. 例） このPCのパブリックIPを教えて
Mac の terminal より `??` の後に文章を入力して Enter します
文章は、日本語にも対応していますので

```
?? このPCのパブリックIPを教えて
```
すると、以下のようにコマンド`curl ifconfig.me`に変換され、さらにコマンドの説明が出力されます

``` bash:実行結果
$?? このPCのパブリックIPを教えて

 ──────────────────── Command ────────────────────

curl ifconfig.me

 ────────────────── Explanation ──────────────────

○ curl is used to issue web requests, e.g. download web pages.
  ◆ ifconfig.me is a web service that returns the public IP address of the requestor.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

このコマンドは問題なさそうなので
` ✅ Run this command`を選択した（上下の矢印キーで移動可能）状態で Enter します

``` bash:実行結果
  This will execute the suggested command in your shell.
  Are you sure? (y/N)
```
提案したコマンドを実行するのか確認されるので`y`を入力

すると、terminal 上で、提案されたコマンド`curl ifconfig.me`が実行され、標準出力の結果がそのまま表示されます
（実行したコマンドは、`history`にも残ります）

``` bash:実行結果
🕒  Hold on, executing commmand...
AAA.BBB.CCC.DDD$
```

このように、自然言語（入力した文章）を任意のシェルコマンドに翻訳し変換、さらに実行することができました

## 2.2. 例） nginxのPodを作成するkubectlコマンド
とても簡単なkubectlコマンドですが、

``` bash:実行結果
$?? nginxのPodを作成するkubectlコマンド

 ──────────────────── Command ────────────────────

kubectl run nginx --image=nginx

 ────────────────── Explanation ──────────────────

○ kubectl is the Kubernetes command line tool.
  ◆ run nginx creates a new deployment called nginx.
    ◇ --image=nginx specifies that we want to use the nginx image.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

今度は、すこし文章を変更して、マニフェストファイルをつくってもらいます
``` bash:実行結果
$?? nginxのPodを作成するマニフェストファイルを生成

 ──────────────────── Command ────────────────────

kubectl run nginx --image=nginx --dry-run=client -o yaml > nginx.yaml

 ────────────────── Explanation ──────────────────

○ kubectl run nginx creates a new pod called nginx.
  ◆ --image=nginx specifies that we want to use the nginx image.
  ◆ --dry-run=client specifies that we want to run the command without actually creating the pod.
  ◆ -o yaml specifies that we want the output in YAML format.
  ◆ > nginx.yaml redirects the output to the file nginx.yaml.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

ちゃんと、`--dry-run=client`オプションを付加してくれました！

## 2.3. 例） ./test.mdの中身をテストからてすとに置き換える
つづいて、文字列置換`sed`をやってもらいます

``` bash:実行結果
$?? ./test.mdの中身をテストからてすとに置き換える

 ──────────────────── Command ────────────────────

sed -i "s/テスト/てすと/g" ./test.md

 ────────────────── Explanation ──────────────────

○ sed is used to search and replace text in a file.
  ◆ -i specifies that we want to edit the file in-place.
  ◆ "s/テスト/てすと/g" specifies the search and replace pattern.
    ◇ s specifies that we want to search and replace.
    ◇ /テスト/ is the search pattern.
    ◇ /てすと/ is the replace pattern.
    ◇ /g specifies that we want to replace all occurrences, not just the first one.
  ◆ ./test.md specifies the file we want to edit.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

良さそうなので、コマンドを実行します
```
🕖  Hold on, executing commmand...
sed: 1: "./test.md": invalid command code .
```

sed コマンドでエラーが出てしまいました...

なので、ここは GPT つながりで Edge Bing Chat さんに聞いてみると
```
おかえりなさい! 何についてチャットしますか?

`sed: 1: "./test.md": invalid command code .`エラーが出てしまいました

‘sed: 1: "./test.md": invalid command code . error’ を検索しています

回答を生成しています…
こんにちは。このエラーは、MacやBSDのsedコマンドで-iオプションを使うときに、バックアップファイルのサフィックスを指定する必要があるために起こる可能性があります123。サフィックスを空にすることもできますが、その場合は-iの後に’'を付ける必要があります1。例えば、次のようにします。

sed -i '' 's/old/new/g' file.md
もしくは、sedの代わりにperlを使うこともできます4。例えば、次のようにします。

perl -pi -e 's/old/new/g' file.md
これで解決できるといいですね。😊
```

今回実行環境が Mac なので -iオプション にバックアップファイルのサフィックスを指定しないことが原因のようです

そこでもう一度、文章の先頭に"MACで"という条件をつけてみます

``` bash:実行結果
$?? MACで./test.mdの中身をテストからてすとに置き換える

 ──────────────────── Command ────────────────────

sed -i '' 's/テスト/てすと/g' ./test.md

 ────────────────── Explanation ──────────────────

○ sed is used to search and replace text in files.
  ◆ -i '' specifies that we want to edit the file in-place.
  ◆ 's/テスト/てすと/g' specifies the search and replace pattern.
    ◇ s means we want to search and replace.
    ◇ /テスト/ is the search pattern.
    ◇ /てすと/ is the replace pattern.
    ◇ /g means we want to replace all occurrences, not just the first one.
  ◆ ./test.md specifies the file we want to edit.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```
こんどは、ちゃんと-iオプションに`''`が付加されており
こちらを実行すると正常終了することでできました!!

## 2.4. 例） Azure CLI で VM の名前とリージョン、リソースグループを抽出してリスト化する
つづいて、Azure CLI もためしてみます

``` bash:実行結果
$?? Azure CLI で VM の名前とリージョン、リソースグループを抽出してリスト化する

 ──────────────────── Command ────────────────────

az vm list --query "[].{name:name,location:location,resourceGroup:resourceGroup}" -o table

 ────────────────── Explanation ──────────────────

○ az vm list lists all virtual machines in the current subscription.
  ◆ --query "[].{name:name,location:location,resourceGroup:resourceGroup}" specifies that we want to
select the name, location and resourceGroup fields from each item in the list.
  ◆ -o table specifies that we want to format the output as a table.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

こちらもよさそうなので、実行してみます
``` bash:実行結果
🕖  Hold on, executing commmand...
Name                                 Location    ResourceGroup
-----------------------------------  ----------  ----------------------------
win2019ad                            eastus      DEMO_VMS
vm-arck8s-ubuntu-demo-eastus-001     eastus      RG_ARCK8S_DEMOVMS_EASTUS_001
vm-spoke001-ubuntu-demo-eastus-001   eastus      RG_SPOKEVNET_DEMO_EASTUS_001
vm-spoke001-win2019-demo-eastus-001  eastus      RG_SPOKEVNET_DEMO_EASTUS_001
vm-spoke002-ubuntu-demo-eastus-001   eastus      RG_SPOKEVNET_DEMO_EASTUS_002
$
```

ちゃんとVMのリストが返ってきました

こちらも"リソースグループがRG_SPOKEVNET_DEMO_EASTUS_001のみ、"という条件を追加してみます

``` bash:実行結果
$?? Azure CLI で リソースグループがRG_SPOKEVNET_DEMO_EASTUS_001のみ、VM の名前とリージョン、リソースグループを抽出してリスト化する

 ──────────────────── Command ────────────────────

az vm list --query "[?resourceGroup=='RG_SPOKEVNET_DEMO_EASTUS_001'].{name:name,location:location,resource
Group:resourceGroup}" --output table

 ────────────────── Explanation ──────────────────

○ az vm list lists all virtual machines in the current subscription.
  ◆ --query specifies a query to filter the list of virtual machines.
    ◇ "[?resourceGroup=='RG_SPOKEVNET_DEMO_EASTUS_001']" filters the list to only include virtual machines
 in the resource group RG_SPOKEVNET_DEMO_EASTUS_001.
    ◇ .{name:name,location:location,resourceGroup:resourceGroup} specifies that we want to return a new
object for each virtual machine with the fields name, location and resourceGroup.
  ◆ --output table specifies that we want to format the output as a table.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

よさそうなので、実行してみます
``` bash:実行結果
🕕  Hold on, executing commmand...
Name                                 Location    ResourceGroup
-----------------------------------  ----------  ----------------------------
vm-spoke001-ubuntu-demo-eastus-001   eastus      RG_SPOKEVNET_DEMO_EASTUS_001
vm-spoke001-win2019-demo-eastus-001  eastus      RG_SPOKEVNET_DEMO_EASTUS_001
$
```
リソースグループでちゃんと絞り込みすることができました！

### 2.4.1. 例）`📝 Revise query`による条件の追加
さきほどは、最初の文章へ条件を追加する形で変更をしましたが、`📝 Revise query`を選択すると、最初の文章へ条件を付加することができます

最初の文章を入力した状態で、`📝 Revise query`を選択して Enter
``` bash:実行結果
$?? Azure CLI で VM の名前とリージョン、リソースグループを抽出してリスト化する

 ──────────────────── Command ────────────────────

az vm list --query "[].{name:name,location:location,resourceGroup:resourceGroup}" -o table

 ────────────────── Explanation ──────────────────

○ az vm list lists all virtual machines in the current subscription.
  ◆ --query "[].{name:name,location:location,resourceGroup:resourceGroup}" specifies that we want to select the name, location and
 resourceGroup fields from each item in the list.
  ◆ -o table specifies that we want to format the output as a table.

  ✅ Run this command
❯ 📝 Revise query
  ❌ Cancel
```

つづいて`Enter your revision:`へ追加の条件として
"リソースグループがRG_SPOKEVNET_DEMO_EASTUS_001"を入力し Enter

``` bash:実行結果
 ──────────────────── Revision ────────────────────

Enter your revision: リソースグループがRG_SPOKEVNET_DEMO_EASTUS_001
```

すると

``` bash:実行結果
$?? Azure CLI で VM の名前とリージョン、リソースグループを抽出してリスト化する

 ───────────────────── Query ─────────────────────

1) Azure CLI で VM の名前とリージョン、リソースグループを抽出してリスト化する 2) リソースグループがRG_SPOKEVNET_DEMO_EASTUS_001

 ──────────────────── Command ────────────────────

az vm list --query "[?resourceGroup=='RG_SPOKEVNET_DEMO_EASTUS_001'].{name:name,location:location,resourceGroup:resourceGroup}" -o
 table

 ────────────────── Explanation ──────────────────

○ az vm list lists all virtual machines in the current subscription.
  ◆ --query specifies a query to filter the list of virtual machines.
    ◇ "[?resourceGroup=='RG_SPOKEVNET_DEMO_EASTUS_001']" filters the list to only include virtual machines in the resource group
RG_SPOKEVNET_DEMO_EASTUS_001.
    ◇ .{name:name,location:location,resourceGroup:resourceGroup} specifies that we want to return a new object for each virtual
machine with the fields name, location and resourceGroup.
  ◆ -o table specifies that we want to format the output as a table.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

このように、`📝 Revise query`利用することで、複数の条件を複合する形でコマンド生成が可能です
（今回の例では説明していませんが、こちらを利用することでコマンドの出力結果について パイプ｜でつなげるようなことも可能）

## 2.5. 例） あなたは誰
ちなみに、コマンドの翻訳、変換に失敗すると以下のように表示されます

``` bash:実行結果
$?? あなたは誰

 ──────────────────── Command ────────────────────

⚠️ Sorry. GitHub Copilot doesn't know how to do that.

❯ 📝 Revise query
  ❌ Cancel
```

これも、こんな感じにそれっぽく文章をなおしてみると

``` bash:実行結果
$?? あなたは誰と表示する

 ──────────────────── Command ────────────────────

echo あなたは誰と

 ────────────────── Explanation ──────────────────

○ echo is used to print text to the terminal.
  ◆ あなたは誰と is the text we want to print.

❯ ✅ Run this command
  📝 Revise query
  ❌ Cancel
```

# 3. さいごに
「今回は、GitHub とは無関係の任意のコマンドしか試していませんが、日本語の文章を入力するだけで、ちゃんとコマンドに翻訳・変換される様子には本当にびっくりしました。
プレビュー段階ではありますが、この技術の可能性はとても大きく感じます。 

**『GitHub Copilot for CLI』** というツールは、開発者だけでなく、git やコードとは直接関係のない **運用関係の方々** にも十分に役立つ可能性を秘めていると私は思います。

もちろん提案されるコマンドについては、理解してから利用する必要がありますが、普段コードとは遠いところで運用作業をされている方々も、このツールを使うことで自然言語をコマンドに変換し、実行することができます。 

皆さんもぜひ **『GitHub Copilot for CLI』** を体験してみてください！」

---