Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/assign-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Assign PR

on:
pull_request_target:
types: [opened]

permissions:
issues: write
pull-requests: read

concurrency:
group: pr-assignee-rotation
cancel-in-progress: false

jobs:
assign:
runs-on: ubuntu-latest
steps:
- name: Assign PR in rotation
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_CREATED_AT: ${{ github.event.pull_request.created_at }}
ROTATION_START_AT: "2026-06-18T08:11:55Z"
run: |
set -euo pipefail

readonly USERS=(ilopezluna ericcurtin doringeman)
readonly BOT_LOGIN="github-actions[bot]"

next_assignee="${USERS[0]}"
page=1

while true; do
prs=$(gh api \
--method GET \
-H "Accept: application/vnd.github+json" \
"/repos/${REPO}/pulls" \
-f state=all \
-f sort=created \
-f direction=desc \
-f per_page=100 \
-f page="${page}")

count=$(jq 'length' <<<"${prs}")
if [ "${count}" -eq 0 ]; then
break
fi

while IFS=$'\t' read -r number created_at; do
if [[ "${number}" == "${PR_NUMBER}" ]]; then
continue
fi

if [[ "${created_at}" > "${PR_CREATED_AT}" || "${created_at}" == "${PR_CREATED_AT}" ]]; then
continue
fi

if [[ "${created_at}" < "${ROTATION_START_AT}" ]]; then
echo "Reached PRs created before rotation start; using ${next_assignee}."
break 2
fi

events=$(gh api \
--method GET \
-H "Accept: application/vnd.github+json" \
"/repos/${REPO}/issues/${number}/events" \
-f per_page=100)
Comment on lines +65 to +69

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Issue event pagination might miss older bot assignments on noisy PRs.

Because the /issues/{number}/events call is limited to 100 items and we don’t paginate, older bot assigned events on noisy PRs can be dropped, causing us to incorrectly fall back to next_assignee. Please either paginate until you’ve found the last bot assignment or use a query that reliably returns the latest relevant assignment (e.g., a targeted GraphQL query or iterating event pages until no more matches).


previous_assignee=$(jq -r \
--arg bot "${BOT_LOGIN}" \
--argjson users "$(printf '%s\n' "${USERS[@]}" | jq -R . | jq -s .)" \
'[.[] | select(.event == "assigned" and .actor.login == $bot and (.assignee.login as $login | $users | index($login)))][-1].assignee.login // empty' \
<<<"${events}")

if [[ -n "${previous_assignee}" ]]; then
for i in "${!USERS[@]}"; do
if [[ "${USERS[$i]}" == "${previous_assignee}" ]]; then
next_assignee="${USERS[$(((i + 1) % ${#USERS[@]}))]}"
echo "Previous rotated PR #${number} was assigned to ${previous_assignee}; assigning ${next_assignee}."
break 3
fi
done
fi
done < <(jq -r '.[] | [.number, .created_at] | @tsv' <<<"${prs}")

page=$((page + 1))
done

gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
"/repos/${REPO}/issues/${PR_NUMBER}/assignees" \
-f "assignees[]=${next_assignee}" >/dev/null

echo "Assigned PR #${PR_NUMBER} to ${next_assignee}."