fix: dev-poll should attempt direct merges before checking agent lock (#531)

Move the direct-merge scan (approved + CI green → try_direct_merge())
above the lock check. Merging an approved PR is a single API call that
doesn't need the dev-agent lock or a Claude session. This ensures
approved PRs get merged even while a dev-agent is running on an
unrelated issue.

The lock still guards dev-agent spawning (AD-002 preserved). Direct
merge failures fall through to the post-lock code for dev-agent
fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-22 06:46:26 +00:00
parent a2370b80b8
commit 236e19eae1

View file

@ -220,6 +220,67 @@ log() {
printf '[%s] poll: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
}
# =============================================================================
# PRE-LOCK: merge approved + CI-green PRs (no Claude session needed)
#
# Merging is a single API call — it doesn't need the dev-agent lock.
# This ensures approved PRs get merged even while a dev-agent is running.
# (See #531: direct merges should not be blocked by agent lock)
# =============================================================================
log "pre-lock: scanning for mergeable PRs"
PL_PRS=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
"${API}/pulls?state=open&limit=20")
PL_MERGED_ANY=false
for i in $(seq 0 $(($(echo "$PL_PRS" | jq 'length') - 1))); do
PL_PR_NUM=$(echo "$PL_PRS" | jq -r ".[$i].number")
PL_PR_SHA=$(echo "$PL_PRS" | jq -r ".[$i].head.sha")
PL_PR_BRANCH=$(echo "$PL_PRS" | jq -r ".[$i].head.ref")
PL_PR_TITLE=$(echo "$PL_PRS" | jq -r ".[$i].title")
PL_PR_BODY=$(echo "$PL_PRS" | jq -r ".[$i].body // \"\"")
# Extract issue number from branch name, PR title, or PR body
PL_ISSUE=$(echo "$PL_PR_BRANCH" | grep -oP '(?<=fix/issue-)\d+' || true)
if [ -z "$PL_ISSUE" ]; then
PL_ISSUE=$(echo "$PL_PR_TITLE" | grep -oP '#\K\d+' | tail -1 || true)
fi
if [ -z "$PL_ISSUE" ]; then
PL_ISSUE=$(echo "$PL_PR_BODY" | grep -oiP '(?:closes|fixes|resolves)\s*#\K\d+' | head -1 || true)
fi
if [ -z "$PL_ISSUE" ]; then
continue
fi
PL_CI_STATE=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
"${API}/commits/${PL_PR_SHA}/status" | jq -r '.state // "unknown"') || true
# Non-code PRs may have no CI — treat as passed
if ! ci_passed "$PL_CI_STATE" && ! ci_required_for_pr "$PL_PR_NUM"; then
PL_CI_STATE="success"
fi
if ! ci_passed "$PL_CI_STATE"; then
continue
fi
# Check for approval (non-stale)
PL_REVIEWS=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
"${API}/pulls/${PL_PR_NUM}/reviews") || true
PL_HAS_APPROVE=$(echo "$PL_REVIEWS" | \
jq -r '[.[] | select(.state == "APPROVED") | select(.stale == false)] | length') || true
if [ "${PL_HAS_APPROVE:-0}" -gt 0 ]; then
if try_direct_merge "$PL_PR_NUM" "$PL_ISSUE"; then
PL_MERGED_ANY=true
fi
# Direct merge failed — will fall through to post-lock dev-agent fallback
fi
done
if [ "$PL_MERGED_ANY" = true ]; then
exit 0
fi
# --- Check if dev-agent already running ---
if [ -f "$LOCKFILE" ]; then
LOCK_PID=$(cat "$LOCKFILE" 2>/dev/null || echo "")