From f1718a56c80e471bfe55e17204b597a712895ad6 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 25 Aug 2026 12:34:44 +0200 Subject: [PATCH] tools: label PRs lacking second approval Signed-off-by: Filip Skokan --- .github/workflows/commit-queue.yml | 27 ++++++++++++++++++++ doc/contributing/commit-queue.md | 7 ++++-- tools/actions/commit-queue.sh | 40 +++++++++++++++++++++++++++--- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/.github/workflows/commit-queue.yml b/.github/workflows/commit-queue.yml index a1d691e9e19f..c44ccc48d2fd 100644 --- a/.github/workflows/commit-queue.yml +++ b/.github/workflows/commit-queue.yml @@ -28,6 +28,7 @@ jobs: if: github.repository == 'nodejs/node' runs-on: ubuntu-slim outputs: + aged_prs: ${{ steps.get_candidate_prs.outputs.aged_prs }} candidates: ${{ steps.get_candidate_prs.outputs.candidates }} steps: - name: Get Pull Request Candidates @@ -50,6 +51,7 @@ jobs: --search "-label:blocked") candidates=$(printf '%s %s\n' "$fast_track_prs" "$aged_prs" | jq -r -s 'reduce .[] as $pr ([]; if index($pr) then . else . + [$pr] end) | join(" ")') + echo "aged_prs=$aged_prs" >> "$GITHUB_OUTPUT" echo "candidates=$candidates" >> "$GITHUB_OUTPUT" env: GH_TOKEN: ${{ github.token }} @@ -93,6 +95,7 @@ jobs: curl -fsSLo "$readme" "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/README.md" numbers= + lacks_second_approval_prs= # shellcheck disable=SC2086 for pr in $CANDIDATES; do metadata="${RUNNER_TEMP}/metadata-${pr}.json" @@ -139,6 +142,14 @@ jobs: if [ "$metadata_status" -ge 20 ] && [ "$metadata_status" -le 29 ]; then echo "pr ${pr} skipped, not ready to land" echo "reason codes: ${metadata_reason_codes}" + if jq -e ' + (.reasonCodes | index("wait-time")) and + (.pullRequest.labels | index("lacks-second-approval") | not) + ' "$metadata" > /dev/null; then + case " $AGED_PRS " in + *" $pr "*) lacks_second_approval_prs="$lacks_second_approval_prs $pr" ;; + esac + fi continue fi @@ -148,11 +159,27 @@ jobs: done numbers=$(echo "$numbers" | xargs) + lacks_second_approval_prs=$(echo "$lacks_second_approval_prs" | xargs) echo "numbers=$numbers" >> "$GITHUB_OUTPUT" + echo "lacks_second_approval_prs=$lacks_second_approval_prs" >> "$GITHUB_OUTPUT" env: + AGED_PRS: ${{ needs.get_candidate_prs.outputs.aged_prs }} CANDIDATES: ${{ needs.get_candidate_prs.outputs.candidates }} GH_TOKEN: ${{ github.token }} + - name: Label Pull Requests Lacking a Second Approval + if: steps.get_mergeable_prs.outputs.lacks_second_approval_prs != '' + run: | + # shellcheck disable=SC2086 + for pr in $PULL_REQUESTS; do + if ! gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label 'lacks-second-approval'; then + echo "::warning::Failed to add lacks-second-approval to PR ${pr}" + fi + done + env: + GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} + PULL_REQUESTS: ${{ steps.get_mergeable_prs.outputs.lacks_second_approval_prs }} + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 if: steps.get_mergeable_prs.outputs.numbers != '' with: diff --git a/doc/contributing/commit-queue.md b/doc/contributing/commit-queue.md index e9669bf33183..1cd35a32718d 100644 --- a/doc/contributing/commit-queue.md +++ b/doc/contributing/commit-queue.md @@ -8,8 +8,11 @@ landing process by automating it via GitHub Actions. With it, collaborators can queue pull requests for landing by adding the `commit-queue` label to a PR. The selector checks readiness with `@node-core/utils`. If the pull request is only blocked on a deferrable condition, currently wait time, the queue leaves the -label in place and retries later. Other failures continue to the existing -landing and failure-reporting path. +label in place and retries later. For pull requests that are at least two days +old and still waiting for a second approval, the queue adds the +`lacks-second-approval` label. The queue removes that label when it removes the +`commit-queue` label. Other failures continue to the existing landing and +failure-reporting path. To make the Commit Queue squash all the commits of a pull request into the first one, add the `commit-queue-squash` label. diff --git a/tools/actions/commit-queue.sh b/tools/actions/commit-queue.sh index 9fb74ed9cad8..e260773d14a5 100755 --- a/tools/actions/commit-queue.sh +++ b/tools/actions/commit-queue.sh @@ -7,6 +7,7 @@ DEFAULT_BRANCH=main COMMIT_QUEUE_LABEL="commit-queue" COMMIT_QUEUE_FAILED_LABEL="commit-queue-failed" +LACKS_SECOND_APPROVAL_LABEL="lacks-second-approval" cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}" @@ -24,11 +25,43 @@ escape_code_block_or_line() { printf '%s%s%s%s%s\n' "$fence" "$sep" "$1" "$sep" "$fence" } +edit_pr_labels() { + pr=$1 + failure_mode=$2 + shift 2 + if gh -R "$GITHUB_REPOSITORY" pr edit "$pr" "$@"; then + return + fi + if [ "$failure_mode" = warn ]; then + echo "::warning::Failed to update labels for PR $pr" + return + fi + return 1 +} + +remove_labels_if_present() { + pr=$1 + shift + labels= + for label in "$@"; do + if jq -e --arg label "$label" \ + 'map(.name) | index($label)' < labels.json > /dev/null; then + labels="${labels}${labels:+,}${label}" + fi + done + + if [ -n "$labels" ]; then + edit_pr_labels "$pr" warn --remove-label "$labels" + fi +} + commit_queue_failed() { pr=$1 reported_failure=${2:-} - gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "${COMMIT_QUEUE_FAILED_LABEL}" --remove-label "${COMMIT_QUEUE_LABEL}" + edit_pr_labels "$pr" required --add-label "$COMMIT_QUEUE_FAILED_LABEL" \ + --remove-label "$COMMIT_QUEUE_LABEL" + remove_labels_if_present "$pr" "$LACKS_SECOND_APPROVAL_LABEL" last_output_line=$(awk 'NF { line = $0 } END { sub(/^[[:space:]]*/, "", line); print line }' output) # shellcheck disable=SC2016 @@ -145,8 +178,9 @@ for pr in "$@"; do [ -z "$MULTIPLE_COMMIT_POLICY" ] && gh -R "$GITHUB_REPOSITORY" pr close "$pr" - # Delete the commit queue label (but ignore errors, it's no big deal if a closed PR still has the label) - gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$COMMIT_QUEUE_LABEL" || true + # Delete the commit queue labels (but ignore errors, it's no big deal if a closed PR still has them) + remove_labels_if_present "$pr" "$COMMIT_QUEUE_LABEL" \ + "$LACKS_SECOND_APPROVAL_LABEL" done rm -f labels.json