Skip to content

Instantly share code, notes, and snippets.

@goofmint
Created November 27, 2025 06:06
Show Gist options
  • Select an option

  • Save goofmint/a0815db03c5855e02480cb6531a20437 to your computer and use it in GitHub Desktop.

Select an option

Save goofmint/a0815db03c5855e02480cb6531a20437 to your computer and use it in GitHub Desktop.
Get Review Comment from GitHub
#!/usr/bin/env sh
set -euo pipefail
usage() {
cat <<EOF
Usage:
get_comment.sh <PR_NUMBER> [--repo OWNER/REPO]
get_comment.sh --help
Description:
指定した GitHub Pull Request の「未解決レビューコメント」のうち、
<summary>🤖 Prompt for AI Agents</summary> セクションに含まれる
<details> タグ内コンテンツのみを TSV 形式で標準出力に出力します。
Arguments:
PR_NUMBER Pull Request 番号 (例: 123)
Options:
-r, --repo OWNER/REPO
対象リポジトリを明示的に指定します。
例: --repo octocat/Hello-World
未指定の場合は、カレントディレクトリの GitHub リポジトリを
`gh repo view` から自動取得します。
-h, --help このヘルプを表示します。
Examples:
# カレントディレクトリが対象リポジトリの場合
get_comment.sh 7
# 任意のディレクトリから、リポジトリを指定して実行
get_comment.sh 7 --repo owner_name/repo_name
EOF
}
PR=""
REPO_ARG=""
# 引数パース
while [ $# -gt 0 ]; do
case "$1" in
-h|--help)
usage
exit 0
;;
-r|--repo)
if [ $# -lt 2 ]; then
echo "Error: --repo オプションには OWNER/REPO を指定してください" >&2
exit 1
fi
REPO_ARG="$2"
shift 2
;;
-*)
echo "Error: 不明なオプションです: $1" >&2
usage >&2
exit 1
;;
*)
if [ -z "${PR:-}" ]; then
PR="$1"
shift
else
echo "Error: 想定外の引数です: $1" >&2
usage >&2
exit 1
fi
;;
esac
done
if [ -z "${PR:-}" ]; then
echo "Error: PR 番号を指定してください" >&2
usage >&2
exit 1
fi
# OWNER / REPO の決定
if [ -n "${REPO_ARG:-}" ]; then
if [[ "$REPO_ARG" != *"/"* ]]; then
echo "Error: --repo には OWNER/REPO 形式で指定してください (例: octocat/Hello-World)" >&2
exit 1
fi
OWNER="${REPO_ARG%%/*}"
REPO="${REPO_ARG#*/}"
else
OWNER=$(gh repo view --json owner --jq .owner.login)
REPO=$(gh repo view --json name --jq .name)
fi
CURSOR=""
while :; do
RESP=$(
gh api graphql \
-f owner="$OWNER" -f name="$REPO" -F number="$PR" ${CURSOR:+-F cursor="$CURSOR"} \
-f query='
query($owner:String!, $name:String!, $number:Int!, $cursor:String) {
repository(owner:$owner, name:$name) {
pullRequest(number:$number) {
reviewThreads(first:100, after:$cursor) {
pageInfo { hasNextPage endCursor }
nodes {
isResolved
comments(first:1) {
nodes { url path body }
}
}
}
}
}
}'
)
printf '%s\n' "$RESP" \
| tr '\000-\037' ' ' \
| jq -r '
(.data.repository.pullRequest.reviewThreads.nodes // [])
| map(select(.isResolved == false and (.comments.nodes | length > 0)))
| map(.comments.nodes[0])
| map(select(.body | contains("<summary>🤖 Prompt for AI Agents</summary>")))
| .[]
| [
.url,
(.path // "-"),
(
.body
| (try capture("(?s)<details>\\s*<summary>🤖 Prompt for AI Agents</summary>\\s*(?<content>.*?)\\s*</details>") catch {content:""})
| .content
| gsub("```"; "")
| sub("^\\s+"; "")
| sub("\\s+$"; "")
| gsub("\r";" ")
| gsub("\n";" ")
| gsub("\t";" ")
)
]
| @tsv
'
HAS_NEXT=$(printf '%s\n' "$RESP" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')
if [ "$HAS_NEXT" != "true" ]; then
break
fi
CURSOR=$(printf '%s\n' "$RESP" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor')
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment