Skip to content

Commit c30da7d

Browse files
committed
chore(stack): Merge preceding stack changes
2 parents 11568c0 + ed6ddae commit c30da7d

624 files changed

Lines changed: 28602 additions & 5078 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/skills/create-java-pr/SKILL.md‎

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ description: Create a pull request in sentry-java. Use when asked to "create pr"
77

88
Prepare local changes and create a pull request for the sentry-java repo.
99

10-
**Required reading:** Before proceeding, read `.cursor/rules/pr.mdc` for the full PR and stacked PR workflow details. That file is the source of truth for PR conventions, stack comment format, branch naming, and merge strategy.
10+
**For stacked PRs:** read `references/stacked-prs.md` before proceeding. It is the source of truth for
11+
stack structure, title naming, stack list format, and merge strategy.
1112

1213
## Step 0: Determine PR Type From Git Branch Context
1314

@@ -66,7 +67,7 @@ git checkout -b <type>/<short-description>
6667

6768
Derive the branch name from the changes being made. Use `feat/`, `fix/`, `ref/`, etc. matching the commit type conventions.
6869

69-
**For stacked PRs:** For the first PR in a new stack, first create and push the collection branch (see `.cursor/rules/pr.mdc` § "Creating the Collection Branch"), then branch the PR off it. For subsequent PRs, branch off the previous stack branch. Use the naming conventions from `.cursor/rules/pr.mdc` § "Branch Naming".
70+
**For stacked PRs:** For the first PR in a new stack, first create and push the collection branch (see `references/stacked-prs.md` § "Why a Collection Branch"), then branch the PR off it. For subsequent PRs, branch off the previous stack branch. Give every branch in the stack a shared prefix naming the feature, with a descriptive suffix per PR.
7071

7172
**CRITICAL: Never merge, fast-forward, or push commits into the collection branch.** It stays at its initial position until the user merges stack PRs through GitHub. Updating it will auto-merge and destroy the entire PR stack.
7273

@@ -88,7 +89,13 @@ Check for uncommitted changes:
8889
git status --porcelain
8990
```
9091

91-
If there are uncommitted changes, invoke the `sentry-skills:commit` skill to stage and commit them following Sentry conventions.
92+
If there are uncommitted changes, invoke the `sentry-skills:commit` skill to stage and commit them following [Sentry commit message conventions](https://develop.sentry.dev/engineering-practices/commit-messages/):
93+
94+
```
95+
<type>(<scope>): <subject>
96+
```
97+
98+
Allowed types: `feat`, `fix`, `ref`, `chore`, `docs`, `test`, `perf`, `build`, `ci`, `style`, `meta`, `license`
9299

93100
**Important:** When staging, ignore changes that are only relevant for local testing and should not be part of the PR. Common examples:
94101

@@ -114,53 +121,38 @@ If the push fails due to diverged history, ask the user how to proceed rather th
114121

115122
## Step 5: Create PR
116123

117-
Invoke the `sentry-skills:create-pr` skill to create a draft PR. When providing the PR body, use the repo's PR template structure from `.github/pull_request_template.md`:
124+
Invoke the `sentry-skills:create-pr` skill to create a draft PR.
125+
126+
Read `.github/pull_request_template.md` and use it as the PR body structure — it is the single source
127+
of truth for the sections and checklist, so never reproduce it from memory. Fill in each section based
128+
on the changes being PR'd, drop the HTML comment hints, and check any checklist items that apply.
129+
130+
**PR title format** — same as the commit subject (Step 3):
118131
119132
```
120-
## :scroll: Description
121-
<Describe the changes in detail>
122-
123-
## :bulb: Motivation and Context
124-
<Why is this change required? What problem does it solve?>
125-
126-
## :green_heart: How did you test it?
127-
<Describe how you tested>
128-
129-
## :pencil: Checklist
130-
- [ ] I added GH Issue ID _&_ Linear ID
131-
- [ ] I added tests to verify the changes.
132-
- [ ] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled.
133-
- [ ] I updated the docs if needed.
134-
- [ ] I updated the wizard if needed.
135-
- [ ] Review from the native team if needed.
136-
- [ ] No breaking change or entry added to the changelog.
137-
- [ ] No breaking change for hybrid SDKs or communicated to hybrid SDKs.
138-
139-
## :crystal_ball: Next steps
133+
<type>(<scope>): <Subject>
140134
```
141135
142-
Fill in each section based on the changes being PR'd. Check any checklist items that apply.
136+
Examples:
137+
- `feat(core): Add structured logging support`
138+
- `fix(android): Prevent crash on API 21 when registering receiver`
143139
144140
**For stacked PRs:**
145141
146142
- Pass `--base <previous-stack-branch>` so the PR targets the previous branch (first PR in a stack targets the collection branch).
147-
- Use the stacked PR title format: `<type>(<scope>): [<Topic> <N>] <Subject>` (see `.cursor/rules/pr.mdc` § "PR Title Naming").
148-
- Include the stack list at the top of the PR body, before the `## :scroll: Description` section (see `.cursor/rules/pr.mdc` § "Stack List in PR Description" for the format).
149-
- Add a merge method reminder at the very end of the PR body (see `.cursor/rules/pr.mdc` § "Stack List in PR Description" for the exact text). This only applies to stack PRs, not the collection branch PR.
143+
- Use the stacked PR title format: `<type>(<scope>): [<Topic> <N>] <Subject>` (see `references/stacked-prs.md` § "PR Title Naming").
144+
- Include the stack list at the top of the PR body, before the `## :scroll: Description` section (see `references/stacked-prs.md` § "Stack List in PR Description" for the format).
145+
- Add a merge method reminder at the very end of the PR body (see `references/stacked-prs.md` § "Stack List in PR Description" for the exact text). This only applies to stack PRs, not the collection branch PR.
150146
151147
Then continue to Step 5.5 (stacked PRs only) or Step 6.
152148
153149
## Step 5.5: Update Stack List on All PRs (stacked PRs only)
154150
155151
Skip this step for standalone PRs.
156152
157-
After creating the PR, update the PR description on **every other PR in the stack — including the collection branch PR** — so all PRs have the same up-to-date stack list. Follow the format and commands in `.cursor/rules/pr.mdc` § "Stack List in PR Description".
153+
After creating the PR, update the PR description on **every other PR in the stack — including the collection branch PR** — so all PRs have the same up-to-date stack list. Follow the format and commands in `references/stacked-prs.md` § "Stack List in PR Description".
158154
159-
**Important:** When updating PR bodies, never use shell redirects (`>`, `>>`) or pipes (`|`) or compound commands (`&&`). These create compound shell expressions that won't match permission patterns. Instead:
160-
- Use `gh pr view <NUMBER> --json body --jq '.body'` to get the body (output returned directly)
161-
- Use the `Write` tool to save it to a temp file
162-
- Use the `Edit` tool to modify the temp file
163-
- Use `gh pr edit <NUMBER> --body-file /tmp/pr-body.md` to update
155+
Edit each body using the procedure in § "Editing PR Descriptions" below.
164156
165157
## Step 6: Update Changelog
166158
@@ -190,6 +182,8 @@ Add an entry to `CHANGELOG.md` under the `## Unreleased` section.
190182
191183
Create the subsection under `## Unreleased` if it does not already exist.
192184
185+
**When rebasing:** A rebase onto `main` can land your branch after a release was cut, where the `## Unreleased` heading your entry lived under has since been renamed to that version number. If that happens, move your new entry into an `## Unreleased` section at the top of `CHANGELOG.md` (create the section if it no longer exists) so it is not left under an already-released version.
186+
193187
#### Entry format
194188
195189
```markdown
@@ -210,8 +204,14 @@ git push
210204
211205
### No changelog needed
212206
213-
If no changelog entry is needed, add `#skip-changelog` to the PR description to disable the changelog CI check:
207+
If no changelog entry is needed, append `#skip-changelog` to the end of the PR description to disable
208+
the changelog CI check, using the procedure in § "Editing PR Descriptions" below.
209+
210+
## Editing PR Descriptions
211+
212+
Do not use shell redirects (`>`, `>>`), pipes (`|`), or compound commands (`&&`, `||`). These create
213+
compound shell expressions that won't match permission patterns. Instead:
214214

215-
1. Get the current body: `gh pr view <PR_NUMBER> --json body --jq '.body'`
216-
2. Use the `Write` tool to save the output to `/tmp/pr-body.md`, appending `\n#skip-changelog\n` at the end
217-
3. Update: `gh pr edit <PR_NUMBER> --body-file /tmp/pr-body.md`
215+
1. Read the body with `gh pr view <PR_NUMBER> --json body --jq '.body'` (output is returned directly)
216+
2. Use the `Write` tool to save it to `/tmp/pr-body.md`, and the `Edit` tool to modify it
217+
3. Update with `gh pr edit <PR_NUMBER> --body-file /tmp/pr-body.md`
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Stacked PRs
2+
3+
Stacked PRs split a large feature into small, easy-to-review PRs where each builds on the previous
4+
one. The general mechanics are the standard [Graphite](https://graphite.dev/) stacking workflow —
5+
this file covers only what is specific to sentry-java.
6+
7+
## Why a Collection Branch
8+
9+
```
10+
main ← collection-branch ← stack-pr-1 ← stack-pr-2 ← stack-pr-3 ← ...
11+
```
12+
13+
A **collection branch** is created from `main` and targets `main`. The first stack PR targets it
14+
rather than `main`, and each later PR targets the previous stack PR's branch.
15+
16+
It exists because PRs targeting `main` are **squash**-merged, which causes repeated merge conflicts
17+
when syncing a stack. Stack PRs are therefore **merge-committed** into the collection branch, and
18+
only the collection branch is squash-merged into `main` at the end — giving `main` one clean commit
19+
for the whole feature.
20+
21+
Create it with an empty commit, so GitHub allows opening a PR:
22+
23+
```bash
24+
git commit --allow-empty -m "collection: <topic>"
25+
```
26+
27+
Push it and open its PR against `main` right away — it is the PR the whole stack is eventually
28+
squash-merged through, and it carries the stack list like every other PR. Give it a plain title
29+
(`<type>(<scope>): <Topic>`, no `[<Topic> <N>]` bracket) and no merge method reminder.
30+
31+
## Rules That Will Destroy a Stack If Broken
32+
33+
**Never update the collection branch yourself.** Never merge, fast-forward, or push stack branch
34+
commits into it. It stays at its initial position (the empty commit on `main`) until the user merges
35+
stack PRs through GitHub one by one. Fast-forwarding it makes GitHub auto-merge and delete every
36+
stack PR branch, destroying the entire stack.
37+
38+
**Never amend or force-push a stack branch.** No `git commit --amend`, `--force`, or
39+
`--force-with-lease` on a branch that is part of a stack — a force-push can cause GitHub to
40+
auto-merge or auto-close the other PRs in the stack. If a commit needs fixing, add a fixup commit.
41+
42+
**Sync only between adjacent stack branches**, by merging forward — never into the collection branch.
43+
Prefer merge over rebase; only rebase if explicitly requested.
44+
45+
**Do not merge PRs.** Only the user merges them, bottom to top.
46+
47+
## PR Title Naming
48+
49+
Include the topic name and a sequential number in brackets:
50+
51+
```
52+
<type>(<scope>): [<Topic> <N>] <Subject>
53+
```
54+
55+
Examples:
56+
- `feat(core): [Global Attributes 1] Add scope-level attributes API`
57+
- `feat(core): [Global Attributes 2] Wire scope attributes into LoggerApi and MetricsApi`
58+
59+
## Stack List in PR Description
60+
61+
Every PR in the stack — **including the collection branch PR** — must have a stack list **at the top
62+
of its description**, before the `## :scroll: Description` section. When a PR is added, update the
63+
description on **all** PRs in the stack. The stack list is also how you enumerate a stack: read it
64+
off any PR body rather than guessing from branch names, which may use different prefixes.
65+
66+
```markdown
67+
## PR Stack (<Topic>)
68+
69+
- #5118
70+
- #5120
71+
- #5121
72+
73+
---
74+
```
75+
76+
No status column — GitHub already shows that. The `---` separates the stack list from the rest of
77+
the description.
78+
79+
**Merge method reminder:** on stack PRs (not the collection branch PR), end the description with:
80+
81+
```markdown
82+
> ⚠️ **Merge this PR using a merge commit** (not squash). Only the collection branch is squash-merged into main.
83+
```
84+
85+
Updating every PR's stack list means editing several descriptions — follow the procedure in
86+
`SKILL.md` § "Editing PR Descriptions".

‎.claude/skills/test/SKILL.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ test -d .venv || make setupPython
7878

7979
This starts the mock Sentry server, starts the sample app (Spring Boot/Tomcat/CLI), runs tests via `./gradlew :sentry-samples:<sample-module>:systemTest`, and cleans up afterwards.
8080

81+
To run **every** system test instead of one module, use the Makefile targets — they also create the
82+
venv for you:
83+
84+
```bash
85+
make systemTest # all system tests (--all)
86+
make systemTestInteractive # pick the setups to run (--interactive)
87+
```
88+
8189
## Step 4: Report Results
8290

8391
Summarize the test outcome:

‎.cursor/BUGBOT.md‎

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# PR Review Guidelines for Cursor Bugbot
2+
3+
You are reviewing a pull request for the Sentry Java/Android SDK.
4+
5+
Read [`AGENTS.md`](../AGENTS.md) for build commands and contributing rules, and the matching
6+
rule file in [`.cursor/rules/`](rules) for the area the diff touches (`api`, `options`, `scopes`,
7+
`offline`, `opentelemetry`, ...).
8+
9+
## Critical
10+
11+
### Never crash or hang the host application
12+
13+
- While we don't want to crash or hang the host application, we also don't want to leave the host
14+
application in a bad or unrecoverable state. Therefore catch the narrowest type the guarded code
15+
can throw.
16+
- Existing broad catches like `catch (Throwable)` are legacy, not precedent. Where a broad catch is
17+
genuinely unavoidable (an entry point running user code or third-party callbacks), it must call
18+
`ExceptionUtils.rethrowIfFatal(t)` first and a code comment must say why the broad catch is
19+
needed.
20+
- Code probing for an optional `compileOnly` dependency must catch the specific `LinkageError`
21+
subclass (`NoClassDefFoundError`, `NoSuchMethodError`, ...) only.
22+
- The SDK must never `captureException`/`captureMessage` for its own failures or for exceptions
23+
thrown inside user callbacks (`beforeSend`, `beforeBreadcrumb`, `tracesSampler`, ...). Log via
24+
`options.getLogger()` instead — capturing here loops. See
25+
[Never capture your own exceptions](https://develop.sentry.dev/sdk/getting-started/principles/#never-capture-your-own-exceptions).
26+
- Flag `System.out`/`System.err`, `printStackTrace()`, and `android.util.Log` in SDK source; use
27+
`options.getLogger().log(...)`.
28+
- Flag resources acquired but not released: streams, files, `ExecutorService`s,
29+
`BroadcastReceiver`s, lifecycle/activity callbacks, sensors, timers. Anything registered during
30+
init must be undone in the integration's `close()`.
31+
- Errors in instrumented user code should bubble up so the host app's handlers see them. Flag
32+
instrumentation that swallows an error without recording it, and instrumentation that captures an
33+
error that would also reach the global handlers (double reporting).
34+
35+
### Security and privacy
36+
37+
- Real secrets, tokens, or DSNs in code, logs, or configs. Obviously-fake DSNs in tests, samples,
38+
and docs are expected — do not flag those.
39+
- New code that collects user-identifiable data (headers, cookies, request/response bodies, URL
40+
query strings, IPs, usernames, file paths, device identifiers) must be gated behind
41+
`options.isSendDefaultPii()`, and must not be on by default otherwise.
42+
- Debug flags, verbose logging, or sampling overrides accidentally left enabled in production
43+
defaults.
44+
45+
### Public API and compatibility
46+
47+
- New public API must be intentional: new classes/methods not for public use need
48+
`@ApiStatus.Internal`, new unstable API needs `@ApiStatus.Experimental`.
49+
- Removing or changing the signature of public API, or silently changing a default, sampling rate,
50+
or feature toggle, without a deprecation and a `CHANGELOG.md`/`MIGRATION.md` note.
51+
- New features must be **opt-in by default** via `SentryOptions` (or a namespaced options class).
52+
If a feature is added without this, ask "are you sure" as a PR comment.
53+
- New fields on `io.sentry.protocol` classes need both serialization and deserialization, plus a
54+
round-trip test.
55+
- Raising `minSdk`, the Java level, or a supported framework version without an explicit callout.
56+
- Ensure dependency bumps are intentional. For example if a dependency is bumped in part of a
57+
matrix that isn't the newest version.
58+
59+
## Java and Android specifics
60+
61+
- The core `sentry` module is Java 8 and must not reference Android or JVM-only APIs. Reach optional
62+
platform code through `Platform`, `LoadClass`, or a separate module.
63+
- Android code calling an API newer than `minSdk` must be guarded by
64+
`BuildInfoProvider.getSdkInfoVersion()`.
65+
- `Sentry.init` can be called from any thread, and on Android it runs on the main thread during app
66+
startup. Flag disk I/O, network calls, reflection, class loading, regex compilation, or eager
67+
allocation newly added to an init path — and static mutable state that is not thread-safe.
68+
- Ensure any new reflection calls are mirrored in the proguard keep rules.
69+
70+
## Instrumentation conventions
71+
72+
- Every started span must be finished on all paths, including error paths.
73+
- Automatically instrumented spans set an origin (`SpanOptions.setOrigin`) and a standard
74+
[span op](https://develop.sentry.dev/sdk/telemetry/traces/span-operations/). Origins must match
75+
`[A-Za-z0-9_.]` — see the
76+
[trace origin spec](https://develop.sentry.dev/sdk/telemetry/traces/trace-origin/).
77+
- New integrations register themselves with `IntegrationUtils.addIntegrationToSdkVersion(...)`.
78+
- If we're adding a feature that requires bytecode manipulation from the
79+
sentry-android-gradle-plugin, make sure the code is properly commented as such to ensure it isn't
80+
accidentally changed in the future.
81+
82+
## Concurrency
83+
84+
- The SDK uses raw java concurrency primitives. Ensure we are using them correctly.
85+
- Ensure that atomic actions are atomic.
86+
- Watch for possible deadlocks in general but especially when two locks are held and another thread
87+
can grab them in the opposite order.
88+
- Prefer using existing executors over creating new threads.
89+
- Do not block the main thread on Android with locking, synchronization or I/O calls.
90+
- Watch for ordering issues when classes can be called from different threads.
91+
- Flag a lock held across a callback into user code, an I/O call, or an `ExecutorService`
92+
submission.
93+
- Mark a field `volatile` when it is written on one thread and read on another without a lock. A
94+
plain field read is a data race, not merely a stale value.
95+
- Read mutable shared state once per operation. Re-reading the same field for several decisions in
96+
one pass lets it change mid-pass, so the results disagree with each other.
97+
- Prefer the `synchronized` keyword. Existing code that uses `AutoClosableReentrantLock` is legacy.
98+
- New classes have a clear and defined threading and concurrency model as part of the javadoc if
99+
needed.
100+
101+
## Clocks
102+
103+
- Ensure we are using a monotonic clock to measure time intervals.
104+
- Ensure we are using a wall clock for dates and timestamps.
105+
- Ensure that time manipulations are not being misused e.g. adding or subtracting wall clocks to
106+
get a duration.
107+
108+
## Tests
109+
110+
- Public behavior (customer facing) changes need tests. A `fix` PR should include a regression test
111+
that fails without the fix; if the diff doesn't make that clear, ask the author to confirm.
112+
- Prefer tests against contracts. Avoid testing implementation details.
113+
- Flag hollow tests: assertions that only prove "did not throw", or that assert on a payload without
114+
checking the newly added data.
115+
- New assertions should use Google Truth (`com.google.common.truth.Truth.assertThat`); `kotlin.test`
116+
stays for structure (`@Test`, `assertFailsWith`). Don't flag existing `kotlin.test` assertions.
117+
- Flag likely flakes: `Thread.sleep`, wall-clock or ordering assumptions, real network or filesystem
118+
access, and shared static state left dirty between tests.
119+
120+
## What NOT to flag
121+
122+
- Formatting and import order — Spotless owns it.
123+
- Contents of generated `.api` files, beyond confirming `apiDump` was run.
124+
- Conventional commit / PR title format, and missing changelog entries — CI and Danger check both.
125+
- Speculative refactors or improvements unrelated to the diff.

‎.cursor/rules/api.mdc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Public API is tracked via `.api` files generated by the [Binary Compatibility Va
3434
- `SentryAndroidOptions` — Android-specific options
3535
- Integration modules may add their own (e.g. `SentrySpringProperties`)
3636

37-
New features must be **opt-in by default** — add a getter/setter pair to the appropriate options class.
37+
See the `options` rule for how to add and wire up a new option.
3838

3939
### Internal Classes (Not Public API)
4040

0 commit comments

Comments
 (0)