diff --git a/migrations_lockfile.txt b/migrations_lockfile.txt index 4d80265f6822e9..6be4ab9cebfec7 100644 --- a/migrations_lockfile.txt +++ b/migrations_lockfile.txt @@ -15,7 +15,7 @@ remote_subscriptions: 0003_drop_remote_subscription replays: 0004_index_together -sentry: 0793_remove_db_constraint_alert_rule_exclusion +sentry: 0794_rm_excluded_included_projects_alertrule social_auth: 0002_default_auto_field diff --git a/src/sentry/deletions/defaults/project.py b/src/sentry/deletions/defaults/project.py index fb06ba353c6fc5..d1d4874652e3df 100644 --- a/src/sentry/deletions/defaults/project.py +++ b/src/sentry/deletions/defaults/project.py @@ -93,7 +93,7 @@ def get_child_relations(self, instance: Project) -> list[BaseRelation]: relations.append( ModelRelation( AlertRule, - {"snuba_query__subscriptions__project": instance, "include_all_projects": False}, + {"snuba_query__subscriptions__project": instance}, ) ) diff --git a/src/sentry/incidents/models/alert_rule.py b/src/sentry/incidents/models/alert_rule.py index a5b7adcfb0f584..ca213c53e9cfb0 100644 --- a/src/sentry/incidents/models/alert_rule.py +++ b/src/sentry/incidents/models/alert_rule.py @@ -301,15 +301,6 @@ class AlertRule(Model): user_id = HybridCloudForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete="SET_NULL") team = FlexibleForeignKey("sentry.Team", null=True, on_delete=models.SET_NULL) - - excluded_projects = models.ManyToManyField( - "sentry.Project", related_name="alert_rule_exclusions", through=AlertRuleExcludedProjects - ) # NOTE: This feature is not currently utilized. - # Determines whether we include all current and future projects from this - # organization in this rule. - include_all_projects = models.BooleanField( - default=False - ) # NOTE: This feature is not currently utilized. name = models.TextField() status = models.SmallIntegerField(default=AlertRuleStatus.PENDING.value) threshold_type = models.SmallIntegerField(null=True) diff --git a/src/sentry/migrations/0794_rm_excluded_included_projects_alertrule.py b/src/sentry/migrations/0794_rm_excluded_included_projects_alertrule.py new file mode 100644 index 00000000000000..0add9ea8dd47c6 --- /dev/null +++ b/src/sentry/migrations/0794_rm_excluded_included_projects_alertrule.py @@ -0,0 +1,45 @@ +# Generated by Django 5.1.1 on 2024-11-22 19:12 + +from django.db import migrations, models + +from sentry.new_migrations.migrations import CheckedMigration +from sentry.new_migrations.monkey.fields import SafeRemoveField +from sentry.new_migrations.monkey.state import DeletionAction + + +class Migration(CheckedMigration): + # This flag is used to mark that a migration shouldn't be automatically run in production. + # This should only be used for operations where it's safe to run the migration after your + # code has deployed. So this should not be used for most operations that alter the schema + # of a table. + # Here are some things that make sense to mark as post deployment: + # - Large data migrations. Typically we want these to be run manually so that they can be + # monitored and not block the deploy for a long period of time while they run. + # - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to + # run this outside deployments so that we don't block them. Note that while adding an index + # is a schema change, it's completely safe to run the operation after the code has deployed. + # Once deployed, run these manually via: https://develop.sentry.dev/database-migrations/#migration-deployment + + is_post_deployment = False + + dependencies = [ + ("sentry", "0793_remove_db_constraint_alert_rule_exclusion"), + ] + + operations = [ + SafeRemoveField( + model_name="alertrule", + name="excluded_projects", + deletion_action=DeletionAction.MOVE_TO_PENDING, + ), + migrations.AlterField( + model_name="alertrule", + name="include_all_projects", + field=models.BooleanField(default=False, null=True), + ), + SafeRemoveField( + model_name="alertrule", + name="include_all_projects", + deletion_action=DeletionAction.MOVE_TO_PENDING, + ), + ] diff --git a/tests/sentry/migrations/test_0730_add_subscription_fk_to_incident.py b/tests/sentry/migrations/test_0730_add_subscription_fk_to_incident.py deleted file mode 100644 index caa91ee9fbab17..00000000000000 --- a/tests/sentry/migrations/test_0730_add_subscription_fk_to_incident.py +++ /dev/null @@ -1,158 +0,0 @@ -from datetime import timedelta - -import pytest - -from sentry.incidents.models.alert_rule import AlertRule, AlertRuleThresholdType -from sentry.snuba.dataset import Dataset -from sentry.snuba.models import SnubaQuery -from sentry.snuba.subscriptions import create_snuba_query -from sentry.testutils.cases import TestMigrations - - -@pytest.mark.skip("Migration is no longer runnable. Retain until migration is removed.") -class AlertRuleProjectBackfillTest(TestMigrations): - migrate_from = "0729_backfill_groupsearchviews_with_pinned_searches" - migrate_to = "0730_add_subscription_fk_to_incident" - - def setup_before_migration(self, app): - self.snuba_query = create_snuba_query( - aggregate="", - dataset=Dataset.Events, - environment=None, - query="", - query_type=SnubaQuery.Type.ERROR, - resolution=timedelta(minutes=5), - time_window=timedelta(minutes=5), - ) - self.alert_rule = AlertRule.objects.create( - organization=self.organization, - snuba_query=self.snuba_query, - name="foo", - threshold_type=AlertRuleThresholdType.ABOVE.value, - threshold_period=1, - include_all_projects=False, - ) - - # creates a QuerySubscription for the alertrule and project - self.alert_rule.subscribe_projects(projects=[self.project]) - self.query_subscription = self.snuba_query.subscriptions.get() - - self.incident = self.create_incident(projects=[self.project], alert_rule=self.alert_rule) - - assert self.incident.alert_rule == self.alert_rule - assert not self.incident.subscription - - snuba_query_existing_sub = create_snuba_query( - aggregate="", - dataset=Dataset.Events, - environment=None, - query="", - query_type=SnubaQuery.Type.ERROR, - resolution=timedelta(minutes=5), - time_window=timedelta(minutes=5), - ) - alert_rule_existing_sub = AlertRule.objects.create( - organization=self.organization, - snuba_query=snuba_query_existing_sub, - name="foo", - threshold_type=AlertRuleThresholdType.ABOVE.value, - threshold_period=1, - include_all_projects=False, - ) - - # creates a QuerySubscription for the alertrule and project - alert_rule_existing_sub.subscribe_projects(projects=[self.project]) - self.query_subscription_existing_sub = snuba_query_existing_sub.subscriptions.get() - - self.incident_existing_sub = self.create_incident( - projects=[self.project], - alert_rule=alert_rule_existing_sub, - subscription=self.query_subscription_existing_sub, - ) - - assert self.incident_existing_sub.alert_rule == alert_rule_existing_sub - assert self.incident_existing_sub.subscription == self.query_subscription_existing_sub - - # Incident with a no subscriptions - snuba_query_no_sub = create_snuba_query( - aggregate="", - dataset=Dataset.Events, - environment=None, - query="", - query_type=SnubaQuery.Type.ERROR, - resolution=timedelta(minutes=5), - time_window=timedelta(minutes=5), - ) - self.alert_rule_no_sub = AlertRule.objects.create( - organization=self.organization, - snuba_query=snuba_query_no_sub, - name="foo", - threshold_type=AlertRuleThresholdType.ABOVE.value, - threshold_period=1, - include_all_projects=False, - ) - - # creates a QuerySubscription for the alertrule and project - self.alert_rule_no_sub.subscribe_projects(projects=[self.project]) - temp_subscription = snuba_query_no_sub.subscriptions.get() - temp_subscription.delete() - - self.incident_no_sub = self.create_incident( - projects=[self.project], alert_rule=self.alert_rule_no_sub - ) - - assert self.incident_no_sub.alert_rule == self.alert_rule_no_sub - assert not self.incident_no_sub.subscription - - # Incident for alert rule with multiple subscriptions - snuba_query_mult = create_snuba_query( - aggregate="", - dataset=Dataset.Events, - environment=None, - query="", - query_type=SnubaQuery.Type.ERROR, - resolution=timedelta(minutes=5), - time_window=timedelta(minutes=5), - ) - self.alert_rule_mult = AlertRule.objects.create( - organization=self.organization, - snuba_query=snuba_query_mult, - name="foo", - threshold_type=AlertRuleThresholdType.ABOVE.value, - threshold_period=1, - include_all_projects=False, - ) - - # creates a QuerySubscription for the alertrule and project - self.alert_rule_mult.subscribe_projects(projects=[self.project]) - self.alert_rule_mult.subscribe_projects(projects=[self.project]) - all_subscriptions = snuba_query_mult.subscriptions.all() - - self.incident_mult = self.create_incident( - projects=[self.project], alert_rule=self.alert_rule_mult - ) - - assert len(all_subscriptions) > 1 - assert self.incident_mult.alert_rule - assert not self.incident_mult.subscription - - @pytest.mark.skip(reason="old migration test") - def test(self): - self.incident.refresh_from_db() - assert self.incident.subscription is not None - assert self.incident.subscription == self.query_subscription - - self.query_subscription.delete() - self.incident.refresh_from_db() - assert self.incident - assert self.incident.subscription is None - - self.incident_existing_sub.refresh_from_db() - assert self.incident_existing_sub.subscription is not None - assert self.incident_existing_sub.subscription == self.query_subscription_existing_sub - - self.incident_no_sub.refresh_from_db() - assert not self.incident_no_sub.subscription - - self.incident_mult.refresh_from_db() - assert not self.incident_mult.subscription