Github Copilotの使用状況を表示するプログラムをCopilot Chatで作る

# どういうこと？

会社でGitHub Copilotを使うにあたって、使用状況を把握して効果測定したい！というのは当然のモチベーションとしてあるのではと思う。GitHub Copilotには[Metics API](https://docs.github.com/ja/rest/copilot/copilot-metrics)が用意されているのでこれを使えば統計情報を取ることができ、IDEでコード提案を受けた時の、
・提案されたコードの数
・受け入れたコードの数
・提案されたコードの行数
・受け入れたコードの行数
といったデータが取得できる。

元々、[Copilot Metrics Viewer](https://github.com/github-copilot-resources/copilot-metrics-viewer)という可視化ツールが公開されてるので、これを使えば早いのだが、「APIから取得したデータを集計して表示するだけならCopilot Chat使って速攻で作れるだろ」と思いやってみた。（言語はPHP）

# プロンプト ⇒ コード生成

> Github CopilotのMetrics APIを使ってCopilotの使用状況の統計データを表示するプログラムを組んでください。
> 表示するデータは以下の４つです。
> ・提案された数
> ・受け入れた数
> ・提案された行数
> ・受け入れた行数

```php
// GitHub Copilot Metrics APIのエンドポイント（組織名を含む）
$organization = "your-organization-name"; // 組織名を指定してください
$apiUrl = "https://api.github.com/orgs/$organization/copilot/metrics";

// APIトークン（GitHub Personal Access Tokenを使用）
$apiToken = "your_github_personal_access_token"; // トークンを設定してください

// cURLを使用してAPIリクエストを送信
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $apiToken",
    "User-Agent: GitHub Copilot Metrics Viewer"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// HTTPステータスコードを確認
if ($httpCode !== 200) {
    echo "APIリクエストに失敗しました。HTTPステータスコード: $httpCode\n";
    exit;
}

// レスポンスをデコード
$data = json_decode($response, true);

// 統計情報を取得
if (isset($data['metrics'])) {
    $metrics = $data['metrics'];

    $suggestedCount = $metrics['suggested_count'] ?? 0;
    $acceptedCount = $metrics['accepted_count'] ?? 0;
    $suggestedLines = $metrics['suggested_lines'] ?? 0;
    $acceptedLines = $metrics['accepted_lines'] ?? 0;

    // 結果を表示
    echo "提案された数: $suggestedCount\n";
    echo "受け入れた数: $acceptedCount\n";
    echo "提案された行数: $suggestedLines\n";
    echo "受け入れた行数: $acceptedLines\n";
} else {
    echo "統計情報を取得できませんでした。\n";
}
```

惜しい。レスポンスから統計情報を取得する部分の配列構造が適当すぎる。
[Metrics APIのレスポンススキーマ](https://docs.github.com/ja/rest/copilot/copilot-metrics?apiVersion=2022-11-28#get-copilot-metrics-for-an-organization)を理解していないので教えてあげる。


> レスポンスの配列構造の例を以下に示します。
> これを元にコードを修正してください。
> 
> [
> {
> "date": "2024-06-24",
> "total_active_users": 24,
> "total_engaged_users": 20,
> "copilot_ide_code_completions": {
> "total_engaged_users": 20,
> "languages": [
> {
>
> （以下略）

```php
// GitHub Copilot Metrics APIのエンドポイント（組織名を含む）
$organization = "your-organization-name"; // 組織名を指定してください
$apiUrl = "https://api.github.com/orgs/$organization/copilot/metrics";

// APIトークン（GitHub Personal Access Tokenを使用）
$apiToken = "your_github_personal_access_token"; // トークンを設定してください

// cURLを使用してAPIリクエストを送信
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $apiToken",
    "User-Agent: GitHub Copilot Metrics Viewer"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// HTTPステータスコードを確認
if ($httpCode !== 200) {
    echo "APIリクエストに失敗しました。HTTPステータスコード: $httpCode\n";
    exit;
}

// レスポンスをデコード
$data = json_decode($response, true);

// 統計情報を取得
if (is_array($data) && !empty($data)) {
    $totalSuggestions = 0;
    $totalAcceptances = 0;
    $totalLinesSuggested = 0;
    $totalLinesAccepted = 0;

    foreach ($data as $entry) {
        if (isset($entry['copilot_ide_code_completions']['editors'])) {
            foreach ($entry['copilot_ide_code_completions']['editors'] as $editor) {
                if (isset($editor['models'])) {
                    foreach ($editor['models'] as $model) {
                        if (isset($model['languages'])) {
                            foreach ($model['languages'] as $language) {
                                $totalSuggestions += $language['total_code_suggestions'] ?? 0;
                                $totalAcceptances += $language['total_code_acceptances'] ?? 0;
                                $totalLinesSuggested += $language['total_code_lines_suggested'] ?? 0;
                                $totalLinesAccepted += $language['total_code_lines_accepted'] ?? 0;
                            }
                        }
                    }
                }
            }
        }
    }

    // 結果を表示
    echo "提案された数: $totalSuggestions\n";
    echo "受け入れた数: $totalAcceptances\n";
    echo "提案された行数: $totalLinesSuggested\n";
    echo "受け入れた行数: $totalLinesAccepted\n";
} else {
    echo "統計情報を取得できませんでした。\n";
}
```

いい感じ。

> 結果の出力はhtmlでお願いします。

```php
// GitHub Copilot Metrics APIのエンドポイント（組織名を含む）
$organization = "your-organization-name"; // 組織名を指定してください
$apiUrl = "https://api.github.com/orgs/$organization/copilot/metrics";

// APIトークン（GitHub Personal Access Tokenを使用）
$apiToken = "your_github_personal_access_token"; // トークンを設定してください

// cURLを使用してAPIリクエストを送信
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $apiToken",
    "User-Agent: GitHub Copilot Metrics Viewer"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// HTTPステータスコードを確認
if ($httpCode !== 200) {
    echo "<p>APIリクエストに失敗しました。HTTPステータスコード: $httpCode</p>";
    exit;
}

// レスポンスをデコード
$data = json_decode($response, true);

// 統計情報を取得
if (is_array($data) && !empty($data)) {
    $totalSuggestions = 0;
    $totalAcceptances = 0;
    $totalLinesSuggested = 0;
    $totalLinesAccepted = 0;

    foreach ($data as $entry) {
        if (isset($entry['copilot_ide_code_completions']['editors'])) {
            foreach ($entry['copilot_ide_code_completions']['editors'] as $editor) {
                if (isset($editor['models'])) {
                    foreach ($editor['models'] as $model) {
                        if (isset($model['languages'])) {
                            foreach ($model['languages'] as $language) {
                                $totalSuggestions += $language['total_code_suggestions'] ?? 0;
                                $totalAcceptances += $language['total_code_acceptances'] ?? 0;
                                $totalLinesSuggested += $language['total_code_lines_suggested'] ?? 0;
                                $totalLinesAccepted += $language['total_code_lines_accepted'] ?? 0;
                            }
                        }
                    }
                }
            }
        }
    }

    // 結果をHTMLで表示
    echo "<!DOCTYPE html>
<html lang='ja'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>Copilot Metrics</title>
</head>
<body>
    <h1>GitHub Copilot 使用状況</h1>
    <ul>
        <li>提案された数: $totalSuggestions</li>
        <li>受け入れた数: $totalAcceptances</li>
        <li>提案された行数: $totalLinesSuggested</li>
        <li>受け入れた行数: $totalLinesAccepted</li>
    </ul>
</body>
</html>";
} else {
    echo "<p>統計情報を取得できませんでした。</p>";
}
```

おお？echoで全部吐いちゃってるけど、まぁいいか。

> グラフも追加してほしいです

```php
// GitHub Copilot Metrics APIのエンドポイント（組織名を含む）
$organization = "your-organization-name"; // 組織名を指定してください
$apiUrl = "https://api.github.com/orgs/$organization/copilot/metrics";

// APIトークン（GitHub Personal Access Tokenを使用）
$apiToken = "your_github_personal_access_token"; // トークンを設定してください

// cURLを使用してAPIリクエストを送信
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $apiToken",
    "User-Agent: GitHub Copilot Metrics Viewer"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// HTTPステータスコードを確認
if ($httpCode !== 200) {
    echo "<p>APIリクエストに失敗しました。HTTPステータスコード: $httpCode</p>";
    exit;
}

// レスポンスをデコード
$data = json_decode($response, true);

// 統計情報を取得
if (is_array($data) && !empty($data)) {
    $totalSuggestions = 0;
    $totalAcceptances = 0;
    $totalLinesSuggested = 0;
    $totalLinesAccepted = 0;

    foreach ($data as $entry) {
        if (isset($entry['copilot_ide_code_completions']['editors'])) {
            foreach ($entry['copilot_ide_code_completions']['editors'] as $editor) {
                if (isset($editor['models'])) {
                    foreach ($editor['models'] as $model) {
                        if (isset($model['languages'])) {
                            foreach ($model['languages'] as $language) {
                                $totalSuggestions += $language['total_code_suggestions'] ?? 0;
                                $totalAcceptances += $language['total_code_acceptances'] ?? 0;
                                $totalLinesSuggested += $language['total_code_lines_suggested'] ?? 0;
                                $totalLinesAccepted += $language['total_code_lines_accepted'] ?? 0;
                            }
                        }
                    }
                }
            }
        }
    }

    // 結果をHTMLで表示
    echo "<!DOCTYPE html>
<html lang='ja'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>Copilot Metrics</title>
    <script src='https://cdn.jsdelivr.net/npm/chart.js'></script>
</head>
<body>
    <h1>GitHub Copilot 使用状況</h1>
    <ul>
        <li>提案された数: $totalSuggestions</li>
        <li>受け入れた数: $totalAcceptances</li>
        <li>提案された行数: $totalLinesSuggested</li>
        <li>受け入れた行数: $totalLinesAccepted</li>
    </ul>
    <canvas id='metricsChart' width='400' height='200'></canvas>
    <script>
        const ctx = document.getElementById('metricsChart').getContext('2d');
        const metricsChart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: ['提案された数', '受け入れた数', '提案された行数', '受け入れた行数'],
                datasets: [{
                    label: 'GitHub Copilot Metrics',
                    data: [$totalSuggestions, $totalAcceptances, $totalLinesSuggested, $totalLinesAccepted],
                    backgroundColor: [
                        'rgba(75, 192, 192, 0.2)',
                        'rgba(54, 162, 235, 0.2)',
                        'rgba(255, 206, 86, 0.2)',
                        'rgba(153, 102, 255, 0.2)'
                    ],
                    borderColor: [
                        'rgba(75, 192, 192, 1)',
                        'rgba(54, 162, 235, 1)',
                        'rgba(255, 206, 86, 1)',
                        'rgba(153, 102, 255, 1)'
                    ],
                    borderWidth: 1
                }]
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    </script>
</body>
</html>";
} else {
    echo "<p>統計情報を取得できませんでした。</p>";
}
```

完成。
あとは組織名とトークンをこちらで入れてあげれば出来上がり。

# 成果物

所要時間：約10分

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108727/4a61f372-1425-4b60-8e9e-b82d5debc054.png)