#!/usr/bin/env bash # Failure-safe rescue: when a run FAILED after a dev agent already pushed commits, the normal # Publish step never ran and the work would be stranded on the branch with no PR (issue #33). # This opens a PR for the pushed branch so nothing is silently lost. It is strictly best-effort: # every failure here is swallowed (the caller also appends `|| true`) so it can never itself break # the run. Comment-only roles (pm/qa) push nothing, so they are skipped. # # Required env (provided by the workflow step): # GT TOKEN_PM TOKEN_INTERN TOKEN_SENIOR TOKEN_JUNIOR TOKEN_LEAD TOKEN_QA # NAME MODE NUM TITLE BRANCH GITHUB_SERVER_URL GITHUB_REPOSITORY set +e # Only dev agents (mode=pr) ever push a branch to rescue. [ "${MODE:-}" = "pr" ] || { echo "rescue: comment-mode agent, nothing to rescue"; exit 0; } [ -n "${BRANCH:-}" ] || { echo "rescue: no branch known, skipping"; exit 0; } # Post/PR as the agent's OWN Gitea user when its token is configured; else the built-in bot. case "$NAME" in pm) TOK="$TOKEN_PM";; intern) TOK="$TOKEN_INTERN";; senior) TOK="$TOKEN_SENIOR";; junior) TOK="$TOKEN_JUNIOR";; lead) TOK="$TOKEN_LEAD";; qa) TOK="$TOKEN_QA";; *) TOK="";; esac [ -z "$TOK" ] && TOK="$GT" API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" hdr=(-H "Authorization: token $TOK" -H "Content-Type: application/json") git fetch -q origin 2>/dev/null || true # Nothing to rescue unless the branch exists on the remote with commits beyond main. ahead=$(git rev-list --count "origin/main..origin/$BRANCH" 2>/dev/null || echo 0) if [ "${ahead:-0}" -eq 0 ]; then echo "rescue: no pushed commits on origin/$BRANCH beyond main โ€” nothing to rescue" exit 0 fi echo "rescue: origin/$BRANCH is $ahead commit(s) ahead of main โ€” ensuring a PR exists" # Idempotent: Gitea ignores ?head=, so match the head branch client-side. resp=$(curl -sS "${hdr[@]}" "$API/pulls?state=open&limit=50" \ | jq -r --arg br "$BRANCH" 'if type=="array" then (map(select(.head.ref==$br)) | .[0] // empty) else empty end' 2>/dev/null) url=$(printf '%s' "$resp" | jq -r '.html_url // empty' 2>/dev/null) if [ -z "$url" ]; then body=$(printf 'The run failed before it could publish, but pushed work exists on this branch โ€” opening a PR so it is not lost.\n\n---\nResolves #%s ยท ๐Ÿค– @%s (auto-rescued after a failed run)' "$NUM" "$NAME") resp=$(curl -sS -X POST "${hdr[@]}" "$API/pulls" \ -d "$(jq -nc --arg t "@$NAME: $TITLE" --arg h "$BRANCH" --arg b "$body" \ '{title:$t, head:$h, base:"main", body:$b}')") echo "rescue PR create ($BRANCH): $resp" url=$(printf '%s' "$resp" | jq -r '.html_url // empty' 2>/dev/null) fi if [ -n "$url" ]; then curl -sS -X POST "${hdr[@]}" "$API/issues/$NUM/comments" \ -d "$(jq -nc --arg b "$(printf '๐Ÿค– **@%s** โ€” โš ๏ธ the run failed, but your pushed work was not lost โ€” a PR was opened for branch \`%s\`:\n- %s' "$NAME" "$BRANCH" "$url")" '{body:$b}')" \ -w '\nrescue comment -> HTTP %{http_code}\n' || true else echo "rescue: could not open/find a PR for $BRANCH" fi exit 0