Skip to content
Draft
Show file tree
Hide file tree
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
27 changes: 27 additions & 0 deletions .github/workflows/commit-queue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }}
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand All @@ -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:
Expand Down
7 changes: 5 additions & 2 deletions doc/contributing/commit-queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
40 changes: 37 additions & 3 deletions tools/actions/commit-queue.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}"

Expand All @@ -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
Expand Down Expand Up @@ -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
Loading