Skip to content

Repo sync

Repo sync #537

name: Check for Spammy PRs

Check warning on line 1 in .github/workflows/check-for-spammy-prs.yml

View workflow run for this annotation

GitHub Actions / Check for Spammy PRs

Workflow execution policy warning (evaluate mode)

On December 2, 2026, GitHub will restrict `pull_request_target` on public repositories by default. To continue allowing the event trigger, configure an Actions policy. Learn more: https://gh.io/securely-using-pull_request_target#default-policy-for-pull_request_target
# Flags low-value public PRs and closes PRs that target branches other than main.
on:
pull_request_target:
types: [opened, edited, reopened, synchronize]
permissions:
contents: read
issues: read
pull-requests: write
jobs:
spammy-pr-check:
name: Label spammy PRs and reject non-main targets
if: >
github.repository == 'github/docs' && github.event_name == 'pull_request_target' &&
github.event.pull_request.user.login != 'docs-bot'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const owner = 'github'
const repo = 'docs'
const pull_number = context.payload.pull_request.number
const targetsNonMain = context.payload.pull_request.base.ref !== 'main'
const files = await github.paginate(github.rest.pulls.listFiles, {
owner,
repo,
pull_number,
per_page: 100,
})
const onlyDeletes = files.length > 0 && files.every(f => f.status === 'removed')
const onlyDeletesLines =
files.some(file => file.deletions > 0) &&
files.every(file => file.additions === 0)
const isEmptyCommit = !files.length
const touchesTooMany = files.length > 10
const isBlankLineEdit = files.length > 0 && files.every(file => {
const changedLines = (file.patch || '')
.split('\n')
.filter(line => /^[+-]/.test(line))
return changedLines.length > 0 &&
changedLines.every(line => line.slice(1).trim() === '')
})
const onlyRenames = files.length > 0 && files.every(
f => f.status === 'renamed' && f.additions === 0 && f.deletions === 0
)
const onlyIndexMd = files.length === 1 && files[0].filename.split('/').pop() === 'index.md'
// Content removals are allowed once the Docs team marks the linked issue `help wanted`.
let hasApprovedIssue = false
if (onlyDeletesLines || onlyDeletes) {
try {
const { repository } = await github.graphql(
`query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
closingIssuesReferences(first: 100) {
nodes {
repository {
nameWithOwner
}
labels(first: 100) {
nodes {
name
}
}
}
}
}
}
}`,
{ owner, repo, number: pull_number },
)
const closingIssues = repository?.pullRequest?.closingIssuesReferences?.nodes || []
// Issues in other repos don't count, since their owners can add the label themselves.
hasApprovedIssue = closingIssues.some(issue =>
issue.repository?.nameWithOwner?.toLowerCase() === `${owner}/${repo}` &&
issue.labels.nodes.some(label => label.name.toLowerCase() === 'help wanted'),
)
} catch (error) {
// Without the lookup, treat the removal as unapproved, as before.
core.warning(`Could not check linked issues: ${error.message}`)
}
}
const unapprovedLineDeletion = onlyDeletesLines && !hasApprovedIssue
const unapprovedFileDeletion = onlyDeletes && !hasApprovedIssue
if (
targetsNonMain ||
unapprovedLineDeletion ||
unapprovedFileDeletion ||
isEmptyCommit ||
touchesTooMany ||
isBlankLineEdit ||
onlyRenames ||
onlyIndexMd
) {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: pull_number,
labels: ['invalid'],
})
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull_number,
body: targetsNonMain
? 'Pull requests must target the `main` branch. This pull request has been closed as invalid. If you think this is incorrect, please mention this in a corresponding issue.'
: unapprovedLineDeletion
? 'This pull request only removes existing content. Before submitting a content-removal pull request, please [open an issue](https://github.com/github/docs/issues/new/choose) explaining the proposed removal and wait for the GitHub Docs team to add the `help wanted` label to it. Once the issue has the `help wanted` label, you can open a new pull request that links the issue with `Closes: #<issue number>` in the description.'
: "This pull request may have been opened accidentally. I'm going to close it now, but feel free to check out our [contribution guidelines](https://docs.github.com/en/contributing), or raise an issue.",
})
if (targetsNonMain) {
await github.rest.pulls.update({
owner,
repo,
pull_number,
state: 'closed',
})
}
if (unapprovedLineDeletion) {
core.setFailed(
'This pull request only deletes lines. An approved issue is required first.',
)
}
}