Skip to content

Commit 0bfe441

Browse files
authored
Merge branch 'master' into tkdodo/ref/knip-zero
2 parents 9abf873 + adeeb0a commit 0bfe441

File tree

44 files changed

+644
-155
lines changed

Some content is hidden

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

44 files changed

+644
-155
lines changed

CHANGES

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
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+
133
25.5.0
234
------
335

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"url": "git://github.com/getsentry/sentry.git"
99
},
1010
"dependencies": {
11-
"@acemarke/react-prod-sourcemaps": "^0.2.1",
1211
"@amplitude/analytics-browser": "^1.5.3",
1312
"@babel/core": "~7.26.10",
1413
"@babel/plugin-transform-runtime": "~7.26.10",

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ ignore_missing_imports = true
112112
# - python3 -m tools.mypy_helpers.find_easiest_modules
113113
[[tool.mypy.overrides]]
114114
module = [
115-
"sentry.api.endpoints.group_integration_details",
116115
"sentry.api.endpoints.organization_events_meta",
117116
"sentry.api.endpoints.organization_events_spans_performance",
118117
"sentry.api.endpoints.organization_releases",

requirements-dev-frozen.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ cryptography==44.0.1
3737
cssselect==1.0.3
3838
cssutils==2.9.0
3939
datadog==0.49.1
40-
devservices==1.1.5
40+
devservices==1.1.6
4141
distlib==0.3.8
4242
distro==1.8.0
4343
django==5.2.1
@@ -181,7 +181,7 @@ selenium==4.16.0
181181
sentry-arroyo==2.21.0
182182
sentry-cli==2.16.0
183183
sentry-covdefaults-disable-branch-coverage==1.0.2
184-
sentry-devenv==1.20.0
184+
sentry-devenv==1.21.0
185185
sentry-forked-django-stubs==5.2.0.post3
186186
sentry-forked-djangorestframework-stubs==3.16.0.post1
187187
sentry-forked-email-reply-parser==0.5.12.post1

requirements-dev.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
--index-url https://pypi.devinfra.sentry.io/simple
22

3-
sentry-devenv>=1.20
4-
devservices>=1.1.5
3+
sentry-devenv>=1.21
4+
devservices>=1.1.6
55

66
covdefaults>=2.3.0
77
sentry-covdefaults-disable-branch-coverage>=1.0.2

src/sentry/api/endpoints/group_integration_details.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
from __future__ import annotations
2+
13
from collections.abc import Mapping, MutableMapping
24
from typing import Any
35

6+
from django.contrib.auth.models import AnonymousUser
47
from django.db import IntegrityError, router, transaction
58
from rest_framework.request import Request
69
from rest_framework.response import Response
@@ -12,8 +15,10 @@
1215
from sentry.api.bases import GroupEndpoint
1316
from sentry.api.serializers import serialize
1417
from sentry.integrations.api.serializers.models.integration import IntegrationSerializer
15-
from sentry.integrations.base import IntegrationFeatures, IntegrationInstallation
18+
from sentry.integrations.base import IntegrationFeatures
19+
from sentry.integrations.mixins.issues import IssueBasicIntegration
1620
from sentry.integrations.models.external_issue import ExternalIssue
21+
from sentry.integrations.models.integration import Integration
1722
from sentry.integrations.project_management.metrics import (
1823
ProjectManagementActionType,
1924
ProjectManagementEvent,
@@ -30,6 +35,7 @@
3035
from sentry.signals import integration_issue_created, integration_issue_linked
3136
from sentry.types.activity import ActivityType
3237
from sentry.users.models.user import User
38+
from sentry.users.services.user.model import RpcUser
3339

3440
MISSING_FEATURE_MESSAGE = "Your organization does not have access to this feature."
3541

@@ -46,7 +52,11 @@ def __init__(
4652
self.config = config
4753

4854
def serialize(
49-
self, obj: RpcIntegration, attrs: Mapping[str, Any], user: User, **kwargs: Any
55+
self,
56+
obj: Integration | RpcIntegration,
57+
attrs: Mapping[str, Any],
58+
user: User | RpcUser | AnonymousUser,
59+
**kwargs: Any,
5060
) -> MutableMapping[str, Any]:
5161
data = super().serialize(obj, attrs, user)
5262

@@ -68,7 +78,7 @@ class GroupIntegrationDetailsEndpoint(GroupEndpoint):
6878
"POST": ApiPublishStatus.UNKNOWN,
6979
}
7080

71-
def _has_issue_feature(self, organization, user):
81+
def _has_issue_feature(self, organization, user) -> bool:
7282
has_issue_basic = features.has(
7383
"organizations:integrations-issue-basic", organization, actor=user
7484
)
@@ -79,16 +89,24 @@ def _has_issue_feature(self, organization, user):
7989

8090
return has_issue_sync or has_issue_basic
8191

82-
def _has_issue_feature_on_integration(self, integration: RpcIntegration):
92+
def _has_issue_feature_on_integration(self, integration: RpcIntegration) -> bool:
8393
return integration.has_feature(
8494
feature=IntegrationFeatures.ISSUE_BASIC
8595
) or integration.has_feature(feature=IntegrationFeatures.ISSUE_SYNC)
8696

97+
def _get_installation(
98+
self, integration: RpcIntegration, organization_id: int
99+
) -> IssueBasicIntegration:
100+
installation = integration.get_installation(organization_id=organization_id)
101+
if not isinstance(installation, IssueBasicIntegration):
102+
raise ValueError(installation)
103+
return installation
104+
87105
def create_issue_activity(
88106
self,
89107
request: Request,
90108
group: Group,
91-
installation: IntegrationInstallation,
109+
installation: IssueBasicIntegration,
92110
external_issue: ExternalIssue,
93111
new: bool,
94112
):
@@ -108,7 +126,9 @@ def create_issue_activity(
108126
)
109127

110128
def get(self, request: Request, group, integration_id) -> Response:
111-
if not self._has_issue_feature(group.organization, request.user):
129+
if not request.user.is_authenticated:
130+
return Response(status=400)
131+
elif not self._has_issue_feature(group.organization, request.user):
112132
return Response({"detail": MISSING_FEATURE_MESSAGE}, status=400)
113133

114134
# Keep link/create separate since create will likely require
@@ -132,16 +152,16 @@ def get(self, request: Request, group, integration_id) -> Response:
132152
{"detail": "This feature is not supported for this integration."}, status=400
133153
)
134154

135-
installation = integration.get_installation(organization_id=organization_id)
136-
config = None
155+
installation = self._get_installation(integration, organization_id)
137156
try:
138157
if action == "link":
139158
config = installation.get_link_issue_config(group, params=request.GET)
140-
141-
if action == "create":
159+
elif action == "create":
142160
config = installation.get_create_issue_config(
143161
group, request.user, params=request.GET
144162
)
163+
else:
164+
raise AssertionError("unreachable")
145165
except IntegrationError as e:
146166
return Response({"detail": str(e)}, status=400)
147167

@@ -156,7 +176,9 @@ def get(self, request: Request, group, integration_id) -> Response:
156176

157177
# was thinking put for link an existing issue, post for create new issue?
158178
def put(self, request: Request, group, integration_id) -> Response:
159-
if not self._has_issue_feature(group.organization, request.user):
179+
if not request.user.is_authenticated:
180+
return Response(status=400)
181+
elif not self._has_issue_feature(group.organization, request.user):
160182
return Response({"detail": MISSING_FEATURE_MESSAGE}, status=400)
161183

162184
external_issue_id = request.data.get("externalIssue")
@@ -181,7 +203,7 @@ def put(self, request: Request, group, integration_id) -> Response:
181203
{"detail": "This feature is not supported for this integration."}, status=400
182204
)
183205

184-
installation = integration.get_installation(organization_id=organization_id)
206+
installation = self._get_installation(integration, organization_id)
185207

186208
try:
187209
data = installation.get_issue(external_issue_id, data=request.data)
@@ -254,7 +276,9 @@ def put(self, request: Request, group, integration_id) -> Response:
254276
return Response(context, status=201)
255277

256278
def post(self, request: Request, group, integration_id) -> Response:
257-
if not self._has_issue_feature(group.organization, request.user):
279+
if not request.user.is_authenticated:
280+
return Response(status=400)
281+
elif not self._has_issue_feature(group.organization, request.user):
258282
return Response({"detail": MISSING_FEATURE_MESSAGE}, status=400)
259283

260284
organization_id = group.project.organization_id
@@ -271,7 +295,7 @@ def post(self, request: Request, group, integration_id) -> Response:
271295
{"detail": "This feature is not supported for this integration."}, status=400
272296
)
273297

274-
installation = integration.get_installation(organization_id=organization_id)
298+
installation = self._get_installation(integration, organization_id)
275299

276300
with ProjectManagementEvent(
277301
action_type=ProjectManagementActionType.CREATE_EXTERNAL_ISSUE_VIA_ISSUE_DETAIL,

src/sentry/conf/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2694,7 +2694,7 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]:
26942694
SENTRY_SELF_HOSTED_ERRORS_ONLY = False
26952695
# only referenced in getsentry to provide the stable beacon version
26962696
# updated with scripts/bump-version.sh
2697-
SELF_HOSTED_STABLE_VERSION = "25.5.0"
2697+
SELF_HOSTED_STABLE_VERSION = "25.5.1"
26982698

26992699
# Whether we should look at X-Forwarded-For header or not
27002700
# when checking REMOTE_ADDR ip addresses

src/sentry/grouping/strategies/base.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,17 @@ def get_grouping_component(
228228
self, event: Event, context: GroupingContext, variant: str | None = None
229229
) -> None | BaseGroupingComponent[Any] | ReturnedVariants:
230230
"""Given a specific variant this calculates the grouping component."""
231-
args = []
232231
iface = event.interfaces.get(self.interface_name)
232+
233233
if iface is None:
234234
return None
235-
args.append(iface)
235+
236236
with context:
237237
# If a variant is passed put it into the context
238238
if variant is not None:
239239
context["variant"] = variant
240-
return self(event=event, context=context, *args)
240+
241+
return self(iface, event=event, context=context)
241242

242243
def get_grouping_components(self, event: Event, context: GroupingContext) -> ReturnedVariants:
243244
"""This returns a dictionary of all components by variant that this
@@ -325,7 +326,7 @@ def __repr__(self) -> str:
325326

326327
def iter_strategies(self) -> Iterator[Strategy[Any]]:
327328
"""Iterates over all strategies by highest score to lowest."""
328-
return iter(sorted(self.strategies.values(), key=lambda x: x.score and -x.score or 0))
329+
return iter(sorted(self.strategies.values(), key=lambda x: -x.score if x.score else 0))
329330

330331
@classmethod
331332
def as_dict(cls) -> dict[str, Any]:

src/sentry/grouping/strategies/configurations.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@
1111
# base is defined.
1212
BASE_STRATEGY = create_strategy_configuration(
1313
None,
14+
# Strategy priority is enforced programaticaly via the `score` argument to the `@strategy`
15+
# decorator (rather than by the order they're listed here), but they are nonetheless listed here
16+
# from highest to lowest priority for documentation purposes. The first strategy to produce a
17+
# result will become the winner.
1418
strategies=[
15-
"expect-ct:v1",
16-
"expect-staple:v1",
17-
"hpkp:v1",
18-
"csp:v1",
19+
"chained-exception:v1", # This handles single exceptions, too
1920
"threads:v1",
2021
"stacktrace:v1",
21-
"chained-exception:v1",
2222
"template:v1",
23+
"csp:v1",
24+
"hpkp:v1",
25+
"expect-staple:v1",
26+
"expect-ct:v1",
2327
"message:v1",
2428
],
2529
delegates=["frame:v1", "stacktrace:v1", "single-exception:v1"],

src/sentry/grouping/strategies/message.py

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,41 @@
2020
if TYPE_CHECKING:
2121
from sentry.eventstore.models import Event
2222

23+
REGEX_PATTERN_KEYS = (
24+
"email",
25+
"url",
26+
"hostname",
27+
"ip",
28+
"uuid",
29+
"sha1",
30+
"md5",
31+
"date",
32+
"duration",
33+
"hex",
34+
"float",
35+
"int",
36+
"quoted_str",
37+
"bool",
38+
)
39+
40+
EXPERIMENT_PROJECTS = [ # Active internal Sentry projects
41+
1,
42+
11276,
43+
54785,
44+
155735,
45+
162676,
46+
221969,
47+
300688,
48+
1267915,
49+
1269704,
50+
1492057,
51+
6424467,
52+
6690737,
53+
4503972821204992,
54+
4505469596663808,
55+
4506400311934976,
56+
]
57+
2358

2459
@metrics.wraps("grouping.normalize_message_for_grouping")
2560
def normalize_message_for_grouping(message: str, event: Event, share_analytics: bool = True) -> str:
@@ -37,23 +72,7 @@ def normalize_message_for_grouping(message: str, event: Event, share_analytics:
3772
trimmed += "..."
3873

3974
parameterizer = Parameterizer(
40-
regex_pattern_keys=(
41-
"email",
42-
"url",
43-
"hostname",
44-
"ip",
45-
"uuid",
46-
"sha1",
47-
"md5",
48-
"date",
49-
"duration",
50-
"hex",
51-
"float",
52-
"int",
53-
"quoted_str",
54-
"bool",
55-
),
56-
experiments=(UniqueIdExperiment,),
75+
regex_pattern_keys=REGEX_PATTERN_KEYS, experiments=(UniqueIdExperiment,)
5776
)
5877

5978
def _shoudl_run_experiment(experiment_name: str) -> bool:
@@ -64,24 +83,7 @@ def _shoudl_run_experiment(experiment_name: str) -> bool:
6483
in_rollout_group(
6584
f"grouping.experiments.parameterization.{experiment_name}", event.project_id
6685
)
67-
or event.project_id
68-
in [ # Active internal Sentry projects
69-
155735,
70-
4503972821204992,
71-
1267915,
72-
221969,
73-
11276,
74-
1269704,
75-
4505469596663808,
76-
1,
77-
54785,
78-
1492057,
79-
162676,
80-
6690737,
81-
300688,
82-
4506400311934976,
83-
6424467,
84-
]
86+
or event.project_id in EXPERIMENT_PROJECTS
8587
)
8688
)
8789

0 commit comments

Comments
 (0)