Skip to content

Commit 8300841

Browse files
authored
Merge branch 'master' into priscila/fix/drawer-header-responsive-alignment
2 parents fb8e185 + 7e3195c commit 8300841

File tree

283 files changed

+6800
-24917
lines changed

Some content is hidden

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

283 files changed

+6800
-24917
lines changed

.github/file-filters.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
sentry_frontend_workflow_file: &sentry_frontend_workflow_file
44
- added|modified: '.github/workflows/frontend.yml'
55

6+
sentry_frontend_snapshots_workflow_file: &sentry_frontend_snapshots_workflow_file
7+
- added|modified: '.github/workflows/frontend-snapshots.yml'
8+
69
# Provides list of changed files to test (jest)
710
# getsentry/sentry does not use the list directly, instead we shard tests inside jest.config.js
811
testable_modified: &testable_modified
@@ -30,6 +33,7 @@ typecheckable_rules_changed: &typecheckable_rules_changed
3033
# Trigger to apply the 'Scope: Frontend' label to PRs
3134
frontend_all: &frontend_all
3235
- *sentry_frontend_workflow_file
36+
- *sentry_frontend_snapshots_workflow_file
3337
- added|modified: '**/*.{ts,tsx,js,jsx,mjs}'
3438
- added|modified: 'static/**/*.{less,json,yml,md,mdx}'
3539
- added|modified: '{vercel,tsconfig,biome,package}.json'

.github/workflows/frontend-snapshots.yml

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,19 @@ jobs:
6969

7070
- name: Install sentry-cli
7171
if: ${{ !cancelled() }}
72-
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.4 sh
72+
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.5 sh
7373

7474
- name: Upload snapshots
7575
id: upload
7676
if: ${{ !cancelled() }}
7777
env:
7878
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_SNAPSHOTS_AUTH_TOKEN }}
79-
run: |
80-
ARGS=(
81-
--log-level=debug
82-
--auth-token "${{ secrets.SENTRY_SNAPSHOTS_AUTH_TOKEN }}"
83-
build snapshots "${{ env.SNAPSHOT_OUTPUT_DIR }}"
84-
--app-id sentry-frontend
85-
--project sentry-frontend
86-
--head-sha "${{ github.event.pull_request.head.sha || github.sha }}"
87-
--vcs-provider github
88-
--head-repo-name "${{ github.repository }}"
89-
)
90-
91-
# PR-only flags: base-sha, base-ref, base-repo-name, head-ref, pr-number
92-
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
93-
ARGS+=(
94-
--base-sha "${{ github.event.pull_request.base.sha }}"
95-
--base-repo-name "${{ github.repository }}"
96-
--head-ref "${{ github.head_ref }}"
97-
--base-ref "${{ github.base_ref }}"
98-
--pr-number "${{ github.event.number }}"
99-
)
100-
fi
101-
102-
sentry-cli "${ARGS[@]}"
79+
run: >
80+
sentry-cli
81+
--log-level=debug
82+
build snapshots "${{ env.SNAPSHOT_OUTPUT_DIR }}"
83+
--app-id sentry-frontend
84+
--project sentry-frontend
10385
10486
- name: Report upload failure to Sentry
10587
if: ${{ failure() && steps.upload.outcome == 'failure' }}

CHANGES

Lines changed: 2286 additions & 0 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ dependencies = [
8787
"sentry-forked-email-reply-parser>=0.5.12.post1",
8888
"sentry-kafka-schemas>=2.1.27",
8989
"sentry-ophio>=1.1.3",
90-
"sentry-protos>=0.8.11",
90+
"sentry-protos>=0.8.12",
9191
"sentry-redis-tools>=0.5.0",
92-
"sentry-relay>=0.9.26",
92+
"sentry-relay>=0.9.27",
93+
"sentry-scm>=0.1.7",
9394
"sentry-sdk[http2]>=2.47.0",
9495
"sentry-usage-accountant>=0.0.10",
9596
# remove once there are no unmarked transitive dependencies on setuptools

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = sentry
3-
version = 26.4.0.dev0
3+
version = 26.5.0.dev0
44
description = A realtime logging and aggregation server.
55
long_description = file: README.md
66
long_description_content_type = text/markdown

src/sentry/api/endpoints/internal/feature_flags.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections.abc import Mapping
2+
13
from django.conf import settings
24
from rest_framework.request import Request
35
from rest_framework.response import Response
@@ -10,6 +12,30 @@
1012
from sentry.runner.settings import configure, discover_configs
1113

1214

15+
def _coerce_early_feature_flag_value(value: object) -> bool | None:
16+
"""
17+
Map API input to a bool for SENTRY_FEATURES. Accepts JSON booleans, 0/1
18+
(common in scripts), and the strings "true"/"false" (case-insensitive).
19+
Returns None if the value cannot be interpreted safely.
20+
"""
21+
if isinstance(value, bool):
22+
return value
23+
if isinstance(value, int):
24+
if value == 1:
25+
return True
26+
if value == 0:
27+
return False
28+
return None
29+
if isinstance(value, str):
30+
lowered = value.lower()
31+
if lowered == "true":
32+
return True
33+
if lowered == "false":
34+
return False
35+
return None
36+
return None
37+
38+
1339
@all_silo_endpoint
1440
class InternalFeatureFlagsEndpoint(Endpoint):
1541
permission_classes = (SuperuserPermission,)
@@ -36,18 +62,38 @@ def put(self, request: Request) -> Response:
3662
if not settings.SENTRY_SELF_HOSTED:
3763
return Response("You are not self-hosting Sentry.", status=403)
3864

39-
data = request.data.keys()
40-
valid_feature_flags = [flag for flag in data if SENTRY_EARLY_FEATURES.get(flag, False)]
65+
payload: object = request.data
66+
if not isinstance(payload, Mapping):
67+
return Response(
68+
{"detail": "Feature flag updates must be a JSON object."},
69+
status=400,
70+
)
71+
72+
valid_feature_flags = [flag for flag in payload if flag in SENTRY_EARLY_FEATURES]
73+
coerced_values: dict[str, bool] = {}
74+
for valid_flag in valid_feature_flags:
75+
coerced = _coerce_early_feature_flag_value(payload.get(valid_flag))
76+
if coerced is None:
77+
return Response(
78+
{
79+
"detail": (
80+
f'Feature flag "{valid_flag}" must be true or false '
81+
f"(boolean, 0 or 1, or the string true or false)."
82+
)
83+
},
84+
status=400,
85+
)
86+
coerced_values[valid_flag] = coerced
87+
4188
_, py, yml = discover_configs()
4289
# Open the file for reading and writing
4390
with open(py, "r+") as file:
4491
lines = file.readlines()
4592
# print(lines)
4693
for valid_flag in valid_feature_flags:
4794
match_found = False
48-
new_string = (
49-
f'\nSENTRY_FEATURES["{valid_flag}"]={request.data.get(valid_flag, False)}\n'
50-
)
95+
python_bool = "True" if coerced_values[valid_flag] else "False"
96+
new_string = f'\nSENTRY_FEATURES["{valid_flag}"]={python_bool}\n'
5197
# Search for the string match and update lines
5298
for i, line in enumerate(lines):
5399
if valid_flag in line:

src/sentry/api/endpoints/organization_spans_fields.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@
3636
from sentry.utils import snuba_rpc
3737

3838

39-
def as_tag_key(name: str, type: Literal["string", "number", "boolean"]):
40-
key, _, _ = translate_internal_to_public_alias(name, type, SupportedTraceItemType.SPANS)
39+
def as_tag_key(name: str, search_type: Literal["string", "number", "boolean"]):
40+
key, _, _ = translate_internal_to_public_alias(name, search_type, SupportedTraceItemType.SPANS)
4141

4242
if key is not None:
4343
name = key
44-
elif type == "number":
44+
elif search_type == "number":
4545
key = f"tags[{name},number]"
46-
elif type == "boolean":
46+
elif search_type == "boolean":
4747
key = f"tags[{name},boolean]"
4848
else:
4949
key = name

src/sentry/api/serializers/models/exporteddata.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,5 @@ def serialize(self, obj, attrs, user, **kwargs):
4747
"status": obj.status,
4848
"checksum": checksum,
4949
"fileName": file_name,
50+
"export_format": obj.export_format,
5051
}

src/sentry/api/serializers/models/organization.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ class BaseOrganizationSerializer(serializers.Serializer):
170170
max_length=DEFAULT_SLUG_MAX_LENGTH,
171171
)
172172

173+
def validate_name(self, value: str) -> str:
174+
if "://" in value:
175+
raise serializers.ValidationError(
176+
"Organization name cannot contain URL schemes (e.g. http:// or https://)."
177+
)
178+
return value
179+
173180
def validate_slug(self, value: str) -> str:
174181
# Historically, the only check just made sure there was more than 1
175182
# character for the slug, but since then, there are many slugs that

src/sentry/api/serializers/models/rule.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from sentry.api.serializers import Serializer, register
1212
from sentry.constants import ObjectStatus
1313
from sentry.db.models.manager.base_query_set import BaseQuerySet
14+
from sentry.integrations.services.integration.model import RpcIntegration
15+
from sentry.integrations.services.integration.service import integration_service
1416
from sentry.models.environment import Environment
1517
from sentry.models.project import Project
1618
from sentry.models.rule import NeglectedRule, Rule, RuleActivity, RuleActivityType
@@ -591,6 +593,22 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
591593
)
592594
actions_by_dcg = self._fetch_actions_by_dcg(all_dcg_ids)
593595

596+
# Batch-fetch integrations for all actions to avoid per-action RPC calls in render_label
597+
all_integration_ids: set[int] = set()
598+
for action_list in actions_by_dcg.values():
599+
for action in action_list:
600+
if action.integration_id is not None:
601+
all_integration_ids.add(action.integration_id)
602+
603+
integration_cache: dict[int, RpcIntegration] = {}
604+
if all_integration_ids and item_list:
605+
integrations = integration_service.get_integrations(
606+
integration_ids=list(all_integration_ids),
607+
organization_id=item_list[0].organization_id,
608+
status=ObjectStatus.ACTIVE,
609+
)
610+
integration_cache = {i.id: i for i in integrations}
611+
594612
last_triggered_lookup: dict[int, datetime] = {}
595613
if "lastTriggered" in self.expand:
596614
last_triggered_lookup = self._fetch_workflow_last_triggered(item_list)
@@ -667,7 +685,7 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
667685
continue
668686

669687
action_data["name"] = action_to_handler[action].render_label(
670-
workflow.organization_id, action_data
688+
workflow.organization_id, action_data, integration_cache=integration_cache
671689
)
672690
installation_uuid = action_data.get("sentryAppInstallationUuid")
673691
install_context = None

0 commit comments

Comments
 (0)