mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
pr-intake runs once per opened PR, and each run lists every open PR by the author. When an author opens several PRs within seconds, every run sees all of them and closes its own, so a newcomer opening two PRs at once loses both, and an author with one merge opening 21 loses all 21. On opened events the limit now counts only lower-numbered PRs, so the earliest ones stay open and only the PRs over the limit are closed. Reopened events still count every open PR, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zyXkUzTZGh3nBwNMtrLaW
81 lines
3.6 KiB
YAML
81 lines
3.6 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 reopened = context.payload.action === 'reopened';
|
|
const open = new Set(openPRs
|
|
.filter((p) => p.user.login === pr.user.login && (reopened || p.number < pull_number))
|
|
.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' });
|