1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHubでAIを強化する | 第3章:コード分析:AIによるインサイト生成

Posted at

はじめに

第2章では、GitHubにIssueを作成し、Pull Request(PR)にコメントを追加するMCPサーバーを構築し、開発タスク自動化エージェントを実現しました。これにより、AIがIssueやPRを操作できるようになり、チームの効率が向上しました。今回は、この基盤を活用して、GitHubリポジトリのコミットデータを解析するコード分析エージェントを構築します。

この第3章では、コミット履歴を分析し、コード変更頻度、主要貢献者、変更パターンのインサイトを生成します。たとえば、AIが「特定のファイルが頻繁に変更されている」ことを検出したり、「特定の開発者が特定のモジュールに集中している」ことを指摘したりできます。コード例とステップごとのガイドで、コード分析AIの構築を体験しましょう。さあ、始めましょう!

コード分析エージェントとは?

コード分析エージェントは、GitHubリポジトリのコミットデータを解析し、開発プロセスに関するインサイトを提供するAIです。MCPサーバーを介して、以下のような機能を実現できます:

  • 変更頻度分析:ファイルやディレクトリごとの変更頻度を計算。
  • 貢献者分析:開発者ごとのコミット数や変更量を評価。
  • パターン抽出:コード変更の傾向(例:バグ修正、機能追加)を特定。

ユースケース

  • コード品質:頻繁に変更されるファイルから潜在的な問題を検出。
  • チームパフォーマンス:貢献者のワークロードや専門領域を評価。
  • リファクタリング支援:変更パターンからリファクタリングの優先順位を提案。

開発環境の準備

第2章の環境を基に、以下の準備を行います:

  • Python 3.8以降mcpライブラリrequestsライブラリClaude Desktop:これまでと同じ。
  • python-dotenv:環境変数の管理(既にインストール済み)。
  • GitHubリポジトリ:分析用のコミットデータを含むリポジトリ。

GitHubのセットアップ

  1. リポジトリ準備
    • 第2章のリポジトリ(例:yourusername/mcp-test-repo)を使用。
    • 複数のコミットを追加(例:コード変更、ドキュメント更新、バグ修正)。
    • 異なる開発者(または模擬ユーザー)でコミットを作成。
    • ファイル構造を多様化(例:src/main.pydocs/README.md)。
  2. GitHubトークンの確認
    • 第2章のトークンを使用(スコープ:repo)。
    • トークンがコミットデータへの読み取り権限を持つことを確認。
  3. 環境変数
    第2章の.envファイルに以下を確認:
    GITHUB_TOKEN=your_token
    GITHUB_REPO=yourusername/mcp-test-repo
    

コード例:コード分析用MCPサーバー

以下のMCPサーバーは、GitHubリポジトリのコミットデータを取得し、変更頻度と貢献者を分析します。

from mcp import MCPServer
import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timedelta
from collections import Counter
import statistics

class GitHubAnalysisServer(MCPServer):
    def __init__(self, host, port, token, repo):
        super().__init__(host, port)
        self.token = token
        self.repo = repo
        self.base_url = "https://api.github.com"
        self.headers = {
            "Authorization": f"Bearer {token}",
            "Accept": "application/vnd.github.v3+json"
        }
        self.register_resource("analyze_commits", self.analyze_commits)

    def get_commits(self, limit=100):
        try:
            url = f"{self.base_url}/repos/{self.repo}/commits"
            query = {"per_page": limit}
            response = requests.get(url, headers=self.headers, params=query)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            return {"status": "error", "message": str(e)}

    def get_commit_diff(self, sha):
        try:
            url = f"{self.base_url}/repos/{self.repo}/commits/{sha}"
            response = requests.get(url, headers=self.headers)
            response.raise_for_status()
            files = response.json().get("files", [])
            return [{"filename": f["filename"], "changes": f["changes"]} for f in files]
        except Exception as e:
            return []

    def analyze_commits(self, params):
        try:
            commits = self.get_commits(limit=params.get("limit", 100))
            if isinstance(commits, dict) and "status" in commits:
                return commits

            author_counts = Counter()
            file_changes = Counter()
            timestamps = []
            change_types = Counter()

            for commit in commits:
                author = commit["commit"]["author"]["name"]
                ts = commit["commit"]["author"]["date"]
                timestamp = datetime.fromisoformat(ts.replace("Z", "+00:00"))
                message = commit["commit"]["message"].lower()

                # 貢献者分析
                author_counts[author] += 1

                # ファイル変更分析
                files = self.get_commit_diff(commit["sha"])
                for file in files:
                    file_changes[file["filename"]] += file["changes"]

                # コミット頻度
                timestamps.append(timestamp)

                # 変更タイプ(簡易)
                if "fix" in message or "bug" in message:
                    change_types["bug_fix"] += 1
                elif "add" in message or "feature" in message:
                    change_types["feature"] += 1
                else:
                    change_types["other"] += 1

            # 頻度分析
            if timestamps:
                time_diffs = [(timestamps[i] - timestamps[i+1]).total_seconds() / 3600 
                             for i in range(len(timestamps)-1)]
                avg_interval = statistics.mean(time_diffs) if time_diffs else 0
                commits_per_day = len(timestamps) / ((datetime.now(tz=timestamps[0].tzinfo) - min(timestamps)).total_seconds() / 86400)
            else:
                avg_interval, commits_per_day = 0, 0

            # トップファイル
            top_files = [{"file": f, "changes": c} for f, c in file_changes.most_common(5)]

            return {
                "status": "success",
                "analysis": {
                    "commit_count": len(commits),
                    "avg_commit_interval_hours": f"{avg_interval:.2f}",
                    "commits_per_day": f"{commits_per_day:.2f}",
                    "top_contributors": [{"author": a, "count": c} for a, c in author_counts.most_common(3)],
                    "top_files": top_files,
                    "change_types": [{"type": t, "count": c} for t, c in change_types.items()]
                }
            }
        except Exception as e:
            return {"status": "error", "message": str(e)}

if __name__ == "__main__":
    load_dotenv()
    server = GitHubAnalysisServer(
        host="localhost",
        port=8129,
        token=os.getenv("GITHUB_TOKEN"),
        repo=os.getenv("GITHUB_REPO")
    )
    print("GitHub分析MCPサーバーを起動中: http://localhost:8129")
    server.start()

コードの説明

  • get_commits:リポジトリのコミットを取得(最大100件)。
  • get_commit_diff:コミットの変更ファイルと変更行数を取得。
  • analyze_commits:コミットデータを解析し、以下のインサイトを生成:
    • コミット総数:取得したコミットの数。
    • 平均コミット間隔:コミット間の平均時間(時間単位)。
    • 1日あたりのコミット数:開発の活発さを評価。
    • トップ貢献者:コミット数が多い上位3ユーザー。
    • トップファイル:変更頻度の高いファイル(行数ベース)。
    • 変更タイプ:コミットメッセージから「バグ修正」「機能追加」「その他」を推定。
  • register_resource:コード分析をリソースとして登録。

前提条件

  • リポジトリに複数のコミットと異なるファイルが存在。
  • GitHubトークンにrepoスコープが付与されている。
  • .envファイルに正しいGITHUB_TOKENGITHUB_REPOが設定済み。

サーバーのテスト

サーバーが正しく動作するか確認します:

  1. サーバー起動

    python github_analysis_server.py
    

    コンソールに「GitHub分析MCPサーバーを起動中: http://localhost:8129」と表示。

  2. コード分析のテスト
    Pythonでリクエストを送信:

    import requests
    import json
    
    url = "http://localhost:8129"
    payload = {
        "jsonrpc": "2.0",
        "method": "analyze_commits",
        "params": {"limit": 50},
        "id": 1
    }
    response = requests.post(url, json=payload)
    print(json.dumps(response.json(), indent=2, ensure_ascii=False))
    

    期待されるレスポンス:

    {
      "jsonrpc": "2.0",
      "result": {
        "status": "success",
        "analysis": {
          "commit_count": 50,
          "avg_commit_interval_hours": "3.20",
          "commits_per_day": "8.50",
          "top_contributors": [
            {"author": "Your Name", "count": 30},
            {"author": "Contributor1", "count": 15},
            {"author": "Contributor2", "count": 5}
          ],
          "top_files": [
            {"file": "src/main.py", "changes": 150},
            {"file": "docs/README.md", "changes": 50}
          ],
          "change_types": [
            {"type": "bug_fix", "count": 10},
            {"type": "feature", "count": 20},
            {"type": "other", "count": 20}
          ]
        }
      },
      "id": 1
    }
    

Claude Desktopとの接続

サーバーをClaude Desktopに接続します:

  1. 設定ファイルの編集
    Claude Desktopの設定ファイル(例:claude_desktop_config.json)に以下を追加:

    {
      "mcp_servers": [
        {
          "name": "GitHubAnalysisServer",
          "url": "http://localhost:8129",
          "auth": "none"
        }
      ]
    }
    
  2. Claudeでテスト
    Claude Desktopを起動し、プロンプトを入力:

    リポジトリのコミットデータを分析してください。
    

    レスポンス例:

    リポジトリ yourusername/mcp-test-repo のコミット分析:
    - コミット数:50
    - 平均コミット間隔:3.20時間
    - 1日あたりのコミット数:8.50
    - トップ貢献者:Your Name(30コミット)、Contributor1(15コミット)、Contributor2(5コミット)
    - 頻繁に変更されたファイル:src/main.py(150行)、docs/README.md(50行)
    - 変更タイプ:機能追加(20)、バグ修正(10)、その他(20)
    

実装のコツと注意点

  • データ品質:コミットが少ない場合、分析結果が制限される。十分なデータ(例:50件以上)を用意。
  • レートリミティング:GitHub APIの制限(例:5000リクエスト/時間)に注意。
  • セキュリティ:本番環境では、auth: noneを避け、トークン認証を導入。
  • テスト:テスト用リポジトリを作成し、本番データに影響を与えない。
  • 拡張性:大量のコミットを処理する場合、キャッシュ(例:Redis)やNLPライブラリ(例:spaCy)でメッセージ分析を強化。

試してみよう:挑戦課題

以下の機能を追加して、エージェントを強化してみてください:

  • 特定のファイル(例:src/main.py)の変更履歴だけを分析するフィルター。
  • コミットメッセージの詳細分析(例:キーワード頻度)。
  • 分析結果をIssueとしてリポジトリに投稿するツール。

まとめと次のステップ

この第3章では、GitHubのコミットデータを活用してコード分析エージェントを構築しました。変更頻度や貢献者を分析することで、AIが開発プロセスのインサイトを提供し、コード品質向上を支援できるようになりました。

次の第4章では、GitHubのWebhookを活用してリアルタイム管理AIを構築します。たとえば、AIが新しいIssueやPRの作成をリアルタイムで検知し、通知や応答を生成します。リアルタイム管理AIに興味がある方は、ぜひお楽しみに!


役に立ったと思ったら、「いいね」や「ストック」をしていただけると嬉しいです!次の章でまたお会いしましょう!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?