Merge pull request 'fix(automation): scan all Claude PRs for review comments; drop author-based bot filter' (#131) from claude/busy-boyd-b16092 into master
All checks were successful
Refresh staging / refresh (push) Successful in 7s
All checks were successful
Refresh staging / refresh (push) Successful in 7s
Reviewed-on: #131
This commit is contained in:
commit
fa0e004691
1 changed files with 22 additions and 12 deletions
|
|
@ -94,21 +94,23 @@ if [ ! -d "$WORKDIR/.git" ]; then
|
||||||
git -C "$WORKDIR" config user.email "claude-autofix@pelagiamarine.com"
|
git -C "$WORKDIR" config user.email "claude-autofix@pelagiamarine.com"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- identity + authorization set ---
|
# --- authorization set ---
|
||||||
# The bot's own login (so its acknowledgements are never treated as instructions).
|
|
||||||
BOT_LOGIN=$(api GET "/user" | jq -r '.login // ""')
|
|
||||||
# Collaborators = users with write access. The repo owner is always allowed.
|
# 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" \
|
COLLAB=$(api GET "/repos/$REPO/collaborators?limit=100" \
|
||||||
| jq -c --arg owner "$owner" '[.[].login] + [$owner] | unique')
|
| 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) ---
|
# --- find Claude-raised open PRs (head branch under the prefix, or labelled claude-pr) ---
|
||||||
prs=$(api GET "/repos/$REPO/pulls?state=open&limit=50" \
|
prs=$(api GET "/repos/$REPO/pulls?state=open&limit=50" \
|
||||||
| jq -c --arg pfx "$PR_BRANCH_PREFIX" \
|
| jq -c --arg pfx "$PR_BRANCH_PREFIX" \
|
||||||
'[ .[] | select((.head.ref | startswith($pfx)) or (((.labels//[])|map(.name))|index("claude-pr"))) ] | sort_by(.number)')
|
'[ .[] | 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')
|
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.
|
# Pull the instruction text that follows the marker out of a comment body.
|
||||||
instr_of() { # BODY -> text after the first marker occurrence, trimmed
|
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
|
p=0
|
||||||
|
processed=0
|
||||||
while [ "$p" -lt "$n_prs" ]; do
|
while [ "$p" -lt "$n_prs" ]; do
|
||||||
pr=$(printf '%s' "$prs" | jq -c ".[$p]")
|
pr=$(printf '%s' "$prs" | jq -c ".[$p]")
|
||||||
p=$((p+1))
|
p=$((p+1))
|
||||||
|
|
@ -133,15 +136,17 @@ while [ "$p" -lt "$n_prs" ]; do
|
||||||
handled=$(printf '%s' "$conv" | jq -c --arg tag "$HANDLED_TAG" \
|
handled=$(printf '%s' "$conv" | jq -c --arg tag "$HANDLED_TAG" \
|
||||||
'[ .[].body // "" | select(contains($tag)) | scan("(?:conv|summary|inline):[0-9]+") ] | unique')
|
'[ .[].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))
|
sel='select(.body != null) | select(.body | contains($m))
|
||||||
| select(.user.login as $u | ($collab | index($u)))
|
| select(.body | contains($tag) | not)
|
||||||
| select(.user.login != $bot)'
|
| 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,
|
[ .[] | $sel | { key:(\"conv:\"+(.id|tostring)), kind:\"conv\", id:.id, user:.user.login,
|
||||||
loc:\"PR conversation\", body:.body } ]")
|
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
|
[ .[] | select(.body != \"\") | $sel
|
||||||
| { key:(\"summary:\"+(.id|tostring)), kind:\"summary\", id:.id, user:.user.login,
|
| { key:(\"summary:\"+(.id|tostring)), kind:\"summary\", id:.id, user:.user.login,
|
||||||
loc:\"review summary\", body:.body } ]")
|
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
|
for rid in $(printf '%s' "$reviews" | jq -r '.[].id'); do
|
||||||
rc=$(api_soft GET "/repos/$REPO/pulls/$num/reviews/$rid/comments")
|
rc=$(api_soft GET "/repos/$REPO/pulls/$num/reviews/$rid/comments")
|
||||||
[ -z "$rc" ] && continue
|
[ -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
|
[ .[] | $sel
|
||||||
| { key:(\"inline:\"+(.id|tostring)), kind:\"inline\", id:.id, user:.user.login,
|
| { key:(\"inline:\"+(.id|tostring)), kind:\"inline\", id:.id, user:.user.login,
|
||||||
loc:(\"inline \"+(.path//\"?\")+\":\"+((.line // .original_line // 0)|tostring)),
|
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]")
|
fresh=$(printf '%s' "$fresh" | jq -c ".[:$MAX_COMMENTS]")
|
||||||
n=$(printf '%s' "$fresh" | jq 'length')
|
n=$(printf '%s' "$fresh" | jq 'length')
|
||||||
if [ "$n" -eq 0 ]; then log " no new '$MARKER' comments"; continue; fi
|
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 ----
|
# ---- check out the PR branch in the work clone ----
|
||||||
git -C "$WORKDIR" fetch origin -q
|
git -C "$WORKDIR" fetch origin -q
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue