From 5b1b37e9f269b77ece7eb00b5d78f08e2c461dce Mon Sep 17 00:00:00 2001 From: Mason Daugherty Date: Mon, 9 Mar 2026 13:10:23 -0400 Subject: [PATCH] ci: auto-close external PRs failing `issue-link` check (#35697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-close external PRs that fail the issue-link or assignee check instead of just failing the CI status. The bot comment now explains the PR was closed and gives numbered steps to resolve — including asking a maintainer to reopen, since external contributors can't reopen PRs themselves. ## Changes - Close the PR via `pulls.update` after posting the bot comment in the `check-issue-link` job, gated on `state === 'open'` to avoid redundant API calls on re-runs - Rewrite bot comment copy for both failure modes (missing link, not assigned) to lead with "This PR has been automatically closed" and end with "ask a maintainer to reopen this PR" --- .github/workflows/require_issue_link.yml | 32 ++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.github/workflows/require_issue_link.yml b/.github/workflows/require_issue_link.yml index 382d5dd70cb..0d524cada4d 100644 --- a/.github/workflows/require_issue_link.yml +++ b/.github/workflows/require_issue_link.yml @@ -107,7 +107,7 @@ jobs: if (error.status !== 404) throw error; } - - name: Post comment and fail + - name: Post comment, close PR, and fail if: steps.check-link.outputs.has-link != 'true' || steps.check-link.outputs.is-assigned != 'true' uses: actions/github-script@v8 with: @@ -122,21 +122,22 @@ jobs: if (!hasLink) { lines = [ marker, - '**This PR is missing a linked issue.** All external contributions must reference an approved issue or discussion.', + '**This PR has been automatically closed** because it does not link to an approved issue.', '', - 'Please add one of the following to your PR description:', - '- `Fixes #`', - '- `Closes #`', - '- `Resolves #`', - '', - 'If no issue exists yet, [open one](https://github.com/' + owner + '/' + repo + '/issues/new/choose) and wait for maintainer approval before proceeding.', + 'All external contributions must reference an approved issue or discussion. Please:', + '1. Find or [open an issue](https://github.com/' + owner + '/' + repo + '/issues/new/choose) describing the change', + '2. Wait for a maintainer to approve and assign you', + '3. Add `Fixes #`, `Closes #`, or `Resolves #` to your PR description', + '4. Ask a maintainer to reopen this PR', ]; } else { lines = [ marker, - '**You are not assigned to the linked issue.** External contributors must be assigned to an issue before opening a PR for it.', + '**This PR has been automatically closed** because you are not assigned to the linked issue.', '', - 'Please comment on the issue to request assignment from a maintainer, then update this PR once you have been assigned.', + 'External contributors must be assigned to an issue before opening a PR for it. Please:', + '1. Comment on the linked issue to request assignment from a maintainer', + '2. Once assigned, ask a maintainer to reopen this PR', ]; } @@ -169,6 +170,17 @@ jobs: console.log('Comment already exists — skipping'); } + // Close the PR + if (context.payload.pull_request.state === 'open') { + await github.rest.pulls.update({ + owner, + repo, + pull_number: prNumber, + state: 'closed', + }); + console.log(`Closed PR #${prNumber}`); + } + const reason = !hasLink ? 'PR must reference an issue using auto-close keywords (e.g., "Fixes #123").' : 'PR author must be assigned to the linked issue.';