Files
VoCat/.github/workflows/pr-size-limit.yml
T

193 lines
6.4 KiB
YAML

name: Pull request size limit
on:
pull_request_target:
branches:
- master
types:
- opened
- synchronize
- reopened
- ready_for_review
permissions:
contents: read
pull-requests: write
issues: write
concurrency:
group: pr-size-limit-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
enforce-size-limit:
# 保持这个名字不变,这样你 Ruleset 里的 Required Check 不需要修改
name: Enforce 5,000-line limit
runs-on: ubuntu-latest
timeout-minutes: 5
env:
MAX_CHANGED_LINES: "5000"
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ github.token }}
steps:
- name: Check conflicts and pull request size via GitHub API
shell: bash
run: |
set -euo pipefail
echo "Checking PR #${PR_NUMBER}"
############################################################
# Helper: comment on and close rejected PR
############################################################
reject_pr() {
local message="$1"
echo "::error::${message}"
COMMENT_PAYLOAD="$(
jq -nc \
--arg body "${message}" \
'{body: $body}'
)"
echo "Posting rejection comment..."
curl \
--fail-with-body \
--silent \
--show-error \
--request POST \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer ${GH_TOKEN}" \
--header "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--data "${COMMENT_PAYLOAD}" \
>/dev/null
echo "Closing PR #${PR_NUMBER}..."
curl \
--fail-with-body \
--silent \
--show-error \
--request PATCH \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer ${GH_TOKEN}" \
--header "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" \
--data '{"state":"closed"}' \
>/dev/null
exit 1
}
############################################################
# Fetch PR metadata from GitHub REST API
############################################################
echo "Fetching pull request metadata from GitHub API..."
PR_JSON=""
for attempt in {1..10}; do
PR_JSON="$(
curl \
--fail-with-body \
--silent \
--show-error \
--request GET \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer ${GH_TOKEN}" \
--header "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}"
)"
MERGEABLE="$(echo "${PR_JSON}" | jq -r '.mergeable')"
if [[ "${MERGEABLE}" != "null" ]]; then
break
fi
echo "Mergeable state is calculating, waiting 2s (attempt ${attempt}/10)..."
sleep 2
done
MERGEABLE="$(echo "${PR_JSON}" | jq -r '.mergeable')"
ADDITIONS="$(echo "${PR_JSON}" | jq -r '.additions // 0')"
DELETIONS="$(echo "${PR_JSON}" | jq -r '.deletions // 0')"
CHANGED_FILES="$(echo "${PR_JSON}" | jq -r '.changed_files // 0')"
CHANGED_LINES=$((ADDITIONS + DELETIONS))
############################################################
# STEP 1: Reject PRs with merge conflicts
############################################################
echo
echo "Checking for merge conflicts..."
if [[ "${MERGEABLE}" == "false" ]]; then
{
echo "### Pull request policy"
echo
echo "- Merge conflicts: ❌ Detected"
echo "- Result: Rejected"
} >> "${GITHUB_STEP_SUMMARY}"
reject_pr "This pull request has merge conflicts with the current master branch and cannot be accepted. Please update your branch with the latest master, resolve all merge conflicts locally, and submit a conflict-free pull request."
fi
echo "No merge conflicts detected (mergeable: ${MERGEABLE})."
############################################################
# Action summary
############################################################
{
echo "### Pull request policy"
echo
echo "- Merge conflicts: ✅ None"
echo "- Changed files: ${CHANGED_FILES}"
echo "- Additions: ${ADDITIONS}"
echo "- Deletions: ${DELETIONS}"
echo "- Total changed lines: ${CHANGED_LINES}"
echo "- Maximum allowed: ${MAX_CHANGED_LINES}"
} >> "${GITHUB_STEP_SUMMARY}"
echo
echo "Changed files: ${CHANGED_FILES}"
echo "Additions: ${ADDITIONS}"
echo "Deletions: ${DELETIONS}"
echo "Total changed lines: ${CHANGED_LINES}"
echo "Limit: ${MAX_CHANGED_LINES}"
############################################################
# STEP 2: Reject oversized PRs
############################################################
if (( CHANGED_LINES > MAX_CHANGED_LINES )); then
reject_pr "This pull request changes ${CHANGED_LINES} lines (${ADDITIONS} additions + ${DELETIONS} deletions) across ${CHANGED_FILES} files, exceeding the repository limit of ${MAX_CHANGED_LINES} changed lines. It has been closed automatically. Please split the changes into smaller pull requests."
fi
############################################################
# PASS
############################################################
echo
echo "Pull request passed all policy checks."
echo "No merge conflicts."
echo "Changed lines: ${CHANGED_LINES}/${MAX_CHANGED_LINES}."
{
echo
echo "### Result"
echo
echo "✅ Pull request passed."
} >> "${GITHUB_STEP_SUMMARY}"