Skip to content

Commit f1c4b86

Browse files
Enforce single commit PRs
1 parent 0278577 commit f1c4b86

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# .github/workflows/pr-single-commit-up-to-date.yml
2+
name: Enforce single commit & up-to-date
3+
4+
on:
5+
pull_request:
6+
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
7+
pull_request_target:
8+
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
9+
10+
permissions:
11+
contents: read
12+
pull-requests: write
13+
14+
jobs:
15+
check-ahead-behind:
16+
if: ${{ !github.event.pull_request.draft }}
17+
runs-on: ubuntu-22.04
18+
steps:
19+
- name: Checkout PR HEAD (full history)
20+
uses: actions/checkout@v4
21+
with:
22+
ref: ${{ github.event.pull_request.head.sha }}
23+
fetch-depth: 0
24+
25+
- name: Fetch base branch
26+
run: |
27+
git fetch origin ${{ github.event.pull_request.base.ref }}
28+
29+
- name: Compute ahead/behind
30+
id: ab
31+
shell: bash
32+
run: |
33+
BASE_SHA=${{ github.event.pull_request.base.sha }}
34+
read BEHIND AHEAD < <(git rev-list --left-right --count ${BASE_SHA}...HEAD)
35+
echo "head=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
36+
echo "base=${BASE_SHA}" >> $GITHUB_OUTPUT
37+
echo "behind=$BEHIND" >> $GITHUB_OUTPUT
38+
echo "ahead=$AHEAD" >> $GITHUB_OUTPUT
39+
echo "Behind: $BEHIND, Ahead: $AHEAD"
40+
41+
- name: Enforce rule
42+
shell: bash
43+
run: |
44+
BASE=${{ steps.ab.outputs.base }}
45+
HEAD=${{ steps.ab.outputs.head}}
46+
BEHIND=${{ steps.ab.outputs.behind }}
47+
AHEAD=${{ steps.ab.outputs.ahead }}
48+
if [[ "$BEHIND" -ne 0 || "$AHEAD" -ne 1 ]]; then
49+
echo "PR must be exactly 1 commit ahead and 0 behind the base branch."
50+
echo "base=$BASE, HEAD=$HEAD"
51+
echo "Ahead=$AHEAD, Behind=$BEHIND"
52+
echo "Rebase and squash to fix."
53+
exit 1
54+
fi
55+
echo "OK: PR is exactly 1 ahead and 0 behind."
56+
57+
- name: Convert PR to draft on failure (base repo context)
58+
if: failure()
59+
uses: actions/github-script@v7
60+
with:
61+
script: |
62+
const pr = context.payload.pull_request;
63+
if (!pr) {
64+
core.setFailed('No pull_request context available.');
65+
} else if (pr.draft) {
66+
core.info('PR is already in draft.');
67+
} else {
68+
await github.request('POST /repos/{owner}/{repo}/pulls/{pull_number}/convert-to-draft', {
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
pull_number: pr.number,
72+
headers: { 'X-GitHub-Api-Version': '2022-11-28' }
73+
});
74+
core.info(`Converted PR #${pr.number} to draft.`);
75+
}

0 commit comments

Comments
 (0)