GitHub Action that merges a pull-request when an event triggers the workflow. Written in Rust, runs as a Docker container action — no Node.js runtime needed on the runner.
Marketplace: https://github.com/marketplace/actions/pull-request-merge
| Name | Required | Default | Description |
|---|---|---|---|
github-token |
yes | — | GitHub token used to call the REST API. Usually ${{ secrets.GITHUB_TOKEN }}. |
number |
yes | — | Pull-request number to merge. |
merge-method |
no | merge |
One of merge, squash, rebase, fast-forward, fast-forward_or_merge. |
allowed-usernames-regex |
no | ^.*$ |
Regex the triggering actor (github.actor) must match. Skips the merge otherwise. |
filter-label |
no | (empty) | Regex matched against PR labels. When set, the merge is skipped unless a label matches, and the first matching label is removed after a successful merge. |
merge-title |
no | (empty) | Commit title used by the merge/squash/rebase API. Ignored for fast-forward. |
merge-message |
no | (empty) | Commit body used by the merge/squash/rebase API. Ignored for fast-forward. |
merge/squash/rebase— callPUT /repos/{owner}/{repo}/pulls/{n}/merge.fast-forward— callPATCH /repos/{owner}/{repo}/git/refs/heads/{base}to move the base branch to the PR's head SHA. This is a true fast-forward: the base ref must already be an ancestor of the head, otherwise GitHub refuses the update. No merge commit is created.fast-forward_or_merge— attempt a fast-forward first; if the base branch is not an ancestor of the head (i.e. the fast-forward fails), fall back to a regularmerge.
The workflow's GITHUB_TOKEN needs write access to both pull requests and
repository contents. Declare this explicitly at the top of your workflow:
permissions:
contents: write # merge / fast-forward the base branch
pull-requests: write # perform the merge and remove the filter labelname: auto-merge
on:
pull_request:
types: [labeled]
permissions:
contents: write
pull-requests: write
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: sudo-bot/action-pull-request-merge@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.pull_request.number }}
filter-label: merge-it
allowed-usernames-regex: ^williamdes$- uses: sudo-bot/action-pull-request-merge@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.pull_request.number }}
merge-method: squash
merge-title: "${{ github.event.pull_request.title }} (#${{ github.event.pull_request.number }})"
merge-message: ${{ github.event.pull_request.body }}- uses: sudo-bot/action-pull-request-merge@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.pull_request.number }}
merge-method: fast-forward
filter-label: merge-it- uses: sudo-bot/action-pull-request-merge@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.pull_request.number }}
allowed-usernames-regex: ^(williamdes|alice|bob)$
filter-label: ^(merge-it|ship-it)$The action performs these checks, in order, and logs what it's doing using
standard ::warning:: / ::error:: workflow commands:
- If
github.actordoes not matchallowed-usernames-regex, the step emits a warning and exits successfully (the workflow is not failed). - The PR is fetched. If its state is
closed, the step warns and exits. - If
filter-labelis set and no label on the PR matches, the step warns and exits. - The merge (or fast-forward) is performed.
- If
filter-labelwas set, the matching label is removed. A failure here produces a warning but does not fail the step.
Any network or API failure during step 4 does fail the step.