Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(mediators): Turn project rule creator to dataclass #79137

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
15 changes: 13 additions & 2 deletions src/sentry/api/endpoints/project_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from sentry.constants import ObjectStatus
from sentry.integrations.slack.tasks.find_channel_id_for_rule import find_channel_id_for_rule
from sentry.integrations.slack.utils.rule_status import RedisRuleStatus
from sentry.mediators.project_rules.creator import Creator
from sentry.models.rule import Rule, RuleActivity, RuleActivityType
from sentry.projects.project_rules.creator import ProjectRuleCreator
from sentry.rules.actions import trigger_sentry_app_action_creators_for_issues
from sentry.rules.actions.base import instantiate_action
from sentry.rules.processing.processor import is_condition_slow
Expand Down Expand Up @@ -844,7 +844,18 @@ def post(self, request: Request, project) -> Response:
created_alert_rule_ui_component = trigger_sentry_app_action_creators_for_issues(
kwargs["actions"]
)
rule = Creator.run(request=request, **kwargs)
rule = ProjectRuleCreator(
name=kwargs["name"],
project=project,
action_match=kwargs["action_match"],
actions=kwargs["actions"],
conditions=conditions,
frequency=kwargs["frequency"],
environment=kwargs["environment"],
owner=owner,
filter_match=kwargs["filter_match"],
request=request,
).run()

RuleActivity.objects.create(
rule=rule, user_id=request.user.id, type=RuleActivityType.CREATED.value
Expand Down
15 changes: 13 additions & 2 deletions src/sentry/integrations/slack/tasks/find_channel_id_for_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
)
from sentry.integrations.slack.utils.constants import SLACK_RATE_LIMITED_MESSAGE
from sentry.integrations.slack.utils.rule_status import RedisRuleStatus
from sentry.mediators.project_rules.creator import Creator
from sentry.mediators.project_rules.updater import Updater
from sentry.models.project import Project
from sentry.models.rule import Rule, RuleActivity, RuleActivityType
from sentry.projects.project_rules.creator import ProjectRuleCreator
from sentry.shared_integrations.exceptions import ApiRateLimitedError, DuplicateDisplayNameError
from sentry.silo.base import SiloMode
from sentry.tasks.base import instrumented_task
Expand Down Expand Up @@ -109,7 +109,18 @@ def find_channel_id_for_rule(
rule = Rule.objects.get(id=rule_id)
rule = Updater.run(rule=rule, pending_save=False, **kwargs)
else:
rule = Creator.run(pending_save=False, **kwargs)
rule = ProjectRuleCreator(
name=kwargs["name"],
project=project,
action_match=kwargs["action_match"],
actions=actions,
conditions=kwargs["conditions"],
frequency=kwargs["frequency"],
environment=kwargs.get("environment"),
owner=kwargs.get("owner"),
filter_match=kwargs.get("filter_match"),
request=kwargs.get("request"),
).run()
if user_id:
RuleActivity.objects.create(
rule=rule, user_id=user_id, type=RuleActivityType.CREATED.value
Expand Down
1 change: 0 additions & 1 deletion src/sentry/mediators/project_rules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from .creator import Creator # NOQA
from .updater import Updater # NOQA
26 changes: 12 additions & 14 deletions src/sentry/monitors/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

from sentry.api.serializers.rest_framework.rule import RuleSerializer
from sentry.db.models import BoundedPositiveIntegerField
from sentry.mediators.project_rules.creator import Creator
from sentry.mediators.project_rules.updater import Updater
from sentry.models.group import Group
from sentry.models.project import Project
from sentry.models.rule import Rule, RuleActivity, RuleActivityType, RuleSource
from sentry.monitors.constants import DEFAULT_CHECKIN_MARGIN, MAX_TIMEOUT, TIMEOUT
from sentry.monitors.models import CheckInStatus, Monitor, MonitorCheckIn
from sentry.projects.project_rules.creator import ProjectRuleCreator
from sentry.signals import (
cron_monitor_created,
first_cron_checkin_received,
Expand Down Expand Up @@ -231,19 +231,17 @@ def create_issue_alert_rule(
if "filters" in data:
conditions.extend(data["filters"])

kwargs = {
"name": data["name"],
"environment": data.get("environment"),
"project": project,
"action_match": data["actionMatch"],
"filter_match": data.get("filterMatch"),
"conditions": conditions,
"actions": data.get("actions", []),
"frequency": data.get("frequency"),
"user_id": request.user.id,
}

rule = Creator.run(request=request, **kwargs)
rule = ProjectRuleCreator(
name=data["name"],
project=project,
action_match=data["actionMatch"],
actions=data.get("actions", []),
conditions=conditions,
frequency=data.get("frequency"),
environment=data.get("environment"),
filter_match=data.get("filterMatch"),
request=request,
).run()
rule.update(source=RuleSource.CRON_MONITOR)
RuleActivity.objects.create(
rule=rule, user_id=request.user.id, type=RuleActivityType.CREATED.value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
from django.db import router
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any

from django.db import router, transaction
from rest_framework.request import Request

from sentry.mediators.mediator import Mediator
from sentry.mediators.param import Param
from sentry.models.project import Project
from sentry.models.rule import Rule
from sentry.types.actor import Actor


class Creator(Mediator):
name = Param(str)
environment = Param(int, required=False)
owner = Param(Actor, required=False)
project = Param(Project)
action_match = Param(str)
filter_match = Param(str, required=False)
actions = Param(list)
conditions = Param(list)
frequency = Param(int)
request = Param(Request, required=False)
using = router.db_for_write(Project)

def call(self):
self.rule = self._create_rule()
return self.rule

def _create_rule(self):
@dataclass
class ProjectRuleCreator:
name: str
project: Project
action_match: str
actions: Sequence[dict[str, Any]]
conditions: Sequence[dict[str, Any]]
frequency: int
environment: int | None = None
owner: Actor | None = None
filter_match: str | None = None
request: Request | None = None

def run(self) -> Rule:
with transaction.atomic(router.db_for_write(Rule)):
self.rule = self._create_rule()
return self.rule

def _create_rule(self) -> Rule:
kwargs = self._get_kwargs()
rule = Rule.objects.create(**kwargs)

return rule

def _get_kwargs(self):
def _get_kwargs(self) -> dict[str, Any]:
data = {
"filter_match": self.filter_match,
"action_match": self.action_match,
Expand Down
8 changes: 4 additions & 4 deletions src/sentry/testutils/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
)
from sentry.issues.ingest import send_issue_occurrence_to_eventstream
from sentry.mail import mail_adapter
from sentry.mediators.project_rules.creator import Creator
from sentry.models.apitoken import ApiToken
from sentry.models.authprovider import AuthProvider as AuthProviderModel
from sentry.models.commit import Commit
Expand Down Expand Up @@ -114,6 +113,7 @@
from sentry.notifications.types import FineTuningAPIKey
from sentry.organizations.services.organization.serial import serialize_rpc_organization
from sentry.plugins.base import plugins
from sentry.projects.project_rules.creator import ProjectRuleCreator
from sentry.replays.lib.event_linking import transform_event_for_linking_payload
from sentry.replays.models import ReplayRecordingSegment
from sentry.rules.base import RuleBase
Expand Down Expand Up @@ -3259,16 +3259,16 @@ def _create_issue_alert_rule(self, monitor, exclude_slug_filter=False):
"uuid": str(uuid4()),
},
]
rule = Creator(
rule = ProjectRuleCreator(
name="New Cool Rule",
project=self.project,
conditions=conditions,
filterMatch="all",
filter_match="all",
action_match="any",
actions=actions,
frequency=5,
environment=self.environment.id,
).call()
).run()
rule.update(source=RuleSource.CRON_MONITOR)

config = monitor.config
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from sentry.mediators.project_rules.creator import Creator
from sentry.models.rule import Rule
from sentry.projects.project_rules.creator import ProjectRuleCreator
from sentry.testutils.cases import TestCase
from sentry.types.actor import Actor


class TestCreator(TestCase):
class TestProjectRuleCreator(TestCase):
def setUp(self):
self.user = self.create_user()
self.org = self.create_organization(name="bloop", owner=self.user)
self.project = self.create_project(
teams=[self.create_team()], name="foo", fire_project_created=True
)

self.creator = Creator(
self.creator = ProjectRuleCreator(
name="New Cool Rule",
owner=Actor.from_id(user_id=self.user.id),
project=self.project,
Expand All @@ -36,8 +36,8 @@ def setUp(self):
)

def test_creates_rule(self):
r = self.creator.call()
rule = Rule.objects.get(id=r.id)
r = self.creator.run()
rule: Rule = Rule.objects.get(id=r.id)
assert rule.label == "New Cool Rule"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to provide a type unless there is another variable that is shadowing rule.

assert rule.owner_user_id == self.user.id
assert rule.owner_team_id is None
Expand Down
Loading