Skip to content

Commit

Permalink
Merge branch 'master' into priscila/ref/onboarding/move-loader-code
Browse files Browse the repository at this point in the history
  • Loading branch information
priscilawebdev authored Sep 23, 2024
2 parents 07dcc45 + 2345d0d commit 65ba2c8
Show file tree
Hide file tree
Showing 179 changed files with 2,911 additions and 1,213 deletions.
23 changes: 21 additions & 2 deletions fixtures/vsts.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ def _stub_vsts(self):
},
)

responses.add(
responses.POST,
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
json={
"access_token": self.access_token,
"token_type": "grant",
"expires_in": 300, # seconds (5 min)
"refresh_token": self.refresh_token,
},
)

responses.add(
responses.GET,
"https://app.vssps.visualstudio.com/_apis/accounts?memberId=%s&api-version=4.1"
Expand Down Expand Up @@ -195,19 +206,27 @@ def assert_vsts_oauth_redirect(self, redirect):
assert redirect.netloc == "app.vssps.visualstudio.com"
assert redirect.path == "/oauth2/authorize"

def assert_vsts_new_oauth_redirect(self, redirect):
assert redirect.scheme == "https"
assert redirect.netloc == "login.microsoftonline.com"
assert redirect.path == "/common/oauth2/v2.0/authorize"

def assert_account_selection(self, response, account_id=None):
account_id = account_id or self.vsts_account_id
assert response.status_code == 200
assert f'<option value="{account_id}"'.encode() in response.content

@assume_test_silo_mode(SiloMode.CONTROL)
def assert_installation(self):
def assert_installation(self, new=False):
# Initial request to the installation URL for VSTS
resp = self.make_init_request()
redirect = urlparse(resp["Location"])

assert resp.status_code == 302
self.assert_vsts_oauth_redirect(redirect)
if new:
self.assert_vsts_new_oauth_redirect(redirect)
else:
self.assert_vsts_oauth_redirect(redirect)

query = parse_qs(redirect.query)

Expand Down
2 changes: 1 addition & 1 deletion migrations_lockfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ hybridcloud: 0016_add_control_cacheversion
nodestore: 0002_nodestore_no_dictfield
remote_subscriptions: 0003_drop_remote_subscription
replays: 0004_index_together
sentry: 0763_add_created_by_to_broadcasts
sentry: 0764_migrate_bad_status_substatus_rows
social_auth: 0002_default_auto_field
uptime: 0013_uptime_subscription_new_unique
workflow_engine: 0005_data_source_detector
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,7 @@ module = [
"sentry.db.models.manager.*",
"sentry.db.models.paranoia",
"sentry.db.models.utils",
"sentry.deletions",
"sentry.deletions.tasks.groups",
"sentry.deletions.*",
"sentry.digests.notifications",
"sentry.eventstore.reprocessing.redis",
"sentry.eventtypes.error",
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev-frozen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ s3transfer==0.10.0
selenium==4.16.0
sentry-arroyo==2.16.5
sentry-cli==2.16.0
sentry-devenv==1.10.0
sentry-devenv==1.10.2
sentry-forked-django-stubs==5.0.4.post2
sentry-forked-djangorestframework-stubs==3.15.1.post1
sentry-kafka-schemas==0.1.109
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--index-url https://pypi.devinfra.sentry.io/simple

sentry-devenv>=1.10.0
sentry-devenv>=1.10.2

covdefaults>=2.3.0
docker>=6
Expand Down
8 changes: 0 additions & 8 deletions src/sentry/api/endpoints/organization_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,6 @@ class EventsApiResponse(TypedDict):
meta: EventsMeta


# When calling make build-spectacular-docs we hit this issue
# https://github.com/tfranzel/drf-spectacular/issues/1041
# This is a work around
EventsMeta.__annotations__["datasetReason"] = str
EventsMeta.__annotations__["isMetricsData"] = bool
EventsMeta.__annotations__["isMetricsExtractedData"] = bool


def rate_limit_events(
request: Request, organization_id_or_slug: str | None = None, *args, **kwargs
) -> dict[str, dict[RateLimitCategory, RateLimit]]:
Expand Down
98 changes: 98 additions & 0 deletions src/sentry/api/endpoints/organization_events_anomalies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from drf_spectacular.utils import extend_schema
from rest_framework.request import Request
from rest_framework.response import Response

from sentry import features
from sentry.api.api_owners import ApiOwner
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import region_silo_endpoint
from sentry.api.bases.organization_events import OrganizationEventsV2EndpointBase
from sentry.api.exceptions import ResourceDoesNotExist
from sentry.api.paginator import OffsetPaginator
from sentry.api.serializers.base import serialize
from sentry.apidocs.constants import (
RESPONSE_BAD_REQUEST,
RESPONSE_FORBIDDEN,
RESPONSE_NOT_FOUND,
RESPONSE_UNAUTHORIZED,
)
from sentry.apidocs.examples.organization_examples import OrganizationExamples
from sentry.apidocs.parameters import GlobalParams
from sentry.apidocs.utils import inline_sentry_response_serializer
from sentry.models.organization import Organization
from sentry.seer.anomaly_detection.get_historical_anomalies import (
get_historical_anomaly_data_from_seer_preview,
)
from sentry.seer.anomaly_detection.types import DetectAnomaliesResponse, TimeSeriesPoint


@region_silo_endpoint
class OrganizationEventsAnomaliesEndpoint(OrganizationEventsV2EndpointBase):
owner = ApiOwner.ALERTS_NOTIFICATIONS
publish_status = {
"POST": ApiPublishStatus.EXPERIMENTAL,
}

@extend_schema(
operation_id="Identify anomalies in historical data",
parameters=[GlobalParams.ORG_ID_OR_SLUG],
responses={
200: inline_sentry_response_serializer(
"ListAlertRuleAnomalies", DetectAnomaliesResponse
),
400: RESPONSE_BAD_REQUEST,
401: RESPONSE_UNAUTHORIZED,
403: RESPONSE_FORBIDDEN,
404: RESPONSE_NOT_FOUND,
},
examples=OrganizationExamples.GET_HISTORICAL_ANOMALIES,
)
def _format_historical_data(self, data) -> list[TimeSeriesPoint] | None:
"""
Format EventsStatsData into the format that the Seer API expects.
EventsStatsData is a list of lists with this format:
[epoch timestamp, {'count': count}]
Convert the data to this format:
list[TimeSeriesPoint]
"""
if data is None:
return data

formatted_data: list[TimeSeriesPoint] = []
for datum in data:
ts_point = TimeSeriesPoint(timestamp=datum[0], value=datum[1].get("count", 0))
formatted_data.append(ts_point)
return formatted_data

def post(self, request: Request, organization: Organization) -> Response:
"""
Return a list of anomalies for a time series of historical event data.
"""
if not features.has("organizations:anomaly-detection-alerts", organization):
raise ResourceDoesNotExist("Your organization does not have access to this feature.")

historical_data = self._format_historical_data(request.data.get("historical_data"))
current_data = self._format_historical_data(request.data.get("current_data"))

config = request.data.get("config")
project_id = request.data.get("project_id")

if project_id is None or not config or not historical_data or not current_data:
return Response(
"Unable to get historical anomaly data: missing required argument(s) project, start, and/or end",
status=400,
)

anomalies = get_historical_anomaly_data_from_seer_preview(
current_data, historical_data, project_id, config
)
# NOTE: returns None if there's a problem with the Seer response
if anomalies is None:
return Response("Unable to get historical anomaly data", status=400)
# NOTE: returns empty list if there is not enough event data
return self.paginate(
request=request,
queryset=anomalies,
paginator_cls=OffsetPaginator,
on_results=lambda x: serialize(x, request.user),
)
3 changes: 2 additions & 1 deletion src/sentry/api/endpoints/organization_member/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def _get_member(
403: RESPONSE_FORBIDDEN,
404: RESPONSE_NOT_FOUND,
},
examples=OrganizationExamples.UPDATE_ORG_MEMBER,
)
def get(
self,
Expand All @@ -136,7 +137,7 @@ def get(
"""
Retrieve an organization member's details.
Will return a pending invite as long as it's already approved.
Response will be a pending invite if it has been approved by organization owners or managers but is waiting to be accepted by the invitee.
"""
allowed_roles = get_allowed_org_roles(request, organization, member)
return Response(
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/organization_member/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def get(self, request: Request, organization) -> Response:
"""
List all organization members.
Response includes pending invites that are approved by organization admins but waiting to be accepted by the invitee.
Response includes pending invites that are approved by organization owners or managers but waiting to be accepted by the invitee.
"""
queryset = OrganizationMember.objects.filter(
Q(user_is_active=True, user_id__isnull=False) | Q(user_id__isnull=True),
Expand Down
9 changes: 7 additions & 2 deletions src/sentry/api/endpoints/organization_release_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from rest_framework.response import Response
from rest_framework.serializers import ListField

from sentry import release_health
from sentry import options, release_health
from sentry.api.api_owners import ApiOwner
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import ReleaseAnalyticsMixin, region_silo_endpoint
Expand Down Expand Up @@ -526,7 +526,12 @@ def put(self, request: Request, organization, version) -> Response:
datetime=release.date_released,
)

return Response(serialize(release, request.user))
no_snuba_for_release_creation = options.get("releases.no_snuba_for_release_creation")
return Response(
serialize(
release, request.user, no_snuba_for_release_creation=no_snuba_for_release_creation
)
)

@extend_schema(
operation_id="Delete an Organization's Release",
Expand Down
4 changes: 3 additions & 1 deletion src/sentry/api/endpoints/organization_releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,9 @@ def post(self, request: Request, organization) -> Response:
update_org_auth_token_last_used(request.auth, [project.id for project in projects])

scope.set_tag("success_status", status)
return Response(serialize(release, request.user), status=status)
return Response(
serialize(release, request.user, no_snuba_for_release_creation=True), status=status
)
scope.set_tag("failure_reason", "serializer_error")
return Response(serializer.errors, status=400)

Expand Down
9 changes: 7 additions & 2 deletions src/sentry/api/endpoints/project_release_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from rest_framework.request import Request
from rest_framework.response import Response

from sentry import options
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import ReleaseAnalyticsMixin, region_silo_endpoint
from sentry.api.bases.project import ProjectEndpoint, ProjectReleasePermission
Expand Down Expand Up @@ -144,8 +145,12 @@ def put(self, request: Request, project, version) -> Response:
data={"version": release.version},
datetime=release.date_released,
)

return Response(serialize(release, request.user))
no_snuba_for_release_creation = options.get("releases.no_snuba_for_release_creation")
return Response(
serialize(
release, request.user, no_snuba_for_release_creation=no_snuba_for_release_creation
)
)

def delete(self, request: Request, project, version) -> Response:
"""
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/project_servicehook_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from sentry.api.serializers import serialize
from sentry.api.validators import ServiceHookValidator
from sentry.constants import ObjectStatus
from sentry.models.servicehook import ServiceHook
from sentry.sentry_apps.models.servicehook import ServiceHook


@region_silo_endpoint
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/project_servicehook_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from sentry.api.base import StatsMixin, region_silo_endpoint
from sentry.api.bases.project import ProjectEndpoint
from sentry.api.exceptions import ResourceDoesNotExist
from sentry.models.servicehook import ServiceHook
from sentry.sentry_apps.models.servicehook import ServiceHook
from sentry.tsdb.base import TSDBModel


Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/project_servicehooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from sentry.api.serializers import serialize
from sentry.api.validators import ServiceHookValidator
from sentry.constants import ObjectStatus
from sentry.models.servicehook import ServiceHook
from sentry.sentry_apps.models.servicehook import ServiceHook
from sentry.sentry_apps.services.hook import hook_service


Expand Down
8 changes: 5 additions & 3 deletions src/sentry/api/serializers/models/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ def __init__(self, environment_func=None):
def get_attrs(self, item_list, user, **kwargs):
# TODO(dcramer); assert on relations
user_ids = [i.user_id for i in item_list if i.user_id]
user_list = user_service.serialize_many(
filter={"user_ids": user_ids}, as_user=serialize_generic_user(user)
)
user_list = []
if user_ids:
user_list = user_service.serialize_many(
filter={"user_ids": user_ids}, as_user=serialize_generic_user(user)
)
users = {u["id"]: u for u in user_list}

commit_ids = {
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/serializers/models/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ def get_attrs(self, item_list, user, **kwargs):
def serialize(self, obj, attrs, user, **kwargs):
context = super().serialize(obj, attrs, user)
context["userCount"] = attrs["user_count"]
context["createdBy"] = obj.created_by_id.id if obj.created_by_id else None
context["createdBy"] = obj.created_by_id.email if obj.created_by_id else None
return context
9 changes: 6 additions & 3 deletions src/sentry/api/serializers/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,12 @@ def _serialize_assignees(self, item_list: Sequence[Group]) -> Mapping[int, Team
for team in Team.objects.filter(id__in=all_team_ids.keys()):
for group_id in all_team_ids[team.id]:
result[group_id] = team
for user in user_service.get_many_by_id(ids=list(all_user_ids.keys())):
for group_id in all_user_ids[user.id]:
result[group_id] = user

user_ids = list(all_user_ids.keys())
if user_ids:
for user in user_service.get_many_by_id(ids=user_ids):
for group_id in all_user_ids[user.id]:
result[group_id] = user

return result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class OrganizationMemberSCIMSerializerResponse(OrganizationMemberSCIMSerializerO

class _TeamRole(TypedDict):
teamSlug: str
role: str
role: str | None


@extend_schema_serializer(exclude_fields=["role", "roleName"])
Expand Down
17 changes: 10 additions & 7 deletions src/sentry/api/serializers/models/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,16 @@ def get_attrs(self, item_list, user, **kwargs):
issue_counts_by_release,
) = self.__get_release_data_with_environments(release_project_envs)

owners = {
d["id"]: d
for d in user_service.serialize_many(
filter={"user_ids": [i.owner_id for i in item_list if i.owner_id]},
as_user=serialize_generic_user(user),
)
}
owners = {}
owner_ids = [i.owner_id for i in item_list if i.owner_id]
if owner_ids:
owners = {
d["id"]: d
for d in user_service.serialize_many(
filter={"user_ids": owner_ids},
as_user=serialize_generic_user(user),
)
}

authors_metadata_attrs = _get_authors_metadata(item_list, user)
release_metadata_attrs = _get_last_commit_metadata(item_list, user)
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/api/serializers/models/servicehook.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sentry.api.serializers import Serializer, register
from sentry.models.servicehook import ServiceHook
from sentry.sentry_apps.models.servicehook import ServiceHook


@register(ServiceHook)
Expand Down
Loading

0 comments on commit 65ba2c8

Please sign in to comment.