Skip to content

Commit 706fe00

Browse files
authored
Merge branch 'master' into corsaCompat-2025-05-14
2 parents 3402a33 + d858161 commit 706fe00

File tree

2,389 files changed

+48771
-70973
lines changed

Some content is hidden

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

2,389 files changed

+48771
-70973
lines changed

.cursor/mcp.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mcpServers": {
3+
"sentry": {
4+
"command": "npx",
5+
"args": ["-y", "mcp-remote@latest", "https://mcp.sentry.dev/sse"]
6+
}
7+
}
8+
}

.github/CODEOWNERS

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ yarn.lock @getsentry/owners-js-de
145145
# Sentry product. These rules generally map to a signle team, but that may not
146146
# always be the case.
147147

148+
# Demo Mode - moved upwards because it wraps other parts of the codebase
149+
# and was assigned many issues to telemetry-experience that should not have been
150+
/src/sentry/demo_mode/ @getsentry/telemetry-experience
151+
/tests/sentry/demo_mode/ @getsentry/telemetry-experience
152+
/static/app/utils/demoMode/ @getsentry/telemetry-experience
153+
148154
## Crons
149155
/static/app/views/monitors @getsentry/crons
150156
/src/sentry/monitors @getsentry/crons
@@ -368,8 +374,6 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge
368374
/src/sentry/toolbar/ @getsentry/replay-frontend @getsentry/replay-backend
369375
/tests/sentry/toolbar/ @getsentry/replay-frontend @getsentry/replay-backend
370376
/static/app/components/devtoolbar/ @getsentry/replay-frontend
371-
/src/sentry/middleware/devtoolbar.py @getsentry/replay-backend
372-
/tests/sentry/middleware/test_devtoolbar.py @getsentry/replay-backend
373377
## End of DevToolbar
374378

375379
## Codecov Merge UX
@@ -508,7 +512,6 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge
508512
/tests/sentry/sentry_metrics/querying/ @getsentry/telemetry-experience
509513
/src/sentry/snuba/metrics/ @getsentry/telemetry-experience
510514
/tests/sentry/snuba/metrics/ @getsentry/telemetry-experience
511-
/src/sentry/demo_mode/
512515

513516
/static/app/actionCreators/metrics.tsx @getsentry/telemetry-experience
514517
/static/app/data/platformCategories.tsx @getsentry/telemetry-experience
@@ -520,7 +523,8 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge
520523
/static/app/views/settings/dynamicSampling/ @getsentry/telemetry-experience
521524
/static/app/views/onboarding* @getsentry/telemetry-experience
522525
/static/app/views/projectInstall/ @getsentry/telemetry-experience
523-
/static/app/utils/demoMode/ @getsentry/telemetry-experience
526+
/static/app/views/insights/agentMonitoring/ @getsentry/telemetry-experience
527+
/static/app/views/insights/pages/platform/ @getsentry/telemetry-experience
524528
## End of Telemetry Experience
525529

526530

@@ -682,6 +686,9 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge
682686
/src/sentry/migrations/ @getsentry/owners-migrations
683687
/src/sentry/*/migrations/ @getsentry/owners-migrations
684688

689+
# Preprod build artifact analysis
690+
/src/sentry/preprod @getsentry/emerge-tool
691+
# End of preprod
685692

686693
## Frontend Platform (keep last as we want highest specificity)
687694
/static/app/utils/theme/ @getsentry/design-engineering

.github/workflows/acceptance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
8585
with:
8686
path: ${{ steps.config.outputs.webpack-path }}
87-
key: ${{ runner.os }}-v2-webpack-cache-${{ hashFiles('webpack.config.ts') }}
87+
key: ${{ runner.os }}-v2-webpack-cache-${{ hashFiles('rspack.config.ts', 'yarn.lock', 'package.json') }}
8888

8989
- name: node_modules cache
9090
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0

.pre-commit-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ repos:
143143
|static/app/utils/profiling/profile/formats/typescript/trace\.json
144144
)$
145145
146+
- id: knip
147+
name: knip
148+
language: system
149+
files: \.(ts|js|tsx|jsx|mjs)$
150+
pass_filenames: false
151+
stages: [pre-push]
152+
entry: bash -c 'if [ -n "${SENTRY_KNIP_PRE_PUSH:-}" ]; then exec ./node_modules/.bin/knip; fi' --
153+
146154
- repo: https://github.com/pre-commit/pygrep-hooks
147155
rev: v1.10.0
148156
hooks:

CHANGES

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,67 @@
1+
25.5.1
2+
------
3+
4+
### Various fixes & improvements
5+
6+
- :wrench: chore(integrations): use `IntegrationProviderSlug` for Integration `key` (#91465) by @iamrajjoshi
7+
- ref: fix types for group_integration_details (#92026) by @asottile-sentry
8+
- Bump `devenv`/`devservices` to make Python SDK 3 compatible (#92028) by @antonpirker
9+
- build(ui): Remove react prod sourcemaps (#92006) by @scttcper
10+
- feat(spans): Produce items from process-segments (#91714) by @untitaker
11+
- feat(explore): Add attribute description throughout explore (#91829) by @Zylphrex
12+
- fix(symbolicator): check source credentials and not the credential token (#92024) by @Litarnus
13+
- feat(replay): Start bringing in new replay context wrappers to test (#91982) by @ryan953
14+
- feat(agents-insights): dashboard placeholder (#92021) by @obostjancic
15+
- ref: remove remote_subscriptions migrations (#92004) by @asottile-sentry
16+
- fix(apps): disallow Manager to rotate an app secret with org:admin scope (#92019) by @oioki
17+
- issues: remove custom save button styling (#91974) by @JonasBa
18+
- replay: replace colors for tokens on timeline (#91933) by @JonasBa
19+
- trace: fix buttons in chonk (#91878) by @JonasBa
20+
- tag: fix bad tag change and flickering text (#91927) by @JonasBa
21+
- chore(sdk): Use add_full_stack by default (#91939) by @armenzg
22+
- fix(codeowners): move demomode upwards in codewards to stop matching everything (#92020) by @shellmayr
23+
- fix(nextjs-insight): Filter spans without component type from tree view (#92017) by @ArthurKnaus
24+
- Add directory for preprod (#91961) by @chromy
25+
- fix(span-buffer): Fix crashing behavior in flusher (#91949) by @untitaker
26+
- feat(agents-insights): feature flag registration (#92014) by @obostjancic
27+
- fix(codeowners): add owner to demomode line (#92012) by @shellmayr
28+
- ref: add flags to migrations lockfile (#91991) by @asottile-sentry
29+
- feat(source-maps): Do not render source maps wizard if platform is react native (#91860) by @priscilawebdev
30+
31+
_Plus 231 more_
32+
33+
25.5.0
34+
------
35+
36+
### Various fixes & improvements
37+
38+
- chore(perf-issues): Add a flag and check it to allow customer to disable detectors (#91734) by @leeandher
39+
- feat(trace-tabs-ui): Adding ops to search on click and hiding trace level ops breakdown (#91684) by @Abdkhan14
40+
- build(ui): Add rspack as webpack alternative (#77077) by @scttcper
41+
- fix(taskworker) Fix async notification parameter serialization (#91720) by @markstory
42+
- fix(profiles): Set the proper span entity to insert data to in tests (#91736) by @phacops
43+
- fix(insights): line of code not working with db module on eap (#91654) by @DominikB2014
44+
- ref(reserved budgets): Update types + constants (#91606) by @isabellaenriquez
45+
- feat(taskworker) Check 2% of tasks for pickle (#91624) by @markstory
46+
- chore(github): Only support pagination for getting labels (#91570) by @armenzg
47+
- Skip test_queries_profile_candidates_from_spans (#91724) by @armenzg
48+
- fix(issue-details): Avoid persisting stacktrace folding behaviour (#91719) by @leeandher
49+
- feat(dashboards): Newly added widgets should scroll into view (#91721) by @narsaynorath
50+
- ref(crons): Use dateAdded over dateCreated (#91667) by @evanpurkhiser
51+
- fix(utils): return 0% for null and undefined values in formatpercentage (#91710) by @shellmayr
52+
- ref: fix nullability of requires_org_level_access (#91694) by @asottile-sentry
53+
- feat(explore): Flatten visualize yaxes into multiple (#91664) by @Zylphrex
54+
- fix(widget-library): Hide filters at top of panel if not small screen (#91716) by @narsaynorath
55+
- feat(attachments): Include all attachment with screenshot in name (#91602) by @armenzg
56+
- fix(insights): show - instead of null when metric value is null (#91656) by @DominikB2014
57+
- feat(ourlogs): Add a "new" badge for logs in the sidebar (#91674) by @colin-sentry
58+
- fix(nextjs-insights): remove project icon from rage/dead click widget (#91711) by @shellmayr
59+
- fix(nextjs-insights): show 0% for failure_rate()==0 instead of <0% (#91709) by @shellmayr
60+
- feat(nextjs-insights): add avg & p95 duration to navigations table (#91708) by @shellmayr
61+
- fix(sandbox): for debugging add telex org to exclude from redirect (#91704) by @constantinius
62+
63+
_Plus 1819 more_
64+
165
25.4.0
266
------
367

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ test-cli: create-db
100100
cd test_cli && sentry init test_conf
101101
cd test_cli && sentry --config=test_conf help
102102
cd test_cli && sentry --config=test_conf upgrade --traceback --noinput
103-
cd test_cli && sentry --config=test_conf export
103+
cd test_cli && sentry --config=test_conf export --help
104104
rm -r test_cli
105105
@echo ""
106106

bin/load-integration-data

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env python
2+
from sentry.runner import configure
3+
4+
configure()
5+
6+
import argparse
7+
8+
import click
9+
from django.core import serializers
10+
from django.db import IntegrityError, router
11+
12+
from sentry.integrations.models.integration import Integration
13+
from sentry.integrations.models.organization_integration import OrganizationIntegration
14+
from sentry.users.models.identity import Identity, IdentityProvider
15+
from sentry.utils.db import atomic_transaction
16+
17+
# The order in which models should be loaded to respect foreign key dependencies.
18+
MODEL_LOAD_ORDER = [
19+
"sentry.identityprovider",
20+
"sentry.integration",
21+
"sentry.identity", # Depends on sentry.identityprovider
22+
"sentry.organizationintegration", # Depends on sentry.integration (and sentry.organization)
23+
]
24+
25+
26+
def load_data(input_file, org_id):
27+
"""
28+
Loads data from a JSON file and saves it to the database.
29+
Assumes that PKs from the file should be preserved.
30+
"""
31+
click.echo(f"Reading serialized data from {input_file}...")
32+
with open(input_file) as f:
33+
serialized_data = f.read()
34+
35+
if not serialized_data.strip() or serialized_data.strip() == "[]":
36+
click.echo("Input file is empty or contains no data. Nothing to load.")
37+
return
38+
39+
click.echo("Deserializing objects...")
40+
try:
41+
deserialized_objects = list(serializers.deserialize("json", serialized_data))
42+
except Exception as e:
43+
click.echo(f"Error during deserialization: {e}")
44+
click.echo(
45+
"Please ensure the input file is a valid JSON dump created by the save_integration_data.py script."
46+
)
47+
return
48+
49+
if not deserialized_objects:
50+
click.echo("No objects were deserialized from the file.")
51+
return
52+
53+
click.echo(f"Deserialized {len(deserialized_objects)} objects.")
54+
55+
# Sort deserialized objects based on MODEL_LOAD_ORDER to handle dependencies.
56+
# Objects not in MODEL_LOAD_ORDER will be placed at the end.
57+
def get_sort_key(d_obj):
58+
model_key = f"{d_obj.object._meta.app_label}.{d_obj.object._meta.model_name}"
59+
try:
60+
return MODEL_LOAD_ORDER.index(model_key)
61+
except ValueError:
62+
return len(MODEL_LOAD_ORDER) # Put unknown models at the end
63+
64+
sorted_deserialized_objects = sorted(deserialized_objects, key=get_sort_key)
65+
66+
saved_count = 0
67+
skipped_count = 0
68+
error_count = 0
69+
70+
parsed_org_id = None
71+
if org_id:
72+
try:
73+
parsed_org_id = int(org_id)
74+
click.echo(
75+
f"Will update OrganizationIntegration objects to organization_id: {parsed_org_id}"
76+
)
77+
except ValueError:
78+
click.echo(
79+
f"Warning: Invalid org_id '{org_id}'. It will be ignored. Please provide a valid integer."
80+
)
81+
parsed_org_id = None
82+
83+
click.echo("Attempting to save objects to the database...")
84+
with atomic_transaction(
85+
using=(
86+
router.db_for_write(Integration),
87+
router.db_for_write(OrganizationIntegration),
88+
router.db_for_write(Identity),
89+
router.db_for_write(IdentityProvider),
90+
)
91+
):
92+
for deserialized_object in sorted_deserialized_objects:
93+
model_name = deserialized_object.object._meta.object_name
94+
pk = deserialized_object.object.pk
95+
96+
# If org_id is provided, update OrganizationIntegration's organization_id
97+
if parsed_org_id is not None and isinstance(
98+
deserialized_object.object, OrganizationIntegration
99+
):
100+
click.echo(
101+
f" Updating organization_id for {model_name} (PK: {pk}) to {parsed_org_id}"
102+
)
103+
deserialized_object.object.organization_id = parsed_org_id
104+
105+
try:
106+
# The deserialized_object.save() method handles saving the object
107+
# and its many-to-many data (if any). It attempts to use the PK
108+
# from the serialized data.
109+
deserialized_object.save()
110+
saved_count += 1
111+
click.echo(f" Saved: {model_name} (PK: {pk})")
112+
except IntegrityError as e:
113+
# This can occur due to PK conflict, unique constraint violation,
114+
# or a non-existent foreign key (e.g., if a referenced User or Organization
115+
# doesn't exist in the target DB).
116+
skipped_count += 1
117+
click.echo(f" Skipped: {model_name} (PK: {pk}) due to IntegrityError: {e}")
118+
except Exception as e:
119+
# Catch other potential errors during save.
120+
error_count += 1
121+
click.echo(f" Error saving: {model_name} (PK: {pk}): {e}")
122+
# Depending on severity, you might want to re-raise to stop the transaction.
123+
# For now, we'll log and continue.
124+
125+
click.echo("\nLoad process completed.")
126+
click.echo(f" Successfully saved: {saved_count} objects.")
127+
click.echo(f" Skipped (IntegrityError): {skipped_count} objects.")
128+
click.echo(f" Errors (Other): {error_count} objects.")
129+
if skipped_count > 0 or error_count > 0:
130+
click.echo(
131+
"Please check skipped/error messages. This might indicate that the target database was not clean,"
132+
)
133+
click.echo("or that required related objects (like Organizations or Users) were missing.")
134+
135+
136+
if __name__ == "__main__":
137+
parser = argparse.ArgumentParser(
138+
description="Load Sentry integration-related models from a JSON file into the database."
139+
)
140+
parser.add_argument(
141+
"--input-file",
142+
required=True,
143+
help="Path to the input JSON file containing the data to load.",
144+
)
145+
parser.add_argument(
146+
"--org-id",
147+
required=False,
148+
help="The organization ID to save integration data for.",
149+
)
150+
args = parser.parse_args()
151+
152+
load_data(args.input_file, args.org_id)

bin/save-integration-data

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
from sentry.runner import configure
3+
4+
configure()
5+
6+
import argparse
7+
8+
import click
9+
from django.core import serializers
10+
11+
from sentry.integrations.models import Integration, OrganizationIntegration
12+
from sentry.users.models.identity import Identity, IdentityProvider
13+
14+
MODELS_TO_SERIALIZE = [
15+
IdentityProvider, # Has no FKs to other serialized models
16+
Integration, # Has no FKs to other serialized models
17+
Identity, # Depends on IdentityProvider
18+
OrganizationIntegration, # Depends on Integration
19+
]
20+
21+
22+
def save_data(output_file):
23+
"""
24+
Collects data from specified models and serializes it to a JSON file.
25+
"""
26+
all_objects_to_serialize = []
27+
click.echo("Collecting data from models...")
28+
for model_cls in MODELS_TO_SERIALIZE:
29+
model_name = f"{model_cls._meta.app_label}.{model_cls._meta.model_name}"
30+
click.echo(f" Fetching from {model_name}...")
31+
# Order by PK for consistent output, though serializer might reorder.
32+
# Convert queryset to list to avoid issues with extending during iteration if any.
33+
objects = list(model_cls.objects.order_by("pk").all())
34+
all_objects_to_serialize.extend(objects)
35+
click.echo(f" Found {len(objects)} objects.")
36+
37+
if not all_objects_to_serialize:
38+
click.echo("No objects found to serialize.")
39+
serialized_data = "[]"
40+
else:
41+
click.echo(f"\nSerializing {len(all_objects_to_serialize)} objects in total...")
42+
serialized_data = serializers.serialize("json", all_objects_to_serialize, indent=2)
43+
44+
click.echo(f"Writing serialized data to {output_file}...")
45+
with open(output_file, "w") as f:
46+
f.write(serialized_data)
47+
click.echo(f"Successfully saved data to {output_file}")
48+
49+
50+
if __name__ == "__main__":
51+
parser = argparse.ArgumentParser(
52+
description="Save Sentry integration-related models to a JSON file."
53+
)
54+
parser.add_argument(
55+
"--output-file",
56+
required=True,
57+
help="Path to the output JSON file where data will be saved.",
58+
)
59+
args = parser.parse_args()
60+
61+
save_data(args.output_file)

build-utils/last-built-plugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3-
import type webpack from 'webpack';
3+
import type {Compiler} from 'webpack';
44

55
type Options = {
66
basePath: string;
@@ -15,7 +15,7 @@ class LastBuiltPlugin {
1515
this.isWatchMode = false;
1616
}
1717

18-
apply(compiler: webpack.Compiler) {
18+
apply(compiler: Compiler) {
1919
compiler.hooks.watchRun.tapAsync('LastBuiltPlugin', (_, callback) => {
2020
this.isWatchMode = true;
2121
callback();

0 commit comments

Comments
 (0)