モチベーション
GitHubのPull Request(PR)を作成してレビューが沢山あったりしたとき、レビュー対応ステータスを把握したいと思い、作ってみた
手順
事前準備
-
Personal access tokens (classic)を作成する
- Select scopesではとりあえず
repo
だけあれば大丈夫
- Select scopesではとりあえず
- 環境変数に作成したtokenを設定する
- terminal上で
export GITHUB_TOKEN='ghp_xxxx'
を実行
- terminal上で
実行
以下コードのpython get_commit_info.py
を実行
get_commit_info
import os
import requests
import re
import csv
# -----------------------------
# 設定(必要に応じて書き換える)
# -----------------------------
# https://github.com/OWNER/REPO/pull/PR_NUMBER
OWNER = "foo"
REPO = "bar"
PR_NUMBER = baz
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
# -----------------------------
# ヘッダー設定
# -----------------------------
HEADERS = {
"Authorization": f"Bearer {GITHUB_TOKEN}",
"Accept": "application/vnd.github+json"
}
# -----------------------------
# GraphQLクエリでレビューコメントのステータス取得
# -----------------------------
# https://docs.github.com/ja/graphql/reference/objects
def get_review_threads(owner, repo, pr_number):
query = """
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
isResolved
comments(first: 1) {
nodes {
bodyText
author { login }
createdAt
}
}
}
}
}
}
}
"""
variables = {
"owner": owner,
"name": repo,
"number": pr_number
}
response = requests.post(
"https://api.github.com/graphql",
headers=HEADERS,
json={"query": query, "variables": variables}
)
res_json = response.json()
if "errors" in res_json:
raise Exception(f"GraphQL error: {res_json['errors']}")
pull_request = res_json.get("data", {}).get("repository", {}).get("pullRequest")
if pull_request is None:
raise Exception("PRが見つかりません。OWNER, REPO, PR_NUMBERを確認してください。")
return pull_request["reviewThreads"]["nodes"]
# -----------------------------
# CSVファイル出力
# -----------------------------
def write_review_status_to_csv(threads, filename="review_status.csv"):
with open(filename, mode='w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["No", "Status", "Commentor", "CreatedAt", "Comment"])
for i, thread in enumerate(threads, 1):
status = "Resolved" if thread["isResolved"] else "Unresolved"
comment = thread["comments"]["nodes"][0]
commentor = comment["author"]["login"]
created = comment["createdAt"]
body = re.sub(r'@.*\n', '', comment["bodyText"]).strip()
print(f"{i:02d}. {status} \t {commentor} \t {created} \t {body}")
writer.writerow([i, status, commentor, created, body])
print(f"{filename} に出力しました。")
# -----------------------------
# 実行
# -----------------------------
if __name__ == "__main__":
if not GITHUB_TOKEN:
raise EnvironmentError("GITHUB_TOKEN が設定されていません。環境変数に追加してください。")
try:
threads = get_review_threads(OWNER, REPO, PR_NUMBER)
if not threads:
print("レビューコメントスレッドが見つかりません。")
else:
write_review_status_to_csv(threads)
except Exception as e:
print(f"エラーが発生しました: {e}")
結果
感想
もっと良い感じに作れるかもしれない。色んなご意見お待ちしてます。