fix: fix: use Forgejo assignee as issue lock to prevent concurrent claims (#38)
This commit is contained in:
parent
98a71f9192
commit
4c08b7840e
3 changed files with 68 additions and 5 deletions
|
|
@ -185,7 +185,11 @@ log "preflight passed"
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# CLAIM ISSUE
|
# CLAIM ISSUE
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
issue_claim "$ISSUE"
|
if ! issue_claim "$ISSUE"; then
|
||||||
|
log "SKIP: failed to claim issue #${ISSUE} (already assigned to another agent)"
|
||||||
|
echo '{"status":"already_done","reason":"issue was claimed by another agent"}' > "$PREFLIGHT_RESULT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
CLAIMED=true
|
CLAIMED=true
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,11 @@ memory_guard 2000
|
||||||
# PRIORITY 1: orphaned in-progress issues
|
# PRIORITY 1: orphaned in-progress issues
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
log "checking for in-progress issues"
|
log "checking for in-progress issues"
|
||||||
|
|
||||||
|
# Get current bot identity for assignee checks
|
||||||
|
BOT_USER=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
"${API%%/repos*}/user" | jq -r '.login') || BOT_USER=""
|
||||||
|
|
||||||
ORPHANS_JSON=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
ORPHANS_JSON=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
"${API}/issues?state=open&labels=in-progress&limit=10&type=issues")
|
"${API}/issues?state=open&labels=in-progress&limit=10&type=issues")
|
||||||
|
|
||||||
|
|
@ -387,7 +392,20 @@ if [ "$ORPHAN_COUNT" -gt 0 ]; then
|
||||||
log "issue #${ISSUE_NUM} has open PR #${HAS_PR} (CI: ${CI_STATE}, waiting)"
|
log "issue #${ISSUE_NUM} has open PR #${HAS_PR} (CI: ${CI_STATE}, waiting)"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "recovering orphaned issue #${ISSUE_NUM} (no PR found)"
|
# Check assignee before adopting orphaned issue
|
||||||
|
ISSUE_JSON=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
"${API}/issues/${ISSUE_NUM}") || true
|
||||||
|
ASSIGNEE=$(echo "$ISSUE_JSON" | jq -r '.assignee.login // ""') || true
|
||||||
|
|
||||||
|
if [ -n "$ASSIGNEE" ] && [ "$ASSIGNEE" != "$BOT_USER" ]; then
|
||||||
|
log "issue #${ISSUE_NUM} assigned to ${ASSIGNEE} — skipping (not orphaned)"
|
||||||
|
# Remove in-progress label since this agent isn't working on it
|
||||||
|
curl -sf -X DELETE -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
"${API}/issues/${ISSUE_NUM}/labels/in-progress" >/dev/null 2>&1 || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "recovering orphaned issue #${ISSUE_NUM} (no PR found, assigned to ${BOT_USER:-unassigned})"
|
||||||
nohup "${SCRIPT_DIR}/dev-agent.sh" "$ISSUE_NUM" >> "$LOGFILE" 2>&1 &
|
nohup "${SCRIPT_DIR}/dev-agent.sh" "$ISSUE_NUM" >> "$LOGFILE" 2>&1 &
|
||||||
log "started dev-agent PID $! for issue #${ISSUE_NUM} (recovery)"
|
log "started dev-agent PID $! for issue #${ISSUE_NUM} (recovery)"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
||||||
|
|
@ -81,11 +81,35 @@ _ilc_in_progress_id() { _ilc_ensure_label_id _ILC_IN_PROGRESS_ID "in-progress"
|
||||||
_ilc_blocked_id() { _ilc_ensure_label_id _ILC_BLOCKED_ID "blocked" "#e11d48"; }
|
_ilc_blocked_id() { _ilc_ensure_label_id _ILC_BLOCKED_ID "blocked" "#e11d48"; }
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# issue_claim — add "in-progress" label, remove "backlog" label.
|
# issue_claim — assign issue to bot, add "in-progress" label, remove "backlog".
|
||||||
# Args: issue_number
|
# Args: issue_number
|
||||||
|
# Returns: 0 on success, 1 if already assigned to another agent
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
issue_claim() {
|
issue_claim() {
|
||||||
local issue="$1"
|
local issue="$1"
|
||||||
|
|
||||||
|
# Get current bot identity
|
||||||
|
local me
|
||||||
|
me=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
"${FORGE_URL}/api/v1/user" | jq -r '.login') || return 1
|
||||||
|
|
||||||
|
# Check current assignee
|
||||||
|
local current
|
||||||
|
current=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
"${FORGE_API}/issues/${issue}" | jq -r '.assignee.login // ""') || return 1
|
||||||
|
|
||||||
|
if [ -n "$current" ] && [ "$current" != "$me" ]; then
|
||||||
|
_ilc_log "issue #${issue} already assigned to ${current} — skipping"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Assign to self (Forgejo rejects if already assigned differently)
|
||||||
|
curl -sf -X PATCH \
|
||||||
|
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${FORGE_API}/issues/${issue}" \
|
||||||
|
-d "{\"assignees\":[\"${me}\"]}" >/dev/null 2>&1 || return 1
|
||||||
|
|
||||||
local ip_id bl_id
|
local ip_id bl_id
|
||||||
ip_id=$(_ilc_in_progress_id)
|
ip_id=$(_ilc_in_progress_id)
|
||||||
bl_id=$(_ilc_backlog_id)
|
bl_id=$(_ilc_backlog_id)
|
||||||
|
|
@ -102,14 +126,23 @@ issue_claim() {
|
||||||
"${FORGE_API}/issues/${issue}/labels/${bl_id}" >/dev/null 2>&1 || true
|
"${FORGE_API}/issues/${issue}/labels/${bl_id}" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
_ilc_log "claimed issue #${issue}"
|
_ilc_log "claimed issue #${issue}"
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# issue_release — remove "in-progress" label, add "backlog" label.
|
# issue_release — remove "in-progress" label, add "backlog" label, clear assignee.
|
||||||
# Args: issue_number
|
# Args: issue_number
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
issue_release() {
|
issue_release() {
|
||||||
local issue="$1"
|
local issue="$1"
|
||||||
|
|
||||||
|
# Clear assignee
|
||||||
|
curl -sf -X PATCH \
|
||||||
|
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${FORGE_API}/issues/${issue}" \
|
||||||
|
-d '{"assignees":[]}' >/dev/null 2>&1 || true
|
||||||
|
|
||||||
local ip_id bl_id
|
local ip_id bl_id
|
||||||
ip_id=$(_ilc_in_progress_id)
|
ip_id=$(_ilc_in_progress_id)
|
||||||
bl_id=$(_ilc_backlog_id)
|
bl_id=$(_ilc_backlog_id)
|
||||||
|
|
@ -184,11 +217,19 @@ issue_block() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# issue_close — PATCH state to closed.
|
# issue_close — clear assignee, PATCH state to closed.
|
||||||
# Args: issue_number
|
# Args: issue_number
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
issue_close() {
|
issue_close() {
|
||||||
local issue="$1"
|
local issue="$1"
|
||||||
|
|
||||||
|
# Clear assignee before closing
|
||||||
|
curl -sf -X PATCH \
|
||||||
|
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${FORGE_API}/issues/${issue}" \
|
||||||
|
-d '{"assignees":[]}' >/dev/null 2>&1 || true
|
||||||
|
|
||||||
curl -sf -X PATCH \
|
curl -sf -X PATCH \
|
||||||
-H "Authorization: token ${FORGE_TOKEN}" \
|
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue