Files
AnyPS5/.github/workflows/pr-intake.yml
T
Adrià FranchandClaude 14f585a439 ci(pr): limit open pull requests by the author's merged count
Authors with no merged pull requests can have 1 open, with at least 1
merged 20, and from 20 merged there is no limit. Reopening a pull
request runs the check again.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 11:28:43 +02:00

78 lines
3.5 KiB
YAML

name: PR intake
on:
pull_request_target:
branches: [main]
types: [opened, reopened]
permissions: {}
concurrency:
group: pr-intake-${{ github.event.pull_request.number }}
jobs:
intake:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/github-script@v8
with:
script: |
const { owner, repo } = context.repo;
const pull_number = context.payload.pull_request.number;
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
if (pr.state !== 'open' || pr.base.ref !== 'main') {
return;
}
const { data: mergedPRs } = await github.rest.search.issuesAndPullRequests({
q: `repo:${owner}/${repo} is:pr is:merged base:main author:${pr.user.login}`,
per_page: 1
});
if (mergedPRs.incomplete_results || !Number.isSafeInteger(mergedPRs.total_count) || mergedPRs.total_count < 0) {
throw new Error('Could not reliably count merged pull requests');
}
const merged = mergedPRs.total_count;
if (merged >= 20) {
return;
}
const allowedOpen = merged >= 1 ? 20 : 1;
const openPRs = await github.paginate(github.rest.pulls.list, {
owner, repo, state: 'open', base: 'main', per_page: 100
});
const open = new Set(openPRs.filter((p) => p.user.login === pr.user.login).map((p) => p.number));
open.add(pull_number);
if (open.size <= allowedOpen) {
return;
}
const name = 'open PR limit';
try {
await github.rest.issues.getLabel({ owner, repo, name });
} catch (error) {
if (error.status !== 404) {
throw error;
}
try {
await github.rest.issues.createLabel({
owner, repo, name, color: 'd93f0b',
description: 'Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20'
});
} catch (createError) {
if (createError.status !== 422) {
throw createError;
}
await github.rest.issues.getLabel({ owner, repo, name });
}
}
await github.rest.issues.addLabels({ owner, repo, issue_number: pull_number, labels: [name] });
const body = 'Thank you for your contribution! Authors with no pull requests merged into `main` can have 1 open pull request at a time, authors with at least 1 merged can have 20, and from 20 merged there is no limit. This PR has been automatically closed and labeled "open PR limit" because that limit was reached. This is not a judgment of the quality of your changes: reopen it once one of your open pull requests is merged or closed.';
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number: pull_number, per_page: 100
});
if (!comments.some((comment) => comment.user.login === 'github-actions[bot]' && comment.body === body)) {
await github.rest.issues.createComment({ owner, repo, issue_number: pull_number, body });
}
await github.rest.pulls.update({ owner, repo, pull_number, state: 'closed' });