-
-
Notifications
You must be signed in to change notification settings - Fork 468
Expand file tree
/
Copy pathpr.mdc
More file actions
262 lines (178 loc) · 9.98 KB
/
pr.mdc
File metadata and controls
262 lines (178 loc) · 9.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
---
alwaysApply: false
description: Pull request creation, stacked PRs, and PR workflow
---
# Pull Request Rules
## Creating a Pull Request
### Step 1: Ensure Feature Branch
If on `main`, create and switch to a new branch:
```bash
git checkout -b <type>/<short-description>
```
Branch names use `feat/`, `fix/`, `ref/`, etc. matching the commit type.
### Step 2: Format Code and Regenerate API Files
```bash
./gradlew spotlessApply apiDump
```
This is **required** before every PR. Fix any failures before continuing.
### Step 3: Commit Changes
Use `git status --porcelain` to review changes. Ignore files only relevant for local testing (hardcoded debug toggles, sample app config, `.env` files). Restore those with `git checkout -- <file>`.
Follow [Sentry commit message conventions](https://develop.sentry.dev/engineering-practices/commit-messages/):
```
<type>(<scope>): <subject>
```
Allowed types: `feat`, `fix`, `ref`, `chore`, `docs`, `test`, `perf`, `build`, `ci`, `style`, `meta`, `license`
- Use imperative present tense ("add" not "added")
- Capitalize subject, no trailing period
- Keep under 100 characters
### Step 4: Push
```bash
git push -u origin HEAD
```
If push fails due to diverged history, ask the user — do not force-push.
### Step 5: Create PR
Create a draft PR using the repo's PR template:
```markdown
## :scroll: Description
<Describe the changes in detail>
## :bulb: Motivation and Context
<Why is this change required? What problem does it solve?>
## :green_heart: How did you test it?
<Describe how you tested>
## :pencil: Checklist
- [ ] I added GH Issue ID _&_ Linear ID
- [ ] I added tests to verify the changes.
- [ ] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled.
- [ ] I updated the docs if needed.
- [ ] I updated the wizard if needed.
- [ ] Review from the native team if needed.
- [ ] No breaking change or entry added to the changelog.
- [ ] No breaking change for hybrid SDKs or communicated to hybrid SDKs.
## :crystal_ball: Next steps
```
### Step 6: Update Changelog
Add an entry to `CHANGELOG.md` under `## Unreleased` in the appropriate subsection:
| Change Type | Subsection |
|---|---|
| New feature | `### Features` |
| Bug fix | `### Fixes` |
| Refactoring, internal cleanup | `### Internal` |
| Dependency update | `### Dependencies` |
Entry format:
```markdown
- <Short description> ([#<PR_NUMBER>](https://github.com/getsentry/sentry-java/pull/<PR_NUMBER>))
```
Commit changelog separately:
```bash
git add CHANGELOG.md && git commit -m "changelog" && git push
```
### PR Title Format
Follow the commit message format:
```
<type>(<scope>): <Subject>
```
Examples:
- `feat(core): Add structured logging support`
- `fix(android): Prevent crash on API 21 when registering receiver`
---
## Stacked PRs
Stacked PRs split a large feature into small, easy-to-review PRs where each builds on the previous one. This follows the same concept as the [Graphite](https://graphite.dev/) stacking workflow.
### Structure
```
main ← collection-branch ← stack-pr-1 ← stack-pr-2 ← stack-pr-3 ← ...
```
- A **collection branch** is created from `main` and targets `main`. It serves as the base for the entire stack.
- The first PR in the stack targets the collection branch (not `main`).
- Each subsequent PR targets the previous stack PR's branch as its base.
- Each PR contains only incremental changes on top of the previous one.
The collection branch exists so that individual stack PRs can be **merge-committed** (not squashed). PRs targeting `main` use squash merging, but that causes repeated merge conflicts when syncing the stack. Merge commits on non-`main` branches avoid this. The collection branch itself is squash-merged into `main` at the end.
### Branch Naming
Prefer a shared prefix for the feature, with descriptive suffixes per PR. The collection branch uses the shared prefix. The type prefix (`feat/`, `fix/`, etc.) may vary depending on the nature of each PR's changes:
```
feat/scope-attributes # collection branch → targets main
feat/scope-attributes-api # PR 1 → targets collection branch
feat/scope-attributes-logger # PR 2 → targets PR 1
fix/attribute-type-detection # PR 3 (fix, different name — that's fine) → targets PR 2
```
### PR Title Naming
Include the topic name and a sequential number in brackets:
```
<type>(<scope>): [<Topic> <N>] <Subject>
```
Examples:
- `feat(core): [Global Attributes 1] Add scope-level attributes API`
- `feat(core): [Global Attributes 2] Wire scope attributes into LoggerApi and MetricsApi`
- `feat(samples): [Global Attributes 3] Showcase scope attributes in Spring Boot 4 sample`
### Finding All PRs in a Stack
Do **not** rely on branch name patterns — later PRs in a stack may use different prefixes or naming. Instead:
1. Find the PR for the current branch:
```bash
gh pr list --head "$(git branch --show-current)" --json number,title,baseRefName --jq '.[0]'
```
2. Read the PR description — the stack list is at the top of the body.
3. If there is no stack list yet, walk the chain in both directions:
```bash
# Find the PR whose head branch is the current PR's base (go up)
gh pr list --head <baseRefName> --json number,title,baseRefName
# Find PRs whose base branch is the current PR's head (go down)
gh pr list --base <currentBranch> --json number,title,headRefName
```
Repeat until you reach the collection branch going up and find no more PRs going down.
### Creating the Collection Branch
Before the first stacked PR, create the collection branch with an empty commit (so GitHub allows opening a PR) and create the collection PR:
```bash
git checkout main
git checkout -b feat/<topic>
git commit --allow-empty -m "collection: <topic>"
git push -u origin HEAD
gh pr create --base main --draft --title "<type>(<scope>): <Topic>" --body "Collection PR for the <Topic> stack. Squash-merge this once all stack PRs are merged."
```
**CRITICAL: Do NOT manually update the collection branch.** Never merge, fast-forward, or push stack branch commits into the collection branch. The collection branch stays at its initial position (the empty commit on `main`) until the user merges individual stack PRs into it one by one through GitHub. If you fast-forward the collection branch to include stack commits, GitHub will auto-merge and delete all stack PR branches, destroying the entire stack.
### Creating a New Stacked PR
1. Start from the tip of the previous stack branch (or the collection branch for the first PR).
2. Create a new branch, make changes, format, commit, and push.
3. Create the PR with `--base <previous-branch>` (the collection branch for the first PR):
```bash
gh pr create --base feat/previous-branch --draft --title "<type>(<scope>): [<Topic> <N>] <Subject>" --body "..."
```
4. Add the stack list to the top of the new PR's description and update it on all existing PRs in the stack (see below).
### Stack List in PR Description
Every PR in the stack — **including the collection branch PR** — must have a stack list **at the top of its description** (before the `## :scroll: Description` section). When a new PR is added, update the description on **all** PRs in the stack and on the collection branch PR.
Format:
```markdown
## PR Stack (<Topic>)
- #5118
- #5120
- #5121
---
```
No status column — GitHub already shows that. The `---` separates the stack list from the rest of the PR description.
**Merge method reminder:** On stack PRs (not the collection branch PR), add the following line at the very end of the PR description:
```markdown
> ⚠️ **Merge this PR using a merge commit** (not squash). Only the collection branch is squash-merged into main.
```
This does not apply to standalone PRs or the collection branch PR.
To update the PR description, use `--body-file` to avoid shell quoting issues with special characters in the body.
**Important:** Do not use shell redirects (`>`, `>>`, `|`) or compound commands (`&&`, `||`). These create compound shell expressions that won't match permission patterns. Instead, use the `Write` and `Edit` tools for file manipulation:
1. Read the current body with `gh pr view <PR_NUMBER> --json body --jq '.body'` (the output is returned directly — use the `Write` tool to save it to `/tmp/pr-body.md`)
2. Use the `Edit` tool to prepend or replace the stack list section in `/tmp/pr-body.md`
3. Update the description: `gh pr edit <PR_NUMBER> --body-file /tmp/pr-body.md`
### Merging Stacked PRs (done by the user, not the agent)
Individual stack PRs are merged in order from bottom to top (PR 1 first, then PR 2, etc.) using **merge commits** (not squash). After each merge, the next PR's base automatically becomes the merged branch's target. GitHub handles rebasing onto the new base.
Once all stack PRs are merged into the collection branch, the collection PR is **squash-merged** into `main`. This gives `main` a clean single commit for the entire feature.
**Do not merge PRs.** Only the user merges PRs.
### Syncing the Stack
When a base PR changes (e.g. after addressing review feedback on PR 1), merge the changes forward through the stack **between adjacent stack PR branches only**:
```bash
# On the branch for PR 2
git checkout feat/scope-attributes-logger
git merge feat/scope-attributes-api
git push
# On the branch for PR 3
git checkout feat/scope-attributes-sample
git merge feat/scope-attributes-logger
git push
```
**Never merge into the collection branch.** Syncing only happens between stack PR branches. The collection branch is untouched until the user merges PRs through GitHub.
Prefer merge over rebase — it preserves commit history, doesn't invalidate existing review comments, and avoids the need for force-pushing. Only rebase if explicitly requested.
**Never amend or force-push stack branches.** Do not use `git commit --amend`, `--force`, or `--force-with-lease` on branches that are part of a stack. Amending a pushed commit requires a force-push, which can cause GitHub to auto-merge or auto-close other PRs in the stack. If a commit needs fixing, add a new fixup commit instead.