From 17c65424adecba12f20b61446d2ebb8b02513dc7 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sun, 5 Apr 2026 11:11:16 -0400 Subject: [PATCH] ci: auto-close draft PRs with policy message (#1765) - Add close-draft-prs.yml workflow that auto-closes draft PRs with explanatory comment directing contributors to submit completed PRs - Update CONTRIBUTING.md with "No draft PRs" policy - Update default PR template with draft PR warning Closes #1762 Co-authored-by: Claude Opus 4.6 --- .github/pull_request_template.md | 2 ++ .github/workflows/close-draft-prs.yml | 51 +++++++++++++++++++++++++++ CONTRIBUTING.md | 1 + 3 files changed, 54 insertions(+) create mode 100644 .github/workflows/close-draft-prs.yml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bafef675f..da44ef515 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -29,6 +29,8 @@ For **features**: the linked issue must have the `approved-feature` label before PRs that arrive without a labeled, approved issue are closed without review. +> **No draft PRs.** Draft PRs are automatically closed. Only open a PR when your code is complete, tests pass, and the correct template is used. See [CONTRIBUTING.md](../CONTRIBUTING.md). + See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full process. --- diff --git a/.github/workflows/close-draft-prs.yml b/.github/workflows/close-draft-prs.yml new file mode 100644 index 000000000..1ccfb885e --- /dev/null +++ b/.github/workflows/close-draft-prs.yml @@ -0,0 +1,51 @@ +name: Close Draft PRs + +on: + pull_request: + types: [opened, reopened, converted_to_draft] + +permissions: + pull-requests: write + +jobs: + close-if-draft: + name: Reject draft PRs + if: github.event.pull_request.draft == true + runs-on: ubuntu-latest + steps: + - name: Comment and close draft PR + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const repoUrl = context.repo.owner + '/' + context.repo.repo; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body: [ + '## Draft PRs are not accepted', + '', + 'This project only accepts completed pull requests. Draft PRs are automatically closed.', + '', + '**Why?** GSD requires all PRs to be ready for review when opened \u2014 with tests passing, the correct PR template used, and a linked approved issue. Draft PRs bypass these quality gates and create review overhead.', + '', + '### What to do instead', + '', + '1. Finish your implementation locally', + '2. Run `npm run test:coverage` and confirm all tests pass', + '3. Open a **non-draft** PR using the [correct template](https://github.com/' + repoUrl + '/blob/main/CONTRIBUTING.md#pull-request-guidelines)', + '', + 'See [CONTRIBUTING.md](https://github.com/' + repoUrl + '/blob/main/CONTRIBUTING.md) for the full process.', + ].join('\n') + }); + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + state: 'closed' + }); + + core.info('Closed draft PR #' + pr.number + ': ' + pr.title); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32a6b4228..b2ad23a70 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,6 +83,7 @@ PRs that arrive without a properly-labeled linked issue are closed automatically **Every PR must link to an approved issue.** PRs without a linked issue are closed without review, no exceptions. +- **No draft PRs** — draft PRs are automatically closed. Only open a PR when it is complete, tested, and ready for review. If your work is not finished, keep it on your local branch until it is. - **Use the correct PR template** — there are separate templates for [Fix](.github/PULL_REQUEST_TEMPLATE/fix.md), [Enhancement](.github/PULL_REQUEST_TEMPLATE/enhancement.md), and [Feature](.github/PULL_REQUEST_TEMPLATE/feature.md). Using the wrong template or using the default template for a feature is a rejection reason. - **Link with a closing keyword** — use `Closes #123`, `Fixes #123`, or `Resolves #123` in the PR body. The CI check will fail and the PR will be auto-closed if no valid issue reference is found. - **One concern per PR** — bug fixes, enhancements, and features must be separate PRs