Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/check-for-spammy-prs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Check for Spammy PRs

# Flags low-value public PRs and closes PRs that target branches other than main.
# Maintainers add the skip-spammy-check label to exempt a PR.

on:
pull_request_target:
Expand All @@ -16,7 +17,8 @@ jobs:
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'
github.event.pull_request.user.login != 'docs-bot' &&
!contains(github.event.pull_request.labels.*.name, 'skip-spammy-check')
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
Expand Down Expand Up @@ -102,6 +104,18 @@ jobs:
onlyRenames ||
onlyIndexMd
) {
// The payload can predate a label added right after the PR opened, so read the labels again.
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: pull_number,
per_page: 100,
})
if (currentLabels.some(label => label.name.toLowerCase() === 'skip-spammy-check')) {
core.info('Skipping because the pull request has the skip-spammy-check label.')
return
}
await github.rest.issues.addLabels({
owner,
repo,
Expand Down
73 changes: 72 additions & 1 deletion .github/workflows/close-on-invalid-label.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ name: Close issue/PR on adding invalid label

# Closes public issues and PRs when the invalid label is added.
# Re-closes invalid PRs that someone without write access reopens.
# Reopens PRs closed as invalid when maintainers add the skip-spammy-check label.

on:
issues:
types: [labeled]
# pull_request_target lets the workflow close forked PRs when they're labeled invalid or reopened.
# pull_request_target lets the workflow close or reopen forked PRs when they're labeled or reopened.
pull_request_target:
types: [labeled, reopened]

Expand Down Expand Up @@ -71,3 +72,73 @@ jobs:
exit 0
fi
gh pr close "$PR_URL" --comment 'This pull request is labeled `invalid`, so only maintainers can reopen it. If you think this is incorrect, please mention this in a corresponding issue.'
# Maintainers add skip-spammy-check to recover a PR that automated checks closed as invalid.
reopen-on-adding-skip-label:
if: github.repository == 'github/docs' && github.event_name == 'pull_request_target' && github.event.label.name == 'skip-spammy-check'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
# A PAT makes the reopen trigger other workflows, such as triage, like a manual reopen.
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const { owner, repo } = context.repo
const pull_number = context.payload.pull_request.number
// The event payload can be stale by the time this job runs, so read the current state.
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number })
const labels = pr.labels.map(label => label.name.toLowerCase())
if (pr.merged || pr.state !== 'closed') {
core.info('The pull request is not closed, so there is nothing to reopen.')
return
}
if (!labels.includes('skip-spammy-check')) {
core.info('The pull request no longer has the skip-spammy-check label.')
return
}
// Automated checks add the invalid label before closing, so PRs without it were closed for another reason.
if (!labels.includes('invalid')) {
core.info('The pull request was not closed as invalid, so it stays closed.')
return
}
try {
await github.rest.pulls.update({ owner, repo, pull_number, state: 'open' })
} catch (error) {
if (error.status !== 422) throw error
// GitHub refuses to reopen a PR after its head or base branch was deleted or force-pushed.
core.warning(`Could not reopen the pull request: ${error.message}`)
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull_number,
body: 'I could not reopen this pull request automatically, most likely because its head or base branch was deleted or force-pushed after it was closed. Restore the branch, then remove and re-add the `skip-spammy-check` label to retry automatic reopening and removal of the `invalid` label.',
})
return
}
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: pull_number,
name: 'invalid',
})
} catch (error) {
// A maintainer or an earlier run may have removed the label already.
if (error.status !== 404) throw error
}
await github.rest.issues.createComment({
owner,
repo,
issue_number: pull_number,
body: 'The `skip-spammy-check` label was added, so I removed the `invalid` label and reopened this pull request. The spammy pull request check skips it while the label is applied.',
})
5 changes: 4 additions & 1 deletion .github/workflows/close-prs-not-targeting-main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Reject PRs targeting non-default branch (scheduled)

# Backup check for check-for-spammy-prs.yml: closes PRs that don't target main
# Backup check for check-for-spammy-prs.yml: closes PRs that don't target main, unless they have the skip-spammy-check label

on:
schedule:
Expand Down Expand Up @@ -39,6 +39,9 @@ jobs:
if (pr.user.login === 'docs-bot') continue
const labels = pr.labels.map(l => l.name)
// Maintainers add this label to allow a PR that targets another branch.
if (labels.some(label => label.toLowerCase() === 'skip-spammy-check')) continue
if (!labels.includes('invalid')) {
await github.rest.issues.addLabels({
owner,
Expand Down
Loading
Loading