Commit Queue #254323
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This action requires the following secrets to be set on the repository: | |
| # GH_USER_TOKEN: GitHub user token, to be used by ncu and to push changes | |
| # JENKINS_USER: GitHub user whose Jenkins token is defined below | |
| # JENKINS_TOKEN: Jenkins token, to be used to check CI status | |
| name: Commit Queue | |
| on: | |
| # `schedule` event is used instead of `pull_request` because when a | |
| # `pull_request` event is triggered on a PR from a fork, GITHUB_TOKEN will | |
| # be read-only, and the Action won't have access to any other repository | |
| # secrets, which it needs to access Jenkins API. | |
| schedule: | |
| - cron: '*/5 * * * *' | |
| concurrency: ${{ github.workflow }} | |
| env: | |
| NODE_VERSION: lts/* | |
| permissions: | |
| contents: read | |
| jobs: | |
| get_candidate_prs: | |
| permissions: | |
| pull-requests: read | |
| if: github.repository == 'nodejs/node' | |
| runs-on: ubuntu-slim | |
| outputs: | |
| candidates: ${{ steps.get_candidate_prs.outputs.candidates }} | |
| steps: | |
| - name: Get Pull Request Candidates | |
| id: get_candidate_prs | |
| run: | | |
| list_prs() { | |
| gh pr list \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --base "$GITHUB_REF_NAME" \ | |
| --label 'commit-queue' \ | |
| "$@" \ | |
| --json 'number' \ | |
| -t '{{ range . }}{{ .number }} {{ end }}' \ | |
| --limit 100 | |
| } | |
| aged_prs=$(list_prs \ | |
| --search "created:<=$(date --date="2 days ago" +"%Y-%m-%dT%H:%M:%S%z") -label:blocked") | |
| fast_track_prs=$(list_prs \ | |
| --label 'fast-track' \ | |
| --search "-label:blocked") | |
| queued_prs=$(list_prs \ | |
| --search "-label:blocked") | |
| candidates=$(printf '%s %s %s\n' "$aged_prs" "$fast_track_prs" "$queued_prs" | | |
| jq -r -s 'reduce .[] as $pr ([]; if index($pr) then . else . + [$pr] end) | join(" ")') | |
| echo "candidates=$candidates" >> "$GITHUB_OUTPUT" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| commitQueue: | |
| needs: get_candidate_prs | |
| if: needs.get_candidate_prs.outputs.candidates != '' | |
| runs-on: ubuntu-slim | |
| steps: | |
| # Install dependencies | |
| - name: Install Node.js | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install @node-core/utils | |
| run: npm install -g @node-core/utils | |
| - name: Set variables | |
| run: | | |
| echo "REPOSITORY=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)" >> "$GITHUB_ENV" | |
| - name: Configure @node-core/utils | |
| run: | | |
| # Keep the config outside the workspace so checkout does not remove it. | |
| ncu-config --global set branch "${GITHUB_REF_NAME}" | |
| ncu-config --global set upstream origin | |
| ncu-config --global set username "$USERNAME" | |
| ncu-config --global set token "$GITHUB_TOKEN" | |
| ncu-config --global set jenkins_token "$JENKINS_TOKEN" | |
| ncu-config --global set repo "${REPOSITORY}" | |
| ncu-config --global set owner "${GITHUB_REPOSITORY_OWNER}" | |
| env: | |
| USERNAME: ${{ secrets.JENKINS_USER }} | |
| GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} | |
| JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }} | |
| - name: Filter Pull Requests | |
| id: get_mergeable_prs | |
| run: | | |
| readme="${RUNNER_TEMP}/README.md" | |
| curl -fsSLo "$readme" "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/README.md" | |
| numbers= | |
| # shellcheck disable=SC2086 | |
| for pr in $CANDIDATES; do | |
| metadata="${RUNNER_TEMP}/metadata-${pr}.json" | |
| output="${RUNNER_TEMP}/metadata-${pr}.txt" | |
| if git node metadata "$pr" \ | |
| --owner "$GITHUB_REPOSITORY_OWNER" \ | |
| --repo "$REPOSITORY" \ | |
| --readme "$readme" \ | |
| --json > "$metadata" 2> "$output"; then | |
| metadata_status=0 | |
| else | |
| metadata_status=$? | |
| fi | |
| if [ -s "$output" ]; then | |
| cat "$output" | |
| fi | |
| case "$metadata_status" in | |
| 0|2[0-9]|4[0-9]) ;; | |
| *) | |
| echo "git node metadata failed for pr ${pr} with exit code ${metadata_status}" | |
| exit 1 | |
| ;; | |
| esac | |
| metadata_exit_code=$(jq -r '.exitCode' "$metadata") || { | |
| echo "failed to parse metadata JSON for pr ${pr}" | |
| exit 1 | |
| } | |
| if [ "$metadata_exit_code" != "$metadata_status" ]; then | |
| echo "metadata JSON exitCode mismatch for pr ${pr}" | |
| exit 1 | |
| fi | |
| metadata_reason_codes=$(jq -r '.reasonCodes | join(", ")' "$metadata") || { | |
| echo "failed to parse metadata reason codes for pr ${pr}" | |
| exit 1 | |
| } | |
| if [ "$metadata_status" -eq 0 ]; then | |
| echo "pr ${pr} is ready for the commit queue" | |
| numbers="$numbers $pr" | |
| continue | |
| fi | |
| if [ "$metadata_status" -ge 20 ] && [ "$metadata_status" -le 29 ]; then | |
| echo "pr ${pr} skipped, not ready to land" | |
| echo "reason codes: ${metadata_reason_codes}" | |
| continue | |
| fi | |
| echo "pr ${pr} will be handled by the commit queue" | |
| echo "reason codes: ${metadata_reason_codes}" | |
| numbers="$numbers $pr" | |
| done | |
| numbers=$(echo "$numbers" | xargs) | |
| echo "numbers=$numbers" >> "$GITHUB_OUTPUT" | |
| env: | |
| CANDIDATES: ${{ needs.get_candidate_prs.outputs.candidates }} | |
| GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| if: steps.get_mergeable_prs.outputs.numbers != '' | |
| with: | |
| # A personal token is required because pushing with GITHUB_TOKEN will | |
| # prevent commits from running CI after they land. It needs | |
| # to be set here because `checkout` configures GitHub authentication | |
| # for push as well. | |
| token: ${{ secrets.GH_USER_TOKEN }} | |
| - name: Start the Commit Queue | |
| if: steps.get_mergeable_prs.outputs.numbers != '' | |
| run: ./tools/actions/commit-queue.sh "${GITHUB_REPOSITORY_OWNER}" "${REPOSITORY}" ${{ steps.get_mergeable_prs.outputs.numbers }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} |