diff --git a/.github/workflows/pr-quota-limit.yml b/.github/workflows/pr-quota-limit.yml new file mode 100644 index 00000000000..4f21a942cc7 --- /dev/null +++ b/.github/workflows/pr-quota-limit.yml @@ -0,0 +1,103 @@ +name: PR Quota Limit + +on: + pull_request: + types: [opened, reopened] + +permissions: + pull-requests: write + issues: write + +jobs: + check-pr-quota: + runs-on: ubuntu-latest + steps: + - name: Check PR quota + uses: actions/github-script@v7 + with: + script: | + try { + const prAuthor = context.payload.pull_request.user.login; + const currentPRNumber = context.payload.pull_request.number; + + console.log(`Checking PR quota for user: ${prAuthor}`); + console.log(`Current PR number: ${currentPRNumber}`); + + // Get all open PRs with pagination support + let allPRs = []; + let page = 1; + let hasMorePages = true; + + while (hasMorePages) { + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100, + page: page + }); + + allPRs = allPRs.concat(prs); + + // If we got less than 100 PRs, we've reached the last page + if (prs.length < 100) { + hasMorePages = false; + } else { + page++; + } + } + + console.log(`Total open PRs in repository: ${allPRs.length}`); + + // Filter PRs by the same author + const userPRs = allPRs.filter(pr => pr.user.login === prAuthor); + const openCount = userPRs.length; + + console.log(`User ${prAuthor} has ${openCount} open PR(s)`); + + // Check if exceeds quota (15 PRs max) + const maxPRs = 15; + if (openCount > maxPRs) { + const availableSlots = 0; + const currentStatus = `${openCount}/${maxPRs}`; + + const message = `Hi, @${prAuthor}, Thanks for your contribution! To ensure quality reviews, we limit how many concurrent open PRs contributors can open. This pull request will be temporarily closed (Current status: ${currentStatus} open). We encourage you to submit a new PR once the quota policy permits future contributions.`; + + console.log(`Quota exceeded! Closing PR #${currentPRNumber}`); + console.log(`User has ${openCount} open PRs, which exceeds the limit of ${maxPRs}`); + console.log(`Message: ${message}`); + + // Add comment to the PR + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: currentPRNumber, + body: message + }); + console.log('Comment added successfully'); + } catch (commentError) { + console.error('Failed to add comment:', commentError.message); + } + + // Close the PR + try { + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: currentPRNumber, + state: 'closed' + }); + console.log(`PR #${currentPRNumber} has been closed due to quota limit.`); + } catch (closeError) { + console.error('Failed to close PR:', closeError.message); + throw closeError; // Re-throw to fail the workflow + } + } else { + const availableSlots = maxPRs - openCount; + console.log(`Quota check passed. User has ${availableSlots} slot(s) available.`); + } + } catch (error) { + console.error('Error in PR quota check:', error.message); + throw error; // Re-throw to fail the workflow + } \ No newline at end of file