Skip to content

Commit 520ae5c

Browse files
ci+docs: Add draft PR enforcement (#5867)
Add a GitHub Actions workflow that automatically converts non-draft PRs to draft on open/reopen, and document the draft PR requirement in CONTRIBUTING.md. **Motivation:** Our [code submission standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#pull-requests) says PRs must start as drafts, but this wasn't enforced. Non-draft PRs trigger review notifications prematurely and signal readiness when the author may not be done. This workflow nudges contributors to open as draft by automatically converting non-draft PRs and posting a comment explaining the policy. **What's included:** - `.github/workflows/enforce-draft-pr.yml` — triggers on `pull_request_target` (opened, reopened), uses the GraphQL `convertPullRequestToDraft` mutation. Includes error handling and comment deduplication on reopen. - `CONTRIBUTING.md` — new "Pull Requests" section documenting the draft requirement and linking to the code submission standard. **Limitations:** GitHub has no pre-creation hook, so the initial CI run and review notifications still fire before the conversion. The value is in training contributors and ensuring draft state before a maintainer picks up the PR. No exemptions — applies to everyone (maintainers, internal, external contributors). --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 12fb1ce commit 520ae5c

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: Enforce Draft PR
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, reopened]
6+
7+
permissions:
8+
pull-requests: write
9+
10+
jobs:
11+
enforce-draft:
12+
name: Enforce Draft PR
13+
runs-on: ubuntu-24.04
14+
if: github.event.pull_request.draft == false
15+
steps:
16+
- name: Convert PR to draft
17+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
18+
with:
19+
script: |
20+
const pullRequest = context.payload.pull_request;
21+
const repo = context.repo;
22+
23+
// Convert to draft via GraphQL (REST API doesn't support this)
24+
try {
25+
await github.graphql(`
26+
mutation($pullRequestId: ID!) {
27+
convertPullRequestToDraft(input: { pullRequestId: $pullRequestId }) {
28+
pullRequest {
29+
isDraft
30+
}
31+
}
32+
}
33+
`, {
34+
pullRequestId: pullRequest.node_id
35+
});
36+
} catch (error) {
37+
core.warning(`Failed to convert PR to draft: ${error.message}`);
38+
return;
39+
}
40+
41+
// Label the PR so maintainers can filter/track violations
42+
await github.rest.issues.addLabels({
43+
...repo,
44+
issue_number: pullRequest.number,
45+
labels: ['converted-to-draft'],
46+
});
47+
48+
// Check for existing bot comment to avoid duplicates on reopen
49+
const comments = await github.rest.issues.listComments({
50+
...repo,
51+
issue_number: pullRequest.number,
52+
});
53+
const botComment = comments.data.find(c =>
54+
c.user.type === 'Bot' &&
55+
c.body.includes('automatically converted to draft')
56+
);
57+
if (botComment) {
58+
core.info('Bot comment already exists, skipping.');
59+
return;
60+
}
61+
62+
const contributingUrl = `https://github.com/${repo.owner}/${repo.repo}/blob/master/CONTRIBUTING.md`;
63+
64+
await github.rest.issues.createComment({
65+
...repo,
66+
issue_number: pullRequest.number,
67+
body: [
68+
`This PR has been automatically converted to draft. All PRs must start as drafts per our [contributing guidelines](${contributingUrl}).`,
69+
'',
70+
'**Next steps:**',
71+
'1. Ensure CI passes',
72+
'2. Fill in the PR description completely',
73+
'3. Mark as "Ready for review" when you\'re done'
74+
].join('\n')
75+
});

CONTRIBUTING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ We will review your pull request as soon as possible. Thank you for contributing
2525

2626
You are welcome to use whatever tools you prefer for making a contribution. However, any changes you propose have to be reviewed and tested by you, a human, first, before you submit a pull request with them for the Sentry team to review. If we feel like that didn't happen, we will close the PR outright. For example, we won't review visibly AI-generated PRs from an agent instructed to look for and "fix" open issues in the repo.
2727

28+
## Pull Requests
29+
30+
All PRs must be created as **drafts**. Non-draft PRs will be automatically converted to draft. Mark your PR as "Ready for review" once:
31+
32+
- CI passes
33+
- The PR description is complete (what, why, and links to relevant issues)
34+
- You've personally reviewed your own changes
35+
36+
A PR should do one thing well. Don't mix functional changes with unrelated refactors or cleanup. Smaller, focused PRs are easier to review, reason about, and revert if needed.
37+
38+
For the full set of PR standards, see the [code submission standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#pull-requests).
39+
2840
## Development Environment
2941

3042
### Set up Python

0 commit comments

Comments
 (0)