Fix open pr count check (#6255)

This commit is contained in:
Evan Mattson
2026-06-02 09:09:36 +09:00
committed by GitHub
parent 5d98beddf5
commit c83a944e85
2 changed files with 69 additions and 36 deletions
+12 -9
View File
@@ -63,19 +63,22 @@ function buildLimitMessage({ author, exemptLabelName, maxOpenPrs, openPrCount })
}
async function getOpenPrCount({ github, owner, repo, author, pullRequestNumber }) {
const query = `repo:${owner}/${repo} is:pr is:open author:${author}`;
const response = await github.rest.search.issuesAndPullRequests({
q: query,
const openPullRequests = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
const indexedPrNumbers = response.data.items.map((item) => item.number);
const currentPrIsIndexed = indexedPrNumbers.includes(pullRequestNumber);
if (currentPrIsIndexed || response.data.total_count >= 100) {
return response.data.total_count;
}
const authorOpenPullRequestNumbers = openPullRequests
.filter((pullRequest) => pullRequest.user?.login === author)
.map((pullRequest) => pullRequest.number);
const currentPrIsOpen = authorOpenPullRequestNumbers.includes(pullRequestNumber);
const existingOpenPrCount = currentPrIsOpen
? authorOpenPullRequestNumbers.length - 1
: authorOpenPullRequestNumbers.length;
return response.data.total_count + 1;
return existingOpenPrCount + 1;
}
async function enforcePrLimit({ github, context, core, exemptLabelName, maxOpenPrs, labelName }) {
+57 -27
View File
@@ -44,23 +44,20 @@ function createCore() {
};
}
function createGithub({ totalCount, itemNumbers, labelExists = true }) {
function createGithub({
itemNumbers,
labelExists = true,
pullRequests = createPullRequestPage({ numbers: itemNumbers }),
}) {
const calls = [];
return {
calls,
async paginate(method, params) {
calls.push({ api: 'paginate', method, params });
return pullRequests;
},
rest: {
search: {
async issuesAndPullRequests(params) {
calls.push({ api: 'search.issuesAndPullRequests', params });
return {
data: {
total_count: totalCount,
items: itemNumbers.map((number) => ({ number })),
},
};
},
},
issues: {
async getLabel(params) {
calls.push({ api: 'issues.getLabel', params });
@@ -85,6 +82,10 @@ function createGithub({ totalCount, itemNumbers, labelExists = true }) {
},
},
pulls: {
async list(params) {
calls.push({ api: 'pulls.list', params });
return { data: pullRequests };
},
async update(params) {
calls.push({ api: 'pulls.update', params });
return { data: { state: params.state } };
@@ -94,6 +95,15 @@ function createGithub({ totalCount, itemNumbers, labelExists = true }) {
};
}
function createPullRequestPage({ author = 'community-user', numbers }) {
return numbers.map((number) => ({
number,
user: {
login: author,
},
}));
}
// ---------------------------------------------------------------------------
// PR limit enforcement
@@ -102,7 +112,6 @@ function createGithub({ totalCount, itemNumbers, labelExists = true }) {
describe('PR limit enforcement', () => {
it('does not close the PR when the author is at the open PR limit', async () => {
const github = createGithub({
totalCount: 10,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 123],
});
@@ -119,14 +128,13 @@ describe('PR limit enforcement', () => {
assert.equal(result.openPrCount, 10);
assert.deepEqual(
github.calls.map((call) => call.api),
['search.issuesAndPullRequests'],
['paginate'],
);
});
it('counts the new PR when search has not indexed it yet', async () => {
it('counts the new PR when the pull list includes it', async () => {
const github = createGithub({
totalCount: 10,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
itemNumbers: [123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
});
const result = await enforcePrLimit({
@@ -143,7 +151,7 @@ describe('PR limit enforcement', () => {
assert.deepEqual(
github.calls.map((call) => call.api),
[
'search.issuesAndPullRequests',
'paginate',
'issues.getLabel',
'issues.addLabels',
'issues.createComment',
@@ -152,9 +160,31 @@ describe('PR limit enforcement', () => {
);
});
it('counts the current PR on top of existing open PRs', async () => {
const github = createGithub({
itemNumbers: [123, ...Array.from({ length: 24 }, (_, index) => index + 1)],
pullRequests: createPullRequestPage({
numbers: [123, ...Array.from({ length: 25 }, (_, index) => index + 1)],
}),
});
const result = await enforcePrLimit({
github,
context: createContext(),
core: createCore(),
exemptLabelName: 'pr-limit-exempt',
maxOpenPrs: 10,
labelName: 'too-many-prs',
});
assert.equal(result.closed, true);
assert.equal(result.openPrCount, 26);
const comment = github.calls.find((call) => call.api === 'issues.createComment').params.body;
assert.match(comment, /This PR would put you at 26 open pull requests/);
});
it('creates the label when it does not already exist', async () => {
const github = createGithub({
totalCount: 11,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123],
labelExists: false,
});
@@ -172,7 +202,7 @@ describe('PR limit enforcement', () => {
assert.deepEqual(
github.calls.map((call) => call.api),
[
'search.issuesAndPullRequests',
'paginate',
'issues.getLabel',
'issues.createLabel',
'issues.addLabels',
@@ -188,7 +218,6 @@ describe('PR limit enforcement', () => {
it('tolerates a 422 race when creating the label', async () => {
const github = createGithub({
totalCount: 11,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123],
labelExists: false,
});
@@ -212,7 +241,7 @@ describe('PR limit enforcement', () => {
assert.deepEqual(
github.calls.map((call) => call.api),
[
'search.issuesAndPullRequests',
'paginate',
'issues.getLabel',
'issues.createLabel',
'issues.addLabels',
@@ -224,8 +253,11 @@ describe('PR limit enforcement', () => {
it('uses a diplomatic close message with the configured limit', async () => {
const github = createGithub({
totalCount: 11,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123],
pullRequests: createPullRequestPage({
author: 'octo-contributor',
numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123],
}),
});
await enforcePrLimit({
@@ -246,7 +278,6 @@ describe('PR limit enforcement', () => {
it('does not close an exempt PR when it is reopened', async () => {
const github = createGithub({
totalCount: 11,
itemNumbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123],
});
@@ -265,10 +296,9 @@ describe('PR limit enforcement', () => {
assert.deepEqual(github.calls, []);
});
it('does not over-count when the current PR is not on the first search page', async () => {
it('counts the current PR when the author has more than one page of open PRs', async () => {
const github = createGithub({
totalCount: 101,
itemNumbers: Array.from({ length: 100 }, (_, index) => index + 1),
itemNumbers: [123, ...Array.from({ length: 100 }, (_, index) => index + 1)],
});
const result = await enforcePrLimit({