GitHub Merge Queue #4406
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
| # Requires repo secret: PERSONAL_ACCESS_TOKEN with permissions: | |
| # Pull Requests: read and write | |
| # Workflow: read and write | |
| # This effectively creates a merge queue out of all PRs marked as auto-merge, but merge queues are | |
| # a GitHub feature is only available to organizations or those on Enterprise Cloud right now. | |
| # https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue | |
| name: GitHub Merge Queue | |
| on: | |
| # A PR merge has occurred, or a PR is no longer eligible for the queue; move on to the next PR | |
| pull_request_target: | |
| types: | |
| - closed | |
| - converted_to_draft | |
| - auto_merge_disabled | |
| # Jiggle the handle every hour just in case | |
| schedule: | |
| - cron: '0 * * * *' | |
| workflow_dispatch: | |
| env: | |
| renovate_rebase_label: 'renovate/rebase' | |
| jobs: | |
| # Update the oldest auto-merge PR that's out-of-date with the base branch | |
| update-pr-branch: | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Required for `gh` CLI | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| - run: | | |
| set -x | |
| pr_search="sort:created-asc" | |
| # Wait for the merge state status to be updated | |
| while true; do | |
| pr_list="$(gh pr list --search "${pr_search}" --json number,mergeable --jq '.[] | [.number, .mergeable] | @csv')" | |
| # No PRs found, so none can be in an 'UNKNOWN' state | |
| [[ "${pr_list}" == "" ]] && break | |
| # At least one PR is not in an 'UNKNOWN' state | |
| echo "${pr_list}" | grep -v "UNKNOWN" && break | |
| echo "$(echo "${pr_list}" | wc -l | awk '{print $1}') PRs in an 'UNKNOWN' mergeable state, waiting ..." | |
| sleep 5 | |
| done | |
| echo "PRs found:" | |
| gh pr list --search "${pr_search}" --json number,title,mergeable,mergeStateStatus,autoMergeRequest | jq | |
| eligible_prs="$(gh pr list --search "${pr_search}" --json number,isDraft,mergeable,mergeStateStatus,autoMergeRequest --jq '.[] | select(.isDraft==false and .mergeable=="MERGEABLE" and .mergeStateStatus=="BEHIND" and .autoMergeRequest!=null) | .number')" | |
| if [[ "${eligible_prs}" == "" ]]; then | |
| echo "No eligible PRs found" | |
| exit 0 | |
| fi | |
| echo "$(echo "${eligible_prs}" | wc -l | awk '{print $1}') eligible PRs found: $(echo "${eligible_prs}" | awk '{print $1}' | awk 'ORS=", "' | sed 's/, *$//')" | |
| while read -r number; do | |
| echo "Updating PR #${number}" | |
| gh pr update-branch "${number}" && break | |
| done <<< "${eligible_prs}" | |
| env: | |
| # GitHub won't run workflows off of code commits+pushes from the `github-actions` user | |
| GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} | |
| # Add a label to the oldest Renovate auto-merge PR that has conflicts, such that Renovate rebases it | |
| renovate-label-adder: | |
| permissions: | |
| # actions/checkout | |
| contents: read | |
| # `gh` CLI actions | |
| pull-requests: write | |
| issues: write | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Required for `gh` CLI | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| - run: | | |
| set -x | |
| author="app/renovate" | |
| pr_search="author:${author} sort:created-asc -label:${{ env.renovate_rebase_label }}" | |
| # Wait for the merge state status to be updated | |
| while true; do | |
| pr_list="$(gh pr list --search "${pr_search}" --json number,mergeable --jq '.[] | [.number, .mergeable] | @csv')" | |
| # No PRs found, so none can be in an 'UNKNOWN' state | |
| [[ "${pr_list}" == "" ]] && break | |
| # At least one PR is not in an 'UNKNOWN' state | |
| echo "${pr_list}" | grep -v "UNKNOWN" && break | |
| echo "$(echo "${pr_list}" | wc -l | awk '{print $1}') PRs in an 'UNKNOWN' mergeable state, waiting ..." | |
| sleep 5 | |
| done | |
| echo "Renovate PRs found:" | |
| gh pr list --search "${pr_search}" --json number,title,mergeable,mergeStateStatus,autoMergeRequest | jq | |
| eligible_prs="$(gh pr list --search "${pr_search}" --json number,isDraft,mergeable,autoMergeRequest --jq '.[] | select(.isDraft==false and .mergeable=="CONFLICTING" and .autoMergeRequest!=null) | .number')" | |
| if [[ "${eligible_prs}" == "" ]]; then | |
| echo "No eligible PRs found" | |
| exit 0 | |
| fi | |
| echo "$(echo "${eligible_prs}" | wc -l | awk '{print $1}') eligible PRs found: $(echo "${eligible_prs}" | awk '{print $1}' | awk 'ORS=", "' | sed 's/, *$//')" | |
| while read -r number; do | |
| echo "Adding label '${{ env.renovate_rebase_label }}' to PR #${number}" | |
| gh pr edit "${number}" --add-label "${{ env.renovate_rebase_label }}" && break | |
| done <<< "${eligible_prs}" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| renovate-label-remover: | |
| if: ${{ github.event_name == 'pull_request' }} | |
| permissions: | |
| # actions/checkout | |
| contents: read | |
| # `gh` CLI actions | |
| pull-requests: write | |
| issues: write | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Required for `gh` CLI | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| - run: | | |
| gh pr edit "${{ github.event.pull_request.number }}" --remove-label "${{ env.renovate_rebase_label }}" | |
| env: | |
| GH_TOKEN: ${{ github.token }} |