Skip to content

opper-ai/pr-gatory-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 

Repository files navigation

pr-gatory

A merge queue for GitHub Actions. PRs enter purgatory — only the worthy get merged.

No GitHub Enterprise required. No external services. Just a workflow.

What it does

Label a PR with mergeme and pr-gatory takes over:

  1. Rebases the PR onto the latest base branch
  2. Waits for all status checks to pass on the rebased code
  3. Squash merges into the base branch and deletes the source branch
  4. Dequeues with a PR comment explaining what went wrong if anything fails

Multiple PRs labeled at the same time? They all get processed. When a job starts, it scans for every open PR with the label and works through them in order — so even if several PRs are labeled while one is already being processed, they'll all be picked up by the time the queue drains.

Quick start

Create .github/workflows/merge-queue.yml in your repo:

name: Merge Queue

on:
  pull_request:
    types: [labeled]

concurrency:
  group: merge-queue
  cancel-in-progress: false

jobs:
  merge:
    if: github.event.label.name == 'mergeme'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      checks: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: opper-ai/pr-gatory-action@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

That's it. Label a PR with mergeme to try it out.

How the queue works

When triggered, the action scans for all open PRs carrying the label and processes them serially — oldest first. The concurrency block ensures only one job runs at a time, so a second trigger that arrives while the first job is busy will wait and then drain whatever remains in the queue when it starts.

PR #1 labeled  ─┐
PR #2 labeled  ─┤──>  job picks up #1, #2, #3 in order  ──>  all merged
PR #3 labeled  ─┘

Each PR rebases onto the base branch at the moment it's processed, which includes all previously merged PRs. This is the key property of a merge queue — no PR merges without being tested against the current state of the target branch.

What happens on failure

pr-gatory removes the mergeme label and leaves a comment on the PR explaining what went wrong:

Failure What pr-gatory does
Merge conflicts Removes from queue, comments to resolve conflicts
Rebase fails Removes from queue, comments to rebase manually
Status checks fail Removes from queue, comments to fix and re-label
Timeout (default 30 min) Removes from queue, comments to re-label
Squash merge rejected Removes from queue, comments about branch protection

To retry, fix the issue and add the mergeme label again.

Inputs

Input Description Default
github-token GitHub token with write access to contents and PRs ${{ github.token }}
label Label that adds a PR to the queue mergeme
poll-interval Seconds between status check polls 30
timeout Max seconds to wait for status checks 1800

Outputs

Output Description
result merged or failed — reflects the last PR processed in the queue

Custom label

- uses: opper-ai/pr-gatory-action@v1
  with:
    github-token: ${{ secrets.GITHUB_TOKEN }}
    label: 'ready-to-merge'

Update the if condition in the workflow to match:

if: github.event.label.name == 'ready-to-merge'

Token permissions

The default GITHUB_TOKEN works for repos without branch protection. If you have branch protection rules that restrict who can push or merge, you'll need a GitHub App token or fine-grained PAT with:

  • Contents: read and write (for rebase push)
  • Pull requests: read and write (for merge, labels, comments)
  • Checks: read (for polling CI status)

Job timeout

GitHub Actions jobs have a default timeout of 6 hours. If your queue is deep and CI is slow, the job may be cancelled mid-way. Increase the job timeout in your workflow if needed:

jobs:
  merge:
    timeout-minutes: 720  # 12 hours

PRs that weren't reached before the timeout will keep their label and be picked up by the next trigger.

Why not GitHub's built-in merge queue?

GitHub has a native merge queue, but it requires a GitHub Enterprise plan or public repos on Team/Free plans with specific configurations. pr-gatory gives you the same core behavior on any plan:

  • Serialized merges tested against the latest base branch
  • Automatic rebase before testing
  • Clear feedback on failures

And since it's just a workflow file and a composite action, you can read and modify every line of it.

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors