From 07270f3d2dde8fca20407bae8390b2c9e60f59db Mon Sep 17 00:00:00 2001 From: Jonathan Langevin Date: Sun, 7 Jun 2026 15:49:52 -0400 Subject: [PATCH] fix: admin-merge wfctl update PRs --- .github/workflows/update-wfctl.yml | 70 ++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-wfctl.yml b/.github/workflows/update-wfctl.yml index 2197b75..10d86c5 100644 --- a/.github/workflows/update-wfctl.yml +++ b/.github/workflows/update-wfctl.yml @@ -90,7 +90,7 @@ jobs: - name: Open update pull request env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.RELEASES_TOKEN || github.token }} VERSION: ${{ github.event.client_payload.version }} run: | set -euo pipefail @@ -118,5 +118,69 @@ jobs: PR_NUMBER="${PR_URL##*/}" fi - gh pr merge "$PR_NUMBER" --auto --squash --delete-branch || \ - echo "Auto-merge unavailable; update PR ${PR_NUMBER} remains open." + gh pr edit "$PR_NUMBER" --add-reviewer copilot-pull-request-reviewer || true + if ! gh pr merge "$PR_NUMBER" --auto --squash --delete-branch; then + echo "::warning::Auto-merge unavailable for wfctl update PR #${PR_NUMBER}; will poll checks and admin-merge." + fi + + review_threads_query="$(cat <<'GRAPHQL' + query($owner:String!, $repo:String!, $number:Int!, $cursor:String) { + repository(owner:$owner, name:$repo) { + pullRequest(number:$number) { + reviewThreads(first:100, after:$cursor) { + nodes { isResolved } + pageInfo { hasNextPage endCursor } + } + } + } + } + GRAPHQL + )" + for attempt in $(seq 1 60); do + pr_state="$(gh pr view "$PR_NUMBER" --json state --jq .state)" + [ "$pr_state" != "MERGED" ] || exit 0 + + if ! checks="$(gh pr checks "$PR_NUMBER" --json name,bucket,state,link 2>/dev/null)"; then + echo "wfctl update PR #${PR_NUMBER}: checks not available yet; poll ${attempt}/60" + sleep 20 + continue + fi + total_checks="$(jq 'length' <<< "$checks")" + if [ "$total_checks" = "0" ]; then + echo "wfctl update PR #${PR_NUMBER}: no checks attached yet; poll ${attempt}/60" + sleep 20 + continue + fi + failed="$(jq '[.[] | select(.bucket == "fail")] | length' <<< "$checks")" + pending="$(jq '[.[] | select(.bucket == "pending")] | length' <<< "$checks")" + if [ "$failed" != "0" ]; then + jq -r '.[] | select(.bucket == "fail") | [.name,.state,.link] | @tsv' <<< "$checks" + exit 1 + fi + if [ "$pending" = "0" ]; then + unresolved_threads=0 + cursor="" + while :; do + args=(-f owner="${GITHUB_REPOSITORY_OWNER}" -f repo="${GITHUB_REPOSITORY#*/}" -F number="$PR_NUMBER" -f query="$review_threads_query") + if [ -n "$cursor" ]; then + args+=(-f cursor="$cursor") + fi + thread_page="$(gh api graphql "${args[@]}")" + page_unresolved="$(jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length' <<< "$thread_page")" + unresolved_threads=$((unresolved_threads + page_unresolved)) + has_next="$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage' <<< "$thread_page")" + [ "$has_next" = "true" ] || break + cursor="$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor' <<< "$thread_page")" + done + if [ "$unresolved_threads" != "0" ]; then + echo "::warning::wfctl update PR #${PR_NUMBER} has unresolved review threads; leaving it open." + exit 0 + fi + gh pr merge "$PR_NUMBER" --squash --admin --delete-branch + exit 0 + fi + echo "wfctl update PR #${PR_NUMBER}: checks pending (${pending}); poll ${attempt}/60" + sleep 20 + done + echo "::error::Timed out waiting for wfctl update PR #${PR_NUMBER} checks." + exit 1