fix(automation): scan all Claude PRs for review comments; drop author-based bot filter #131

Merged
shad0w merged 1 commit from claude/busy-boyd-b16092 into master 2026-06-24 10:28:17 +00:00

View file

@ -94,21 +94,23 @@ if [ ! -d "$WORKDIR/.git" ]; then
git -C "$WORKDIR" config user.email "claude-autofix@pelagiamarine.com"
fi
# --- identity + authorization set ---
# The bot's own login (so its acknowledgements are never treated as instructions).
BOT_LOGIN=$(api GET "/user" | jq -r '.login // ""')
# --- authorization set ---
# Collaborators = users with write access. The repo owner is always allowed.
# (The bot may post as the owner's account, so we never filter by author to spot
# the bot's own comments -- its acknowledgements are excluded by the HANDLED_TAG
# marker instead, and human acks lack the claude-review: marker anyway.)
COLLAB=$(api GET "/repos/$REPO/collaborators?limit=100" \
| jq -c --arg owner "$owner" '[.[].login] + [$owner] | unique')
log "Authorized commenters: $(printf '%s' "$COLLAB" | jq -r 'join(", ")') (bot=$BOT_LOGIN)"
log "Authorized commenters: $(printf '%s' "$COLLAB" | jq -r 'join(", ")')"
# --- find Claude-raised open PRs (head branch under the prefix, or labelled claude-pr) ---
prs=$(api GET "/repos/$REPO/pulls?state=open&limit=50" \
| jq -c --arg pfx "$PR_BRANCH_PREFIX" \
'[ .[] | select((.head.ref | startswith($pfx)) or (((.labels//[])|map(.name))|index("claude-pr"))) ] | sort_by(.number)')
prs=$(printf '%s' "$prs" | jq -c ".[:$MAX_PRS]")
# Scan ALL matching PRs (not truncated) -- the per-run cap below limits only how
# many PRs Claude actually RUNS on, so comment-less PRs never crowd out newer ones.
n_prs=$(printf '%s' "$prs" | jq 'length')
log "Found $n_prs Claude-raised open PR(s) to scan for '$MARKER' comments"
log "Found $n_prs Claude-raised open PR(s) to scan for '$MARKER' comments (will run Claude on up to $MAX_PRS with new comments)"
# Pull the instruction text that follows the marker out of a comment body.
instr_of() { # BODY -> text after the first marker occurrence, trimmed
@ -117,6 +119,7 @@ instr_of() { # BODY -> text after the first marker occurrence, trimmed
}
p=0
processed=0
while [ "$p" -lt "$n_prs" ]; do
pr=$(printf '%s' "$prs" | jq -c ".[$p]")
p=$((p+1))
@ -133,15 +136,17 @@ while [ "$p" -lt "$n_prs" ]; do
handled=$(printf '%s' "$conv" | jq -c --arg tag "$HANDLED_TAG" \
'[ .[].body // "" | select(contains($tag)) | scan("(?:conv|summary|inline):[0-9]+") ] | unique')
# A candidate must carry the marker, NOT be one of the bot's own ack comments
# (those carry HANDLED_TAG), and come from an authorized (collaborator) user.
sel='select(.body != null) | select(.body | contains($m))
| select(.user.login as $u | ($collab | index($u)))
| select(.user.login != $bot)'
| select(.body | contains($tag) | not)
| select(.user.login as $u | ($collab | index($u)))'
conv_tasks=$(printf '%s' "$conv" | jq -c --arg m "$MARKER" --argjson collab "$COLLAB" --arg bot "$BOT_LOGIN" "
conv_tasks=$(printf '%s' "$conv" | jq -c --arg m "$MARKER" --arg tag "$HANDLED_TAG" --argjson collab "$COLLAB" "
[ .[] | $sel | { key:(\"conv:\"+(.id|tostring)), kind:\"conv\", id:.id, user:.user.login,
loc:\"PR conversation\", body:.body } ]")
summary_tasks=$(printf '%s' "$reviews" | jq -c --arg m "$MARKER" --argjson collab "$COLLAB" --arg bot "$BOT_LOGIN" "
summary_tasks=$(printf '%s' "$reviews" | jq -c --arg m "$MARKER" --arg tag "$HANDLED_TAG" --argjson collab "$COLLAB" "
[ .[] | select(.body != \"\") | $sel
| { key:(\"summary:\"+(.id|tostring)), kind:\"summary\", id:.id, user:.user.login,
loc:\"review summary\", body:.body } ]")
@ -151,7 +156,7 @@ while [ "$p" -lt "$n_prs" ]; do
for rid in $(printf '%s' "$reviews" | jq -r '.[].id'); do
rc=$(api_soft GET "/repos/$REPO/pulls/$num/reviews/$rid/comments")
[ -z "$rc" ] && continue
t=$(printf '%s' "$rc" | jq -c --arg m "$MARKER" --argjson collab "$COLLAB" --arg bot "$BOT_LOGIN" "
t=$(printf '%s' "$rc" | jq -c --arg m "$MARKER" --arg tag "$HANDLED_TAG" --argjson collab "$COLLAB" "
[ .[] | $sel
| { key:(\"inline:\"+(.id|tostring)), kind:\"inline\", id:.id, user:.user.login,
loc:(\"inline \"+(.path//\"?\")+\":\"+((.line // .original_line // 0)|tostring)),
@ -164,7 +169,12 @@ while [ "$p" -lt "$n_prs" ]; do
fresh=$(printf '%s' "$fresh" | jq -c ".[:$MAX_COMMENTS]")
n=$(printf '%s' "$fresh" | jq 'length')
if [ "$n" -eq 0 ]; then log " no new '$MARKER' comments"; continue; fi
log " $n new '$MARKER' comment(s) to address"
if [ "$processed" -ge "$MAX_PRS" ]; then
log " $n new '$MARKER' comment(s) but per-run cap ($MAX_PRS) reached; deferring PR #$num to next run"
continue
fi
processed=$((processed+1))
log " $n new '$MARKER' comment(s) to address (PR $processed/$MAX_PRS this run)"
# ---- check out the PR branch in the work clone ----
git -C "$WORKDIR" fetch origin -q