Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
1adb4fa
ref(plugins): Inline PluginComponentBase into its two subclasses (#11…
ryan953 May 26, 2026
beebb2b
feat(search): Register feature flag for recommended issue sort (#116191)
roggenkemper May 26, 2026
1070716
fix(issues): Make GroupSearchViewPermission fail closed for unknown o…
roggenkemper May 26, 2026
396de95
fix(security): Add project-level access check to GroupEventJsonView (…
roggenkemper May 26, 2026
34d677b
ref(spans): Extract flush_segment pipeline helpers (#116149)
lvthanh03 May 26, 2026
50400eb
fix(discover): Add org id to project filter (#116174)
nsdeschenes May 26, 2026
d8c5355
fix(discover): Add missing check for DiscoverSavedQueryVisitEndpoint …
nsdeschenes May 26, 2026
54dfe15
fix(search): Prevent Ask AI from doubling pasted query text (#116050)
isaacwang-sentry May 26, 2026
49abc57
fix(issues): match short id when combined with filters (#116153)
cvxluo May 26, 2026
f49b1af
feat(search): Surface recommended sort in UI when active via query pa…
roggenkemper May 26, 2026
0db91ad
chore(taskworker): Move devenv for profiles consumer to taskbroker (#…
untitaker May 26, 2026
131c63d
chore(typing): Remove `tests.sentry.issues.test_utils` from mypy igno…
shashjar May 26, 2026
bd1a8f7
feat(alerts): Add cleanup task to NotificationMessage (#116027)
ceorourke May 26, 2026
5b9be1f
fix(supergroups): move to post process task (#116195)
cvxluo May 26, 2026
9d49bb6
ref(utils): Various clarifications in `SafeRolloutComparator` code (#…
lobsterkatie May 26, 2026
0818156
fix(api-docs): correct event/replay/processing-error ID schemas (#116…
cvxluo May 26, 2026
8f9b260
chore(alerts): Remove AlertRuleSerializer (#116052)
ceorourke May 26, 2026
eb6c25a
feat(aci): Add sort param to workflow group history endpoint (#116031)
malwilley May 26, 2026
b006f90
chore(typing): Remove `tests.sentry.api.helpers.test_group_index` fro…
shashjar May 26, 2026
97880b2
ref(flags): Remove organizations:dashboards-drilldown-flow (#115670)
wedamija May 26, 2026
0ae8723
chore(autofix): Remove SCM requirement from autofix (#116206)
Zylphrex May 26, 2026
13ae4ff
feat(api-docs): publish project event details endpoint (#116059)
cvxluo May 26, 2026
c6327bd
ref(profiling): rename explore/profiling URL to explore/profiles (#11…
JoshuaKGoldberg May 26, 2026
b68ea04
ref(eslint): turn on no-unsafe-member-access for scraps (#116004)
TkDodo May 26, 2026
66da697
ref(seer): Remove seer-slack-workflows and seer-slack-explorer flags …
leeandher May 26, 2026
9831785
feat(seer): Add structured LLM context for replay list and detail pag…
Mihir-Mavalankar May 26, 2026
99f29ce
ref(mypy): Rename sort_stronger_modules to sort_weaklist (#116106)
armenzg May 26, 2026
c4fcb9f
fix(snapshots): Add instrumentation logging to snapshot download stre…
NicoHinderling May 26, 2026
9363a27
fix(explore): Use unique ids for visuals (#116204)
nsdeschenes May 26, 2026
4085619
fix(tracemetrics): Use equation alias format for widget builder (#116…
narsaynorath May 26, 2026
3dedd8c
chore(dashboards): remove text widget flag references backend (#116207)
nikkikapadia May 26, 2026
65b7262
chore(dashboards): remove text widget flag references frontend (#116210)
nikkikapadia May 26, 2026
fb36d28
feat(cmdk): Freeze visible action list during keyboard navigation (#1…
JonasBa May 26, 2026
1829c22
ref(utils): Make ParityChecker print out mismatches in a PII safe way…
Christinarlong May 26, 2026
443fec8
feat(search): Add recommended sort option to issue stream dropdown (#…
roggenkemper May 26, 2026
85b1329
fix(kafkapublisher): leaks memory: rdkafka stats grow without poll() …
moleus May 26, 2026
33e3655
deps: Upgrade sentry-scm to 0.16.0 (#116215)
cmanallen May 26, 2026
de836bc
chore(cells) Mainline org create via control (#116046)
markstory May 26, 2026
79b28b9
fix(issues): Fix sidebar comment box horizontal overflow (#116209)
scttcper May 26, 2026
8a215d2
chore(seer): Use `elif` instead of `if` in actionability filter logic…
shashjar May 26, 2026
dc57858
fix(events): correctly parse full parameter in group hashes endpoint …
cvxluo May 26, 2026
32990e6
fix(api): correctly parse `full` parameter in project events endpoint…
cvxluo May 26, 2026
aaca066
fix(webhooks): Route sentry app actions through send_alert_webhook_v2…
Christinarlong May 26, 2026
3963ffa
ref(seer): Move agent access check from entrypoint to operator (#116143)
leeandher May 26, 2026
cd5e6c0
feat(github-enterprise): Add API-driven pipeline backend for GHE inte…
evanpurkhiser May 26, 2026
590b629
chore(billing): Bump sentry-protos to 0.13.0 (#116133)
dashed May 26, 2026
1e74547
chore(workflow-engine): Edit flag with the correct prefix (#116198)
leeandher May 26, 2026
63415ef
fix(workflows): Filter out workflows from other organizations (#116075)
kcons May 26, 2026
b7c7417
chore: Remove code coverage stacktrace insights (#115417)
calvin-codecov May 26, 2026
194c378
chore(workflow-engine): Remove unused const (#116230)
leeandher May 26, 2026
c047824
docs(snapshots): Add public OpenAPI documentation for snapshot endpoi…
NicoHinderling May 26, 2026
91adf04
chore(relocation) Exclude Email model from relocations (#116226)
markstory May 26, 2026
1e0f751
ref(api-docs): add GroupDetailsResponse type, params, and example (#1…
cvxluo May 26, 2026
a1a5680
feat(issues): Bring back `SEER_PR_CREATED` activity creation and hide…
shashjar May 26, 2026
f57c72d
feat(webhooks): Add payload validation during dual-write migration (#…
Christinarlong May 26, 2026
79ff7ba
feat(github-enterprise): Add frontend pipeline steps for GHE integrat…
evanpurkhiser May 26, 2026
3689187
chore(vercel): Add logs on failure to add project (#116235)
ceorourke May 26, 2026
763211d
feat(cmdk): Add Open in Production and Open in Development actions (#…
JonasBa May 26, 2026
8a17856
Revert "chore(relocation) Exclude Email model from relocations (#1162…
getsentry-bot May 26, 2026
f31719b
fix(events): Debug param wasn't being passed down correctly (#116152)
wmak May 26, 2026
56ed755
fix(issue search): Fix invalid search query error message for device …
shashjar May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ repos:
types: [python]
- id: sort-mypy-weaklist
name: sort mypy weaklist
entry: python3 -m tools.mypy_helpers.sort_stronger_modules
entry: python3 -m tools.mypy_helpers.sort_weaklist
files: ^pyproject\.toml$
language: python
- id: check-mypy-weaklist
Expand Down
3 changes: 0 additions & 3 deletions api-docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@
"/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/hooks/{hook_id}/": {
"$ref": "paths/projects/service-hook-details.json"
},
"/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/events/{event_id}/": {
"$ref": "paths/events/project-event-details.json"
},
"/api/0/projects/{organization_id_or_slug}/{project_id_or_slug}/issues/": {
"$ref": "paths/events/project-issues.json"
},
Expand Down
556 changes: 0 additions & 556 deletions api-docs/paths/events/project-event-details.json

This file was deleted.

44 changes: 39 additions & 5 deletions devservices/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,18 @@ x-sentry-service-config:
repo_name: chartcuterie
branch: master
repo_link: https://github.com/getsentry/chartcuterie.git
taskbroker:
taskbroker: &taskbroker
description: Service used to process asynchronous tasks
remote:
repo_name: taskbroker
branch: main
repo_link: https://github.com/getsentry/taskbroker.git
mode: containerized
# ingest-profiles runs taskbroker in passthrough mode (STREAM-1041). Ideally
# this would be a remote dependency like taskbroker, but devservices doesn't
# support passing custom environment variables to remote services (DI-1956).
ingest-profiles:
description: Kafka consumer for processing profiling data via taskbroker passthrough mode
memcached:
description: Memcached used for caching
spotlight:
Expand Down Expand Up @@ -125,6 +130,8 @@ x-sentry-service-config:
description: Dedicated taskworker for eval Relay project config tasks
taskworker-scheduler:
description: Task scheduler that can spawn tasks based on their schedules
taskworker-ingest-profiles:
description: Taskworker for ingest-profiles passthrough broker
# Kafka consumer services for event ingestion
ingest-events:
description: Kafka consumer for processing ingested events
Expand All @@ -134,8 +141,6 @@ x-sentry-service-config:
description: Kafka consumer for processing ingested transactions
ingest-monitors:
description: Kafka consumer for processing monitor check-ins
ingest-profiles:
description: Kafka consumer for processing profiling data
ingest-occurrences:
description: Kafka consumer for processing issue occurrences
ingest-feedback-events:
Expand Down Expand Up @@ -241,6 +246,7 @@ x-sentry-service-config:
ingest-occurrences,
taskbroker,
taskworker,
taskworker-ingest-profiles,
post-process-forwarder-errors,
post-process-forwarder-transactions,
]
Expand Down Expand Up @@ -333,6 +339,7 @@ x-sentry-service-config:
spotlight,
taskbroker,
taskworker,
taskworker-ingest-profiles,
vroom,
]
full:
Expand Down Expand Up @@ -367,6 +374,7 @@ x-sentry-service-config:
post-process-forwarder-issue-platform,
taskbroker,
taskworker,
taskworker-ingest-profiles,
taskworker-scheduler,
]

Expand All @@ -385,6 +393,8 @@ x-programs:
command: sentry run taskworker --namespace relay --concurrency 1 --processing-pool-name eval-relay
taskworker-scheduler:
command: sentry run taskworker-scheduler
taskworker-ingest-profiles:
command: sentry run taskworker --rpc-host localhost:50052 --namespace ingest.profiling.passthrough
ingest-events:
command: sentry run consumer ingest-events --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
ingest-attachments:
Expand All @@ -399,8 +409,6 @@ x-programs:
command: sentry run consumer monitors-clock-tasks --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
monitors-incident-occurrences:
command: sentry run consumer monitors-incident-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
ingest-profiles:
command: sentry run consumer ingest-profiles --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
ingest-occurrences:
command: sentry run consumer ingest-occurrences --consumer-group=sentry-consumer --auto-offset-reset=latest --no-strict-offset-reset
process-spans:
Expand Down Expand Up @@ -483,6 +491,32 @@ services:
- devservices
labels:
- orchestrator=devservices
# Taskbroker in passthrough mode for ingest-profiles topic (STREAM-1041).
# This is a local service rather than a remote dependency because devservices
# doesn't support passing custom environment variables to remote services (DI-1956).
ingest-profiles:
image: ghcr.io/getsentry/taskbroker:nightly
environment:
TASKBROKER_KAFKA_CLUSTER: 'kafka-kafka-1:9093'
TASKBROKER_KAFKA_TOPIC: 'profiles'
TASKBROKER_KAFKA_CONSUMER_GROUP: 'ingest-profiles'
TASKBROKER_CREATE_MISSING_TOPICS: 'true'
TASKBROKER_RAW_MODE: 'true'
TASKBROKER_RAW_NAMESPACE: 'ingest.profiling.passthrough'
TASKBROKER_RAW_APPLICATION: 'sentry'
TASKBROKER_RAW_TASKNAME: 'sentry.profiles.task.process_profile_from_kafka'
# TODO(STREAM-1041): Remove debug logging once passthrough mode is stable
TASKBROKER_LOG_FILTER: 'debug'
ports:
- '127.0.0.1:50052:50051'
networks:
- devservices
extra_hosts:
- host.docker.internal:host-gateway
labels:
- orchestrator=devservices
restart: unless-stopped
platform: linux/amd64

networks:
devservices:
Expand Down
2 changes: 2 additions & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,8 @@ export default typescript.config([
...(enableTypeAwareLinting && {
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
}),
},
Expand Down
7 changes: 2 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ dependencies = [
"sentry-forked-email-reply-parser>=0.5.12.post1",
"sentry-kafka-schemas>=2.1.27",
"sentry-ophio>=1.1.3",
"sentry-protos>=0.10.0",
"sentry-protos>=0.13.0",
"sentry-redis-tools>=0.5.0",
"sentry-relay>=0.9.27",
"sentry-scm>=0.14.0",
"sentry-scm==0.16.0",
"sentry-sdk[http2]>=2.59.0",
"sentry-usage-accountant>=0.0.10",
# remove once there are no unmarked transitive dependencies on setuptools
Expand Down Expand Up @@ -397,8 +397,6 @@ module = [
"sentry.services.eventstore.models",
"sentry.snuba.metrics.query_builder",
"sentry.testutils.cases",
"tests.sentry.api.helpers.test_group_index",
"tests.sentry.issues.test_utils",
]
disable_error_code = [
"arg-type",
Expand Down Expand Up @@ -1640,7 +1638,6 @@ module = [
"sentry.web.frontend.debug.debug_error_embed",
"sentry.web.frontend.debug.debug_feedback_issue",
"sentry.web.frontend.debug.debug_generic_issue",
"sentry.web.frontend.debug.debug_incident_trigger_email",
"sentry.web.frontend.debug.debug_invalid_identity_email",
"sentry.web.frontend.debug.debug_mfa_added_email",
"sentry.web.frontend.debug.debug_mfa_removed_email",
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/bases/organization_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def get_dataset(self, request: Request, organization: Organization) -> Any:
# Feature flag the occurrence endpoint
if (
dataset_label == SupportedTraceItemType.OCCURRENCES.value
and not EAPOccurrencesComparator.should_use_experiment("api.events.endpoints")
and not EAPOccurrencesComparator.should_use_experimental_data("api.events.endpoints")
):
raise ParseError(detail=f"{dataset_label} is not supported currently")
elif dataset_label == SupportedTraceItemType.REPLAYS.value and not features.has(
Expand Down
22 changes: 17 additions & 5 deletions src/sentry/api/endpoints/organization_events_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,24 @@ def serialize_stats_data(
) -> StatsResponse:
# We need the current timestamp for the Ingestion Delay incomplete reason
now = datetime.now().timestamp()
stats_meta = StatsMeta(
dataset=DATASET_LABELS[dataset],
start=snuba_params.start_date.timestamp() * 1000,
end=snuba_params.end_date.timestamp() * 1000,
)
if snuba_params.debug:
debug_info = None
if isinstance(result, SnubaTSResult) and "debug_info" in result.data["meta"]:
debug_info = result.data["meta"]["debug_info"]
elif isinstance(result, dict):
debug_info = {}
for key, keyed_result in result.items():
if "debug_info" in keyed_result.data["meta"]:
debug_info[key] = keyed_result.data["meta"]["debug_info"]
# ignore typing here cause we don't want the openapi docs to include debug_info
stats_meta["debug_info"] = debug_info # type: ignore[typeddict-unknown-key]
response = StatsResponse(
meta=StatsMeta(
dataset=DATASET_LABELS[dataset],
start=snuba_params.start_date.timestamp() * 1000,
end=snuba_params.end_date.timestamp() * 1000,
),
meta=stats_meta,
timeSeries=self.serialize_result(result, axes, rollup, now),
)
return response
Expand Down
4 changes: 2 additions & 2 deletions src/sentry/api/endpoints/organization_events_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def load_performance_issues(self, light: bool, snuba_params: SnubaParams) -> Non
control_data=occurrence_ids,
experimental_data=eap_occurrence_ids,
callsite=callsite,
is_experimental_data_a_null_result=len(eap_occurrence_ids) == 0,
is_experimental_data_nullish=len(eap_occurrence_ids) == 0,
reasonable_match_comparator=lambda snuba, eap: {
row["occurrence_id"] for row in eap
}.issubset({row["occurrence_id"] for row in snuba}),
Expand Down Expand Up @@ -827,7 +827,7 @@ def query_trace_data(
control_data=transformed_results[1],
experimental_data=eap_errors,
callsite=errors_callsite,
is_experimental_data_a_null_result=len(eap_errors) == 0,
is_experimental_data_nullish=len(eap_errors) == 0,
reasonable_match_comparator=lambda snuba, eap: {e["id"] for e in eap}.issubset(
{e["id"] for e in snuba}
),
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/organization_trace_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def run_errors_query(trace_id: str, snuba_params: SnubaParams) -> int:
snuba_count,
eap_count,
callsite,
is_experimental_data_a_null_result=(eap_count == 0),
is_experimental_data_nullish=(eap_count == 0),
reasonable_match_comparator=lambda snuba, eap: eap <= snuba,
debug_context={
"trace_id": trace_id,
Expand Down
4 changes: 2 additions & 2 deletions src/sentry/api/endpoints/organization_traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def enrich_eap_traces_with_extra_data(
traces_errors,
eap_traces_errors,
errors_callsite,
is_experimental_data_a_null_result=len(eap_traces_errors) == 0,
is_experimental_data_nullish=len(eap_traces_errors) == 0,
reasonable_match_comparator=_reasonable_trace_count_map_match,
debug_context=debug_context,
)
Expand All @@ -386,7 +386,7 @@ def enrich_eap_traces_with_extra_data(
traces_occurrences,
eap_traces_occurrences,
occurrences_callsite,
is_experimental_data_a_null_result=len(eap_traces_occurrences) == 0,
is_experimental_data_nullish=len(eap_traces_occurrences) == 0,
reasonable_match_comparator=_reasonable_trace_count_map_match,
debug_context=debug_context,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def get_errors_counts_timeseries_by_project_and_release(
snuba_results,
eap_results,
"release_thresholds.get_errors_counts_timeseries",
is_experimental_data_a_null_result=len(eap_results) == 0,
is_experimental_data_nullish=len(eap_results) == 0,
reasonable_match_comparator=lambda snuba_rows, eap_rows: keyed_counts_subset_match(
snuba_rows,
eap_rows,
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/helpers/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def run_group_events_query(
snuba_data,
eap_data,
callsite,
is_experimental_data_a_null_result=len(eap_data) == 0,
is_experimental_data_nullish=len(eap_data) == 0,
reasonable_match_comparator=_reasonable_group_events_match,
debug_context={
"group_id": group.id,
Expand Down
15 changes: 10 additions & 5 deletions src/sentry/api/helpers/group_index/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,16 @@ def get_by_short_id(
is_short_id_lookup: str,
query: str,
) -> Group | None:
if is_short_id_lookup == "1" and looks_like_short_id(query):
try:
return Group.objects.by_qualified_short_id(organization_id, query)
except Group.DoesNotExist:
pass
if is_short_id_lookup != "1":
return None
# A short id token anywhere in the query is treated as a direct hit,
# so it composes with filters.
for token in query.split():
if looks_like_short_id(token):
try:
return Group.objects.by_qualified_short_id(organization_id, token)
except Group.DoesNotExist:
continue
return None


Expand Down
4 changes: 2 additions & 2 deletions src/sentry/api/helpers/group_index/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ def handle_is_public(


def handle_assigned_to(
assigned_actor: Actor,
assigned_actor: Actor | None,
assigned_by: str | None,
integration: str | None,
group_list: Sequence[Group],
Expand All @@ -1073,7 +1073,7 @@ def handle_assigned_to(
if integration in [ActivityIntegration.SLACK.value, ActivityIntegration.MSTEAMS.value]
else dict()
)
if assigned_actor:
if assigned_actor is not None:
resolved_actor = assigned_actor.resolve()
for group in group_list:
assignment = GroupAssignee.objects.assign(
Expand Down
25 changes: 25 additions & 0 deletions src/sentry/api/serializers/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,31 @@ class BaseGroupSerializerResponse(BaseGroupResponseOptional):
annotations: list[GroupAnnotation]


class GroupDetailsResponseOptional(TypedDict, total=False):
# Included by default; removable via `?collapse=release|tags|stats`
firstRelease: dict[str, Any] | None
lastRelease: dict[str, Any] | None
tags: list[dict[str, Any]]
stats: dict[str, list[list[float]]]
# Opt-in via `?expand=...`
inbox: dict[str, Any] | None
owners: list[dict[str, Any]] | None
forecast: dict[str, Any]
integrationIssues: list[dict[str, Any]]
sentryAppIssues: list[dict[str, Any]]
latestEventHasAttachments: bool


class GroupDetailsResponse(BaseGroupSerializerResponse, GroupDetailsResponseOptional):
activity: list[dict[str, Any]]
seenBy: list[dict[str, Any]]
pluginActions: list[Any]
pluginIssues: list[dict[str, Any]]
pluginContexts: list[dict[str, Any]]
userReportCount: int
participants: list[dict[str, Any]]


class SeenStats(TypedDict):
times_seen: int
first_seen: datetime | None
Expand Down
7 changes: 0 additions & 7 deletions src/sentry/api/serializers/rest_framework/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,13 +462,6 @@ def to_internal_value(self, data):
return super().to_internal_value(data)

def _validate_text_widget(self, data):
if not features.has(
"organizations:dashboards-text-widgets",
organization=self.context["organization"],
actor=self.context["request"].user,
):
raise serializers.ValidationError({"display_type": "Text widgets are not enabled"})

if data.get("widget_type"):
raise serializers.ValidationError(
{"widget_type": "Text widgets don't have a widget type or dataset"}
Expand Down
Loading
Loading