From 9bfd5ad18e23ee00b6c1e298c0ad1f5cc1648308 Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Wed, 25 Mar 2026 14:50:46 +0100 Subject: [PATCH 1/3] ci+docs: Add draft PR enforcement Add workflow to auto-convert non-draft PRs to draft on open/reopen. Add Pull Requests section to CONTRIBUTING.md documenting the draft requirement and linking to the code submission standard. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/enforce-draft-pr.yml | 68 ++++++++++++++++++++++++++ CONTRIBUTING.md | 12 +++++ 2 files changed, 80 insertions(+) create mode 100644 .github/workflows/enforce-draft-pr.yml diff --git a/.github/workflows/enforce-draft-pr.yml b/.github/workflows/enforce-draft-pr.yml new file mode 100644 index 0000000000..7fdceb8816 --- /dev/null +++ b/.github/workflows/enforce-draft-pr.yml @@ -0,0 +1,68 @@ +name: Enforce Draft PR + +on: + pull_request_target: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + enforce-draft: + name: Enforce Draft PR + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false + steps: + - name: Convert PR to draft + uses: actions/github-script@v7 + with: + script: | + const pullRequest = context.payload.pull_request; + const repo = context.repo; + + // Convert to draft via GraphQL (REST API doesn't support this) + try { + await github.graphql(` + mutation($pullRequestId: ID!) { + convertPullRequestToDraft(input: { pullRequestId: $pullRequestId }) { + pullRequest { + isDraft + } + } + } + `, { + pullRequestId: pullRequest.node_id + }); + } catch (error) { + core.warning(`Failed to convert PR to draft: ${error.message}`); + return; + } + + // Check for existing bot comment to avoid duplicates on reopen + const comments = await github.rest.issues.listComments({ + ...repo, + issue_number: pullRequest.number, + }); + const botComment = comments.data.find(c => + c.user.type === 'Bot' && + c.body.includes('automatically converted to draft') + ); + if (botComment) { + core.info('Bot comment already exists, skipping.'); + return; + } + + const contributingUrl = `https://github.com/${repo.owner}/${repo.repo}/blob/master/CONTRIBUTING.md`; + + await github.rest.issues.createComment({ + ...repo, + issue_number: pullRequest.number, + body: [ + `This PR has been automatically converted to draft. All PRs must start as drafts per our [contributing guidelines](${contributingUrl}).`, + '', + '**Next steps:**', + '1. Ensure CI passes', + '2. Fill in the PR description completely', + '3. Mark as "Ready for review" when you\'re done' + ].join('\n') + }); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9831d8a01..60105c8bac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,6 +21,18 @@ We will review your pull request as soon as possible. Thank you for contributing 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. +## Pull Requests + +All PRs must be created as **drafts**. Non-draft PRs will be automatically converted to draft. Mark your PR as "Ready for review" once: + +- CI passes +- The PR description is complete (what, why, and links to relevant issues) +- You've personally reviewed your own changes + +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. + +For the full set of PR standards, see the [code submission standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#pull-requests). + ## Development Environment ### Set up Python From 5eea42a5e6ae55ac3bbf195272793215283f2f39 Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Wed, 25 Mar 2026 15:02:21 +0100 Subject: [PATCH 2/3] chore: Apply suggestions from code review Co-authored-by: sentry-warden[bot] <258096371+sentry-warden[bot]@users.noreply.github.com> --- .github/workflows/enforce-draft-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/enforce-draft-pr.yml b/.github/workflows/enforce-draft-pr.yml index 7fdceb8816..88376b0b75 100644 --- a/.github/workflows/enforce-draft-pr.yml +++ b/.github/workflows/enforce-draft-pr.yml @@ -14,7 +14,7 @@ jobs: if: github.event.pull_request.draft == false steps: - name: Convert PR to draft - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const pullRequest = context.payload.pull_request; From 9f4e918b4e9e53cfd252e40227fd9d29a9a315d2 Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Wed, 25 Mar 2026 15:10:14 +0100 Subject: [PATCH 3/3] ci: Add converted-to-draft label to enforce-draft workflow Adds a label to PRs that were auto-converted to draft, enabling maintainers to filter and track how often the rule is violated. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/enforce-draft-pr.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/enforce-draft-pr.yml b/.github/workflows/enforce-draft-pr.yml index 88376b0b75..6a5da12272 100644 --- a/.github/workflows/enforce-draft-pr.yml +++ b/.github/workflows/enforce-draft-pr.yml @@ -38,6 +38,13 @@ jobs: return; } + // Label the PR so maintainers can filter/track violations + await github.rest.issues.addLabels({ + ...repo, + issue_number: pullRequest.number, + labels: ['converted-to-draft'], + }); + // Check for existing bot comment to avoid duplicates on reopen const comments = await github.rest.issues.listComments({ ...repo,