3
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 の Issues を NotebookLM で調査

Last updated at Posted at 2024-11-28

GitHub にあるリポジトリの Issues を Markdown に変換して、NotebookLM で調査します。

トラブルが発生したとき、大量の Issue から類似の問題が報告されているか確認するのに威力を発揮します。

GitHub CLI

Issues のダウンロードは GitHub CLI を使用します。

認証

GitHub CLI は GitHub API を使用します。GitHub API は、認証の有無でレート制限が変わります。

1 時間あたり、未認証では 60 リクエスト、認証済なら 5,000 リクエストです。大量の Issues の取得には複数回のリクエストが必要となるため、認証を済ませておくことを推奨します。

認証は gh auth login として、指示に従ってください。ブラウザ経由での方法と、トークンを貼り付ける方法の 2 種類が選択できます。

Issues の取得

以下のコマンドで、指定したリポジトリの open なすべての Issue が取得できます。

gh api repos/OWNER/REPO/issues --paginate | python -m json.tool > issues.json

OWNER/REPO は適宜書き換えてください。

取得した JSON には各 Issue にぶら下がっているコメントは含まれないため、必要な場合は別途取得する必要があります。(後述)

gh のサブコマンドとして用意されている gh issue list を使う方が素直だとは思いますが、試行錯誤の結果、ざっとすべての情報を取得するには gh api の方が手軽だと判断しました。

Markdown への変換

jq コマンドで情報を絞り込んで Markdown に変換します。

jq -r '(.[0].repository_url | split("/")[-2:] | join("/")) + " Issues" + ([.[] | "\n\n# \(.number). \(.title)\n\n\(.body)" | gsub("\r"; "")] | add)' issues.json > issues.md

gh コマンドでも直接 jq 互換の整形が可能です。今回は必要に応じて情報が取り出せるように、JSON の取得と整形を分離しました。

参考: Python

jq で何をやっているかは、参考までに Python で同じ処理を書いておくので、比較してみてください。

import json

with open('issues.json', 'r', encoding='utf-8') as f:
    issues = json.load(f)

with open('issues.md', 'w', encoding='utf-8') as f:
    # jq: (.[0].repository_url | split("/")[-2:] | join("/")) + " Issues"
    f.write('/'.join(issues[0]['repository_url'].split('/')[-2:]) + " Issues")

    # jq: [.[] | "\n\n# \(.number). \(.title)\n\n\(.body)" | gsub("\r"; "")] | add
    f.write("".join(
        f"\n\n# {i['number']}. {i['title']}\n\n{i['body'] or 'null'}".replace('\r', '')
        for i in issues
    ))

    f.write("\n")

このようなコードを書かなくても、jq ならワンライナーで処理できるということです。

NotebookLM

変換した issues.md を NotebookLM に読み込ませれば、ピンポイントで内容について質問できます。

使用例: Ollama

Ollama について質問した例を示します。👉詳細

image.png

コメント

コメントは Issue ごとに個別に取得する必要があります。リクエスト回数が増大して、ログのサイズも巨大になります。

gh issue view 番号 --repo OWNER/REPO --json number,title,body,comments | python -m json.tool > issues/番号.json

番号OWNER/REPO は適宜書き換えてください。

既に取得した issues.json を基にコメント付きで取得する例です。

TARGET=OWNER/REPO
mkdir -p $TARGET
for i in `jq -r '.[].number' issues.json`; do
  echo $TARGET/$i;
  (gh issue view $i --repo $TARGET --json number,title,body,comments | python -m json.tool > $TARGET/$i.json);
done

試しにコメント付きで Markdown に変換して NotebookLM に読み込ませてみたのですが、情報量が増えすぎたためか肝心な情報が薄まって、既出チェックにはあまり向かないようでした。

個別の事例を探すのではなく、開発コミュニティの雰囲気を知るなどの目的であれば、コメント付きのデータを読み込ませるのも面白いと思います。

変換コード例: Python

取得した個別の Issue を 1 つの JSON にマージして、Markdown に変換するコード例を示します。

import json
from pathlib import Path

def merge_issues(owner_repo):
    """ダウンロードした issue の JSON ファイルをマージして出力し、データを返す"""
    dir_path = Path(owner_repo)

    if not dir_path.is_dir():
        print(f"Directory not found: {dir_path}", file=sys.stderr)
        return

    # 数字のみのファイル名を取得
    json_files = sorted(
        (f for f in dir_path.glob("*.json") if f.stem.isdigit()),
        key=lambda p: int(p.stem)
    )

    # JSON ファイルを読み込んでマージ
    issues = []
    for json_file in json_files:
        try:
            with open(json_file, "r", encoding="utf-8") as f:
                issues.append(json.load(f))
        except (json.JSONDecodeError, ValueError) as e:
            print(f"Error reading {json_file}: {e}", file=sys.stderr)
            continue

    # マージしたデータを保存
    output_file = Path(owner_repo) / "merge.json"
    with open(output_file, "w", encoding="utf-8") as f:
        json.dump(issues, f, indent=2, ensure_ascii=False)

    print(f"Merged {len(issues)} issues into {output_file}")
    return issues

def convert_issues_to_markdown(owner_repo, issues):
    """issues を Markdown に変換して保存する"""
    output_file = Path(owner_repo) / "merge.md"
    with open(output_file, "w", encoding="utf-8") as f:
        print(f"{owner_repo} Issues", file=f)
        for issue in issues:
            print(file=f)
            print(f"# {issue['number']}. {issue['title']}", file=f)
            print(file=f)
            print(issue['body'].replace("\r\n", "\n").rstrip(), file=f)
            for comment in issue['comments']:
                print(file=f)
                print(f"## {comment['author']['login']}", file=f)
                print(file=f)
                print(comment['body'].replace("\r\n", "\n").rstrip(), file=f)
    print(f"Converted {len(issues)} issues into {output_file}")

target = "OWNER/REPO"
issues = merge_issues(target)
convert_issues_to_markdown(target, issues)

関連記事

この手法を実際に問題解決に使用した記事です。

3
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
3
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?