Skip to content

Enforce single commit PRs #26

Enforce single commit PRs

Enforce single commit PRs #26

# .github/workflows/pr-single-commit-up-to-date.yml
name: Enforce single commit & up-to-date
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
permissions:
contents: read
pull-requests: write
jobs:
check-ahead-behind:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-22.04
steps:
- name: Checkout PR HEAD (full history)
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Fetch base branch
run: |
git fetch origin ${{ github.event.pull_request.base.ref }}
- name: Compute ahead/behind
id: ab
shell: bash
run: |
BASE_SHA=${{ github.event.pull_request.base.sha }}
read BEHIND AHEAD < <(git rev-list --left-right --count ${BASE_SHA}...HEAD)
echo "head=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "base=${BASE_SHA}" >> $GITHUB_OUTPUT
echo "behind=$BEHIND" >> $GITHUB_OUTPUT
echo "ahead=$AHEAD" >> $GITHUB_OUTPUT
echo "Behind: $BEHIND, Ahead: $AHEAD"
- name: Enforce rule
shell: bash
run: |
BASE=${{ steps.ab.outputs.base }}
HEAD=${{ steps.ab.outputs.head}}
BEHIND=${{ steps.ab.outputs.behind }}
AHEAD=${{ steps.ab.outputs.ahead }}
if [[ "$BEHIND" -ne 0 || "$AHEAD" -ne 1 ]]; then
echo "PR must be exactly 1 commit ahead and 0 behind the base branch."
echo "base=$BASE, HEAD=$HEAD"
echo "Ahead=$AHEAD, Behind=$BEHIND"
echo "Rebase and squash to fix."
exit 1
fi
echo "OK: PR is exactly 1 ahead and 0 behind."
- name: Convert PR to draft on failure (base repo context)
if: failure()
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
if (!pr) {
core.setFailed('No pull_request context available.');
} else if (pr.draft) {
core.info('PR is already in draft.');
} else {
await github.request('POST /repos/{owner}/{repo}/pulls/{pull_number}/convert-to-draft', {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
headers: { 'X-GitHub-Api-Version': '2022-11-28' }
});
core.info(`Converted PR #${pr.number} to draft.`);
}