Skip to content

Commit 735ca66

Browse files
authored
Merge branch 'master' into sessions-discover
2 parents 8217a27 + 0f2bd7f commit 735ca66

File tree

13 files changed

+110
-29
lines changed

13 files changed

+110
-29
lines changed

src/sentry/api/endpoints/organization_traces.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def data_fn(offset: int, limit: int):
111111
max_timestamp = timestamp
112112

113113
# TODO: move to use `update_snuba_params_with_timestamp`
114-
time_buffer = options.get("performance.traces.transaction_query_timebuffer_days")
115-
buffer = timedelta(days=time_buffer)
114+
time_buffer = options.get("performance.traces.trace-explorer-buffer-hours")
115+
buffer = timedelta(hours=time_buffer)
116116
params["start"] = min_timestamp - buffer
117117
params["end"] = max_timestamp + buffer
118118
snuba_params.start = min_timestamp - buffer

src/sentry/models/actor.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,30 @@ def from_actor_identifier(cls, actor_identifier: int | str | None) -> ActorTuple
296296
except IndexError as e:
297297
raise serializers.ValidationError(f"Unable to resolve actor identifier: {e}")
298298

299+
@classmethod
300+
def from_id(cls, user_id: int | None, team_id: int | None) -> ActorTuple | None:
301+
from sentry.models.team import Team
302+
from sentry.models.user import User
303+
304+
if user_id and team_id:
305+
raise ValueError("user_id and team_id may not both be specified")
306+
if user_id and not team_id:
307+
return cls(user_id, User)
308+
if team_id and not user_id:
309+
return cls(team_id, Team)
310+
311+
return None
312+
313+
@classmethod
314+
def from_ids(cls, user_ids: Sequence[int], team_ids: Sequence[int]) -> Sequence[ActorTuple]:
315+
from sentry.models.team import Team
316+
from sentry.models.user import User
317+
318+
return [
319+
*[cls(user_id, User) for user_id in user_ids],
320+
*[cls(team_id, Team) for team_id in team_ids],
321+
]
322+
299323
def resolve(self) -> Team | RpcUser:
300324
return fetch_actor_by_id(self.type, self.id)
301325

src/sentry/monitors/endpoints/base_monitor_details.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from sentry.models.project import Project
1818
from sentry.models.rule import Rule, RuleActivity, RuleActivityType
1919
from sentry.models.scheduledeletion import RegionScheduledDeletion
20+
from sentry.models.team import Team
21+
from sentry.models.user import User
2022
from sentry.monitors.models import (
2123
CheckInStatus,
2224
Monitor,
@@ -94,7 +96,13 @@ def update_monitor(
9496
if "is_muted" in result:
9597
params["is_muted"] = result["is_muted"]
9698
if "owner" in result:
97-
params["owner_actor_id"] = result["owner"].id if result["owner"] else None
99+
owner = result["owner"]
100+
params["owner_user_id"] = None
101+
params["owner_team_id"] = None
102+
if owner and owner.type == User:
103+
params["owner_user_id"] = owner.id
104+
elif owner and owner.type == Team:
105+
params["owner_team_id"] = owner.id
98106
if "config" in result:
99107
params["config"] = result["config"]
100108

src/sentry/monitors/endpoints/organization_monitor_index.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from sentry.db.models.query import in_iexact
3333
from sentry.models.environment import Environment
3434
from sentry.models.organization import Organization
35+
from sentry.models.team import Team
36+
from sentry.models.user import User
3537
from sentry.monitors.models import (
3638
Monitor,
3739
MonitorEnvironment,
@@ -259,16 +261,20 @@ def post(self, request: Request, organization) -> Response:
259261

260262
result = validator.validated_data
261263

262-
if result.get("owner"):
263-
owner_id = result.get("owner").id
264-
else:
265-
owner_id = None
264+
owner = result.get("owner")
265+
owner_user_id = None
266+
owner_team_id = None
267+
if owner and owner.type == User:
268+
owner_user_id = owner.id
269+
elif owner and owner.type == Team:
270+
owner_team_id = owner.id
266271

267272
try:
268273
monitor = Monitor.objects.create(
269274
project_id=result["project"].id,
270275
organization_id=organization.id,
271-
owner_actor_id=owner_id,
276+
owner_user_id=owner_user_id,
277+
owner_team_id=owner_team_id,
272278
name=result["name"],
273279
slug=result.get("slug"),
274280
status=result["status"],

src/sentry/monitors/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from sentry.db.models.fields.slug import SentrySlugField
3636
from sentry.db.models.utils import slugify_instance
3737
from sentry.locks import locks
38+
from sentry.models.actor import ActorTuple
3839
from sentry.models.environment import Environment
3940
from sentry.models.rule import Rule, RuleSource
4041
from sentry.monitors.constants import MAX_SLUG_LENGTH
@@ -306,6 +307,10 @@ def save(self, *args, **kwargs):
306307
)
307308
return super().save(*args, **kwargs)
308309

310+
@property
311+
def owner_actor(self) -> ActorTuple | None:
312+
return ActorTuple.from_id(self.owner_user_id, self.owner_team_id)
313+
309314
@property
310315
def schedule(self) -> CrontabSchedule | IntervalSchedule:
311316
schedule_type = self.config["schedule_type"]

src/sentry/monitors/serializers.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from sentry.api.serializers import ProjectSerializerResponse, Serializer, register, serialize
99
from sentry.api.serializers.models.actor import ActorSerializer, ActorSerializerResponse
10-
from sentry.models.actor import Actor, ActorTuple
10+
from sentry.models.actor import ActorTuple
1111
from sentry.models.project import Project
1212
from sentry.monitors.utils import fetch_associated_groups
1313
from sentry.monitors.validators import IntervalNames
@@ -181,14 +181,13 @@ def get_attrs(self, item_list, user, **kwargs):
181181
for project, serialized_project in zip(projects, serialize(list(projects), user))
182182
}
183183

184-
actors = Actor.objects.filter(id__in=[i.owner_actor_id for i in item_list])
185-
actor_tuples = [a.get_actor_tuple() for a in actors]
186-
187-
actors_serialized = serialize(
188-
ActorTuple.resolve_many(actor_tuples), user, ActorSerializer()
184+
actors = ActorTuple.from_ids(
185+
[m.owner_user_id for m in item_list if m.owner_user_id],
186+
[m.owner_team_id for m in item_list if m.owner_team_id],
189187
)
188+
actors_serialized = serialize(ActorTuple.resolve_many(actors), user, ActorSerializer())
190189
actor_data = {
191-
actor.id: serialized_actor for actor, serialized_actor in zip(actors, actors_serialized)
190+
actor: serialized_actor for actor, serialized_actor in zip(actors, actors_serialized)
192191
}
193192

194193
monitor_environments = (
@@ -218,7 +217,7 @@ def get_attrs(self, item_list, user, **kwargs):
218217
item: {
219218
"project": projects_data[item.project_id] if item.project_id else None,
220219
"environments": environment_data[item.id],
221-
"owner": actor_data.get(item.owner_actor_id),
220+
"owner": actor_data.get(item.owner_actor),
222221
}
223222
for item in item_list
224223
}

src/sentry/monitors/validators.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ class MonitorValidator(CamelSnakeSerializer):
254254
required=False,
255255
allow_null=True,
256256
help_text="The ID of the team or user that owns the monitor. (eg. user:51 or team:6)",
257-
as_actor=True,
258257
)
259258
is_muted = serializers.BooleanField(
260259
required=False,

src/sentry/options/defaults.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,12 @@
17461746
default=False,
17471747
flags=FLAG_AUTOMATOR_MODIFIABLE,
17481748
)
1749+
register(
1750+
"performance.traces.trace-explorer-buffer-hours",
1751+
type=Float,
1752+
default=1.0,
1753+
flags=FLAG_AUTOMATOR_MODIFIABLE,
1754+
) # hours
17491755

17501756
# Dynamic Sampling system-wide options
17511757
# Size of the sliding window used for dynamic sampling. It is defaulted to 24 hours.

src/sentry/testutils/cases.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
from sentry.issues.ingest import send_issue_occurrence_to_eventstream
7171
from sentry.mail import mail_adapter
7272
from sentry.mediators.project_rules.creator import Creator
73-
from sentry.models.actor import get_actor_for_user
7473
from sentry.models.apitoken import ApiToken
7574
from sentry.models.authprovider import AuthProvider as AuthProviderModel
7675
from sentry.models.commit import Commit
@@ -3061,8 +3060,8 @@ def setUp(self):
30613060

30623061
class MonitorTestCase(APITestCase):
30633062
def _create_monitor(self, **kwargs):
3064-
if "owner_actor_id" not in kwargs:
3065-
kwargs["owner_actor_id"] = get_actor_for_user(self.user).id
3063+
if "owner_user_id" not in kwargs:
3064+
kwargs["owner_user_id"] = self.user.id
30663065

30673066
return Monitor.objects.create(
30683067
organization_id=self.organization.id,

static/app/views/settings/project/projectOwnership/codeownerErrors.spec.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,35 @@ describe('CodeownerErrors', () => {
1010
const project = ProjectFixture();
1111
const org = OrganizationFixture();
1212

13+
it('should render error', async () => {
14+
const codeowner = CodeOwnerFixture({
15+
errors: {
16+
missing_user_emails: [],
17+
missing_external_users: [],
18+
missing_external_teams: ['@getsentry/something'],
19+
teams_without_access: [],
20+
users_without_access: [],
21+
},
22+
});
23+
render(
24+
<CodeOwnerErrors
25+
codeowners={[codeowner]}
26+
projectSlug={project.slug}
27+
orgSlug={org.slug}
28+
/>
29+
);
30+
31+
await userEvent.click(
32+
screen.getByText(
33+
'There was 1 ownership issue within Sentry on the latest sync with the CODEOWNERS file'
34+
)
35+
);
36+
expect(
37+
screen.getByText(`There’s a problem linking teams and members from an integration`)
38+
).toBeInTheDocument();
39+
expect(screen.getByText('@getsentry/something')).toBeInTheDocument();
40+
});
41+
1342
it('should render errors', async () => {
1443
const codeowner = CodeOwnerFixture({
1544
errors: {

static/app/views/settings/project/projectOwnership/codeownerErrors.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ export function CodeOwnerErrors({
172172
</AlertContentContainer>
173173
}
174174
>
175-
{`There were ${errorCount} ownership issues within Sentry on the latest sync with the CODEOWNERS file`}
175+
{errorCount === 1
176+
? `There was ${errorCount} ownership issue within Sentry on the latest sync with the CODEOWNERS file`
177+
: `There were ${errorCount} ownership issues within Sentry on the latest sync with the CODEOWNERS file`}
176178
</Alert>
177179
);
178180
})}

tests/sentry/monitors/endpoints/test_base_monitor_details.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import pytest
55

66
from sentry.constants import ObjectStatus
7-
from sentry.models.actor import get_actor_for_team, get_actor_for_user
87
from sentry.models.environment import Environment
98
from sentry.models.rule import Rule, RuleActivity, RuleActivityType
109
from sentry.models.scheduledeletion import RegionScheduledDeletion
@@ -171,8 +170,10 @@ def test_owner_user(self):
171170
}
172171

173172
def test_owner_team(self):
174-
team_actor = get_actor_for_team(self.team)
175-
monitor = self._create_monitor(owner_actor_id=team_actor.id)
173+
monitor = self._create_monitor(
174+
owner_user_id=None,
175+
owner_team_id=self.team.id,
176+
)
176177
resp = self.get_success_response(self.organization.slug, monitor.slug)
177178

178179
assert resp.data["owner"] == {
@@ -220,7 +221,8 @@ def test_slug(self):
220221

221222
def test_owner(self):
222223
monitor = self._create_monitor()
223-
assert monitor.owner_actor_id == get_actor_for_user(self.user).id
224+
assert monitor.owner_user_id == self.user.id
225+
assert monitor.owner_team_id is None
224226

225227
resp = self.get_success_response(
226228
self.organization.slug, monitor.slug, method="PUT", **{"owner": f"team:{self.team.id}"}
@@ -229,7 +231,8 @@ def test_owner(self):
229231
assert resp.data["owner"]["name"] == self.team.name
230232

231233
monitor = Monitor.objects.get(id=monitor.id)
232-
assert monitor.owner_actor_id == get_actor_for_team(self.team).id
234+
assert monitor.owner_team_id == self.team.id
235+
assert monitor.owner_user_id is None
233236

234237
# Clear owner
235238
resp = self.get_success_response(
@@ -238,7 +241,8 @@ def test_owner(self):
238241
assert resp.data["owner"] is None
239242

240243
monitor = Monitor.objects.get(id=monitor.id)
241-
assert monitor.owner_actor_id is None
244+
assert monitor.owner_user_id is None
245+
assert monitor.owner_team_id is None
242246

243247
# Validate error cases
244248
resp = self.get_error_response(

tests/sentry/monitors/endpoints/test_organization_monitor_index.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from rest_framework.exceptions import ErrorDetail
99

1010
from sentry.constants import ObjectStatus
11-
from sentry.models.actor import get_actor_for_user
1211
from sentry.models.rule import Rule, RuleSource
1312
from sentry.monitors.models import Monitor, MonitorStatus, MonitorType, ScheduleType
1413
from sentry.quotas.base import SeatAssignmentResult
@@ -298,7 +297,8 @@ def test_simple(self, mock_record):
298297
assert monitor.project_id == self.project.id
299298
assert monitor.name == "My Monitor"
300299
assert monitor.status == ObjectStatus.ACTIVE
301-
assert monitor.owner_actor_id == get_actor_for_user(self.user).id
300+
assert monitor.owner_user_id == self.user.id
301+
assert monitor.owner_team_id is None
302302
assert monitor.type == MonitorType.CRON_JOB
303303
assert monitor.config == {
304304
"schedule_type": ScheduleType.CRONTAB,

0 commit comments

Comments
 (0)