diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 703f7ecee..f7090fa24 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -24,7 +24,7 @@ jobs: force_label() { gh label create "$1" --color "$2" --description "$3" --force; } force_label 'needs rebase' b60205 'Conflicts with main, rebase needed' - force_label 'intake paused' d93f0b 'Closed while PR intake is limited to authors with at least 10 PRs merged into main' + force_label 'open PR limit' d93f0b 'Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20' force_label ci 5319e7 '.github' force_label agc 1d76db 'libSceAgc*' force_label shader 1d76db 'core/shader' diff --git a/.github/workflows/pr-intake.yml b/.github/workflows/pr-intake.yml index c45ffe04c..6ae30f8b5 100644 --- a/.github/workflows/pr-intake.yml +++ b/.github/workflows/pr-intake.yml @@ -3,7 +3,7 @@ name: PR intake on: pull_request_target: branches: [main] - types: [opened] + types: [opened, reopened] permissions: {} @@ -27,7 +27,6 @@ jobs: if (pr.state !== 'open' || pr.base.ref !== 'main') { return; } - const minimumMergedPRs = 10; 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 @@ -35,10 +34,20 @@ jobs: if (mergedPRs.incomplete_results || !Number.isSafeInteger(mergedPRs.total_count) || mergedPRs.total_count < 0) { throw new Error('Could not reliably count merged pull requests'); } - if (mergedPRs.total_count >= minimumMergedPRs) { + const merged = mergedPRs.total_count; + if (merged >= 20) { return; } - const name = 'intake paused'; + 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) { @@ -48,7 +57,7 @@ jobs: try { await github.rest.issues.createLabel({ owner, repo, name, color: 'd93f0b', - description: 'Closed while PR intake is limited to authors with at least 10 PRs merged into main' + 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) { @@ -58,7 +67,7 @@ jobs: } } await github.rest.issues.addLabels({ owner, repo, issue_number: pull_number, labels: [name] }); - const body = 'Thank you for your interest in the project! We are sorry, but we cannot accept more PRs while we work through the existing backlog. This PR has been automatically closed and labeled "intake paused". This is not a judgment of the quality of your changes.'; + 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 }); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c85c888c6..570f87604 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,6 +50,7 @@ python3 tools/check_conventions.py --base origin/main The [pull request template](.github/pull_request_template.md) is the checklist for these rules. - One branch per topic, based on current `main`. Follow-up work goes in a new pull request, not into an open one. +- Open pull requests per author are limited by how many of theirs are merged into `main`: 1 with none merged, 20 with at least 1, no limit from 20. A pull request opened or reopened over the limit is closed automatically; reopen it once another one is merged or closed. - Before starting, check that no open pull request already implements the same functions. - Keep the branch up to date with `main` and resolve conflicts yourself; rebasing and force-pushing is fine. - If a pull request needs another one first, say so in the description (`Depends on #N`).