Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
da8d53b
fix(organization) Fix an issue with deleting an older Organization (#…
swartzrock Mar 31, 2026
0e78176
perf(events): Use cached group lookup on existing grouphash associati…
beezz Mar 31, 2026
13cf85c
Remove Add Billing Metric Usage admin UI (#111805)
noahsmartin Mar 31, 2026
dfb3249
fix(dashboards): Render star icon header for is_starred_transaction c…
DominikB2014 Mar 31, 2026
a5f6160
fix(copilot): Update models for GitHub Copilot Tasks API field migrat…
JoshFerge Mar 31, 2026
57ae7b6
ref(seer): Move organizationConfigIntegrationsQueryOptions to be co-l…
ryan953 Mar 31, 2026
1d2b4ca
feat(supergroups): Add feedback component and experimental badge to d…
scttcper Mar 31, 2026
d947df8
ref(nav) realign indicators (#111816)
JonasBa Mar 31, 2026
e24356d
Revert "feat(seer): Update default triggers for Code Review (#111829)"
getsentry-bot Mar 31, 2026
be610d1
ref(grouping): remove `useReranking` from similar issues UI (#111867)
cvxluo Mar 31, 2026
0cd47ac
ref(grouping): always use reranking for similarity (#111866)
cvxluo Mar 31, 2026
615e4b5
feat(pipeline): Detect API-driven pipelines in existing callback URL …
evanpurkhiser Mar 31, 2026
823f751
feat(seer): Add RPC interface for retrieving the installation_id (#11…
cmanallen Mar 31, 2026
6a04d30
✨ feat(gitlab): add inbound status sync support (#107139)
iamrajjoshi Mar 31, 2026
f2fc521
ref(errors): Explicitly throw on empty group_id snuba query (#110923)
thetruecpaul Mar 31, 2026
0d24b83
feat(seer): Update default triggers for Code Review (#111911)
ryan953 Mar 31, 2026
b266553
chore(deps): bump pyjwt from 2.10.1 to 2.12.0 (#110969)
dependabot[bot] Mar 31, 2026
7dd85b0
feat(core-ui): Add ClearButton to CompositeSelect (#111706)
nsdeschenes Mar 31, 2026
a09a4b1
chore(grouping): Remove unused seer backfill options (#111896)
cvxluo Mar 31, 2026
db61be2
feat(slack): Implement process_mention_for_slack task for Explorer (#…
alexsohn1126 Mar 31, 2026
8a8d0cf
ref(aci): Use Section component for form sections in Alerts builder (…
malwilley Mar 31, 2026
506d7d9
ref(cells): Update assert_webhook_payloads_for_mailbox (#111856)
lynnagara Mar 31, 2026
748eea6
chore(aci): All create monitor buttons should link to type selection …
malwilley Mar 31, 2026
48a6b9a
ref(cells): Update slack and discord tasks to accept cell_name (#111858)
lynnagara Mar 31, 2026
9b4d18d
feat(search): Switch filter operator from contains to is on dropdown …
nsdeschenes Mar 31, 2026
bb1eb15
feat(sentry apps): Add circuit breaker into webhook code (#111723)
Christinarlong Mar 31, 2026
ba1591e
fix(st): add src/sentry/constants.py to full_suite_triggers (#111922)
joshuarli Mar 31, 2026
e8a2643
feat(features): Add data browsing widget unfurl feature flag (#111897)
DominikB2014 Mar 31, 2026
e818053
feat(occurrences on eap): Implement EAP query for tagstore groups use…
shashjar Mar 31, 2026
181221d
ref: bump sentry-arroyo to 2.38.5 (#111789)
getsentry-bot Mar 31, 2026
9b16dfe
fix(onboarding): Wrap connected tag in Container to constrain width (…
jaydgoss Mar 31, 2026
c196e71
feat(admin): Replace startup program notes field with program dropdow…
rahulchhabria Mar 31, 2026
9e883ab
feat(preprod): Add shadow taskbroker dispatch for launchpad integrati…
NicoHinderling Mar 31, 2026
d28c826
feat(github): Add API-driven GitHub integration setup (#111728)
evanpurkhiser Mar 31, 2026
8ecaf1c
fix(grouping): Fix int parameterization bugs (#111870)
lobsterkatie Mar 31, 2026
ec94c1d
feat(occurrences on eap): Implement EAP query for tagstore groups use…
shashjar Mar 31, 2026
f49ecc7
feat(occurrences on eap): Implement EAP query for tagstore group tag …
shashjar Mar 31, 2026
2ec9940
refs(github): Remove github-multi-org-upsell-modal flag (#111940)
evanpurkhiser Mar 31, 2026
5800193
feat(preprod): Add value, conditions, and config to size analysis evi…
mtopo27 Mar 31, 2026
a5b35d9
Remove github-multi-org-upsell-modal feature flag from frontend (#111…
evanpurkhiser Mar 31, 2026
391f517
ref(grouping): Simplify parameterizer code (#111345)
lobsterkatie Mar 31, 2026
7abfaf7
ref(cells): Update org creation testutils to pass cell kwarg (#111819)
lynnagara Mar 31, 2026
d0a7b18
ref(apigateway): async proxy timeouts configuration (#111918)
gi0baro Mar 31, 2026
e260849
perf(workflows): Avoid excessive querying in WorkflowEngineRuleSerial…
kcons Mar 31, 2026
3085867
feat(seer): Seer Autofix Settings Overview page (#110758)
ryan953 Mar 31, 2026
5f0a97f
fix(issues): Avoid supergroup refetches on row removal (#111865)
scttcper Mar 31, 2026
8503c7d
perf(feedback): Collapse stats on feedback group details request (#11…
scttcper Mar 31, 2026
f6c8196
styles(autofix): Add more whitespace to autofix cards (#111951)
Zylphrex Mar 31, 2026
2a005ec
perf(workflows): Batch Action fetching in WorkflowEngineRuleSerialize…
kcons Mar 31, 2026
50cabc0
feat(feedback): Redirect to the feedback details page when given a pr…
ryan953 Mar 31, 2026
3f75bac
ref(seer): Async load ScmRepoTreeModal where its used (#111959)
ryan953 Mar 31, 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: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/src/sentry/sentry_apps/ @getsentry/product-owners-settings-integrations @getsentry/ecosystem
/tests/sentry/sentry_apps/ @getsentry/product-owners-settings-integrations @getsentry/ecosystem
/src/sentry/utils/sentry_apps/ @getsentry/ecosystem
/tests/sentry/utils/sentry_apps/ @getsentry/ecosystem
/src/sentry/middleware/integrations/ @getsentry/ecosystem
/src/sentry/api/endpoints/project_rule*.py @getsentry/alerts-notifications
/src/sentry/api/serializers/models/rule.py @getsentry/alerts-notifications
Expand Down Expand Up @@ -890,6 +891,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get

# Cell architecture
/.agents/skills/cell-architecture @getsentry/sre-infrastructure-engineering
tests/sentry/core/endpoints/test_organization_cell.py @getsentry/sre-infrastructure-engineering
# End of cell architecture

# Foundational Storage
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/scripts/compute-sentry-selected-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

FULL_SUITE_TRIGGERS: list[str | re.Pattern[str]] = [
"src/sentry/testutils/pytest/sentry.py",
"src/sentry/constants.py",
"pyproject.toml",
"src/sentry/conf/server.py",
"src/sentry/web/urls.py",
Expand Down
150 changes: 150 additions & 0 deletions fixtures/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,156 @@ def create_gitlab_repo(
}
"""

ISSUE_CLOSED_EVENT = b"""{
"object_kind": "issue",
"event_type": "issue",
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/avatar.jpg",
"email": "admin@example.com"
},
"project": {
"id": 15,
"name": "Sentry",
"description": "",
"web_url": "http://example.com/cool-group/sentry",
"avatar_url": null,
"git_ssh_url": "git@example.com:cool-group/sentry.git",
"git_http_url": "http://example.com/cool-group/sentry.git",
"namespace": "cool-group",
"visibility_level": 0,
"path_with_namespace": "cool-group/sentry",
"default_branch": "master",
"homepage": "http://example.com/cool-group/sentry",
"url": "git@example.com:cool-group/sentry.git",
"ssh_url": "git@example.com:cool-group/sentry.git",
"http_url": "http://example.com/cool-group/sentry.git"
},
"object_attributes": {
"id": 301,
"title": "Test issue",
"assignee_ids": [],
"assignee_id": null,
"author_id": 1,
"project_id": 15,
"created_at": "2023-01-01 00:00:00 UTC",
"updated_at": "2023-01-01 00:00:00 UTC",
"position": 0,
"branch_name": null,
"description": "Test issue description",
"milestone_id": null,
"state": "closed",
"iid": 23,
"url": "http://example.com/cool-group/sentry/issues/23",
"action": "close"
},
"assignees": [],
"labels": []
}
"""

ISSUE_REOPENED_EVENT = b"""{
"object_kind": "issue",
"event_type": "issue",
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/avatar.jpg",
"email": "admin@example.com"
},
"project": {
"id": 15,
"name": "Sentry",
"description": "",
"web_url": "http://example.com/cool-group/sentry",
"avatar_url": null,
"git_ssh_url": "git@example.com:cool-group/sentry.git",
"git_http_url": "http://example.com/cool-group/sentry.git",
"namespace": "cool-group",
"visibility_level": 0,
"path_with_namespace": "cool-group/sentry",
"default_branch": "master",
"homepage": "http://example.com/cool-group/sentry",
"url": "git@example.com:cool-group/sentry.git",
"ssh_url": "git@example.com:cool-group/sentry.git",
"http_url": "http://example.com/cool-group/sentry.git"
},
"object_attributes": {
"id": 301,
"title": "Test issue",
"assignee_ids": [],
"assignee_id": null,
"author_id": 1,
"project_id": 15,
"created_at": "2023-01-01 00:00:00 UTC",
"updated_at": "2023-01-01 00:00:00 UTC",
"position": 0,
"branch_name": null,
"description": "Test issue description",
"milestone_id": null,
"state": "opened",
"iid": 23,
"url": "http://example.com/cool-group/sentry/issues/23",
"action": "reopen"
},
"assignees": [],
"labels": []
}
"""

ISSUE_OPENED_EVENT = b"""{
"object_kind": "issue",
"event_type": "issue",
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/avatar.jpg",
"email": "admin@example.com"
},
"project": {
"id": 15,
"name": "Sentry",
"description": "",
"web_url": "http://example.com/cool-group/sentry",
"avatar_url": null,
"git_ssh_url": "git@example.com:cool-group/sentry.git",
"git_http_url": "http://example.com/cool-group/sentry.git",
"namespace": "cool-group",
"visibility_level": 0,
"path_with_namespace": "cool-group/sentry",
"default_branch": "master",
"homepage": "http://example.com/cool-group/sentry",
"url": "git@example.com:cool-group/sentry.git",
"ssh_url": "git@example.com:cool-group/sentry.git",
"http_url": "http://example.com/cool-group/sentry.git"
},
"object_attributes": {
"id": 301,
"title": "Test issue",
"assignee_ids": [],
"assignee_id": null,
"author_id": 1,
"project_id": 15,
"created_at": "2023-01-01 00:00:00 UTC",
"updated_at": "2023-01-01 00:00:00 UTC",
"position": 0,
"branch_name": null,
"description": "Test issue description",
"milestone_id": null,
"state": "opened",
"iid": 23,
"url": "http://example.com/cool-group/sentry/issues/23",
"action": "open"
},
"assignees": [],
"labels": []
}
"""

COMPARE_RESPONSE = r"""
{
"commit": {
Expand Down
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dependencies = [
"rfc3339-validator>=0.1.2",
"rfc3986-validator>=0.1.1",
# [end] jsonschema format validators
"sentry-arroyo>=2.38.1",
"sentry-arroyo>=2.38.5",
"sentry-conventions>=0.3.0",
"sentry-forked-email-reply-parser>=0.5.12.post1",
"sentry-kafka-schemas>=2.1.27",
Expand Down Expand Up @@ -172,7 +172,7 @@ dev = [
"responses>=0.23.1",
"ruff>=0.14.0",
"selenium>=4.16.0",
"sentry-cli>=2.16.0",
"sentry-cli>=3.3.0",
"sentry-covdefaults-disable-branch-coverage>=1.0.2",
"sentry-devenv>=1.28.0",
"django-stubs>=5.2.9",
Expand Down Expand Up @@ -300,6 +300,10 @@ filterwarnings = [
# a deprecated constant. But, still report it as a warning so that we're
# informed and can evaluate.
"default:ATTRIBUTE_NAMES\\..* is deprecated.*:DeprecationWarning",

# PyJWT 2.12.0 introduced InsecureKeyLengthWarning for HMAC keys shorter than
# 32 bytes. Tests use short secrets intentionally; production secrets are long enough.
"ignore:.*HMAC key.*below the minimum recommended length.*:jwt.warnings.InsecureKeyLengthWarning",
]
looponfailroots = ["src", "tests"]

Expand Down
45 changes: 34 additions & 11 deletions src/sentry/api/serializers/models/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
WorkflowDataConditionGroup,
)
from sentry.workflow_engine.models.data_condition import is_slow_condition
from sentry.workflow_engine.models.data_condition_group_action import DataConditionGroupAction
from sentry.workflow_engine.models.detector_workflow import DetectorWorkflow
from sentry.workflow_engine.processors.workflow_fire_history import get_last_fired_dates
from sentry.workflow_engine.registry import condition_handler_registry
Expand Down Expand Up @@ -398,15 +399,13 @@ def _fetch_workflow_users(self, item_list: Sequence[Workflow]) -> dict[int, RpcU
)
}

def _fetch_workflow_projects(
self, item_list: Sequence[Workflow]
) -> dict[Workflow, set[Project]]:
workflow_to_projects: dict[Workflow, set[Project]] = defaultdict(set)
def _fetch_workflow_projects(self, item_list: Sequence[Workflow]) -> dict[int, set[Project]]:
workflow_to_projects: dict[int, set[Project]] = defaultdict(set)
detector_workflows = DetectorWorkflow.objects.filter(
workflow_id__in=[item.id for item in item_list]
).prefetch_related("detector__project")
for detector_workflow in detector_workflows:
workflow_to_projects[detector_workflow.workflow].add(detector_workflow.detector.project)
).select_related("detector__project")
for dw in detector_workflows:
workflow_to_projects[dw.workflow_id].add(dw.detector.project)

return workflow_to_projects

Expand Down Expand Up @@ -456,8 +455,23 @@ def _fetch_workflow_owner(self, workflow: Workflow) -> str | None:
return actor.identifier
return None

def _fetch_actions(self, condition_group: DataConditionGroup) -> BaseQuerySet[Action]:
return Action.objects.filter(dataconditiongroupaction__condition_group=condition_group)
def _fetch_actions_by_dcg(self, condition_group_ids: Sequence[int]) -> dict[int, list[Action]]:
dcg_actions = (
DataConditionGroupAction.objects.filter(
condition_group_id__in=condition_group_ids,
)
.exclude(
action__status__in=[
ObjectStatus.DELETION_IN_PROGRESS,
ObjectStatus.PENDING_DELETION,
],
)
.select_related("action")
)
result: dict[int, list[Action]] = defaultdict(list)
for dcg_action in dcg_actions:
result[dcg_action.condition_group_id].append(dcg_action.action)
return result

def _generate_rule_conditions_filters(
self, workflow: Workflow, project: Project, workflow_dcg: WorkflowDataConditionGroup
Expand Down Expand Up @@ -570,6 +584,15 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
# Bulk fetch workflow -> rule ids
workflow_rule_ids = self._fetch_workflow_rule_ids(item_list)

# Bulk fetch actions for all condition groups across all workflows
all_dcg_ids: list[int] = []
for wf in workflows:
all_dcg_ids.extend(
wdcg.condition_group_id
for wdcg in wf.prefetched_wdcgs # type: ignore[attr-defined]
)
actions_by_dcg = self._fetch_actions_by_dcg(all_dcg_ids)

last_triggered_lookup: dict[int, datetime] = {}
if "lastTriggered" in self.expand:
last_triggered_lookup = self._fetch_workflow_last_triggered(item_list)
Expand All @@ -583,7 +606,7 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
result[workflow]["owner"] = owner

result[workflow]["environment"] = workflow.environment
result[workflow]["projects"] = list(workflow_to_projects[workflow])
result[workflow]["projects"] = list(workflow_to_projects[workflow.id])
result[workflow]["rule_id"] = workflow_rule_ids.get(
workflow.id, get_fake_id_from_object_id(workflow.id)
)
Expand All @@ -608,7 +631,7 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
result[workflow]["filter_match"] = workflow_dcg.condition_group.logic_type

# build up actions data
actions = self._fetch_actions(workflow_dcg.condition_group)
actions = actions_by_dcg.get(workflow_dcg.condition_group_id, [])
action_to_handler = {}
for action in actions:
try:
Expand Down
6 changes: 5 additions & 1 deletion src/sentry/conf/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3016,7 +3016,11 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]:
SENTRY_PREPROD_ARTIFACT_EVENTS_FUTURES_MAX_LIMIT = 10000

# How long we should wait for a gateway proxy request to return before giving up
GATEWAY_PROXY_TIMEOUT: int | None = None
GATEWAY_PROXY_TIMEOUT: int | None = (
int(os.environ["SENTRY_APIGW_PROXY_TIMEOUT"])
if os.environ.get("SENTRY_APIGW_PROXY_TIMEOUT")
else None
)

SENTRY_SLICING_LOGICAL_PARTITION_COUNT = 256
# This maps a Sliceable for slicing by name and (lower logical partition, upper physical partition)
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/deletions/defaults/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def get_child_relations(self, instance: Organization) -> list[BaseRelation]:
AlertRule,
Release,
Project,
Workflow,
Environment,
Dashboard,
TeamKeyTransaction,
Expand All @@ -64,7 +65,6 @@ def get_child_relations(self, instance: Organization) -> list[BaseRelation]:
task=DiscoverSavedQueryDeletionTask,
)
)
relations.append(ModelRelation(Workflow, {"organization_id": instance.id}))

return relations

Expand Down
2 changes: 1 addition & 1 deletion src/sentry/event_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ def handle_existing_grouphash(
# this function had races around group creation which made this race
# more user visible. For more context, see 84c6f75a and d0e22787, as
# well as GH-5085.
group = Group.objects.get(id=existing_grouphash.group_id)
group = Group.objects.get_from_cache(id=existing_grouphash.group_id, use_replica=False)

# As far as we know this has never happened, but in theory at least, the error event hashing
# algorithm and other event hashing algorithms could come up with the same hash value in the
Expand Down
6 changes: 4 additions & 2 deletions src/sentry/features/temporary.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:insights-modules-use-eap", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable access to insights metrics alerts
manager.add("organizations:insights-alerts", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable data browsing widget unfurl
manager.add("organizations:data-browsing-widget-unfurl", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable dual-write of Seer project preferences to Sentry DB and Seer API
manager.add("organizations:seer-project-settings-dual-write", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Enable public RPC endpoint for local seer development
Expand Down Expand Up @@ -478,8 +480,6 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:cache-detectors-by-data-source", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Enable single trace summary
manager.add("organizations:single-trace-summary", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable seeing upsell modal when clicking upgrade for multi-org
manager.add("organizations:github-multi-org-upsell-modal", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enables CMD+K supercharged (omni search)
manager.add("organizations:cmd-k-supercharged", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enables DSN lookup in CMD+K palette
Expand All @@ -492,6 +492,8 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:conduit-demo", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable hard timeout alarm for webhooks
manager.add("organizations:sentry-app-webhook-hard-timeout", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Enable circuit breaker for webhook endpoint failure detection
manager.add("organizations:sentry-app-webhook-circuit-breaker", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)

# Enables organization access to the new notification platform
manager.add("organizations:notification-platform.internal-testing", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
Expand Down
3 changes: 0 additions & 3 deletions src/sentry/grouping/ingest/seer.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,6 @@ def _build_seer_request(
"exception_type": filter_null_from_string(exception_type) if exception_type else None,
"k": options.get("seer.similarity.ingest.num_matches_to_request"),
"referrer": "ingest",
"use_reranking": options.get("seer.similarity.ingest.use_reranking"),
"model": model_version,
"training_mode": training_mode,
"platform": event.platform or "unknown",
Expand Down Expand Up @@ -413,8 +412,6 @@ def get_seer_similar_issues(
# By asking Seer to find zero matches, we can trick it into thinking there aren't
# any, thereby forcing it to create the record
"k": 0,
# Turn off re-ranking to speed up the process of finding nothing
"use_reranking": False,
}

# TODO: Temporary log to prove things are working as they should. This should come in a pair
Expand Down
Loading
Loading