diff --git a/migrations_lockfile.txt b/migrations_lockfile.txt index b3474546c491..a56e626cddec 100644 --- a/migrations_lockfile.txt +++ b/migrations_lockfile.txt @@ -5,38 +5,34 @@ ahead of you. To resolve this, rebase against latest master and regenerate your migration. This file will then be regenerated, and you should be able to merge without conflicts. -discover: 0003_discover_json_field +discover: 0001_squashed_0003_discover_json_field -explore: 0007_update_numeric_attrs_to_bools - -feedback: 0007_cleanup_failed_safe_deletes +explore: 0001_squashed_0007_update_numeric_attrs_to_bools flags: 0001_squashed_0004_add_flag_audit_log_provider_column -hybridcloud: 0030_remove_orgslugreservationreplica_delete +hybridcloud: 0001_squashed_0030_remove_orgslugreservationreplica_delete -insights: 0002_backfill_team_starred +insights: 0001_squashed_0002_backfill_team_starred -monitors: 0013_delete_monitor_is_muted_field +monitors: 0001_squashed_0013_delete_monitor_is_muted_field nodestore: 0001_squashed_0002_nodestore_no_dictfield -notifications: 0012_drop_metric_alert_cols_notificationmessage - -preprod: 0030_add_images_errored_to_snapshot_comparison +notifications: 0001_squashed_0012_drop_metric_alert_cols_notificationmessage -releases: 0004_cleanup_failed_safe_deletes +preprod: 0001_squashed_0030_add_images_errored_to_snapshot_comparison -replays: 0007_organizationmember_replay_access +replays: 0001_squashed_0007_organizationmember_replay_access -seer: 0018_backfill_seer_agent_run_group_id +seer: 0001_squashed_0018_backfill_seer_agent_run_group_id -sentry: 1117_drop_organizationmapping_codecov_access_delete +sentry: 0001_squashed_1117_drop_organizationmapping_codecov_access_delete -social_auth: 0003_social_auth_json_field +social_auth: 0001_squashed_0003_social_auth_json_field tempest: 0001_squashed_0003_use_encrypted_char_field -uptime: 0055_backfill_2xx_status_assertion +uptime: 0001_squashed_0055_backfill_2xx_status_assertion -workflow_engine: 0114_sanitize_dynamic_form_field_choices +workflow_engine: 0001_squashed_0114_sanitize_dynamic_form_field_choices diff --git a/src/sentry/discover/migrations/0001_move_discover_models.py b/src/sentry/discover/migrations/0001_move_discover_models.py deleted file mode 100644 index a95f609c9180..000000000000 --- a/src/sentry/discover/migrations/0001_move_discover_models.py +++ /dev/null @@ -1,138 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-08 14:54 - -import django.db.models.deletion -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - initial = True - - dependencies = [ - ("sentry", "0945_move_discover_models"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.CreateModel( - name="DiscoverSavedQuery", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "created_by_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ("name", models.CharField(max_length=255)), - ("query", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("version", models.IntegerField(null=True)), - ("date_created", models.DateTimeField(auto_now_add=True)), - ("date_updated", models.DateTimeField(auto_now=True)), - ( - "visits", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - default=1, null=True - ), - ), - ( - "last_visited", - models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ("is_homepage", models.BooleanField(blank=True, null=True)), - ( - "dataset", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ( - "dataset_source", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - ], - options={ - "db_table": "sentry_discoversavedquery", - }, - ), - migrations.CreateModel( - name="DiscoverSavedQueryProject", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "discover_saved_query", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="discover.discoversavedquery", - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_discoversavedqueryproject", - "unique_together": {("project", "discover_saved_query")}, - }, - ), - migrations.AddField( - model_name="discoversavedquery", - name="projects", - field=models.ManyToManyField( - through="discover.DiscoverSavedQueryProject", to="sentry.project" - ), - ), - migrations.AddConstraint( - model_name="discoversavedquery", - constraint=models.UniqueConstraint( - condition=models.Q(("is_homepage", True)), - fields=("organization", "created_by_id", "is_homepage"), - name="unique_user_homepage_query", - ), - ), - ] - ) - ] diff --git a/src/sentry/seer/migrations/0008_add_seer_run_models.py b/src/sentry/discover/migrations/0001_squashed_0003_discover_json_field.py similarity index 54% rename from src/sentry/seer/migrations/0008_add_seer_run_models.py rename to src/sentry/discover/migrations/0001_squashed_0003_discover_json_field.py index fa0b04dc3aec..ba6bf7b73000 100644 --- a/src/sentry/seer/migrations/0008_add_seer_run_models.py +++ b/src/sentry/discover/migrations/0001_squashed_0003_discover_json_field.py @@ -1,10 +1,10 @@ -# Generated by Django 5.2.12 on 2026-04-23 18:29 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.deletion +import django.utils.timezone import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key -import uuid from django.db import migrations, models from sentry.new_migrations.migrations import CheckedMigration @@ -23,16 +23,26 @@ class Migration(CheckedMigration): # 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 + is_post_deployment = True + + replaces = [ + ("discover", "0001_move_discover_models"), + ("discover", "0002_link_migrated_explore_query_in_discover"), + ("discover", "0003_discover_json_field"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks dependencies = [ - ("seer", "0007_add_extras_to_nightshiftrun"), - ("sentry", "1070_increase_integration_external_id_length"), + ("explore", "0001_squashed_0007_update_numeric_attrs_to_bools"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ migrations.CreateModel( - name="SeerRun", + name="DiscoverSavedQuery", fields=[ ( "id", @@ -40,29 +50,46 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), ( - "user_id", + "created_by_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), + ("name", models.CharField(max_length=255)), + ("query", models.JSONField()), + ("version", models.IntegerField(null=True)), + ("date_created", models.DateTimeField(auto_now_add=True)), + ("date_updated", models.DateTimeField(auto_now=True)), ( - "uuid", - models.UUIDField(default=uuid.uuid4, editable=False, unique=True), + "visits", + sentry.db.models.fields.bounded.BoundedBigIntegerField(default=1, null=True), ), ( - "seer_run_state_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True, unique=True), + "last_visited", + models.DateTimeField(default=django.utils.timezone.now, null=True), ), - ("type", models.CharField(max_length=256)), + ("is_homepage", models.BooleanField(blank=True, null=True)), ( - "mirror_status", - models.CharField(db_default="pending", default="pending", max_length=256), + "dataset", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, default=0 + ), + ), + ( + "dataset_source", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, default=0 + ), + ), + ( + "explore_query", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="explore.exploresavedquery", + ), ), - ("last_triggered_at", models.DateTimeField()), - ("extras", models.JSONField(db_default={}, default=dict)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -72,11 +99,11 @@ class Migration(CheckedMigration): ), ], options={ - "db_table": "seer_seerrun", + "db_table": "sentry_discoversavedquery", }, ), migrations.CreateModel( - name="SeerAgentRun", + name="DiscoverSavedQueryProject", fields=[ ( "id", @@ -84,65 +111,38 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("title", models.CharField(max_length=256)), - ("source", models.CharField(max_length=256)), - ("extras", models.JSONField(db_default={}, default=dict)), ( - "group", + "discover_saved_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - to="sentry.group", + on_delete=django.db.models.deletion.CASCADE, + to="discover.discoversavedquery", ), ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - to="sentry.project", - ), - ), - ( - "run", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="agent", - to="seer.seerrun", + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" ), ), ], options={ - "db_table": "seer_seeragentrun", + "db_table": "sentry_discoversavedqueryproject", + "unique_together": {("project", "discover_saved_query")}, }, ), - migrations.AddIndex( - model_name="seerrun", - index=models.Index( - fields=["organization", "-last_triggered_at"], - name="seer_seerru_organiz_c90199_idx", + migrations.AddField( + model_name="discoversavedquery", + name="projects", + field=models.ManyToManyField( + through="discover.DiscoverSavedQueryProject", to="sentry.project" ), ), - migrations.AddIndex( - model_name="seerrun", - index=models.Index( - fields=["organization", "user_id", "-last_triggered_at"], - name="seer_seerru_organiz_8b7357_idx", + migrations.AddConstraint( + model_name="discoversavedquery", + constraint=models.UniqueConstraint( + condition=models.Q(("is_homepage", True)), + fields=("organization", "created_by_id", "is_homepage"), + name="unique_user_homepage_query", ), ), - migrations.AddIndex( - model_name="seerrun", - index=models.Index( - fields=["organization", "type", "-last_triggered_at"], - name="seer_seerru_organiz_eb75f1_idx", - ), - ), - migrations.AddIndex( - model_name="seerrun", - index=models.Index(fields=["last_triggered_at"], name="seer_seerru_last_tr_9581cc_idx"), - ), ] diff --git a/src/sentry/discover/migrations/0002_link_migrated_explore_query_in_discover.py b/src/sentry/discover/migrations/0002_link_migrated_explore_query_in_discover.py deleted file mode 100644 index 15da6806abd0..000000000000 --- a/src/sentry/discover/migrations/0002_link_migrated_explore_query_in_discover.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-10 15:15 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("discover", "0001_move_discover_models"), - ("explore", "0006_add_changed_reason_field_explore"), - ] - - operations = [ - migrations.AddField( - model_name="discoversavedquery", - name="explore_query", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="explore.exploresavedquery", - ), - ), - ] diff --git a/src/sentry/discover/migrations/0003_discover_json_field.py b/src/sentry/discover/migrations/0003_discover_json_field.py deleted file mode 100644 index a663ef6d7246..000000000000 --- a/src/sentry/discover/migrations/0003_discover_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-04 19:23 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("discover", "0002_link_migrated_explore_query_in_discover"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_discoversavedquery", "query")], - state_operations=[ - migrations.AlterField( - model_name="discoversavedquery", - name="query", - field=models.JSONField(), - ), - ], - ) - ] diff --git a/src/sentry/explore/migrations/0001_squashed_0004_add_explore_last_visited_table.py b/src/sentry/explore/migrations/0001_squashed_0007_update_numeric_attrs_to_bools.py similarity index 86% rename from src/sentry/explore/migrations/0001_squashed_0004_add_explore_last_visited_table.py rename to src/sentry/explore/migrations/0001_squashed_0007_update_numeric_attrs_to_bools.py index 4bf9f4dd7ee4..6e23412db3f2 100644 --- a/src/sentry/explore/migrations/0001_squashed_0004_add_explore_last_visited_table.py +++ b/src/sentry/explore/migrations/0001_squashed_0007_update_numeric_attrs_to_bools.py @@ -1,14 +1,13 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:29 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.constraints import django.db.models.deletion import django.utils.timezone -from django.db import migrations, models - import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.db.models.fields.jsonfield +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -28,10 +27,10 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("explore", "0001_add_explore_saved_query_model"), - ("explore", "0002_add_starred_explore_query_model"), - ("explore", "0003_add_prebuilt_column_to_explore_saved_queries"), - ("explore", "0004_add_explore_last_visited_table"), + ("explore", "0001_squashed_0004_add_explore_last_visited_table"), + ("explore", "0005_explore_django_json_field"), + ("explore", "0006_add_changed_reason_field_explore"), + ("explore", "0007_update_numeric_attrs_to_bools"), ] initial = True @@ -39,7 +38,7 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ @@ -61,7 +60,7 @@ class Migration(CheckedMigration): ), ), ("name", models.CharField(max_length=255)), - ("query", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("query", models.JSONField()), ( "visits", sentry.db.models.fields.bounded.BoundedBigIntegerField(default=1, null=True), @@ -70,7 +69,10 @@ class Migration(CheckedMigration): "last_visited", models.DateTimeField(default=django.utils.timezone.now, null=True), ), - ("dataset", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "dataset", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("is_multi_query", models.BooleanField(default=False)), ( "prebuilt_id", @@ -84,10 +86,12 @@ class Migration(CheckedMigration): db_default=None, null=True ), ), + ("changed_reason", models.JSONField(default=None, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -107,7 +111,8 @@ class Migration(CheckedMigration): ( "explore_saved_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="explore.exploresavedquery" + on_delete=django.db.models.deletion.CASCADE, + to="explore.exploresavedquery", ), ), ( @@ -146,17 +151,22 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("last_visited", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_visited", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "explore_saved_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="explore.exploresavedquery" + on_delete=django.db.models.deletion.CASCADE, + to="explore.exploresavedquery", ), ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -191,18 +201,23 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("position", models.PositiveSmallIntegerField(db_default=None, null=True)), + ( + "position", + models.PositiveSmallIntegerField(db_default=None, null=True), + ), ("starred", models.BooleanField(db_default=True)), ( "explore_saved_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="explore.exploresavedquery" + on_delete=django.db.models.deletion.CASCADE, + to="explore.exploresavedquery", ), ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], diff --git a/src/sentry/explore/migrations/0005_explore_django_json_field.py b/src/sentry/explore/migrations/0005_explore_django_json_field.py deleted file mode 100644 index f17c0d7b0847..000000000000 --- a/src/sentry/explore/migrations/0005_explore_django_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-27 16:17 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = [ - ("explore", "0001_squashed_0004_add_explore_last_visited_table"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("explore_exploresavedquery", "query")], - state_operations=[ - migrations.AlterField( - model_name="exploresavedquery", - name="query", - field=models.JSONField(), - ), - ], - ) - ] diff --git a/src/sentry/explore/migrations/0006_add_changed_reason_field_explore.py b/src/sentry/explore/migrations/0006_add_changed_reason_field_explore.py deleted file mode 100644 index b5b0f35cc791..000000000000 --- a/src/sentry/explore/migrations/0006_add_changed_reason_field_explore.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-10 14:27 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("explore", "0005_explore_django_json_field"), - ] - - operations = [ - migrations.AddField( - model_name="exploresavedquery", - name="changed_reason", - field=models.JSONField(default=None, null=True), - ), - ] diff --git a/src/sentry/explore/migrations/0007_update_numeric_attrs_to_bools.py b/src/sentry/explore/migrations/0007_update_numeric_attrs_to_bools.py deleted file mode 100644 index 44156522339b..000000000000 --- a/src/sentry/explore/migrations/0007_update_numeric_attrs_to_bools.py +++ /dev/null @@ -1,220 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-04 20:33 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps -from typing import Any -from enum import Enum -import logging -import re - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.explore.models import ExploreSavedQueryDataset -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -from sentry_protos.snuba.v1.endpoint_trace_item_attributes_pb2 import ( - TraceItemAttributeNamesRequest, -) -from sentry_protos.snuba.v1.request_common_pb2 import ( - PageToken, - TraceItemType, - RequestMeta, -) -from sentry_protos.snuba.v1.trace_item_attribute_pb2 import AttributeKey - -from sentry.api.event_search import ( - SearchConfig, - default_config, - parse_search_query, - SearchFilter, -) -from sentry.search.eap.types import SearchResolverConfig -from sentry.search.events.types import SnubaParams -from sentry.utils import snuba_rpc -from sentry.snuba.ourlogs import OurLogs -from sentry.snuba.spans_rpc import Spans - - -logger = logging.getLogger(__name__) - -TAG_KEY_RE = re.compile(r"^(sentry_tags|tags)\[(?P.*)\]$") - - -class SupportedTraceItemType(str, Enum): - LOGS = "logs" - SPANS = "spans" - UPTIME_RESULTS = "uptime_results" - TRACEMETRICS = "tracemetrics" - PROFILE_FUNCTIONS = "profile_functions" - PREPROD = "preprod" - ATTACHMENTS = "attachments" - PROCESSING_ERRORS = "processing_errors" - OCCURRENCES = "occurrences" - - -SUPPORTED_TRACE_ITEM_TYPE_MAP = { - SupportedTraceItemType.LOGS: TraceItemType.TRACE_ITEM_TYPE_LOG, - SupportedTraceItemType.SPANS: TraceItemType.TRACE_ITEM_TYPE_SPAN, - SupportedTraceItemType.UPTIME_RESULTS: TraceItemType.TRACE_ITEM_TYPE_UPTIME_RESULT, - SupportedTraceItemType.TRACEMETRICS: TraceItemType.TRACE_ITEM_TYPE_METRIC, - SupportedTraceItemType.PROFILE_FUNCTIONS: TraceItemType.TRACE_ITEM_TYPE_PROFILE_FUNCTION, - SupportedTraceItemType.PREPROD: TraceItemType.TRACE_ITEM_TYPE_PREPROD, - SupportedTraceItemType.ATTACHMENTS: TraceItemType.TRACE_ITEM_TYPE_ATTACHMENT, - SupportedTraceItemType.PROCESSING_ERRORS: TraceItemType.TRACE_ITEM_TYPE_PROCESSING_ERROR, -} - - -def get_dataset(dataset_label: str) -> Any | None: - return { - "spans": Spans, - "logs": OurLogs, - "segment_spans": Spans, - }.get(dataset_label) - - -def _check_if_bool(meta: RequestMeta, name: str, bool_cache: dict[str, bool]) -> bool: - if name in bool_cache: - return bool_cache[name] - rpc_request = TraceItemAttributeNamesRequest( - meta=meta, - limit=10, - page_token=PageToken(offset=0), - type=AttributeKey.Type.TYPE_BOOLEAN, - value_substring_match=name, - ) - try: - rpc_response = snuba_rpc.attribute_names_rpc(rpc_request) - bool_cache[name] = ( - len(rpc_response.attributes) == 1 and rpc_response.attributes[0].name == name - ) - except Exception as error: - logger.exception( - "Error retrieving attribute info", - extra={ - "tag": name, - "error": error, - }, - ) - bool_cache[name] = False - return bool_cache[name] - - -def update_numeric_attrs_to_bools(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - ExploreSavedQuery = apps.get_model("explore", "ExploreSavedQuery") - - for saved_query in RangeQuerySetWrapperWithProgressBar( - ExploreSavedQuery.objects.filter(query__query__icontains="number]") - ): - try: - trace_item_type = ExploreSavedQueryDataset.get_type_name(saved_query.dataset) - dataset = get_dataset(trace_item_type) - if dataset is None: - continue - - queries = saved_query.query["query"] - period = saved_query.query.get("range", "14d") or "14d" - - resolver = dataset.get_resolver( - SnubaParams( - organization=saved_query.organization, - stats_period=period, - projects=list(saved_query.projects.all()), - ), - SearchResolverConfig(), - ) - changed = False - for query in queries: - # We only cache per query cause the results can change query to query - bool_cache: dict[str, bool] = {} - meta = resolver.resolve_meta(referrer="migration") - meta.trace_item_type = SUPPORTED_TRACE_ITEM_TYPE_MAP.get( - trace_item_type, TraceItemType.TRACE_ITEM_TYPE_SPAN - ) - new_fields = [] - for field in query["fields"]: - if TAG_KEY_RE.match(field): - resolved_column, _ = resolver.resolve_column(field) - if resolved_column.search_type == "number" and _check_if_bool( - meta, - resolved_column.internal_name, - bool_cache, - ): - new_fields.append(f"tags[{resolved_column.internal_name},boolean]") - continue - new_fields.append(field) - if query["fields"] != new_fields: - query["fields"] = new_fields - changed = True - - # If there's a query, do our best effort to update the terms to use boolean syntax - if "query" in query: - parsed_terms = parse_search_query( - query["query"], - config=SearchConfig.create_from( - default_config, - wildcard_free_text=True, - ), - params=resolver.params.filter_params, - get_field_type=resolver.get_field_type, - get_function_result_type=resolver.get_field_type, - ) - new_query = query["query"] - for term in parsed_terms: - # this isn't perfect, but we can see that there aren't any queries where this wouldn't be enough - # the current problem is that there isn't a good way to go back from parsed_terms -> a search query - if isinstance(term, SearchFilter) and term.key.is_tag: - resolved_column, _ = resolver.resolve_column(term.key.name) - if resolved_column.search_type == "number" and _check_if_bool( - meta, resolved_column.internal_name, bool_cache - ): - key = f"tags[{resolved_column.internal_name},boolean]" - target = f"tags[{resolved_column.internal_name},number]" - new_query = new_query.replace(f"{target}:1", f"{key}:True") - new_query = new_query.replace(f"{target}:0", f"{key}:False") - key = f"tags[{resolved_column.internal_name}, boolean]" - target = f"tags[{resolved_column.internal_name}, number]" - new_query = new_query.replace(f"{target}:1", f"{key}:True") - new_query = new_query.replace(f"{target}:0", f"{key}:False") - if query["query"] != new_query: - query["query"] = new_query - changed = True - - if changed: - saved_query.save() - except Exception as error: - logger.exception( - "Error updating a query", - extra={ - "saved_query": saved_query.id, - "error": error, - }, - ) - - -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 = True - - dependencies = [ - ("sentry", "1041_projectkeymapping"), - ("explore", "0006_add_changed_reason_field_explore"), - ] - - operations = [ - migrations.RunPython( - reverse_code=migrations.RunPython.noop, - code=update_numeric_attrs_to_bools, - hints={"tables": ["explore_saved_query"]}, - ), - ] diff --git a/src/sentry/feedback/migrations/0001_squashed_0004_index_together.py b/src/sentry/feedback/migrations/0001_squashed_0004_index_together.py deleted file mode 100644 index cc2a38f45d87..000000000000 --- a/src/sentry/feedback/migrations/0001_squashed_0004_index_together.py +++ /dev/null @@ -1,85 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:29 - -import django.db.models.deletion -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.uuid -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - replaces = [ - ("feedback", "0001_feedback"), - ("feedback", "0002_feedback_add_org_id_and_rename_event_id"), - ("feedback", "0003_feedback_add_env"), - ("feedback", "0004_index_together"), - ] - - initial = True - - checked = False # This is an initial migration and can take locks - - dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), - ] - - operations = [ - migrations.CreateModel( - name="Feedback", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "project_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("replay_id", models.CharField(db_index=True, max_length=100, null=True)), - ("url", models.CharField(max_length=1000, null=True)), - ("message", models.TextField()), - ("feedback_id", sentry.db.models.fields.uuid.UUIDField(max_length=32, unique=True)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("data", models.JSONField(null=True)), - ( - "environment", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.environment", - ), - ), - ], - options={ - "db_table": "feedback_feedback", - "indexes": [ - models.Index( - fields=["project_id", "date_added"], name="feedback_fe_project_84fbf7_idx" - ) - ], - }, - ), - ] diff --git a/src/sentry/feedback/migrations/0005_feedback_fk_not_db_contstr.py b/src/sentry/feedback/migrations/0005_feedback_fk_not_db_contstr.py deleted file mode 100644 index 4bf7005574c6..000000000000 --- a/src/sentry/feedback/migrations/0005_feedback_fk_not_db_contstr.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 15:45 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("feedback", "0001_squashed_0004_index_together"), - ("sentry", "0980_integrations_json_field"), - ] - - operations = [ - migrations.AlterField( - model_name="feedback", - name="environment", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.environment", - ), - ), - SafeDeleteModel( - name="feedback", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/feedback/migrations/0006_safe_del_feedback_model.py b/src/sentry/feedback/migrations/0006_safe_del_feedback_model.py deleted file mode 100644 index 4cd632b6e96b..000000000000 --- a/src/sentry/feedback/migrations/0006_safe_del_feedback_model.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 16:33 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("feedback", "0005_feedback_fk_not_db_contstr"), - ] - - operations = [ - SafeDeleteModel(name="feedback", deletion_action=DeletionAction.DELETE), - ] diff --git a/src/sentry/feedback/migrations/0007_cleanup_failed_safe_deletes.py b/src/sentry/feedback/migrations/0007_cleanup_failed_safe_deletes.py deleted file mode 100644 index 9f30b09c82e8..000000000000 --- a/src/sentry/feedback/migrations/0007_cleanup_failed_safe_deletes.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 00:38 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = [ - ("feedback", "0006_safe_del_feedback_model"), - ] - - operations = [ - # Clean up table that may not have been deleted due to missing - # historical_silo_assignments entry before the fix - SafeRunSQL( - sql="DROP TABLE IF EXISTS feedback_feedback CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["feedback_feedback"]}, - ), - ] diff --git a/src/sentry/flags/migrations/0001_squashed_0004_add_flag_audit_log_provider_column.py b/src/sentry/flags/migrations/0001_squashed_0004_add_flag_audit_log_provider_column.py index 3a747fbe2227..4091a609184e 100644 --- a/src/sentry/flags/migrations/0001_squashed_0004_add_flag_audit_log_provider_column.py +++ b/src/sentry/flags/migrations/0001_squashed_0004_add_flag_audit_log_provider_column.py @@ -37,7 +37,7 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ diff --git a/src/sentry/hybridcloud/migrations/0001_squashed_0021_django_arrayfield_scope_list.py b/src/sentry/hybridcloud/migrations/0001_squashed_0030_remove_orgslugreservationreplica_delete.py similarity index 79% rename from src/sentry/hybridcloud/migrations/0001_squashed_0021_django_arrayfield_scope_list.py rename to src/sentry/hybridcloud/migrations/0001_squashed_0030_remove_orgslugreservationreplica_delete.py index cfc607855ee1..86d9a2ba35d7 100644 --- a/src/sentry/hybridcloud/migrations/0001_squashed_0021_django_arrayfield_scope_list.py +++ b/src/sentry/hybridcloud/migrations/0001_squashed_0030_remove_orgslugreservationreplica_delete.py @@ -1,17 +1,16 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:29 +# Generated by Django 5.2.14 on 2026-06-16 19:05 +import bitfield.models import datetime - import django.contrib.postgres.fields import django.db.models.deletion import django.utils.timezone -from django.conf import settings -from django.db import migrations, models - -import bitfield.models import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key +from django.conf import settings +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -31,27 +30,16 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("hybridcloud", "0001_add_api_key_replica"), - ("hybridcloud", "0002_add_slug_reservation_replica_model"), - ("hybridcloud", "0003_add_scopes_to_api_key_replica"), - ("hybridcloud", "0004_add_cache_version"), - ("hybridcloud", "0005_add_missing_org_integration_scope"), - ("hybridcloud", "0006_add_apitokenreplica"), - ("hybridcloud", "0007_add_orgauthtokenreplica"), - ("hybridcloud", "0008_add_externalactorreplica"), - ("hybridcloud", "0009_make_user_id_optional_for_slug_reservation_replica"), - ("hybridcloud", "0010_add_webhook_payload"), - ("hybridcloud", "0011_add_hybridcloudapitoken_index"), - ("hybridcloud", "0012_apitoken_increase_token_length"), - ("hybridcloud", "0013_add_orgauthtokenreplica_token_index"), - ("hybridcloud", "0014_apitokenreplica_add_hashed_token"), - ("hybridcloud", "0015_apitokenreplica_hashed_token_index"), - ("hybridcloud", "0016_add_control_cacheversion"), - ("hybridcloud", "0017_add_scoping_organization_apitokenreplica"), - ("hybridcloud", "0018_add_alert_and_member_invite_scopes_to_sentry_apps"), - ("hybridcloud", "0019_add_provider_webhook_payload"), - ("hybridcloud", "0020_fix_scope_list_type"), - ("hybridcloud", "0021_django_arrayfield_scope_list"), + ("hybridcloud", "0001_squashed_0021_django_arrayfield_scope_list"), + ("hybridcloud", "0022_webhook_payload_update"), + ("hybridcloud", "0023_correct_webhook_payload_constraint"), + ("hybridcloud", "0024_add_project_distribution_scope"), + ("hybridcloud", "0025_rename_slugreservationreplica_region_name_to_cell_name"), + ("hybridcloud", "0026_webhookpayload_rename_region_name_to_cell_name"), + ("hybridcloud", "0027_region_cache_version_to_cell_cache_version"), + ("hybridcloud", "0028_add_org_ci_scope"), + ("hybridcloud", "0029_remove_orgslugreservationreplica_pending"), + ("hybridcloud", "0030_remove_orgslugreservationreplica_delete"), ] initial = True @@ -59,13 +47,13 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name="ControlCacheVersion", + name="CellCacheVersion", fields=[ ( "id", @@ -77,11 +65,11 @@ class Migration(CheckedMigration): ("version", models.PositiveBigIntegerField(default=0)), ], options={ - "db_table": "hybridcloud_controlcacheversion", + "db_table": "hybridcloud_regioncacheversion", }, ), migrations.CreateModel( - name="RegionCacheVersion", + name="ControlCacheVersion", fields=[ ( "id", @@ -93,7 +81,7 @@ class Migration(CheckedMigration): ("version", models.PositiveBigIntegerField(default=0)), ], options={ - "db_table": "hybridcloud_regioncacheversion", + "db_table": "hybridcloud_controlcacheversion", }, ), migrations.CreateModel( @@ -129,6 +117,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -156,7 +146,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -164,50 +155,6 @@ class Migration(CheckedMigration): "db_table": "hybridcloud_apikeyreplica", }, ), - migrations.CreateModel( - name="OrganizationSlugReservationReplica", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "organization_slug_reservation_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.organizationslugreservation", - db_index=True, - on_delete="CASCADE", - unique=True, - ), - ), - ("slug", models.SlugField(unique=True)), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ( - "user_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - db_index=True, null=True - ), - ), - ("region_name", models.CharField(max_length=48)), - ( - "reservation_type", - sentry.db.models.fields.bounded.BoundedBigIntegerField(default=0), - ), - ( - "date_added", - models.DateTimeField(default=django.utils.timezone.now, editable=False), - ), - ], - options={ - "db_table": "hybridcloud_organizationslugreservationreplica", - "unique_together": {("organization_id", "reservation_type")}, - }, - ), migrations.CreateModel( name="WebhookPayload", fields=[ @@ -219,13 +166,14 @@ class Migration(CheckedMigration): ), ("mailbox_name", models.CharField()), ("provider", models.CharField(blank=True, null=True)), - ("region_name", models.CharField()), + ("destination_type", models.CharField(db_default="sentry_region")), + ("cell_name", models.CharField(db_column="region_name", null=True)), ("integration_id", models.BigIntegerField(null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "schedule_for", models.DateTimeField( - default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.UTC) + default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.timezone.utc) ), ), ("attempts", models.IntegerField(default=0)), @@ -241,7 +189,8 @@ class Migration(CheckedMigration): models.Index(fields=["schedule_for"], name="hybridcloud_schedul_ee7ad7_idx"), models.Index(fields=["provider"], name="webhookpayload_provider_idx"), models.Index( - fields=["mailbox_name", "id"], name="webhookpayload_mailbox_id_idx" + fields=["mailbox_name", "id"], + name="webhookpayload_mailbox_id_idx", ), models.Index( models.ExpressionWrapper( @@ -256,6 +205,16 @@ class Migration(CheckedMigration): name="webhookpayload_priority_idx", ), ], + "constraints": [ + models.CheckConstraint( + condition=models.Q( + models.Q(("destination_type", "sentry_region"), _negated=True), + ("cell_name__isnull", False), + _connector="OR", + ), + name="webhookpayload_region_name_not_null", + ) + ], }, ), migrations.CreateModel( @@ -291,6 +250,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -304,7 +265,10 @@ class Migration(CheckedMigration): ( "application_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.ApiApplication", db_index=True, null=True, on_delete="CASCADE" + "sentry.ApiApplication", + db_index=True, + null=True, + on_delete="CASCADE", ), ), ("application_is_active", models.BooleanField(default=False)), @@ -328,7 +292,10 @@ class Migration(CheckedMigration): ( "scoping_organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, null=True, on_delete="CASCADE" + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", ), ), ( @@ -357,7 +324,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("externalactor_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "externalactor_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ( "team_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -370,13 +340,17 @@ class Migration(CheckedMigration): "sentry.Organization", db_index=True, on_delete="CASCADE" ), ), - ("provider", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "provider", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("external_name", models.TextField()), ("external_id", models.TextField(null=True)), ( "integration", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.integration" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.integration", ), ), ( @@ -422,7 +396,11 @@ class Migration(CheckedMigration): ( "created_by_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), @@ -430,7 +408,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], diff --git a/src/sentry/hybridcloud/migrations/0022_webhook_payload_update.py b/src/sentry/hybridcloud/migrations/0022_webhook_payload_update.py deleted file mode 100644 index 05a99d31a87a..000000000000 --- a/src/sentry/hybridcloud/migrations/0022_webhook_payload_update.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-18 20:12 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0001_squashed_0021_django_arrayfield_scope_list"), - ] - - operations = [ - migrations.AddField( - model_name="webhookpayload", - name="destination_type", - field=models.CharField(db_default="sentry_region"), - ), - migrations.AlterField( - model_name="webhookpayload", - name="region_name", - field=models.CharField(null=True), - ), - migrations.AddConstraint( - model_name="webhookpayload", - constraint=models.CheckConstraint( - condition=models.Q( - ("destination_type", "sentry_region"), ("region_name__isnull", False) - ), - name="webhookpayload_region_name_not_null", - ), - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0023_correct_webhook_payload_constraint.py b/src/sentry/hybridcloud/migrations/0023_correct_webhook_payload_constraint.py deleted file mode 100644 index 14ca93a3feb4..000000000000 --- a/src/sentry/hybridcloud/migrations/0023_correct_webhook_payload_constraint.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-26 19:37 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0022_webhook_payload_update"), - ] - - operations = [ - migrations.RemoveConstraint( - model_name="webhookpayload", - name="webhookpayload_region_name_not_null", - ), - migrations.AddConstraint( - model_name="webhookpayload", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q(("destination_type", "sentry_region"), _negated=True), - ("region_name__isnull", False), - _connector="OR", - ), - name="webhookpayload_region_name_not_null", - ), - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0024_add_project_distribution_scope.py b/src/sentry/hybridcloud/migrations/0024_add_project_distribution_scope.py deleted file mode 100644 index 92fbe2c0f782..000000000000 --- a/src/sentry/hybridcloud/migrations/0024_add_project_distribution_scope.py +++ /dev/null @@ -1,89 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-27 10:46 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0023_correct_webhook_payload_constraint"), - ] - - operations = [ - migrations.AlterField( - model_name="apikeyreplica", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apitokenreplica", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0025_rename_slugreservationreplica_region_name_to_cell_name.py b/src/sentry/hybridcloud/migrations/0025_rename_slugreservationreplica_region_name_to_cell_name.py deleted file mode 100644 index d4872cd9ba07..000000000000 --- a/src/sentry/hybridcloud/migrations/0025_rename_slugreservationreplica_region_name_to_cell_name.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-09 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0024_add_project_distribution_scope"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationslugreservationreplica", - name="region_name", - field=models.CharField(db_column="region_name", max_length=48, null=False), - ), - migrations.RenameField( - model_name="organizationslugreservationreplica", - old_name="region_name", - new_name="cell_name", - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0026_webhookpayload_rename_region_name_to_cell_name.py b/src/sentry/hybridcloud/migrations/0026_webhookpayload_rename_region_name_to_cell_name.py deleted file mode 100644 index aeed93f51238..000000000000 --- a/src/sentry/hybridcloud/migrations/0026_webhookpayload_rename_region_name_to_cell_name.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-09 21:12 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0025_rename_slugreservationreplica_region_name_to_cell_name"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[], - state_operations=[ - migrations.RemoveConstraint( - model_name="webhookpayload", - name="webhookpayload_region_name_not_null", - ), - migrations.AlterField( - model_name="webhookpayload", - name="region_name", - field=models.CharField(db_column="region_name", null=True), - ), - migrations.RenameField( - model_name="webhookpayload", - old_name="region_name", - new_name="cell_name", - ), - migrations.AddConstraint( - model_name="webhookpayload", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q(("destination_type", "sentry_region"), _negated=True), - ("cell_name__isnull", False), - _connector="OR", - ), - name="webhookpayload_region_name_not_null", - ), - ), - ], - ) - ] diff --git a/src/sentry/hybridcloud/migrations/0027_region_cache_version_to_cell_cache_version.py b/src/sentry/hybridcloud/migrations/0027_region_cache_version_to_cell_cache_version.py deleted file mode 100644 index f97a395aa102..000000000000 --- a/src/sentry/hybridcloud/migrations/0027_region_cache_version_to_cell_cache_version.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-13 20:16 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0026_webhookpayload_rename_region_name_to_cell_name"), - ] - - operations = [ - # The model is renamed but db_table is explicitly set to the old name, so no DDL is needed. - migrations.SeparateDatabaseAndState( - database_operations=[], - state_operations=[ - migrations.RenameModel( - old_name="RegionCacheVersion", - new_name="CellCacheVersion", - ), - ], - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0028_add_org_ci_scope.py b/src/sentry/hybridcloud/migrations/0028_add_org_ci_scope.py deleted file mode 100644 index fcdbd602901e..000000000000 --- a/src/sentry/hybridcloud/migrations/0028_add_org_ci_scope.py +++ /dev/null @@ -1,91 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-22 15:30 - -import bitfield.models -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("hybridcloud", "0027_region_cache_version_to_cell_cache_version"), - ] - - operations = [ - migrations.AlterField( - model_name="apikeyreplica", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apitokenreplica", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0029_remove_orgslugreservationreplica_pending.py b/src/sentry/hybridcloud/migrations/0029_remove_orgslugreservationreplica_pending.py deleted file mode 100644 index ad4bbce56fcc..000000000000 --- a/src/sentry/hybridcloud/migrations/0029_remove_orgslugreservationreplica_pending.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-05 19:11 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("hybridcloud", "0028_add_org_ci_scope"), - ] - - operations = [ - SafeDeleteModel( - name="OrganizationSlugReservationReplica", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/hybridcloud/migrations/0030_remove_orgslugreservationreplica_delete.py b/src/sentry/hybridcloud/migrations/0030_remove_orgslugreservationreplica_delete.py deleted file mode 100644 index 2c5c27534b82..000000000000 --- a/src/sentry/hybridcloud/migrations/0030_remove_orgslugreservationreplica_delete.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-08 15:39 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("hybridcloud", "0029_remove_orgslugreservationreplica_pending"), - ] - - operations = [ - SafeDeleteModel( - name="OrganizationSlugReservationReplica", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/insights/migrations/0001_squashed_0001_add_starred_transactions_model.py b/src/sentry/insights/migrations/0001_squashed_0002_backfill_team_starred.py similarity index 90% rename from src/sentry/insights/migrations/0001_squashed_0001_add_starred_transactions_model.py rename to src/sentry/insights/migrations/0001_squashed_0002_backfill_team_starred.py index 7ea5078004b6..96b7f655dd0c 100644 --- a/src/sentry/insights/migrations/0001_squashed_0001_add_starred_transactions_model.py +++ b/src/sentry/insights/migrations/0001_squashed_0002_backfill_team_starred.py @@ -1,11 +1,11 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:30 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.deletion -from django.db import migrations, models - import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -25,7 +25,8 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("insights", "0001_add_starred_transactions_model"), + ("insights", "0001_squashed_0001_add_starred_transactions_model"), + ("insights", "0002_backfill_team_starred"), ] initial = True @@ -33,7 +34,7 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ @@ -58,7 +59,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( diff --git a/src/sentry/insights/migrations/0002_backfill_team_starred.py b/src/sentry/insights/migrations/0002_backfill_team_starred.py deleted file mode 100644 index 75dedd940a53..000000000000 --- a/src/sentry/insights/migrations/0002_backfill_team_starred.py +++ /dev/null @@ -1,87 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-10 16:25 -import logging - -from django.db import IntegrityError, migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - - -def migrate_team_stars_to_user_stars( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - TeamKeyTransaction = apps.get_model("sentry", "teamkeytransaction") - InsightsStarredSegment = apps.get_model("insights", "insightsstarredsegment") - OrganizationMemberTeam = apps.get_model("sentry", "Organizationmemberteam") - - queryset = TeamKeyTransaction.objects.select_related( - "organization", "project_team", "project_team__team", "project_team__project" - ).all() - for team_starred_transaction in RangeQuerySetWrapperWithProgressBar(queryset): - starred_transaction = team_starred_transaction - - segment_name: str = starred_transaction.transaction - projectTeam = starred_transaction.project_team - organization = starred_transaction.organization - - user_ids = OrganizationMemberTeam.objects.filter(team=projectTeam.team).values_list( - "organizationmember__user_id", flat=True - ) - - segments_to_create = [ - InsightsStarredSegment( - organization_id=organization.id, - project_id=projectTeam.project_id, - user_id=user_id, - segment_name=segment_name, - ) - for user_id in user_ids - if user_id is not None - ] - with transaction.atomic(router.db_for_write(InsightsStarredSegment)): - try: - InsightsStarredSegment.objects.bulk_create( - segments_to_create, - ignore_conflicts=True, - ) - except IntegrityError as e: - logger.exception( - "Error bulk updating team", - extra={ - "projectTeam.id": projectTeam.id, - "organization.id": organization.id, - "error": e, - }, - ) - - -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 = True - - dependencies = [ - ("insights", "0001_squashed_0001_add_starred_transactions_model"), - ] - - operations = [ - migrations.RunPython( - migrate_team_stars_to_user_stars, - migrations.RunPython.noop, - hints={"tables": ["insights_starred_segments"]}, - ), - ] diff --git a/src/sentry/migrations/0001_squashed_0904_onboarding_task_project_id_idx.py b/src/sentry/migrations/0001_squashed_1117_drop_organizationmapping_codecov_access_delete.py similarity index 75% rename from src/sentry/migrations/0001_squashed_0904_onboarding_task_project_id_idx.py rename to src/sentry/migrations/0001_squashed_1117_drop_organizationmapping_codecov_access_delete.py index 64742c84e62d..c75f68a2a48c 100644 --- a/src/sentry/migrations/0001_squashed_0904_onboarding_task_project_id_idx.py +++ b/src/sentry/migrations/0001_squashed_1117_drop_organizationmapping_codecov_access_delete.py @@ -1,32 +1,27 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:31 +# Generated by Django 5.2.14 on 2026-06-16 19:05 +from sentry.new_migrations.monkey.special import SafeRunSQL +import bitfield.models import datetime -import uuid - import django.contrib.postgres.constraints import django.contrib.postgres.fields import django.contrib.postgres.fields.ranges import django.db.models.constraints import django.db.models.deletion +import django.db.models.expressions import django.db.models.fields.json import django.db.models.functions.comparison import django.db.models.functions.datetime import django.db.models.functions.text import django.db.models.manager import django.utils.timezone -from django.conf import settings -from django.db import migrations, models - -import bitfield.models import sentry.backup.mixins -import sentry.db.models.fields.array import sentry.db.models.fields.bounded -import sentry.db.models.fields.citext +import sentry.db.models.fields.encryption.encrypted_json_field import sentry.db.models.fields.foreignkey import sentry.db.models.fields.gzippeddict import sentry.db.models.fields.hybrid_cloud_foreign_key import sentry.db.models.fields.jsonfield -import sentry.db.models.fields.picklefield import sentry.db.models.fields.slug import sentry.db.models.fields.text import sentry.db.models.fields.uuid @@ -34,12 +29,15 @@ import sentry.deletions.models.scheduleddeletion import sentry.incidents.models.alert_rule import sentry.models.apiapplication +import sentry.models.apidevicecode import sentry.models.apigrant import sentry.models.apitoken import sentry.models.broadcast +import sentry.models.code_review_event import sentry.models.files.abstractfile import sentry.models.files.abstractfileblob import sentry.models.groupopenperiod +import sentry.models.groupopenperiodactivity import sentry.models.groupshare import sentry.models.organizationmemberinvite import sentry.models.orgauthtoken @@ -51,9 +49,13 @@ import sentry.sentry_apps.models.servicehook import sentry.users.models.authenticator import sentry.users.models.user +import sentry.users.models.user_merge_verification_code import sentry.utils.security.hash +import uuid +from django.conf import settings +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL class Migration(CheckedMigration): @@ -72,427 +74,220 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("sentry", "0001_squashed_0484_break_org_member_user_fk"), - ("sentry", "0485_remove_scheduled_job"), - ("sentry", "0486_integer_pr_comment_issue_list"), - ("sentry", "0487_add_indexes_to_bundles"), - ("sentry", "0488_add_orgauthtoken"), - ("sentry", "0489_index_checkin_timeout"), - ("sentry", "0490_add_is_test_to_org"), - ("sentry", "0491_remove_orgmemmap_unique_constraints"), - ("sentry", "0492_pickle_to_json_sentry_groupedmessage"), - ("sentry", "0493_pickle_to_json_sentry_activity"), - ("sentry", "0494_add_traceid_checkin"), - ("sentry", "0495_add_date_last_modified_to_artifact_bundle"), - ("sentry", "0496_update_userid_state"), - ("sentry", "0497_add_comment_reactions_column"), - ("sentry", "0498_typed_bitfield"), - ("sentry", "0499_typed_bitfield_revert"), - ("sentry", "0500_set_none_date_last_modified_to_date_uploaded"), - ("sentry", "0501_typed_bitfield_remove_labels"), - ("sentry", "0502_savedsearch_update_me_myteams"), - ("sentry", "0503_alter_notification_actor_nullable"), - ("sentry", "0504_add_artifact_bundle_index"), - ("sentry", "0505_debugfile_date_accessed"), - ("sentry", "0506_null_boolean_fields"), - ("sentry", "0507_add_oidc_scopes"), - ("sentry", "0507_delete_pending_deletion_rules"), - ("sentry", "0508_index_checkin_monitorenvironment"), - ("sentry", "0508_merging_migrations"), - ("sentry", "0509_merging_migrations"), - ("sentry", "0510_index_checkin_traceid"), - ("sentry", "0511_pickle_to_json_sentry_rawevent"), - ("sentry", "0512_add_proguard_release_association"), - ("sentry", "0513_django_jsonfield"), - ("sentry", "0514_migrate_priority_saved_searches"), - ("sentry", "0515_slugify_invalid_monitors"), - ("sentry", "0516_switch_pagerduty_silo"), - ("sentry", "0517_backfill_pagerdutyservices_into_org_integrations"), - ("sentry", "0518_cleanup_bundles_indexes"), - ("sentry", "0519_remove_repo_name_constraint"), - ("sentry", "0520_add_flat_file_index_table"), - ("sentry", "0521_migrate_world_map_widgets"), - ("sentry", "0522_migrate_discover_savedquery_worldmaps"), - ("sentry", "0523_add_new_index_to_groupedmessage"), - ("sentry", "0524_flip_checkin_index"), - ("sentry", "0525_add_next_checkin_latest"), - ("sentry", "0526_pr_comment_type_column"), - ("sentry", "0527_backfill_next_checkin_latest"), - ("sentry", "0528_truncate_flat_index"), - ("sentry", "0529_remove_pagerduty_service"), - ("sentry", "0530_new_notification_tables"), - ("sentry", "0531_add_notification_uuid_to_incident_activity"), - ("sentry", "0532_denormalize_team_and_user_x_actor"), - ("sentry", "0533_make_flatfile_unique_again"), - ("sentry", "0534_add_notification_uuid_to_rule_fire_history"), - ("sentry", "0535_add_created_date_to_outbox_model"), - ("sentry", "0536_backfill_tombstones"), - ("sentry", "0537_backfill_xactor_team_and_user_ids"), - ("sentry", "0538_remove_name_data_from_rule"), - ("sentry", "0539_add_last_state_change_monitorenv"), - ("sentry", "0540_add_release_threshold_table"), - ("sentry", "0541_add_replicated_auth_models"), - ("sentry", "0542_rm_flatfile_file"), - ("sentry", "0543_add_team_id_to_groupsubscription"), - ("sentry", "0544_remove_groupsubscription_columns"), - ("sentry", "0545_add_last_verified_auth_ident_replica"), - ("sentry", "0546_backfill_fix_bad_xactors"), - ("sentry", "0547_add_commitfilechange_language_column"), - ("sentry", "0548_add_is_unclaimed_boolean_to_user"), - ("sentry", "0549_re_add_groupsubscription_columns"), - ("sentry", "0550_migrate_no_action_dupe_issue_alerts"), - ("sentry", "0551_drop_xactor_actor"), - ("sentry", "0552_create_neglectedalert_table"), - ("sentry", "0553_add_new_index_to_groupedmessage_table"), - ("sentry", "0554_add_team_replica"), - ("sentry", "0555_set_neglectedrule_email_date_columns_nullable"), - ("sentry", "0556_organizationmapping_replicate_require_2fa"), - ("sentry", "0557_threshold_related_name"), - ("sentry", "0558_add_organization_member_team_replica"), - ("sentry", "0559_custom_dynamic_sampling_rule"), - ("sentry", "0560_add_monitorincident_table"), - ("sentry", "0561_backfill_new_notification_tables"), - ("sentry", "0562_drop_xactor_actor_from_state"), - ("sentry", "0563_commitfilechange_drop_language_column"), - ("sentry", "0564_commitfilechange_delete_language_column"), - ("sentry", "0565_fix_diff_env_dupe_alerts"), - ("sentry", "0566_remove_cron_missed_margins_zero"), - ("sentry", "0567_add_slug_reservation_model"), - ("sentry", "0568_monitors_fix_next_checkin_latest"), - ("sentry", "0569_dashboard_widgets_indicator"), - ("sentry", "0570_repository_add_languages_column"), - ("sentry", "0571_add_hybrid_cloud_foreign_key_to_slug_reservation"), - ("sentry", "0572_sentry_remove_unused_eventuser_index"), - ("sentry", "0573_add_first_seen_index_groupedmessage"), - ("sentry", "0574_backfill_weekly_report_settings"), - ("sentry", "0575_incident_date_added_index"), - ("sentry", "0576_add_missing_org_integration_scope"), - ("sentry", "0577_drop_latest_incident_index"), - ("sentry", "0578_add_query_and_users_to_custom_dynamic_sampling_rules"), - ("sentry", "0579_index_incident_trigger"), - ("sentry", "0580_threhsold_window_positive_integer"), - ("sentry", "0581_add_user_and_team_to_alert_rules"), - ("sentry", "0582_add_status_indexes_checkins"), - ("sentry", "0583_add_early_adopter_to_organization_mapping"), - ("sentry", "0584_apitoken_add_name_and_last_chars"), - ("sentry", "0585_add_orgmember_partnership_restricted_flag"), - ("sentry", "0586_add_has_feedbacks_flag"), - ("sentry", "0587_remove_unused_neglectedrule_rows"), - ("sentry", "0588_add_relocation_models"), - ("sentry", "0589_add_commit_date_added_indices"), - ("sentry", "0590_add_metadata_to_sentry_app"), - ("sentry", "0591_remove_relocation_hybrid_cloud_foreign_keys"), - ("sentry", "0592_delete_relocation_hybrid_cloud_foreign_keys"), - ("sentry", "0593_add_notification_flag_to_dynamic_sampling_custom_rule"), - ("sentry", "0594_trivial_but_dangerous_2"), - ("sentry", "0595_trivial_but_dangerous_3"), - ("sentry", "0596_trivial_but_dangerous_4"), - ("sentry", "0597_trivial_but_dangerous_5"), - ("sentry", "0598_trivial_but_dangerous_1"), - ("sentry", "0599_add_import_chunk"), - ("sentry", "0600_eventattachment_metadata"), - ("sentry", "0601_add_has_sourcemaps_project_flag"), - ("sentry", "0602_import_chunk_unique_together"), - ("sentry", "0603_add_dangerous_but_trivial_index"), - ("sentry", "0604_remove_dangerous_but_trivial_index"), - ("sentry", "0605_addremove_dangerous_but_trivial_index"), - ("sentry", "0606_update_user_to_optional_organization_slug_reservation"), - ("sentry", "0607_drop_externalactor_actorid"), - ("sentry", "0608_notification_setting_db_constraint"), - ("sentry", "0609_remove_notification_setting_model"), - ("sentry", "0610_remove_notification_setting_table"), - ("sentry", "0611_add_regression_group_model"), - ("sentry", "0612_expand_relocation_model"), - ("sentry", "0613_drop_eventuser_table_part_1"), - ("sentry", "0614_drop_eventuser_table_part_2"), - ("sentry", "0615_add_dashboard_widget_query_on_demand_table"), - ("sentry", "0616_drop_event_user_id_from_userreport_table_step_1"), - ("sentry", "0617_monitor_boolean_fields_muted_disabled"), - ("sentry", "0618_drop_event_user_id_from_userreport_table_step_2"), - ("sentry", "0619_monitors_migrate_is_muted"), - ("sentry", "0620_add_has_new_feedbacks_flag"), - ("sentry", "0621_set_muted_monitors_to_active"), - ("sentry", "0622_add_has_custom_metrics_flag"), - ("sentry", "0623_increase_regression_fingerprint_length"), - ("sentry", "0624_add_is_muted_monitorenvironment"), - ("sentry", "0625_change_rule_label_type_to_char256"), - ("sentry", "0626_add_member_project_creation_bitfield"), - ("sentry", "0627_change_to_sentry_slug"), - ("sentry", "0628_better_menv_latest_index"), - ("sentry", "0629_eventattachment_index"), - ("sentry", "0630_better_monitor_latest_index"), - ("sentry", "0631_add_priority_columns_to_groupedmessage"), - ("sentry", "0632_apitoken_backfill_last_chars"), - ("sentry", "0633_add_priority_locked_at_to_groupedmessage"), - ("sentry", "0634_backfill_github_webhook_outbox_shard_ids"), - ("sentry", "0635_groupenvironment_index"), - ("sentry", "0636_monitor_incident_env_resolving_index"), - ("sentry", "0637_remove_pr_comment_pr_id_constraint"), - ("sentry", "0638_add_date_added_to_dashboard_widget_on_demand"), - ("sentry", "0639_add_spec_version_to_dashboard_on_demand"), - ("sentry", "0640_index_together"), - ("sentry", "0641_backfill_group_attributes"), - ("sentry", "0642_index_together_release"), - ("sentry", "0643_add_date_modified_col_dashboard_widget_query"), - ("sentry", "0644_backfill_priority_for_groups"), - ("sentry", "0645_backfill_add_uuid_to_all_rule_actions"), - ("sentry", "0646_create_notification_message_table"), - ("sentry", "0647_apitoken_add_hashed_columns"), - ("sentry", "0648_monitor_env_break_env_fk"), - ("sentry", "0649_add_index_for_group_priority"), - ("sentry", "0650_create_sentryshot"), - ("sentry", "0651_enable_activated_alert_rules"), - ("sentry", "0652_alert_rule_activation_condition"), - ("sentry", "0653_apitoken_add_token_type"), - ("sentry", "0654_rename_priority_sort_to_trends"), - ("sentry", "0655_apitoken_increase_token_length"), - ("sentry", "0656_add_discover_dataset_split_dashboard"), - ("sentry", "0657_add_status_column_for_alert_rule_trigger_action"), - ("sentry", "0658_projectkey_usecase"), - ("sentry", "0659_artifactbundleindex_cleanup"), - ("sentry", "0660_fix_cron_monitor_invalid_orgs"), - ("sentry", "0661_artifactbundleindex_cleanup_step2"), - ("sentry", "0662_monitor_drop_last_state_change"), - ("sentry", "0663_artifactbundleindex_cleanup_step3"), - ("sentry", "0664_create_new_broken_monitor_detection_table"), - ("sentry", "0665_monitor_drop_last_state_change_db"), - ("sentry", "0666_monitor_incident_default_grouphash"), - ("sentry", "0667_drop_django_team_org_role_column"), - ("sentry", "0668_add_active_monitor_incident_index"), - ("sentry", "0669_alert_rule_activation"), - ("sentry", "0670_monitor_incident_cleanup_duplicates"), - ("sentry", "0671_enforce_unqiue_active_incidents"), - ("sentry", "0672_backfill_ukraine_timezone_name"), - ("sentry", "0673_add_env_muted_to_broken_detection"), - ("sentry", "0674_monitor_clear_missed_timeout_as_error"), - ("sentry", "0675_dashboard_widget_query_rename_priority_sort_to_trends"), - ("sentry", "0676_apitoken_hashed_indexes"), - ("sentry", "0677_unpickle_project_options_again"), - ("sentry", "0678_add_is_hidden_dashboard_widget_query"), - ("sentry", "0679_add_query_sub_fk_to_aar_activations"), - ("sentry", "0680_unpickle_options_again"), - ("sentry", "0681_unpickle_authenticator_again"), - ("sentry", "0682_monitors_constrain_to_project_id_slug"), - ("sentry", "0683_reprocessing_datetime_indexes"), - ("sentry", "0684_monitor_check_in_config_nullable"), - ("sentry", "0685_alert_rule_conditons_rename_singular"), - ("sentry", "0686_remove_config_from_checkin_state_operation"), - ("sentry", "0687_alert_rule_project_backfill_migration"), - ("sentry", "0688_add_project_flag_high_priority_alerts"), - ("sentry", "0689_drop_config_from_cron_checkin"), - ("sentry", "0690_remove_project_team_avatar"), - ("sentry", "0691_remove_project_team_avatar_model"), - ("sentry", "0692_backfill_group_priority_again"), - ("sentry", "0693_add_monitors_ownership_actor_id"), - ("sentry", "0694_db_index_alert_rule_actions"), - ("sentry", "0695_add_monitors_ownership_owner_user_id_team_id"), - ("sentry", "0696_remove_monitor_owner_actor_id"), - ("sentry", "0697_remove_monitor_owner_actor_id_db"), - ("sentry", "0698_remove_file_id_from_control_avatars"), - ("sentry", "0699_update_monitor_owner_team_id_cascsade"), - ("sentry", "0700_drop_fileid_controlavatar"), - ("sentry", "0701_backfill_alertrule_user_team"), - ("sentry", "0702_alert_rule_project_backfill_migration_2"), - ("sentry", "0703_add_team_user_to_rule"), - ("sentry", "0704_backfill_rule_user_team"), - ("sentry", "0705_grouphistory_add_userteam"), - ("sentry", "0706_grouphistory_userteam_backfill"), - ("sentry", "0707_alert_rule_activations_incidents_fk"), - ("sentry", "0708_rule_remove_owner_state"), - ("sentry", "0709_alertrule_remove_owner_state"), - ("sentry", "0710_grouphistory_remove_actor_state"), - ("sentry", "0711_backfill_group_attributes_to_self_hosted"), - ("sentry", "0712_create_tombstone_compound_indexes"), - ("sentry", "0713_team_remove_actor_state"), - ("sentry", "0714_drop_project_team_avatar"), - ("sentry", "0715_remove_actormodel_constraints"), - ("sentry", "0716_remove_actormodel"), - ("sentry", "0717_query_subscription_timebox"), - ("sentry", "0718_delete_timebox_columns"), - ("sentry", "0719_querysubscription_timebox_column_deletion_db"), - ("sentry", "0720_remove_actor_columns"), - ("sentry", "0721_delete_sentryfunctions"), - ("sentry", "0722_drop_sentryfunctions"), - ("sentry", "0723_project_template_models"), - ("sentry", "0724_discover_saved_query_dataset"), - ("sentry", "0725_create_sentry_groupsearchview_table"), - ("sentry", "0726_apitoken_backfill_hashes"), - ("sentry", "0727_add_description_alertrule"), - ("sentry", "0728_incident_subscription_fk"), - ("sentry", "0729_backfill_groupsearchviews_with_pinned_searches"), - ("sentry", "0730_add_subscription_fk_to_incident"), - ("sentry", "0731_add_insight_project_flags"), - ("sentry", "0732_add_span_attribute_extraction_rules"), - ("sentry", "0733_relocation_provenance"), - ("sentry", "0734_rm_reprocessing_step1"), - ("sentry", "0735_sunset_appstore_connect_integration"), - ("sentry", "0736_rm_reprocessing_step2"), - ("sentry", "0737_add_discover_saved_query_dataset_source"), - ("sentry", "0738_rm_reprocessing_step3"), - ("sentry", "0739_backfill_group_info_to_group_attributes"), - ("sentry", "0740_one_relocation_file_kind_per_relocation"), - ("sentry", "0741_metric_alert_anomaly_detection"), - ("sentry", "0742_backfill_alertrule_detection_type"), - ("sentry", "0743_backfill_broken_monitor_notification_setting_option"), - ("sentry", "0744_add_dataset_source_field_to_dashboards"), - ("sentry", "0745_add_prevent_superuser_access_bitflag"), - ("sentry", "0746_add_bitflags_to_hybrid_cloud"), - ("sentry", "0747_create_datasecrecywaiver_table"), - ("sentry", "0748_create_grouphashmetadata_table"), - ("sentry", "0749_disable_member_invite"), - ("sentry", "0750_disable_member_invite_in_hybrid_cloud"), - ("sentry", "0751_grouphashmetadata_use_one_to_one_field_for_grouphash"), - ("sentry", "0752_fix_substatus_for_unresolved_groups"), - ("sentry", "0753_fix_substatus_for_ignored_groups"), - ("sentry", "0754_extend_broadcast_model"), - ("sentry", "0755_remove_fk_constraints_spanattributeextraction"), - ("sentry", "0756_grouprelease_represented_in_django"), - ("sentry", "0757_add_scopes_to_apiapplication"), - ("sentry", "0758_remove_spanattributeextraction_models"), - ("sentry", "0759_remove_spanattributeextraction_tables"), - ("sentry", "0760_remove_appstore_connect_integration_tables"), - ("sentry", "0761_add_substatus_constraint_to_groups"), - ("sentry", "0762_drop_substatus_constraint_to_groups"), - ("sentry", "0763_add_created_by_to_broadcasts"), - ("sentry", "0764_migrate_bad_status_substatus_rows"), - ("sentry", "0765_add_org_to_api_auth"), - ("sentry", "0766_fix_substatus_for_pending_merge"), - ("sentry", "0767_add_selected_aggregate_to_dashboards_widget_query"), - ("sentry", "0768_fix_old_group_first_seen_dates"), - ("sentry", "0769_add_seer_fields_to_grouphash_metadata"), - ("sentry", "0770_increase_project_slug_max_length"), - ("sentry", "0771_add_grouping_config_to_grouphash_metadata"), - ("sentry", "0772_backfill_grouphash_metadata_grouping_config"), - ("sentry", "0773_make_group_score_nullable"), - ("sentry", "0774_drop_group_score_in_state_only"), - ("sentry", "0775_add_dashboard_permissions_model"), - ("sentry", "0776_drop_group_score_in_database"), - ("sentry", "0777_add_related_name_to_dashboard_permissions"), - ("sentry", "0778_userreport_comments_max_length"), - ("sentry", "0779_remove_groups_from_group_inbox"), - ("sentry", "0780_create_sentry_rollback_models"), - ("sentry", "0781_add_hash_basis_to_grouphash_metadata"), - ("sentry", "0782_align_deletedproject_slug_length"), - ("sentry", "0783_remove_release_project_id"), - ("sentry", "0784_remove_broadcasts_cta_column"), - ("sentry", "0785_add_new_field_to_dashboard_permissions"), - ("sentry", "0786_drop_broadcasts_cta_column"), - ("sentry", "0787_make_dashboard_perms_col_nullable"), - ("sentry", "0788_remove__dashboard_perms_col"), - ("sentry", "0789_add_unique_constraint_to_rollbackorganization"), - ("sentry", "0790_delete_dashboard_perms_col"), - ("sentry", "0791_add_hashing_metadata_to_grouphash_metadata"), - ("sentry", "0792_add_unique_index_apiauthorization"), - ("sentry", "0793_remove_db_constraint_alert_rule_exclusion"), - ("sentry", "0794_rm_excluded_included_projects_alertrule"), - ("sentry", "0795_drop_included_excluded_projects"), - ("sentry", "0796_rm_excluded_projects_triggers"), - ("sentry", "0797_drop_excluded_project_triggers"), - ("sentry", "0798_add_favorite_dashboard_col"), - ("sentry", "0799_cron_incident_index"), - ("sentry", "0800_rm_incidentseen_incidentsubscription"), - ("sentry", "0801_drop_incidentseen_incidentsubscription"), - ("sentry", "0802_remove_grouping_auto_update_option"), - ("sentry", "0803_delete_unused_metricskeyindexer_pt1"), - ("sentry", "0804_delete_metrics_key_indexer_pt2"), - ("sentry", "0805_add_alert_and_member_invite_scopes_to_sentry_apps"), - ("sentry", "0806_remove_monitor_attachment_id_pt1"), - ("sentry", "0807_remove_monitor_attachment_id_pt2"), - ("sentry", "0808_change_grouphash_metadata_seer_matched_grouphash_deletion_config"), - ("sentry", "0809_delete_auth_provider_default_teams"), - ("sentry", "0810_add_project_has_flag"), - ("sentry", "0811_fully_delete_auth_provider_default_teams"), - ("sentry", "0812_rm_activation_incident"), - ("sentry", "0813_rm_alertruleactivation_models"), - ("sentry", "0814_drop_alertactivations"), - ("sentry", "0816_add_timestamp_to_group_tombstone"), - ("sentry", "0818_enforce_check_in_environment_not_null"), - ("sentry", "0819_alert_rule_snuba_query_non_null"), - ("sentry", "0820_snuba_query_non_none"), - ("sentry", "0821_create_groupsearchview_page_filter_columns"), - ("sentry", "0822_alert_rule_always_organization"), - ("sentry", "0823_projectcodeowners_raw_never_null"), - ("sentry", "0824_projectcodeowners_schema_non_null"), - ("sentry", "0825_remove_notificationmessage_unique_ag_constraint"), - ("sentry", "0826_make_sentryapp_uuid_unique"), - ("sentry", "0827_projectteam_non_null"), - ("sentry", "0828_add_platform_to_grouphash_metadata"), - ("sentry", "0829_add_additional_timestamps_to_checkins"), - ("sentry", "0830_add_external_id_to_project"), - ("sentry", "0831_add_index_external_id_organization_to_project"), - ("sentry", "0832_make_grouphash_metadata_date_added_nullable"), - ("sentry", "0833_add_relocationtransfer_models"), - ("sentry", "0834_add_index_on_authidentity_last_synced"), - ("sentry", "0835_add_schema_version_to_grouphash_metadata"), - ("sentry", "0836_create_groupsearchviewstarred_table"), - ("sentry", "0837_create_groupsearchviewlastseen_table"), - ("sentry", "0838_backfill_groupsearchview_positions_to_gsvstarred"), - ("sentry", "0839_add_visibility_column_to_groupsearchview"), - ("sentry", "0840_savedsearch_type_non_null"), - ("sentry", "0841_backfill_desynced_starred_views"), - ("sentry", "0842_create_organization_member_invite_table"), - ("sentry", "0843_make_groupsearchview_postition_nullable_for_deletion"), - ("sentry", "0844_remove_project_cascade_in_create_first_project"), - ("sentry", "0845_safe_drop_groupsearchviewposition"), - ("sentry", "0846_hard_drop_groupsearchview_position"), - ("sentry", "0847_remove_duplicate_and_unused_indexes"), - ("sentry", "0848_crons_post_migration_constraints"), - ("sentry", "0849_monitor_checkin_unknown"), - ("sentry", "0850_crons_drop_location"), - ("sentry", "0851_new_group_nullable"), - ("sentry", "0852_delete_new_groups_column"), - ("sentry", "0853_add_group_open_periods"), - ("sentry", "0854_add_project_sdk_model"), - ("sentry", "0855_give_monitor_type_a_db_default"), - ("sentry", "0856_monitors_remove_type_column_state"), - ("sentry", "0857_update_group_open_periods_constraint"), - ("sentry", "0858_backfill_groupsearchviews_with_org_visibility"), - ("sentry", "0859_monitors_remove_type_column_db"), - ("sentry", "0860_add_new_groupopenperiod_constraint"), - ("sentry", "0861_monitors_remove_location"), - ("sentry", "0862_monitors_remove_location_db"), - ("sentry", "0863_update_organization_member_invite_model"), - ("sentry", "0864_move_monitors"), - ("sentry", "0865_file_offsets"), - ("sentry", "0866_grouptype_index"), - ("sentry", "0867_fix_drift_default_to_db_default"), - ("sentry", "0868_delete_group_open_periods"), - ("sentry", "0869_fix_drift_db_default_pt2"), - ("sentry", "0870_delete_non_member_views"), - ("sentry", "0871_fix_some_drift"), - ("sentry", "0872_fix_drift_deleted_columns"), - ("sentry", "0873_update_groupsearchview_visibility_default"), - ("sentry", "0874_positive_integer_drift"), - ("sentry", "0875_integer_drift_group_1"), - ("sentry", "0876_integer_drift_group_2"), - ("sentry", "0877_integer_drift_release"), - ("sentry", "0878_backfill_open_periods"), - ("sentry", "0879_add_seer_fields_to_group"), - ("sentry", "0880_orgauthtoken_bigint"), - ("sentry", "0881_delete_single_prioritized_groupsearchviews"), - ("sentry", "0882_projectoptions_idx_on_key"), - ("sentry", "0883_delete_incident_snapshot_tables_pt1"), - ("sentry", "0884_delete_incident_snapshot_tables_pt2"), - ("sentry", "0885_remove_project_integrations_table"), - ("sentry", "0886_django_arrayfield_scope_list"), - ("sentry", "0887_environment_deleted_column"), - ("sentry", "0888_groupopenperiod_gist_index_in_code"), - ("sentry", "0889_remove_index_on_key_field"), - ("sentry", "0890_remove_index_on_group_release_last_seen"), - ("sentry", "0891_remove_project_integrations_table_physical"), - ("sentry", "0892_sentry_app_json_field"), - ("sentry", "0893_rulesnooze_added_with_timezone"), - ("sentry", "0894_split_discover_dataset_saved_queries"), - ("sentry", "0895_relocation_provenance_smallint"), - ("sentry", "0896_org_level_access_not_null"), - ("sentry", "0897_rm_extraneous_groupedmessage_index"), - ("sentry", "0898_groupedmessage_wrong_int_type"), - ("sentry", "0899_organization_slug_upper_idx"), - ("sentry", "0900_group_link_group_id_no_index"), - ("sentry", "0901_org_slug_wrong_index_name"), - ("sentry", "0902_detection_type_match_size"), - ("sentry", "0903_missing_indexes_in_state"), - ("sentry", "0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0905_fix_workflow_engine_cycle"), + ("sentry", "0906_django_arrayfield_users"), + ("sentry", "0907_sentry_apps_array"), + ("sentry", "0908_increase_email_field_length"), + ("sentry", "0909_django_array_field_not_release"), + ("sentry", "0910_make_organizationmemberteam_is_active_default"), + ("sentry", "0911_increase_email_model_email_field_length"), + ("sentry", "0912_make_organizationmemberteam_replica_is_active_true"), + ("sentry", "0913_split_discover_dataset_dashboards_self_hosted"), + ("sentry", "0914_increase_orgmember_user_email_max_length"), + ("sentry", "0915_add_user_email_unique_column"), + ("sentry", "0916_delete_open_period_rows"), + ("sentry", "0917_convert_org_saved_searches_to_views"), + ("sentry", "0918_sentry_release_arrayfield"), + ("sentry", "0919_project_slug_non_null"), + ("sentry", "0920_convert_org_saved_searches_to_views_revised"), + ("sentry", "0921_convert_org_saved_searches_to_views_rerevised"), + ("sentry", "0922_dashboard_starred_add_position_column_and_constraint"), + ("sentry", "0923_dashboard_starred_backfill_orgs"), + ("sentry", "0924_dashboard_add_unique_constraint_for_user_org_position"), + ("sentry", "0925_backfill_open_periods"), + ("sentry", "0926_dashboard_favorite_defer_position_constraint"), + ("sentry", "0927_dashboard_add_unique_constraint_user_dashboard"), + ("sentry", "0928_move_notifications_models"), + ("sentry", "0929_no_pickle_authenticator"), + ("sentry", "0930_make_open_period_range_boundary_inclusive"), + ("sentry", "0931_add_hit_counter_columns_to_grouptombstone"), + ("sentry", "0932_update_grouptombstone_with_auto_now_add"), + ("sentry", "0933_add_has_agents_insights_flag"), + ("sentry", "0934_options_nullable_value"), + ("sentry", "0935_drop_old_openperiod_exclusion_constraint"), + ("sentry", "0936_prompts_activity_index"), + ("sentry", "0937_fix_defaults"), + ("sentry", "0938_rm_eventattachment_fileid_part1"), + ("sentry", "0939_rm_eventattachment_fileid_part2"), + ("sentry", "0940_auditlog_json_field"), + ("sentry", "0941_create_temporary_verification_code_table"), + ("sentry", "0942_dashboard_remove_extra_user_org_position_constraint"), + ("sentry", "0943_create_data_access_grant"), + ("sentry", "0944_flags_not_null"), + ("sentry", "0945_move_discover_models"), + ("sentry", "0946_add_has_mcp_insights_flag"), + ("sentry", "0947_add_dashboard_last_visited_model"), + ("sentry", "0948_ds_waiver_org_fk_not_db_constr"), + ("sentry", "0949_add_dashboard_widget_snapshot_model"), + ("sentry", "0950_safe_del_dswaiver"), + ("sentry", "0951_delete_ds_waiver"), + ("sentry", "0952_fix_span_item_event_type_alerts"), + ("sentry", "0953_make_releasefiles_tti"), + ("sentry", "0954_user_option_json_field"), + ("sentry", "0955_org_option_json_field"), + ("sentry", "0956_add_group_by_to_snuba_query"), + ("sentry", "0957_projecttemplateoption_json"), + ("sentry", "0958_base_option_json_field"), + ("sentry", "0959_add_has_logs_bit_to_project_model"), + ("sentry", "0960_project_option_json_field"), + ("sentry", "0961_identity_json_field"), + ("sentry", "0962_json_fields_too_big"), + ("sentry", "0963_scheduleddeletion_json_field"), + ("sentry", "0964_add_commitcomparison_table"), + ("sentry", "0965_gzippeddict_big_tables"), + ("sentry", "0966_groupopenperiod_data_pending_inc_detector_id_index"), + ("sentry", "0967_large_tables_legacy_json_field"), + ("sentry", "0968_delete_dashboardwidgetsnapshot_db_constraint"), + ("sentry", "0969_safe_del_dashboardwidgetsnapshot"), + ("sentry", "0970_remove_pullrequestcommit_fk_constraint"), + ("sentry", "0971_make_dashboard_widget_order_optional_field"), + ("sentry", "0972_commit_comparison_drop_unique"), + ("sentry", "0973_safe_del_dashboardwidgetsnapshot"), + ("sentry", "0974_hc_json_field"), + ("sentry", "0975_grouplink_json_field"), + ("sentry", "0976_sentry_app_json_field"), + ("sentry", "0977_commitfilechange_break_commit_fk"), + ("sentry", "0978_break_commit_fks"), + ("sentry", "0979_add_apiapplication_version"), + ("sentry", "0980_integrations_json_field"), + ("sentry", "0981_add_dashboard_migration_fields"), + ("sentry", "0982_redirect_fk_and_date"), + ("sentry", "0983_create_groupopenperiodactivity_table"), + ("sentry", "0984_authprovider_json_field"), + ("sentry", "0985_add_timestamp_to_grouphash_table"), + ("sentry", "0986_add_future_release_version_to_groupresolution"), + ("sentry", "0987_authidentity_json_field"), + ("sentry", "0988_data_forwarding"), + ("sentry", "0989_add_release_date_added_idx"), + ("sentry", "0990_groupowner_json_field"), + ("sentry", "0991_projectownership_json_field"), + ("sentry", "0992_latestrepoerelease_indexes"), + ("sentry", "0993_add_event_id_to_grouphash_metadata"), + ("sentry", "0994_add_groupreaction_table"), + ("sentry", "0995_add_date_updated_to_grouphash_metadata"), + ("sentry", "0996_add_dashboard_field_link_model"), + ("sentry", "0997_add_has_trace_metrics_bit_to_project_model"), + ("sentry", "0998_add_prebuilt_id_to_dashboards"), + ("sentry", "0999_add_extrapolation_mode_to_snuba_query"), + ("sentry", "1000_add_project_distribution_scope"), + ("sentry", "1001_prevent_grouphistory_infinte_recursion"), + ("sentry", "1002_group_history_prev_history_remove_db_constraint"), + ("sentry", "1003_group_history_prev_history_safe_removal"), + ("sentry", "1004_group_history_prev_history_delete"), + ("sentry", "1005_add_groupemailthread_project_date_index"), + ("sentry", "1006_drop_legacy_incidentseen_incidentsubscription"), + ("sentry", "1007_cleanup_failed_safe_deletes"), + ("sentry", "1008_loosen_unique_title_contraint"), + ("sentry", "1009_add_date_updated_to_organizationmapping"), + ("sentry", "1010_add_organizationcontributors_table"), + ("sentry", "1011_update_oc_integration_cascade_to_null"), + ("sentry", "1012_add_event_id_to_open_period"), + ("sentry", "1013_add_repositorysettings_table"), + ("sentry", "1014_add_pkce_to_apigrant"), + ("sentry", "1015_backfill_self_hosted_sentry_app_emails"), + ("sentry", "1016_remove_on_command_phrase_trigger"), + ("sentry", "1017_add_apidevicecode"), + ("sentry", "1018_encrypt_integration_metadata"), + ("sentry", "1019_add_integration_debug_json"), + ("sentry", "1020_alter_apiapplication_client_secret_nullable"), + ("sentry", "1021_add_date_added_date_updated_to_repositorysettings"), + ("sentry", "1022_add_event_id_to_groupopenperiodactivity"), + ("sentry", "1023_add_commitcomparison_unique_constraints"), + ("sentry", "1024_delete_never_active_users_without_emails_self_hosted"), + ("sentry", "1025_backfill_groupopenperiodactivity_event_id"), + ("sentry", "1026_add_index_groupopenperiodactivity_open_period_type_event_id"), + ("sentry", "1027_encrypt_data_forwarding_configurations"), + ("sentry", "1028_remove_group_open_period_event_id"), + ("sentry", "1029_delete_group_open_period_event_id"), + ("sentry", "1030_add_commitcomparison_extras"), + ("sentry", "1031_encrypt_identity_data_field"), + ("sentry", "1032_code_review_event"), + ("sentry", "1033_remove_grouprelease_group_id_last_seen_idx"), + ("sentry", "1034_remove_code_review_event"), + ("sentry", "1035_delete_code_review_event"), + ("sentry", "1036_orgmapping_date_updated_trunc_index"), + ("sentry", "1037_add_grouphashmetadata_seer_latest_training_model"), + ("sentry", "1038_add_index_groupopenperiodactivity_event_id"), + ("sentry", "1039_widget_description_to_textfield"), + ("sentry", "1040_drop_fk_projecttemplate"), + ("sentry", "1041_projectkeymapping"), + ("sentry", "1042_create_code_review_event"), + ("sentry", "1043_big_redirect_slug"), + ("sentry", "1044_remove_projecttemplate_model"), + ("sentry", "1045_dashboard_favorite_user_add_starred_column"), + ("sentry", "1046_projecttemplate_cleanup"), + ("sentry", "1047_rename_orgmapping_region_name_to_cell_name"), + ("sentry", "1048_organizationmapping_cell_name_idx"), + ("sentry", "1049_rename_slugreservation_region_name_to_cell_name"), + ("sentry", "1050_projectkeymapping_uniq_constraint"), + ("sentry", "1051_rename_controloutbox_region_name_to_cell_name"), + ("sentry", "1052_rename_regionoutbox_to_celloutbox"), + ("sentry", "1053_protect_projectdebugfile_file"), + ("sentry", "1054_rename_regionscheduleddeletion_to_cellscheduleddeletion"), + ("sentry", "1055_rename_regiontombstone_to_celltombstone"), + ("sentry", "1056_add_explorer_autofix_fields"), + ("sentry", "1057_drop_legacy_alert_rule_tables"), + ("sentry", "1058_change_code_mapping_unique_constraint"), + ("sentry", "1059_add_groupopenperiodactivity_date_added_index"), + ("sentry", "1060_eventattachment_date_expires"), + ("sentry", "1061_eventattachment_date_expires_index"), + ("sentry", "1062_backfill_eventattachment_date_expires"), + ("sentry", "1063_remove_customdynamicsamplingrule"), + ("sentry", "1064_eventattachment_date_expires_now"), + ("sentry", "1065_delete_customdynamicsamplingrule"), + ("sentry", "1066_add_export_format_in_data_export_obj"), + ("sentry", "1067_add_dashboard_revision_model"), + ("sentry", "1068_rename_relocationtransfer_region_to_cell"), + ("sentry", "1069_add_organization_avatar_replica"), + ("sentry", "1070_increase_integration_external_id_length"), + ("sentry", "1071_add_broadcast_sync_locked"), + ("sentry", "1072_backfill_scm_integration_config"), + ("sentry", "1073_add_org_ci_scope"), + ("sentry", "1074_remove_dashboardtombstone"), + ("sentry", "1075_add_user_is_suspended"), + ("sentry", "1076_delete_dashboardtombstone"), + ("sentry", "1077_add_is_disabled_field"), + ("sentry", "1078_drop_querysubscription_time_window"), + ("sentry", "1079_purge_scm_legacy_org_options"), + ("sentry", "1080_backfill_deprecated_dashboard_widget_display_types"), + ("sentry", "1081_remove_neglectedrule"), + ("sentry", "1082_drop_neglectedrule_table"), + ("sentry", "1083_remove_dashboardlastvisited"), + ("sentry", "1084_delete_dashboardlastvisited"), + ("sentry", "1085_add_date_synced_to_projectcodeowners"), + ("sentry", "1086_add_source_to_external_actor"), + ("sentry", "1087_add_projectrepository"), + ("sentry", "1088_remove_rulefirehistory"), + ("sentry", "1089_drop_rulefirehistory"), + ("sentry", "1090_rm_triggered_incidents_alertruletrigger"), + ("sentry", "1091_delete_triggered_incidents_alertruletrigger"), + ("sentry", "1092_backfill_projectrepository"), + ("sentry", "1093_remove_incidenttrigger"), + ("sentry", "1094_delete_incidenttrigger"), + ("sentry", "1095_make_project_repository_fk_notnull"), + ("sentry", "1096_backfill_mcp_dashboard_widget_filters"), + ("sentry", "1097_add_new_unique_constraints"), + ("sentry", "1098_remove_old_fks"), + ("sentry", "1099_drop_old_fk_columns"), + ("sentry", "1100_add_relocation_file_bucket_path"), + ("sentry", "1101_remove_email_model_pending"), + ("sentry", "1102_activity_project_type_index"), + ("sentry", "1103_backfill_auto_link_repos_by_name"), + ("sentry", "1104_remove_email_model_drop"), + ("sentry", "1105_pr_merge_metrics"), + ("sentry", "1106_pullrequest_head_commit_sha_index"), + ("sentry", "1107_commitauthor_public_email_queried_at"), + ("sentry", "1108_drop_organizationmapping_codecov_access_pending"), + ("sentry", "1109_add_group_action_log_entry"), + ("sentry", "1110_add_team_avatar"), + ("sentry", "1111_add_index_for_group_link"), + ("sentry", "1112_pullrequest_metrics_fields"), + ("sentry", "1113_extend_repository_name_length"), + ("sentry", "1114_extend_repository_url_length"), + ("sentry", "1115_projectdebugfile_add_objectstore_columns"), + ("sentry", "1116_add_project_custom_inbound_filter"), + ("sentry", "1117_drop_organizationmapping_codecov_access_delete"), ] initial = True @@ -514,8 +309,15 @@ class Migration(CheckedMigration): ), ), ("username", models.CharField(max_length=128, unique=True)), - ("name", models.CharField(blank=True, db_column="first_name", max_length=200)), - ("email", models.EmailField(blank=True, max_length=75)), + ( + "name", + models.CharField(blank=True, db_column="first_name", max_length=200), + ), + ("email", models.EmailField(blank=True, max_length=200)), + ( + "email_unique", + models.EmailField(max_length=200, null=True, unique=True), + ), ("is_staff", models.BooleanField(default=False)), ("is_active", models.BooleanField(default=True)), ("is_unclaimed", models.BooleanField(db_default=False, default=False)), @@ -523,15 +325,25 @@ class Migration(CheckedMigration): ("is_managed", models.BooleanField(default=False)), ("is_sentry_app", models.BooleanField(default=None, null=True)), ("is_password_expired", models.BooleanField(default=False)), + ("is_suspended", models.BooleanField(db_default=False, default=False)), ("last_password_change", models.DateTimeField(null=True)), ( "flags", - bitfield.models.BitField(["newsletter_consent_prompt"], default=0, null=True), + bitfield.models.BitField(["newsletter_consent_prompt"], default=0), ), ("session_nonce", models.CharField(max_length=12, null=True)), - ("date_joined", models.DateTimeField(default=django.utils.timezone.now)), - ("last_active", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("avatar_type", models.PositiveSmallIntegerField(db_default=0, default=0)), + ( + "date_joined", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "last_active", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ( + "avatar_type", + models.PositiveSmallIntegerField(db_default=0, default=0), + ), ( "avatar_url", models.CharField(db_default=None, default=None, max_length=120, null=True), @@ -567,7 +379,10 @@ class Migration(CheckedMigration): ("resolve_threshold", models.FloatField(null=True)), ("threshold_period", models.IntegerField()), ("comparison_delta", models.IntegerField(null=True)), - ("date_modified", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_modified", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "monitor_type", @@ -630,6 +445,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -646,7 +463,10 @@ class Migration(CheckedMigration): "sentry.Organization", db_index=True, on_delete="CASCADE" ), ), - ("label", models.CharField(blank=True, default="Default", max_length=64)), + ( + "label", + models.CharField(blank=True, default="Default", max_length=64), + ), ("key", models.CharField(max_length=32, unique=True)), ( "status", @@ -678,13 +498,19 @@ class Migration(CheckedMigration): "bundle_id", models.UUIDField(db_index=True, default="00000000-00000000-00000000-00000000"), ), - ("artifact_count", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "artifact_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("indexing_state", models.IntegerField(default=None, null=True)), ( "date_added", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), - ("date_uploaded", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_uploaded", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_last_modified", models.DateTimeField(null=True)), ], options={ @@ -703,11 +529,14 @@ class Migration(CheckedMigration): ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, on_delete="CASCADE", unique=True + "sentry.Organization", + db_index=True, + on_delete="CASCADE", + unique=True, ), ), ("provider", models.CharField(max_length=128)), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("config", models.JSONField(default=dict)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "sync_time", @@ -719,7 +548,10 @@ class Migration(CheckedMigration): sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=50), ), ("default_global_access", models.BooleanField(default=True)), - ("flags", bitfield.models.BitField(["allow_unlinked", "scim_enabled"], default=0)), + ( + "flags", + bitfield.models.BitField(["allow_unlinked", "scim_enabled"], default=0), + ), ], options={ "db_table": "sentry_authprovider", @@ -740,8 +572,14 @@ class Migration(CheckedMigration): "timestamp", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), - ("headers", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("size", sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True)), + ( + "headers", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), + ( + "size", + sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True), + ), ("checksum", models.CharField(db_index=True, max_length=40, null=True)), ], options={ @@ -759,7 +597,10 @@ class Migration(CheckedMigration): ), ), ("path", models.TextField(null=True)), - ("size", sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True)), + ( + "size", + sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True), + ), ("checksum", models.CharField(max_length=40, unique=True)), ( "timestamp", @@ -781,12 +622,15 @@ class Migration(CheckedMigration): ), ), ("key", models.CharField(max_length=128, unique=True)), - ("last_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "last_updated_by", models.CharField(db_default="unknown", default="unknown", max_length=16), ), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), + ("value", models.JSONField(null=True)), ], options={ "db_table": "sentry_controloption", @@ -804,10 +648,13 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), - ("relocation_uuid", sentry.db.models.fields.uuid.UUIDField(max_length=32)), + ( + "relocation_uuid", + sentry.db.models.fields.uuid.UUIDField(max_length=32), + ), ("org_slug", models.CharField()), - ("requesting_region", models.CharField()), - ("exporting_region", models.CharField()), + ("requesting_cell", models.CharField(db_column="requesting_region")), + ("exporting_cell", models.CharField(db_column="exporting_region")), ("state", models.CharField(default="request")), ( "scheduled_for", @@ -832,7 +679,7 @@ class Migration(CheckedMigration): ( "created_by_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, on_delete="CASCADE" + "sentry.User", db_index=True, null=True, on_delete="CASCADE" ), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), @@ -845,6 +692,12 @@ class Migration(CheckedMigration): models.DateTimeField(default=django.utils.timezone.now, null=True), ), ("filters", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "prebuilt_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=None, null=True + ), + ), ], options={ "db_table": "sentry_dashboard", @@ -860,10 +713,19 @@ class Migration(CheckedMigration): ), ), ("actor_label", models.CharField(max_length=64, null=True)), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), ("actor_key", models.CharField(max_length=32, null=True)), - ("ip_address", models.GenericIPAddressField(null=True, unpack_ipv4=True)), - ("date_deleted", models.DateTimeField(default=django.utils.timezone.now)), + ( + "ip_address", + models.GenericIPAddressField(null=True, unpack_ipv4=True), + ), + ( + "date_deleted", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_created", models.DateTimeField(null=True)), ("reason", models.TextField(blank=True, null=True)), ("name", models.CharField(max_length=64, null=True)), @@ -883,10 +745,19 @@ class Migration(CheckedMigration): ), ), ("actor_label", models.CharField(max_length=64, null=True)), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), ("actor_key", models.CharField(max_length=32, null=True)), - ("ip_address", models.GenericIPAddressField(null=True, unpack_ipv4=True)), - ("date_deleted", models.DateTimeField(default=django.utils.timezone.now)), + ( + "ip_address", + models.GenericIPAddressField(null=True, unpack_ipv4=True), + ), + ( + "date_deleted", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_created", models.DateTimeField(null=True)), ("reason", models.TextField(blank=True, null=True)), ("slug", models.CharField(max_length=100, null=True)), @@ -913,10 +784,19 @@ class Migration(CheckedMigration): ), ), ("actor_label", models.CharField(max_length=64, null=True)), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), ("actor_key", models.CharField(max_length=32, null=True)), - ("ip_address", models.GenericIPAddressField(null=True, unpack_ipv4=True)), - ("date_deleted", models.DateTimeField(default=django.utils.timezone.now)), + ( + "ip_address", + models.GenericIPAddressField(null=True, unpack_ipv4=True), + ), + ( + "date_deleted", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_created", models.DateTimeField(null=True)), ("reason", models.TextField(blank=True, null=True)), ("name", models.CharField(max_length=64, null=True)), @@ -953,14 +833,14 @@ class Migration(CheckedMigration): ("url", models.URLField()), ("popularity", models.PositiveSmallIntegerField(default=1, null=True)), ("is_draft", models.BooleanField(default=True)), - ("metadata", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ("metadata", models.JSONField(default=dict, null=True)), ], options={ "db_table": "sentry_docintegration", }, ), migrations.CreateModel( - name="Email", + name="Environment", fields=[ ( "id", @@ -968,23 +848,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("email", sentry.db.models.fields.citext.CIEmailField(max_length=75, unique=True)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ], - options={ - "db_table": "sentry_email", - }, - ), - migrations.CreateModel( - name="Environment", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), ), - ("organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), ("name", models.CharField(max_length=64)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ], @@ -1016,8 +883,15 @@ class Migration(CheckedMigration): ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("date_finished", models.DateTimeField(null=True)), ("date_expired", models.DateTimeField(db_index=True, null=True)), - ("query_type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("query_info", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ( + "query_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "query_info", + sentry.db.models.fields.jsonfield.JSONField(default=dict), + ), + ("export_format", models.CharField(default="csv", null=True)), ], options={ "db_table": "sentry_exporteddata", @@ -1038,8 +912,14 @@ class Migration(CheckedMigration): "timestamp", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), - ("headers", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("size", sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True)), + ( + "headers", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), + ( + "size", + sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True), + ), ("checksum", models.CharField(db_index=True, max_length=40, null=True)), ("path", models.TextField(null=True)), ], @@ -1058,7 +938,10 @@ class Migration(CheckedMigration): ), ), ("path", models.TextField(null=True)), - ("size", sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True)), + ( + "size", + sentry.db.models.fields.bounded.WrappingU32IntegerField(null=True), + ), ("checksum", models.CharField(max_length=40, unique=True)), ( "timestamp", @@ -1079,7 +962,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("logger", models.CharField(blank=True, db_index=True, default="", max_length=64)), + ( + "logger", + models.CharField(blank=True, db_index=True, default="", max_length=64), + ), ( "level", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -1104,7 +990,10 @@ class Migration(CheckedMigration): db_index=True, default=0 ), ), - ("substatus", sentry.db.models.fields.bounded.BoundedIntegerField(null=True)), + ( + "substatus", + sentry.db.models.fields.bounded.BoundedIntegerField(null=True), + ), ( "times_seen", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -1132,9 +1021,12 @@ class Migration(CheckedMigration): ("is_public", models.BooleanField(default=False, null=True)), ( "data", - sentry.db.models.fields.gzippeddict.GzippedDictField(blank=True, null=True), + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), + ( + "short_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), - ("short_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), ( "type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -1145,6 +1037,10 @@ class Migration(CheckedMigration): ("priority_locked_at", models.DateTimeField(null=True)), ("seer_fixability_score", models.FloatField(null=True)), ("seer_autofix_last_triggered", models.DateTimeField(null=True)), + ( + "seer_explorer_autofix_last_triggered", + models.DateTimeField(null=True), + ), ], options={ "verbose_name": "grouped message", @@ -1162,8 +1058,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("name", models.TextField(max_length=128)), ( "user_id", @@ -1171,16 +1073,25 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("visibility", models.CharField(db_default="organization", max_length=16)), + ( + "visibility", + models.CharField(db_default="organization", max_length=16), + ), ("query", models.TextField()), ( "query_sort", models.CharField( - default=sentry.models.savedsearch.SortOptions["DATE"], max_length=16 + default=sentry.models.savedsearch.SortOptions["DATE"], + max_length=16, ), ), ("is_all_projects", models.BooleanField(db_default=False)), - ("environments", sentry.db.models.fields.array.ArrayField(default=list, null=True)), + ( + "environments", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ("time_filters", models.JSONField(db_default={"period": "14d"})), ], options={ @@ -1197,12 +1108,15 @@ class Migration(CheckedMigration): ), ), ("key", models.CharField(max_length=128, unique=True)), - ("last_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "last_updated_by", models.CharField(db_default="unknown", default="unknown", max_length=16), ), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), + ("value", models.JSONField(null=True)), ], options={ "db_table": "sentry_option", @@ -1210,7 +1124,7 @@ class Migration(CheckedMigration): bases=(sentry.backup.mixins.OverwritableConfigMixin, models.Model), ), migrations.CreateModel( - name="OrganizationMapping", + name="OrganizationAvatarReplica", fields=[ ( "id", @@ -1218,43 +1132,22 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), ( "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - db_index=True, unique=True + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Organization", + db_index=True, + on_delete="CASCADE", + unique=True, ), ), - ("slug", models.SlugField(unique=True)), - ("name", models.CharField(max_length=64)), - ("date_created", models.DateTimeField(default=django.utils.timezone.now)), - ("customer_id", models.CharField(db_index=True, max_length=255, null=True)), - ("verified", models.BooleanField(default=False)), - ("idempotency_key", models.CharField(max_length=48)), - ("region_name", models.CharField(max_length=48)), - ("status", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("allow_joinleave", models.BooleanField(db_default=False, default=False)), - ("enhanced_privacy", models.BooleanField(db_default=False, default=False)), - ("require_2fa", models.BooleanField(db_default=False, default=False)), - ("early_adopter", models.BooleanField(db_default=False, default=False)), - ("disable_shared_issues", models.BooleanField(db_default=False, default=False)), - ( - "disable_new_visibility_features", - models.BooleanField(db_default=False, default=False), - ), - ( - "require_email_verification", - models.BooleanField(db_default=False, default=False), - ), - ("codecov_access", models.BooleanField(db_default=False, default=False)), - ( - "disable_member_project_creation", - models.BooleanField(db_default=False, default=False), - ), - ("prevent_superuser_access", models.BooleanField(db_default=False, default=False)), - ("disable_member_invite", models.BooleanField(db_default=False, default=False)), + ("avatar_type", models.PositiveSmallIntegerField(default=0)), + ("avatar_ident", models.CharField(max_length=32)), ], options={ - "db_table": "sentry_organizationmapping", + "db_table": "sentry_organizationavatarreplica", }, ), migrations.CreateModel( @@ -1268,10 +1161,13 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), - ("relocation_uuid", sentry.db.models.fields.uuid.UUIDField(max_length=32)), + ( + "relocation_uuid", + sentry.db.models.fields.uuid.UUIDField(max_length=32), + ), ("org_slug", models.CharField()), - ("requesting_region", models.CharField()), - ("exporting_region", models.CharField()), + ("requesting_cell", models.CharField(db_column="requesting_region")), + ("exporting_cell", models.CharField(db_column="exporting_region")), ("state", models.CharField(default="request")), ( "scheduled_for", @@ -1311,7 +1207,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("uuid", models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ( + "uuid", + models.UUIDField(db_index=True, default=uuid.uuid4, editable=False), + ), ("sentry_url", models.URLField()), ("component_identifier", models.CharField()), ( @@ -1342,10 +1241,16 @@ class Migration(CheckedMigration): ( "application_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.ApiApplication", db_index=True, null=True, on_delete="CASCADE" + "sentry.ApiApplication", + db_index=True, + null=True, + on_delete="CASCADE", ), ), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True)), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), ( "installation_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -1372,14 +1277,22 @@ class Migration(CheckedMigration): "secret", models.TextField(default=sentry.sentry_apps.models.servicehook.generate_secret), ), - ("events", sentry.db.models.fields.array.ArrayField(null=True)), + ( + "events", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ( "status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( db_index=True, default=0 ), ), - ("version", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "version", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ], options={ @@ -1395,10 +1308,21 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("name", models.CharField(max_length=32, unique=True)), - ("permissions", sentry.db.models.fields.array.ArrayField(null=True)), + ( + "permissions", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ], options={ "db_table": "sentry_userrole", @@ -1425,7 +1349,8 @@ class Migration(CheckedMigration): ( "alert_rule", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.alertrule" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.alertrule", ), ), ( @@ -1459,12 +1384,14 @@ class Migration(CheckedMigration): ( "alert_rule", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.alertrule" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.alertrule", ), ), ], options={ "db_table": "sentry_alertruletrigger", + "unique_together": {("alert_rule", "label")}, }, ), migrations.CreateModel( @@ -1501,7 +1428,10 @@ class Migration(CheckedMigration): ("target_identifier", models.TextField(null=True)), ("target_display", models.TextField(null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("sentry_app_config", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "sentry_app_config", + sentry.db.models.fields.jsonfield.JSONField(null=True), + ), ( "status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -1511,7 +1441,8 @@ class Migration(CheckedMigration): ( "alert_rule_trigger", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.alertruletrigger" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.alertruletrigger", ), ), ], @@ -1538,7 +1469,9 @@ class Migration(CheckedMigration): ), ( "client_secret", - models.TextField(default=sentry.models.apiapplication.generate_token), + models.TextField( + default=sentry.models.apiapplication.generate_token, null=True + ), ), ( "name", @@ -1560,8 +1493,22 @@ class Migration(CheckedMigration): ("privacy_url", models.URLField(null=True)), ("terms_url", models.URLField(null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("scopes", sentry.db.models.fields.array.ArrayField(null=True)), - ("requires_org_level_access", models.BooleanField(db_default=False, default=False)), + ( + "scopes", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), + ( + "requires_org_level_access", + models.BooleanField(db_default=False, default=False), + ), + ( + "version", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, db_index=True, default=0 + ), + ), ( "owner", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -1576,7 +1523,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="ApiGrant", + name="ApiDeviceCode", fields=[ ( "id", @@ -1585,43 +1532,120 @@ class Migration(CheckedMigration): ), ), ( - "code", + "device_code", models.CharField( - db_index=True, default=sentry.models.apigrant.generate_code, max_length=64 + default=sentry.models.apidevicecode.generate_device_code, + max_length=64, + unique=True, ), ), ( - "expires_at", - models.DateTimeField( - db_index=True, default=sentry.models.apigrant.default_expiration + "user_code", + models.CharField( + default=sentry.models.apidevicecode.generate_user_code, + max_length=16, + unique=True, ), ), - ("redirect_uri", models.CharField(max_length=255)), ( - "scopes", - bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "openid", - "profile", - "email", - ], - default=None, + "organization_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", + ), + ), + ( + "scope_list", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), + ( + "expires_at", + models.DateTimeField( + db_index=True, + default=sentry.models.apidevicecode.default_expiration, + ), + ), + ( + "status", + models.CharField( + default=sentry.models.apidevicecode.DeviceCodeStatus["PENDING"], + max_length=20, + ), + ), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ( + "application", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.apiapplication", + ), + ), + ( + "user", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "db_table": "sentry_apidevicecode", + }, + ), + migrations.CreateModel( + name="ApiGrant", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "code", + models.CharField( + db_index=True, + default=sentry.models.apigrant.generate_code, + max_length=64, + ), + ), + ( + "expires_at", + models.DateTimeField( + db_index=True, default=sentry.models.apigrant.default_expiration + ), + ), + ("redirect_uri", models.CharField(max_length=255)), + ( + "scopes", + bitfield.models.BitField( + [ + "project:read", + "project:write", + "project:admin", + "project:releases", + "team:read", + "team:write", + "team:admin", + "event:read", + "event:write", + "event:admin", + "org:read", + "org:write", + "org:admin", + "member:read", + "member:write", + "member:admin", + "openid", + "profile", + "email", + ], + default=None, ), ), ( @@ -1633,19 +1657,26 @@ class Migration(CheckedMigration): ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, null=True, on_delete="CASCADE" + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", ), ), + ("code_challenge", models.CharField(max_length=128, null=True)), + ("code_challenge_method", models.CharField(max_length=10, null=True)), ( "application", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.apiapplication" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.apiapplication", ), ), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -1686,6 +1717,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -1699,17 +1732,25 @@ class Migration(CheckedMigration): ( "scoping_organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, null=True, on_delete="CASCADE" + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", ), ), ("name", models.CharField(max_length=255, null=True)), ( "token", models.CharField( - default=sentry.models.apitoken.generate_token, max_length=71, unique=True + default=sentry.models.apitoken.generate_token, + max_length=71, + unique=True, ), ), - ("hashed_token", models.CharField(max_length=128, null=True, unique=True)), + ( + "hashed_token", + models.CharField(max_length=128, null=True, unique=True), + ), ("token_type", models.CharField(max_length=7, null=True)), ("token_last_characters", models.CharField(max_length=4, null=True)), ( @@ -1721,7 +1762,10 @@ class Migration(CheckedMigration): unique=True, ), ), - ("hashed_refresh_token", models.CharField(max_length=128, null=True, unique=True)), + ( + "hashed_refresh_token", + models.CharField(max_length=128, null=True, unique=True), + ), ( "expires_at", models.DateTimeField( @@ -1740,7 +1784,8 @@ class Migration(CheckedMigration): ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -1760,7 +1805,10 @@ class Migration(CheckedMigration): ( "auth_identity_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.AuthIdentity", db_index=True, on_delete="CASCADE", unique=True + "sentry.AuthIdentity", + db_index=True, + on_delete="CASCADE", + unique=True, ), ), ( @@ -1776,7 +1824,7 @@ class Migration(CheckedMigration): ), ), ("ident", models.CharField(max_length=128)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("data", models.JSONField(default=dict)), ( "last_verified", models.DateTimeField( @@ -1788,7 +1836,10 @@ class Migration(CheckedMigration): ], options={ "db_table": "sentry_authidentityreplica", - "unique_together": {("auth_provider_id", "ident"), ("auth_provider_id", "user_id")}, + "unique_together": { + ("auth_provider_id", "ident"), + ("auth_provider_id", "user_id"), + }, }, ), migrations.CreateModel( @@ -1808,12 +1859,15 @@ class Migration(CheckedMigration): ( "date_expires", models.DateTimeField( - blank=True, default=sentry.models.broadcast.default_expiration, null=True + blank=True, + default=sentry.models.broadcast.default_expiration, + null=True, ), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("media_url", models.URLField(blank=True, null=True)), ("category", models.CharField(blank=True, max_length=32, null=True)), + ("sync_locked", models.BooleanField(db_default=False, default=False)), ( "created_by_id", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -1827,6 +1881,139 @@ class Migration(CheckedMigration): "db_table": "sentry_broadcast", }, ), + migrations.CreateModel( + name="CellOutbox", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "shard_scope", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "shard_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "category", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "object_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ("payload", models.JSONField(null=True)), + ( + "scheduled_from", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "scheduled_for", + models.DateTimeField( + default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.timezone.utc) + ), + ), + ( + "date_added", + models.DateTimeField( + db_default=django.db.models.functions.datetime.Now(), + default=django.utils.timezone.now, + editable=False, + ), + ), + ], + options={ + "db_table": "sentry_regionoutbox", + "indexes": [ + models.Index( + fields=[ + "shard_scope", + "shard_identifier", + "category", + "object_identifier", + ], + name="sentry_regi_shard_s_bfff84_idx", + ), + models.Index( + fields=["shard_scope", "shard_identifier", "scheduled_for"], + name="sentry_regi_shard_s_cd9995_idx", + ), + models.Index( + fields=["shard_scope", "shard_identifier", "id"], + name="sentry_regi_shard_s_e7412f_idx", + ), + ], + }, + ), + migrations.CreateModel( + name="CellScheduledDeletion", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "guid", + models.CharField( + default=sentry.deletions.models.scheduleddeletion.default_guid, + max_length=32, + unique=True, + ), + ), + ("app_label", models.CharField(max_length=64)), + ("model_name", models.CharField(max_length=64)), + ("object_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_scheduled", + models.DateTimeField( + default=sentry.deletions.models.scheduleddeletion.default_date_schedule + ), + ), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ("data", models.JSONField(default=dict)), + ("in_progress", models.BooleanField(default=False)), + ], + options={ + "db_table": "sentry_regionscheduleddeletion", + "unique_together": {("app_label", "model_name", "object_id")}, + }, + ), + migrations.CreateModel( + name="CellTombstone", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("table_name", models.CharField(max_length=48)), + ( + "object_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ("created_at", models.DateTimeField(default=django.utils.timezone.now)), + ], + options={ + "db_table": "sentry_regiontombstone", + "indexes": [ + models.Index( + fields=["table_name", "object_identifier"], + name="sentry_regi_table_n_cd667a_idx", + ) + ], + }, + ), migrations.CreateModel( name="CommitAuthor", fields=[ @@ -1843,6 +2030,7 @@ class Migration(CheckedMigration): ("name", models.CharField(max_length=128, null=True)), ("email", models.CharField(max_length=200)), ("external_id", models.CharField(max_length=164, null=True)), + ("public_email_queried_at", models.DateTimeField(null=True)), ], options={ "db_table": "sentry_commitauthor", @@ -1865,7 +2053,10 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("repository_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "repository_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("key", models.CharField(max_length=64)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("message", models.TextField(null=True)), @@ -1883,7 +2074,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="CommitFileChange", + name="CommitComparison", fields=[ ( "id", @@ -1891,21 +2082,69 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), ( "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("filename", models.TextField()), - ("type", models.CharField(max_length=1)), + ("head_sha", models.CharField(max_length=64)), + ("base_sha", models.CharField(max_length=64, null=True)), + ("provider", models.CharField(max_length=64, null=True)), + ("head_repo_name", models.CharField(max_length=255)), + ("base_repo_name", models.CharField(max_length=255, null=True)), + ("head_ref", models.CharField(max_length=255, null=True)), + ("base_ref", models.CharField(max_length=255, null=True)), + ("pr_number", models.PositiveIntegerField(null=True)), + ("extras", models.JSONField(db_default={}, default=dict)), ( - "commit", + "base_commit", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="base_commit_set", + to="sentry.commit", + ), + ), + ( + "head_commit", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="head_commit_set", + to="sentry.commit", ), ), ], + options={ + "db_table": "sentry_commitcomparison", + }, + ), + migrations.CreateModel( + name="CommitFileChange", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), + ( + "commit_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), + ("filename", models.TextField()), + ("type", models.CharField(max_length=1)), + ], options={ "db_table": "sentry_commitfilechange", + "unique_together": {("commit_id", "filename")}, }, ), migrations.CreateModel( @@ -1921,13 +2160,15 @@ class Migration(CheckedMigration): ( "blob", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="sentry.controlfileblob" + on_delete=django.db.models.deletion.PROTECT, + to="sentry.controlfileblob", ), ), ( "file", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.controlfile" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.controlfile", ), ), ], @@ -1958,7 +2199,8 @@ class Migration(CheckedMigration): ( "blob", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.controlfileblob" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.controlfileblob", ), ), ], @@ -1975,17 +2217,35 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "import_uuid", sentry.db.models.fields.uuid.UUIDField(db_index=True, max_length=32), ), ("model", models.CharField(db_index=True, max_length=64)), - ("min_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("min_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "min_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "min_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ( "min_inserted_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), @@ -2013,17 +2273,35 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "import_uuid", sentry.db.models.fields.uuid.UUIDField(db_index=True, max_length=32), ), ("model", models.CharField(db_index=True, max_length=64)), - ("min_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("min_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "min_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "min_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ( "min_inserted_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), @@ -2051,16 +2329,31 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("shard_scope", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("shard_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("category", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("object_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("payload", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ("scheduled_from", models.DateTimeField(default=django.utils.timezone.now)), + ( + "shard_scope", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "shard_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "category", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "object_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ("payload", models.JSONField(null=True)), + ( + "scheduled_from", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "scheduled_for", models.DateTimeField( - default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.UTC) + default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.timezone.utc) ), ), ( @@ -2071,14 +2364,14 @@ class Migration(CheckedMigration): editable=False, ), ), - ("region_name", models.CharField(max_length=48)), + ("cell_name", models.CharField(db_column="region_name", max_length=48)), ], options={ "db_table": "sentry_controloutbox", "indexes": [ models.Index( fields=[ - "region_name", + "cell_name", "shard_scope", "shard_identifier", "category", @@ -2087,11 +2380,16 @@ class Migration(CheckedMigration): name="sentry_cont_region__1c1c72_idx", ), models.Index( - fields=["region_name", "shard_scope", "shard_identifier", "scheduled_for"], + fields=[ + "cell_name", + "shard_scope", + "shard_identifier", + "scheduled_for", + ], name="sentry_cont_region__0c4512_idx", ), models.Index( - fields=["region_name", "shard_scope", "shard_identifier", "id"], + fields=["cell_name", "shard_scope", "shard_identifier", "id"], name="sentry_cont_region__a95d82_idx", ), ], @@ -2107,7 +2405,10 @@ class Migration(CheckedMigration): ), ), ("table_name", models.CharField(max_length=48)), - ("object_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "object_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("created_at", models.DateTimeField(default=django.utils.timezone.now)), ], options={ @@ -2121,7 +2422,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="DashboardFavoriteUser", + name="DashboardPermissions", fields=[ ( "id", @@ -2129,27 +2430,25 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), ( - "user_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, on_delete="CASCADE" - ), + "is_editable_by_everyone", + models.BooleanField(db_default=True, default=True), ), ( "dashboard", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="permissions", + to="sentry.dashboard", ), ), ], options={ - "db_table": "sentry_dashboardfavoriteuser", + "db_table": "sentry_dashboardpermissions", }, ), migrations.CreateModel( - name="DashboardPermissions", + name="DashboardRevision", fields=[ ( "id", @@ -2157,18 +2456,28 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("is_editable_by_everyone", models.BooleanField(db_default=True, default=True)), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "created_by_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.User", db_index=True, null=True, on_delete="SET_NULL" + ), + ), + ("title", models.CharField(max_length=255)), + ("source", models.CharField(default="edit", max_length=32)), + ("snapshot", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("snapshot_schema_version", models.IntegerField()), ( "dashboard", - models.OneToOneField( + sentry.db.models.fields.foreignkey.FlexibleForeignKey( on_delete=django.db.models.deletion.CASCADE, - related_name="permissions", to="sentry.dashboard", ), ), ], options={ - "db_table": "sentry_dashboardpermissions", + "db_table": "sentry_dashboardrevision", }, ), migrations.CreateModel( @@ -2180,12 +2489,18 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("order", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "order", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), ("title", models.CharField(max_length=255)), - ("description", models.CharField(max_length=255, null=True)), + ("description", models.TextField(blank=True, null=True)), ("thresholds", sentry.db.models.fields.jsonfield.JSONField(null=True)), ("interval", models.CharField(max_length=10, null=True)), - ("display_type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "display_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "widget_type", @@ -2203,19 +2518,115 @@ class Migration(CheckedMigration): db_default=0, default=0 ), ), + ("widget_snapshot", models.JSONField(null=True)), + ("changed_reason", models.JSONField(null=True)), + ( + "dashboard", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboard", + ), + ), + ], + options={ + "db_table": "sentry_dashboardwidget", + }, + ), + migrations.CreateModel( + name="DashboardWidgetQuery", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("name", models.CharField(max_length=255)), + ( + "fields", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), + ("conditions", models.TextField()), + ( + "aggregates", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), null=True, size=None + ), + ), + ( + "columns", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), null=True, size=None + ), + ), + ( + "field_aliases", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), null=True, size=None + ), + ), + ("orderby", models.TextField(default="")), + ( + "order", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_modified", + models.DateTimeField( + db_default=django.db.models.functions.datetime.Now(), + default=django.utils.timezone.now, + ), + ), + ("is_hidden", models.BooleanField(db_default=False, default=False)), + ("selected_aggregate", models.IntegerField(null=True)), + ( + "widget", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboardwidget", + ), + ), + ], + options={ + "db_table": "sentry_dashboardwidgetquery", + }, + ), + migrations.CreateModel( + name="DashboardFieldLink", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("field", models.TextField()), ( "dashboard", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboard", + ), + ), + ( + "dashboard_widget_query", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboardwidgetquery", ), ), ], options={ - "db_table": "sentry_dashboardwidget", + "db_table": "sentry_dashboardfieldlink", }, ), migrations.CreateModel( - name="DashboardWidgetQuery", + name="DashboardWidgetQueryOnDemand", fields=[ ( "id", @@ -2223,52 +2634,39 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("name", models.CharField(max_length=255)), - ("fields", sentry.db.models.fields.array.ArrayField(null=True)), - ("conditions", models.TextField()), - ( - "aggregates", - django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), null=True, size=None - ), - ), ( - "columns", + "spec_hashes", django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), null=True, size=None + base_field=models.TextField(), default=list, size=None ), ), + ("spec_version", models.IntegerField(null=True)), + ("extraction_state", models.CharField(max_length=30)), ( - "field_aliases", - django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), null=True, size=None - ), + "date_modified", + models.DateTimeField(default=django.utils.timezone.now), ), - ("orderby", models.TextField(default="")), - ("order", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "date_modified", + "date_added", models.DateTimeField( db_default=django.db.models.functions.datetime.Now(), default=django.utils.timezone.now, ), ), - ("is_hidden", models.BooleanField(db_default=False, default=False)), - ("selected_aggregate", models.IntegerField(null=True)), ( - "widget", + "dashboard_widget_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboardwidget" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboardwidgetquery", ), ), ], options={ - "db_table": "sentry_dashboardwidgetquery", + "db_table": "sentry_dashboardwidgetqueryondemand", }, ), migrations.CreateModel( - name="DashboardWidgetQueryOnDemand", + name="DataAccessGrant", fields=[ ( "id", @@ -2276,27 +2674,47 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("spec_hashes", sentry.db.models.fields.array.ArrayField(null=True)), - ("spec_version", models.IntegerField(null=True)), - ("extraction_state", models.CharField(max_length=30)), - ("date_modified", models.DateTimeField(default=django.utils.timezone.now)), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), ( - "date_added", - models.DateTimeField( - db_default=django.db.models.functions.datetime.Now(), - default=django.utils.timezone.now, + "organization_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Organization", db_index=True, on_delete="CASCADE" ), ), + ("grant_type", models.CharField(max_length=24)), + ("ticket_id", models.CharField(max_length=64, null=True)), ( - "dashboard_widget_query", + "grant_start", + models.DateTimeField(default=django.utils.timezone.now), + ), + ("grant_end", models.DateTimeField(default=django.utils.timezone.now)), + ("revocation_date", models.DateTimeField(blank=True, null=True)), + ( + "revocation_reason", + models.CharField(blank=True, max_length=20, null=True), + ), + ( + "granted_by_user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.dashboardwidgetquery", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="granted_data_access_grants", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "revoked_by_user", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="revoked_data_access_grants", + to=settings.AUTH_USER_MODEL, ), ), ], options={ - "db_table": "sentry_dashboardwidgetqueryondemand", + "db_table": "sentry_dataaccessgrant", }, ), migrations.CreateModel( @@ -2318,7 +2736,8 @@ class Migration(CheckedMigration): ( "artifact_bundle", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.artifactbundle" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.artifactbundle", ), ), ], @@ -2340,7 +2759,10 @@ class Migration(CheckedMigration): "control_file_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True, unique=True), ), - ("avatar_type", models.PositiveSmallIntegerField(db_default=0, default=0)), + ( + "avatar_type", + models.PositiveSmallIntegerField(db_default=0, default=0), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "doc_integration", @@ -2364,7 +2786,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ( "group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField( @@ -2375,16 +2800,24 @@ class Migration(CheckedMigration): ("type", models.CharField(db_index=True, max_length=64)), ("name", models.TextField()), ("content_type", models.TextField(null=True)), - ("size", sentry.db.models.fields.bounded.BoundedIntegerField(null=True)), + ( + "size", + sentry.db.models.fields.bounded.BoundedIntegerField(null=True), + ), ("sha1", models.CharField(max_length=40, null=True)), ( "date_added", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), ( - "file_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - db_index=True, null=True + "date_expires", + models.DateTimeField( + db_default=django.db.models.expressions.CombinedExpression( + django.db.models.functions.datetime.Now(), + "+", + models.Value(datetime.timedelta(days=30)), + ), + db_index=True, ), ), ("blob_path", models.TextField(null=True)), @@ -2393,10 +2826,12 @@ class Migration(CheckedMigration): "db_table": "sentry_eventattachment", "indexes": [ models.Index( - fields=["project_id", "date_added"], name="sentry_even_project_62b83b_idx" + fields=["project_id", "date_added"], + name="sentry_even_project_62b83b_idx", ), models.Index( - fields=["project_id", "event_id"], name="sentry_even_project_974f7b_idx" + fields=["project_id", "event_id"], + name="sentry_even_project_974f7b_idx", ), ], }, @@ -2410,12 +2845,16 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("blob_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True)), + ( + "blob_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), ("offset", sentry.db.models.fields.bounded.BoundedBigIntegerField()), ( "data_export", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.exporteddata" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.exporteddata", ), ), ], @@ -2453,7 +2892,8 @@ class Migration(CheckedMigration): ( "blob", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="sentry.fileblob" + on_delete=django.db.models.deletion.PROTECT, + to="sentry.fileblob", ), ), ( @@ -2488,7 +2928,8 @@ class Migration(CheckedMigration): ( "blob", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.fileblob" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.fileblob", ), ), ], @@ -2514,11 +2955,16 @@ class Migration(CheckedMigration): ), ), ("datetime", models.DateTimeField(default=django.utils.timezone.now)), - ("data", sentry.db.models.fields.gzippeddict.GzippedDictField(null=True)), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", ), ), ], @@ -2526,6 +2972,60 @@ class Migration(CheckedMigration): "db_table": "sentry_activity", }, ), + migrations.CreateModel( + name="GroupActionLogEntry", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "original_group_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ("type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "actor_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ("source", models.CharField(max_length=64)), + ("data", models.JSONField(default=dict)), + ( + "date_added", + models.DateTimeField(db_default=django.db.models.functions.datetime.Now()), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("idempotency_key", models.CharField(max_length=64, null=True)), + ], + options={ + "db_table": "sentry_groupactionlogentry", + "indexes": [ + models.Index( + fields=["group_id", "date_added", "id"], + name="sentry_grou_group_i_cc465f_idx", + ), + models.Index( + fields=["project_id", "group_id"], + name="sentry_grou_project_6ed08e_idx", + ), + ], + "constraints": [ + models.UniqueConstraint( + condition=models.Q(("idempotency_key__isnull", False)), + fields=("group_id", "idempotency_key"), + name="uniq_groupactionlogentry_group_idempotency_key", + ) + ], + }, + ), migrations.CreateModel( name="GroupCommitResolution", fields=[ @@ -2566,11 +3066,20 @@ class Migration(CheckedMigration): db_index=True, null=True ), ), - ("state", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True)), + ( + "state", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", ), ), ], @@ -2587,16 +3096,28 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("schema_version", models.CharField(null=True)), ("platform", models.CharField(null=True)), + ("event_id", models.CharField(max_length=32, null=True)), ("latest_grouping_config", models.CharField(null=True)), ("hash_basis", models.CharField(null=True)), - ("hashing_metadata", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "hashing_metadata", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), ("seer_date_sent", models.DateTimeField(null=True)), ("seer_event_sent", models.CharField(max_length=32, null=True)), ("seer_model", models.CharField(null=True)), ("seer_match_distance", models.FloatField(null=True)), + ("seer_latest_training_model", models.CharField(null=True)), ( "grouphash", models.OneToOneField( @@ -2641,6 +3162,80 @@ class Migration(CheckedMigration): "db_table": "sentry_groupmeta", }, ), + migrations.CreateModel( + name="GroupOpenPeriod", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "user_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.User", db_index=True, null=True, on_delete="SET_NULL" + ), + ), + ( + "date_started", + models.DateTimeField(default=django.utils.timezone.now), + ), + ("date_ended", models.DateTimeField(null=True)), + ("data", models.JSONField(default=dict)), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + ), + ), + ( + "resolution_activity", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.activity", + ), + ), + ], + options={ + "db_table": "sentry_groupopenperiod", + }, + ), + migrations.CreateModel( + name="GroupOpenPeriodActivity", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("type", models.IntegerField()), + ("value", models.IntegerField(null=True)), + ("event_id", models.CharField(max_length=32, null=True)), + ( + "notification_uuid", + models.UUIDField( + default=sentry.models.groupopenperiodactivity.generate_random_uuid + ), + ), + ( + "group_open_period", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.groupopenperiod", + ), + ), + ], + options={ + "db_table": "sentry_groupopenperiodactivity", + }, + ), migrations.CreateModel( name="GroupRedirect", fields=[ @@ -2654,7 +3249,6 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), - ("group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True)), ( "previous_group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(unique=True), @@ -2664,12 +3258,22 @@ class Migration(CheckedMigration): sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), ("previous_project_slug", models.SlugField(null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="primary_group_of_redirect", + to="sentry.group", + ), + ), ], options={ "db_table": "sentry_groupredirect", - "unique_together": { - ("organization_id", "previous_short_id", "previous_project_slug") - }, }, ), migrations.CreateModel( @@ -2698,11 +3302,9 @@ class Migration(CheckedMigration): "db_table": "sentry_grouprelease", "indexes": [ models.Index( - fields=["group_id", "first_seen"], name="sentry_grou_group_i_6eaff8_idx" - ), - models.Index( - fields=["group_id", "-last_seen"], name="sentry_grou_group_i_b6e502_idx" - ), + fields=["group_id", "first_seen"], + name="sentry_grou_group_i_6eaff8_idx", + ) ], "unique_together": {("group_id", "release_id", "environment")}, }, @@ -2717,8 +3319,14 @@ class Migration(CheckedMigration): ), ), ("until", models.DateTimeField(null=True)), - ("count", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True)), - ("window", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True)), + ( + "count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ( + "window", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), ( "user_count", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), @@ -2735,7 +3343,9 @@ class Migration(CheckedMigration): ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group", unique=True + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", + unique=True, ), ), ], @@ -2753,8 +3363,11 @@ class Migration(CheckedMigration): ), ), ("type", models.CharField(max_length=64)), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ("config", models.JSONField(default=dict)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("external_id", models.CharField(max_length=64, null=True)), ], options={ @@ -2766,27 +3379,45 @@ class Migration(CheckedMigration): name="Identity", fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("external_id", models.TextField()), + ( + "data", + sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( + default=dict + ), + ), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "scopes", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None ), ), - ("external_id", models.TextField()), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), - ("scopes", sentry.db.models.fields.array.ArrayField(null=True)), - ("date_verified", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_verified", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ( "idp", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.identityprovider" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.identityprovider", ), ), ], @@ -2812,14 +3443,21 @@ class Migration(CheckedMigration): ("status_method", models.PositiveSmallIntegerField(default=3)), ("type", models.PositiveSmallIntegerField()), ("title", models.TextField()), - ("date_started", models.DateTimeField(default=django.utils.timezone.now)), - ("date_detected", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_started", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_detected", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("date_closed", models.DateTimeField(null=True)), ( "alert_rule", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="sentry.alertrule" + on_delete=django.db.models.deletion.PROTECT, + to="sentry.alertrule", ), ), ], @@ -2851,7 +3489,8 @@ class Migration(CheckedMigration): ( "incident", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.incident" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.incident", ), ), ], @@ -2860,7 +3499,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="IncidentTrigger", + name="Integration", fields=[ ( "id", @@ -2868,56 +3507,30 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("status", models.SmallIntegerField()), - ("date_modified", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "alert_rule_trigger", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.alertruletrigger" - ), + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), ), ( - "incident", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_index=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.incident", - ), + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), ), - ], - options={ - "db_table": "sentry_incidenttrigger", - }, - ), - migrations.AddField( - model_name="alertruletrigger", - name="triggered_incidents", - field=models.ManyToManyField( - related_name="triggers", through="sentry.IncidentTrigger", to="sentry.incident" - ), - ), - migrations.CreateModel( - name="Integration", - fields=[ + ("provider", models.CharField(max_length=64)), + ("external_id", models.CharField(max_length=256)), + ("name", models.CharField(max_length=200)), ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False + "metadata", + sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( + default=dict ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("provider", models.CharField(max_length=64)), - ("external_id", models.CharField(max_length=64)), - ("name", models.CharField(max_length=200)), - ("metadata", sentry.db.models.fields.jsonfield.JSONField(default=dict)), ( "status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( default=0, null=True ), ), + ("debug_data", models.JSONField(default=dict, null=True)), ], options={ "db_table": "sentry_integration", @@ -2937,7 +3550,10 @@ class Migration(CheckedMigration): "organization_integration_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(db_index=True), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("name", models.CharField(max_length=128)), ("external_id", models.CharField(max_length=64)), @@ -2964,7 +3580,10 @@ class Migration(CheckedMigration): sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), ), ("user_description", models.TextField(null=True)), - ("feature", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "feature", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ], options={ @@ -2981,77 +3600,36 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("repository_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("environment_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("release_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("deploy_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("commit_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ], - options={ - "db_table": "sentry_latestrelease", - "unique_together": {("repository_id", "environment_id")}, - }, - ), - migrations.CreateModel( - name="LostPasswordHash", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), + "repository_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), ), - ("hash", models.CharField(max_length=32)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - unique=True, - ), + "environment_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ], - options={ - "db_table": "sentry_lostpasswordhash", - }, - ), - migrations.CreateModel( - name="NotificationSettingOption", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), + "release_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("scope_type", models.CharField(max_length=32)), - ("scope_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), ( - "team_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Team", db_index=True, null=True, on_delete="CASCADE" - ), + "deploy_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), - ("type", models.CharField(max_length=32)), - ("value", models.CharField(max_length=32)), ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, + "commit_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, null=True ), ), ], options={ - "db_table": "sentry_notificationsettingoption", + "db_table": "sentry_latestrelease", + "unique_together": {("repository_id", "environment_id")}, }, ), migrations.CreateModel( - name="NotificationSettingProvider", + name="LostPasswordHash", fields=[ ( "id", @@ -3059,30 +3637,19 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("scope_type", models.CharField(max_length=32)), - ("scope_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ( - "team_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Team", db_index=True, null=True, on_delete="CASCADE" - ), - ), - ("type", models.CharField(max_length=32)), - ("value", models.CharField(max_length=32)), - ("provider", models.CharField(max_length=32)), + ("hash", models.CharField(max_length=32)), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, + unique=True, ), ), ], options={ - "db_table": "sentry_notificationsettingprovider", + "db_table": "sentry_lostpasswordhash", }, ), migrations.CreateModel( @@ -3096,7 +3663,10 @@ class Migration(CheckedMigration): ), ("name", models.CharField(max_length=64)), ("slug", sentry.db.models.fields.slug.SentryOrgSlugField(unique=True)), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("default_role", models.CharField(default="member", max_length=32)), ("is_test", models.BooleanField(db_default=False, default=False)), @@ -3130,51 +3700,6 @@ class Migration(CheckedMigration): ], }, ), - migrations.CreateModel( - name="NotificationAction", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "integration_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Integration", - blank=True, - db_index=True, - null=True, - on_delete="CASCADE", - ), - ), - ( - "sentry_app_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.SentryApp", - blank=True, - db_index=True, - null=True, - on_delete="CASCADE", - ), - ), - ("type", models.SmallIntegerField()), - ("target_type", models.SmallIntegerField()), - ("target_identifier", models.TextField(null=True)), - ("target_display", models.TextField(null=True)), - ("trigger_type", models.SmallIntegerField()), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "sentry_notificationaction", - }, - ), migrations.AddField( model_name="incident", name="organization", @@ -3203,13 +3728,15 @@ class Migration(CheckedMigration): ( "group_search_view", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.groupsearchview" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.groupsearchview", ), ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -3234,17 +3761,22 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("last_visited", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_visited", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "group_search_view", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.groupsearchview" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.groupsearchview", ), ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -3269,14 +3801,21 @@ class Migration(CheckedMigration): ), ), ("feature_id", models.PositiveIntegerField()), - ("date_completed", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_completed", + models.DateTimeField(default=django.utils.timezone.now), + ), ("complete", models.BooleanField(default=False)), ("applicable", models.BooleanField(default=True)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -3303,7 +3842,10 @@ class Migration(CheckedMigration): ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("title", models.TextField(null=True)), ("description", models.TextField(null=True)), - ("metadata", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "metadata", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), + ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -3319,95 +3861,13 @@ class Migration(CheckedMigration): ), migrations.AddField( model_name="exporteddata", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - migrations.CreateModel( - name="DiscoverSavedQuery", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "created_by_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ("name", models.CharField(max_length=255)), - ("query", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("version", models.IntegerField(null=True)), - ("date_created", models.DateTimeField(auto_now_add=True)), - ("date_updated", models.DateTimeField(auto_now=True)), - ( - "visits", - sentry.db.models.fields.bounded.BoundedBigIntegerField(default=1, null=True), - ), - ( - "last_visited", - models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ("is_homepage", models.BooleanField(blank=True, null=True)), - ( - "dataset", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ( - "dataset_source", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "sentry_discoversavedquery", - }, - ), - migrations.CreateModel( - name="DataSecrecyWaiver", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("access_start", models.DateTimeField(default=django.utils.timezone.now)), - ("access_end", models.DateTimeField(default=django.utils.timezone.now)), - ( - "zendesk_tickets", - sentry.db.models.fields.array.ArrayField(default=list, null=True), - ), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - unique=True, - ), - ), - ], - options={ - "db_table": "sentry_datasecrecywaiver", - }, + name="organization", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + ), ), migrations.CreateModel( - name="DashboardTombstone", + name="DataForwarder", fields=[ ( "id", @@ -3415,31 +3875,31 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("is_enabled", models.BooleanField(default=True)), + ("enroll_new_projects", models.BooleanField(default=False)), + ("provider", models.CharField(max_length=64)), ( - "slug", - sentry.db.models.fields.slug.SentrySlugField(db_index=False, max_length=255), + "config", + sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( + default=dict + ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], options={ - "db_table": "sentry_dashboardtombstone", + "db_table": "sentry_dataforwarder", }, ), - migrations.AddField( - model_name="dashboard", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), migrations.CreateModel( - name="CustomDynamicSamplingRule", + name="DashboardFavoriteUser", fields=[ ( "id", @@ -3447,35 +3907,42 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("is_active", models.BooleanField(default=True)), - ("is_org_level", models.BooleanField(default=False)), - ("rule_id", models.IntegerField(default=0)), - ("condition", models.TextField()), - ("sample_rate", models.FloatField(default=0.0)), - ("start_date", models.DateTimeField(default=django.utils.timezone.now)), - ("end_date", models.DateTimeField()), - ("num_samples", models.IntegerField()), - ("condition_hash", models.CharField(max_length=40)), - ("query", models.TextField(null=True)), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), ( - "created_by_id", + "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="CASCADE" + "sentry.User", db_index=True, on_delete="CASCADE" + ), + ), + ("position", models.PositiveSmallIntegerField(null=True)), + ("favorited", models.BooleanField(db_default=True)), + ( + "dashboard", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboard", ), ), - ("notification_sent", models.BooleanField(blank=True, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], options={ - "db_table": "sentry_customdynamicsamplingrule", + "db_table": "sentry_dashboardfavoriteuser", }, ), + migrations.AddField( + model_name="dashboard", + name="organization", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + ), + ), migrations.CreateModel( name="AuthProviderReplica", fields=[ @@ -3488,11 +3955,14 @@ class Migration(CheckedMigration): ( "auth_provider_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.AuthProvider", db_index=True, on_delete="CASCADE", unique=True + "sentry.AuthProvider", + db_index=True, + on_delete="CASCADE", + unique=True, ), ), ("provider", models.CharField(max_length=128)), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("config", models.JSONField(default=dict)), ( "default_role", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=50), @@ -3550,6 +4020,44 @@ class Migration(CheckedMigration): "db_table": "sentry_organizationavatar", }, ), + migrations.CreateModel( + name="OrganizationContributors", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "integration_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Integration", db_index=True, on_delete="DO_NOTHING" + ), + ), + ( + "external_identifier", + models.CharField(db_index=True, max_length=255), + ), + ("alias", models.CharField(blank=True, max_length=255, null=True)), + ( + "num_actions", + sentry.db.models.fields.bounded.BoundedIntegerField(default=0), + ), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ], + options={ + "db_table": "sentry_organizationcontributors", + }, + ), migrations.CreateModel( name="OrganizationIntegration", fields=[ @@ -3559,27 +4067,40 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( "sentry.Organization", db_index=True, on_delete="CASCADE" ), ), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("config", models.JSONField(default=dict)), ( "default_auth_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( db_index=True, null=True ), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), - ("grace_period_end", models.DateTimeField(blank=True, db_index=True, null=True)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "grace_period_end", + models.DateTimeField(blank=True, db_index=True, null=True), + ), ( "integration", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.integration" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.integration", ), ), ], @@ -3587,6 +4108,97 @@ class Migration(CheckedMigration): "db_table": "sentry_organizationintegration", }, ), + migrations.CreateModel( + name="OrganizationMapping", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, unique=True + ), + ), + ("slug", models.SlugField(unique=True)), + ("name", models.CharField(max_length=64)), + ( + "date_created", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "customer_id", + models.CharField(db_index=True, max_length=255, null=True), + ), + ("verified", models.BooleanField(default=False)), + ("idempotency_key", models.CharField(max_length=48)), + ("cell_name", models.CharField(db_column="region_name", max_length=48)), + ( + "status", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ( + "allow_joinleave", + models.BooleanField(db_default=False, default=False), + ), + ( + "enhanced_privacy", + models.BooleanField(db_default=False, default=False), + ), + ("require_2fa", models.BooleanField(db_default=False, default=False)), + ("early_adopter", models.BooleanField(db_default=False, default=False)), + ( + "disable_shared_issues", + models.BooleanField(db_default=False, default=False), + ), + ( + "disable_new_visibility_features", + models.BooleanField(db_default=False, default=False), + ), + ( + "require_email_verification", + models.BooleanField(db_default=False, default=False), + ), + ( + "disable_member_project_creation", + models.BooleanField(db_default=False, default=False), + ), + ( + "prevent_superuser_access", + models.BooleanField(db_default=False, default=False), + ), + ( + "disable_member_invite", + models.BooleanField(db_default=False, default=False), + ), + ( + "date_updated", + models.DateTimeField( + auto_now=True, + db_default=django.db.models.functions.datetime.Now(), + ), + ), + ], + options={ + "db_table": "sentry_organizationmapping", + "indexes": [ + sentry.db.models.indexes.IndexWithPostgresNameLimits( + django.db.models.functions.datetime.TruncSecond("date_updated"), + models.F("id"), + name="sentry_orgmapping_date_updated_id_idx", + ), + sentry.db.models.indexes.IndexWithPostgresNameLimits( + models.F("cell_name"), + django.db.models.functions.datetime.TruncSecond("date_updated"), + models.F("id"), + name="sentry_orgmapping_cell_name_date_updated_id_idx", + ), + ], + }, + ), migrations.CreateModel( name="OrganizationMember", fields=[ @@ -3599,7 +4211,11 @@ class Migration(CheckedMigration): ( "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="CASCADE" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="CASCADE", ), ), ("email", models.EmailField(blank=True, max_length=75, null=True)), @@ -3618,17 +4234,27 @@ class Migration(CheckedMigration): default=0, ), ), - ("token", models.CharField(blank=True, max_length=64, null=True, unique=True)), + ( + "token", + models.CharField(blank=True, max_length=64, null=True, unique=True), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("token_expires_at", models.DateTimeField(default=None, null=True)), ("has_global_access", models.BooleanField(default=True)), ( "inviter_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), - ("invite_status", models.PositiveSmallIntegerField(default=0, null=True)), + ( + "invite_status", + models.PositiveSmallIntegerField(default=0, null=True), + ), ( "type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -3636,7 +4262,7 @@ class Migration(CheckedMigration): ), ), ("user_is_active", models.BooleanField(db_default=True, default=True)), - ("user_email", models.CharField(blank=True, max_length=75, null=True)), + ("user_email", models.CharField(blank=True, max_length=200, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -3664,7 +4290,11 @@ class Migration(CheckedMigration): ( "inviter_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), ("invite_status", models.PositiveSmallIntegerField(default=0)), @@ -3688,7 +4318,10 @@ class Migration(CheckedMigration): ("sso_linked", models.BooleanField(default=False)), ("sso_invalid", models.BooleanField(default=False)), ("member_limit_restricted", models.BooleanField(default=False)), - ("idp_provisioned", models.BooleanField(db_default=False, default=False)), + ( + "idp_provisioned", + models.BooleanField(db_default=False, default=False), + ), ("idp_role_restricted", models.BooleanField(default=False)), ("partnership_restricted", models.BooleanField(default=False)), ( @@ -3702,7 +4335,8 @@ class Migration(CheckedMigration): ( "organization_member", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organizationmember" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organizationmember", ), ), ], @@ -3734,7 +4368,10 @@ class Migration(CheckedMigration): ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("role", models.CharField(default="member", max_length=32)), ("email", models.EmailField(blank=True, max_length=75, null=True)), - ("invite_status", models.PositiveSmallIntegerField(default=0, null=True)), + ( + "invite_status", + models.PositiveSmallIntegerField(default=0, null=True), + ), ( "inviter", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -3789,7 +4426,7 @@ class Migration(CheckedMigration): "organizationmemberteam_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("is_active", models.BooleanField()), + ("is_active", models.BooleanField(db_default=True)), ("role", models.CharField(blank=True, max_length=32, null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ], @@ -3808,11 +4445,12 @@ class Migration(CheckedMigration): ), ), ("key", models.CharField(max_length=64)), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), + ("value", models.JSONField(null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -3842,7 +4480,7 @@ class Migration(CheckedMigration): db_index=True, null=True ), ), - ("region_name", models.CharField(max_length=48)), + ("cell_name", models.CharField(db_column="region_name", max_length=48)), ( "reservation_type", sentry.db.models.fields.bounded.BoundedBigIntegerField(default=0), @@ -3889,7 +4527,11 @@ class Migration(CheckedMigration): ( "project_last_used_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Project", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.Project", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), ("date_deactivated", models.DateTimeField(blank=True, null=True)), @@ -3917,7 +4559,10 @@ class Migration(CheckedMigration): ), ), ("string", models.CharField(max_length=200)), - ("organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "last_seen", @@ -3950,7 +4595,7 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("slug", sentry.db.models.fields.slug.SentrySlugField(max_length=100, null=True)), + ("slug", sentry.db.models.fields.slug.SentrySlugField(max_length=100)), ("name", models.CharField(max_length=200)), ("forced_color", models.CharField(blank=True, max_length=6, null=True)), ("public", models.BooleanField(default=False)), @@ -3995,16 +4640,20 @@ class Migration(CheckedMigration): "has_insights_queues", "has_insights_llm_monitoring", "has_flags", + "has_insights_agent_monitoring", + "has_insights_mcp", + "has_logs", + "has_trace_metrics", ], default=10, - null=True, ), ), ("platform", models.CharField(max_length=64, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -4063,15 +4712,25 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("completion_seen", models.DateTimeField(null=True)), - ("date_completed", models.DateTimeField(default=django.utils.timezone.now)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ( + "date_completed", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), ("task", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( @@ -4088,39 +4747,6 @@ class Migration(CheckedMigration): "db_table": "sentry_organizationonboardingtask", }, ), - migrations.CreateModel( - name="NotificationActionProject", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.notificationaction" - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_notificationactionproject", - }, - ), - migrations.AddField( - model_name="notificationaction", - name="projects", - field=models.ManyToManyField( - through="sentry.NotificationActionProject", to="sentry.project" - ), - ), migrations.CreateModel( name="IncidentProject", fields=[ @@ -4133,7 +4759,8 @@ class Migration(CheckedMigration): ( "incident", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.incident" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.incident", ), ), ( @@ -4154,7 +4781,9 @@ class Migration(CheckedMigration): model_name="incident", name="projects", field=models.ManyToManyField( - related_name="incidents", through="sentry.IncidentProject", to="sentry.project" + related_name="incidents", + through="sentry.IncidentProject", + to="sentry.project", ), ), migrations.CreateModel( @@ -4166,7 +4795,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "previous_group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(unique=True), @@ -4187,6 +4819,11 @@ class Migration(CheckedMigration): "actor_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), ), + ( + "times_seen", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(db_default=0), + ), + ("last_seen", models.DateTimeField(auto_now_add=True, null=True)), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4210,7 +4847,9 @@ class Migration(CheckedMigration): ( "uuid", models.CharField( - default=sentry.models.groupshare.default_uuid, max_length=32, unique=True + default=sentry.models.groupshare.default_uuid, + max_length=32, + unique=True, ), ), ( @@ -4223,7 +4862,9 @@ class Migration(CheckedMigration): ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group", unique=True + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", + unique=True, ), ), ( @@ -4284,7 +4925,8 @@ class Migration(CheckedMigration): ( "group_search_view", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.groupsearchview" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.groupsearchview", ), ), ( @@ -4306,7 +4948,7 @@ class Migration(CheckedMigration): ), ), migrations.CreateModel( - name="GroupOpenPeriod", + name="GroupReaction", fields=[ ( "id", @@ -4316,27 +4958,29 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), + ("reaction", models.BooleanField()), ( "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), - ("date_started", models.DateTimeField(default=django.utils.timezone.now)), - ("date_ended", models.DateTimeField(null=True)), - ("data", models.JSONField(default=dict)), + ("source", models.PositiveSmallIntegerField()), ( - "group", + "commit", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.commit", ), ), ( - "resolution_activity", + "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.activity", + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", ), ), ( @@ -4347,9 +4991,16 @@ class Migration(CheckedMigration): ), ], options={ - "db_table": "sentry_groupopenperiod", + "db_table": "sentry_groupreaction", }, ), + migrations.AddField( + model_name="groupopenperiod", + name="project", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + ), + ), migrations.CreateModel( name="GroupLink", fields=[ @@ -4368,7 +5019,7 @@ class Migration(CheckedMigration): "relationship", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=2), ), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("data", models.JSONField(default=dict)), ( "datetime", models.DateTimeField(db_index=True, default=django.utils.timezone.now), @@ -4405,7 +5056,10 @@ class Migration(CheckedMigration): ), ), ("reason", models.PositiveSmallIntegerField(default=0)), - ("reason_details", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "reason_details", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), + ), ( "date_added", models.DateTimeField(db_index=True, default=django.utils.timezone.now), @@ -4446,7 +5100,9 @@ class Migration(CheckedMigration): model_name="grouphash", name="project", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.project", ), ), migrations.CreateModel( @@ -4460,7 +5116,10 @@ class Migration(CheckedMigration): ), ("email", models.EmailField(max_length=75)), ("msgid", models.CharField(max_length=100)), - ("date", models.DateTimeField(db_index=True, default=django.utils.timezone.now)), + ( + "date", + models.DateTimeField(db_index=True, default=django.utils.timezone.now), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4497,7 +5156,10 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4539,7 +5201,8 @@ class Migration(CheckedMigration): ( "environment", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.environment" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.environment", ), ), ( @@ -4559,7 +5222,7 @@ class Migration(CheckedMigration): field=models.ManyToManyField(through="sentry.EnvironmentProject", to="sentry.project"), ), migrations.CreateModel( - name="DiscoverSavedQueryProject", + name="DataForwarderProject", fields=[ ( "id", @@ -4567,10 +5230,21 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("is_enabled", models.BooleanField(default=True)), + ( + "overrides", + sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( + default=dict + ), + ), ( - "discover_saved_query", + "data_forwarder", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.discoversavedquery" + on_delete=django.db.models.deletion.CASCADE, + related_name="projects", + to="sentry.dataforwarder", ), ), ( @@ -4581,14 +5255,16 @@ class Migration(CheckedMigration): ), ], options={ - "db_table": "sentry_discoversavedqueryproject", + "db_table": "sentry_dataforwarderproject", }, ), migrations.AddField( - model_name="discoversavedquery", - name="projects", + model_name="dataforwarder", + name="enrolled_projects", field=models.ManyToManyField( - through="sentry.DiscoverSavedQueryProject", to="sentry.project" + related_name="data_forwarders", + through="sentry.DataForwarderProject", + to="sentry.project", ), ), migrations.CreateModel( @@ -4603,7 +5279,8 @@ class Migration(CheckedMigration): ( "dashboard", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.dashboard", ), ), ( @@ -4623,7 +5300,7 @@ class Migration(CheckedMigration): field=models.ManyToManyField(through="sentry.DashboardProject", to="sentry.project"), ), migrations.CreateModel( - name="CustomDynamicSamplingRuleProject", + name="CustomInboundFilter", fields=[ ( "id", @@ -4631,33 +5308,24 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ( - "custom_dynamic_sampling_rule", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.customdynamicsamplingrule", - ), - ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("name", models.CharField(blank=True, max_length=256, null=True)), + ("active", models.BooleanField(db_default=True, default=True)), + ("conditions", models.JSONField(default=list)), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + on_delete=django.db.models.deletion.CASCADE, + related_name="custom_inbound_filters", + to="sentry.project", ), ), ], options={ - "db_table": "sentry_customdynamicsamplingruleproject", + "db_table": "sentry_custominboundfilter", }, ), - migrations.AddField( - model_name="customdynamicsamplingrule", - name="projects", - field=models.ManyToManyField( - related_name="custom_dynamic_sampling_rules", - through="sentry.CustomDynamicSamplingRuleProject", - to="sentry.project", - ), - ), migrations.CreateModel( name="Counter", fields=[ @@ -4739,12 +5407,16 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "artifact_bundle", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.artifactbundle" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.artifactbundle", ), ), ], @@ -4767,7 +5439,10 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4803,7 +5478,10 @@ class Migration(CheckedMigration): ), ("debug_id", models.CharField(db_column="uuid", max_length=64)), ("code_id", models.CharField(max_length=64, null=True)), - ("data", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), + ), ( "date_accessed", models.DateTimeField( @@ -4811,10 +5489,19 @@ class Migration(CheckedMigration): default=django.utils.timezone.now, ), ), + ("storage_path", models.TextField(null=True)), + ("content_type", models.TextField(null=True)), + ( + "file_size", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ("date_created", models.DateTimeField(null=True)), ( "file", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.file" + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="sentry.file", ), ), ], @@ -4831,15 +5518,22 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("release_name", models.CharField(max_length=250)), ("proguard_uuid", models.UUIDField(db_index=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "project_debug_file", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.projectdebugfile" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.projectdebugfile", ), ), ], @@ -4866,7 +5560,10 @@ class Migration(CheckedMigration): db_index=True, default=0 ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "rate_limit_count", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), @@ -4875,8 +5572,14 @@ class Migration(CheckedMigration): "rate_limit_window", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), ), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("use_case", models.CharField(db_default="user", default="user", max_length=32)), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), + ( + "use_case", + models.CharField(db_default="user", default="user", max_length=32), + ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4890,6 +5593,50 @@ class Migration(CheckedMigration): "db_table": "sentry_projectkey", }, ), + migrations.CreateModel( + name="ProjectKeyMapping", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "project_key_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "public_key", + models.CharField(db_index=True, max_length=32, unique=True), + ), + ("cell_name", models.CharField(max_length=48)), + ( + "date_updated", + models.DateTimeField( + auto_now=True, + db_default=django.db.models.functions.datetime.Now(), + ), + ), + ], + options={ + "db_table": "sentry_projectkeymapping", + "indexes": [ + sentry.db.models.indexes.IndexWithPostgresNameLimits( + models.F("cell_name"), + django.db.models.functions.datetime.TruncSecond("date_updated"), + models.F("id"), + name="sentry_projkeymapping_cell_name_date_updated_id_idx", + ) + ], + "constraints": [ + models.UniqueConstraint( + fields=("project_key_id", "cell_name"), + name="sentry_projectkeymapping_project_key_id_cell_name_uniq", + ) + ], + }, + ), migrations.CreateModel( name="ProjectOption", fields=[ @@ -4900,7 +5647,10 @@ class Migration(CheckedMigration): ), ), ("key", models.CharField(max_length=64)), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), + ( + "value", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -4922,11 +5672,17 @@ class Migration(CheckedMigration): ), ), ("raw", models.TextField(null=True)), - ("schema", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ("schema", models.JSONField(null=True)), ("fallthrough", models.BooleanField(default=True)), ("auto_assignment", models.BooleanField(default=True)), - ("date_created", models.DateTimeField(default=django.utils.timezone.now)), - ("last_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_created", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "last_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ("is_active", models.BooleanField(default=True)), ("codeowners_auto_sync", models.BooleanField(default=True, null=True)), ( @@ -4955,7 +5711,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("platform", models.CharField(max_length=64)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("last_seen", models.DateTimeField(default=django.utils.timezone.now)), @@ -4974,12 +5733,16 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("redirect_slug", models.SlugField()), + ( + "redirect_slug", + sentry.db.models.fields.slug.SentrySlugField(max_length=100), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( @@ -5016,37 +5779,7 @@ class Migration(CheckedMigration): ], ), migrations.CreateModel( - name="ProjectTemplate", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("name", models.CharField(max_length=200)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "sentry_projecttemplate", - }, - ), - migrations.AddField( - model_name="project", - name="template", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.projecttemplate" - ), - ), - migrations.CreateModel( - name="ProjectTemplateOption", + name="ProjectTransactionThreshold", fields=[ ( "id", @@ -5054,32 +5787,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("key", models.CharField(max_length=64)), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), ( - "project_template", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="options", - to="sentry.projecttemplate", - ), + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), ), - ], - options={ - "db_table": "sentry_projecttemplateoption", - }, - ), - migrations.CreateModel( - name="ProjectTransactionThreshold", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), ("threshold", models.IntegerField()), ("metric", models.PositiveSmallIntegerField(default=1)), ( @@ -5091,7 +5806,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( @@ -5117,8 +5833,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("transaction", models.CharField(max_length=200)), ("threshold", models.IntegerField()), ("metric", models.PositiveSmallIntegerField(default=1)), @@ -5131,7 +5853,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( @@ -5170,17 +5893,99 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("feature", models.CharField(max_length=64)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default={})), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ("feature", models.CharField(max_length=64)), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ], + options={ + "db_table": "sentry_promptsactivity", + "indexes": [ + models.Index( + fields=["feature", "organization_id", "project_id"], + name="sentry_prom_feature_56978d_idx", + ) + ], + "unique_together": {("user_id", "feature", "organization_id", "project_id")}, + }, + ), + migrations.CreateModel( + name="PullRequest", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), + ( + "repository_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ("key", models.CharField(max_length=64)), + ( + "date_added", + models.DateTimeField(db_index=True, default=django.utils.timezone.now), + ), + ("title", models.TextField(null=True)), + ("message", models.TextField(null=True)), + ( + "merge_commit_sha", + models.CharField(db_index=True, max_length=64, null=True), + ), + ("opened_at", models.DateTimeField(null=True)), + ("closed_at", models.DateTimeField(null=True)), + ("merged_at", models.DateTimeField(null=True)), + ("state", models.CharField(max_length=32, null=True)), + ("head_commit_sha", models.CharField(max_length=64, null=True)), + ("draft", models.BooleanField(null=True)), + ( + "author", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.commitauthor", + ), + ), + ], + options={ + "db_table": "sentry_pull_request", + }, + ), + migrations.CreateModel( + name="PullRequestActivity", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("event_type", models.CharField(max_length=64)), + ("webhook_id", models.CharField(max_length=255)), + ("payload", models.JSONField(default=dict)), + ( + "pull_request", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.pullrequest", + ), + ), ], options={ - "db_table": "sentry_promptsactivity", - "unique_together": {("user_id", "feature", "organization_id", "project_id")}, + "db_table": "sentry_pullrequest_activity", }, ), migrations.CreateModel( - name="PullRequest", + name="PullRequestAttribution", fields=[ ( "id", @@ -5188,30 +5993,22 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("signal_type", models.CharField(max_length=64)), + ("signal_details", models.JSONField(null=True)), + ("source", models.CharField(max_length=128)), + ("is_valid", models.BooleanField(default=True)), ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("repository_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("key", models.CharField(max_length=64)), - ( - "date_added", - models.DateTimeField(db_index=True, default=django.utils.timezone.now), - ), - ("title", models.TextField(null=True)), - ("message", models.TextField(null=True)), - ("merge_commit_sha", models.CharField(db_index=True, max_length=64, null=True)), - ( - "author", + "pull_request", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, - to="sentry.commitauthor", + to="sentry.pullrequest", ), ), ], options={ - "db_table": "sentry_pull_request", + "db_table": "sentry_pullrequest_attribution", }, ), migrations.CreateModel( @@ -5223,7 +6020,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("external_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "external_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("created_at", models.DateTimeField()), ("updated_at", models.DateTimeField()), ( @@ -5233,7 +6033,10 @@ class Migration(CheckedMigration): size=None, ), ), - ("reactions", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "reactions", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), ( "comment_type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -5243,7 +6046,8 @@ class Migration(CheckedMigration): ( "pull_request", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.pullrequest" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.pullrequest", ), ), ], @@ -5263,13 +6067,16 @@ class Migration(CheckedMigration): ( "commit", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" + db_constraint=False, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.commit", ), ), ( "pull_request", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.pullrequest" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.pullrequest", ), ), ], @@ -5277,6 +6084,66 @@ class Migration(CheckedMigration): "db_table": "sentry_pullrequest_commit", }, ), + migrations.CreateModel( + name="PullRequestMetrics", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("verdict", models.CharField(max_length=64, null=True)), + ( + "additions", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "deletions", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "files_changed", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "commits_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "comments_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "review_comments_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, default=0 + ), + ), + ( + "participants_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "reviews_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ("is_assigned", models.BooleanField(default=False)), + ( + "pull_request", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="metrics", + to="sentry.pullrequest", + ), + ), + ], + options={ + "db_table": "sentry_pullrequest_metrics", + }, + ), migrations.CreateModel( name="QuerySubscription", fields=[ @@ -5340,7 +6207,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -5357,17 +6225,35 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "import_uuid", sentry.db.models.fields.uuid.UUIDField(db_index=True, max_length=32), ), ("model", models.CharField(db_index=True, max_length=64)), - ("min_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_ordinal", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("min_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("max_source_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "min_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_ordinal", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "min_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "max_source_pk", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ( "min_inserted_pk", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), @@ -5386,113 +6272,6 @@ class Migration(CheckedMigration): "unique_together": {("import_uuid", "model", "min_ordinal")}, }, ), - migrations.CreateModel( - name="RegionOutbox", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("shard_scope", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("shard_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("category", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("object_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("payload", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ("scheduled_from", models.DateTimeField(default=django.utils.timezone.now)), - ( - "scheduled_for", - models.DateTimeField( - default=datetime.datetime(2016, 8, 1, 0, 0, tzinfo=datetime.UTC) - ), - ), - ( - "date_added", - models.DateTimeField( - db_default=django.db.models.functions.datetime.Now(), - default=django.utils.timezone.now, - editable=False, - ), - ), - ], - options={ - "db_table": "sentry_regionoutbox", - "indexes": [ - models.Index( - fields=["shard_scope", "shard_identifier", "category", "object_identifier"], - name="sentry_regi_shard_s_bfff84_idx", - ), - models.Index( - fields=["shard_scope", "shard_identifier", "scheduled_for"], - name="sentry_regi_shard_s_cd9995_idx", - ), - models.Index( - fields=["shard_scope", "shard_identifier", "id"], - name="sentry_regi_shard_s_e7412f_idx", - ), - ], - }, - ), - migrations.CreateModel( - name="RegionScheduledDeletion", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "guid", - models.CharField( - default=sentry.deletions.models.scheduleddeletion.default_guid, - max_length=32, - unique=True, - ), - ), - ("app_label", models.CharField(max_length=64)), - ("model_name", models.CharField(max_length=64)), - ("object_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ( - "date_scheduled", - models.DateTimeField( - default=sentry.deletions.models.scheduleddeletion.default_date_schedule - ), - ), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default={})), - ("in_progress", models.BooleanField(default=False)), - ], - options={ - "db_table": "sentry_regionscheduleddeletion", - "unique_together": {("app_label", "model_name", "object_id")}, - }, - ), - migrations.CreateModel( - name="RegionTombstone", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("table_name", models.CharField(max_length=48)), - ("object_identifier", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("created_at", models.DateTimeField(default=django.utils.timezone.now)), - ], - options={ - "db_table": "sentry_regiontombstone", - "indexes": [ - models.Index( - fields=["table_name", "object_identifier"], - name="sentry_regi_table_n_cd667a_idx", - ) - ], - }, - ), migrations.CreateModel( name="RegressionGroup", fields=[ @@ -5540,7 +6319,10 @@ class Migration(CheckedMigration): ("version", models.CharField(default="0.0.1", max_length=32)), ("first_seen", models.DateTimeField(default=django.utils.timezone.now)), ("last_seen", models.DateTimeField(default=django.utils.timezone.now)), - ("public_key", models.CharField(db_index=True, max_length=200, null=True)), + ( + "public_key", + models.CharField(db_index=True, max_length=200, null=True), + ), ], options={ "db_table": "sentry_relayusage", @@ -5566,14 +6348,24 @@ class Migration(CheckedMigration): ("version", models.CharField(max_length=250)), ("ref", models.CharField(blank=True, max_length=250, null=True)), ("url", models.URLField(blank=True, null=True)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_added", + models.DateTimeField(db_index=True, default=django.utils.timezone.now), + ), ("date_started", models.DateTimeField(blank=True, null=True)), ("date_released", models.DateTimeField(blank=True, null=True)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default={})), + ( + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), ( "owner_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), ( @@ -5586,7 +6378,15 @@ class Migration(CheckedMigration): "last_commit_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), - ("authors", sentry.db.models.fields.array.ArrayField(null=True)), + ( + "authors", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), + default=list, + null=True, + size=None, + ), + ), ( "total_deploys", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -5609,7 +6409,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -5630,7 +6431,14 @@ class Migration(CheckedMigration): "current_release_version", models.CharField(blank=True, max_length=250, null=True), ), - ("type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True)), + ( + "future_release_version", + models.CharField(blank=True, max_length=250, null=True), + ), + ( + "type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), ( "actor_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), @@ -5639,11 +6447,16 @@ class Migration(CheckedMigration): "datetime", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group", unique=True + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", + unique=True, ), ), ( @@ -5706,7 +6519,9 @@ class Migration(CheckedMigration): model_name="group", name="first_release", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.PROTECT, to="sentry.release" + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="sentry.release", ), ), migrations.CreateModel( @@ -5759,7 +6574,10 @@ class Migration(CheckedMigration): ("date_started", models.DateTimeField(blank=True, null=True)), ("name", models.CharField(blank=True, max_length=64, null=True)), ("url", models.URLField(blank=True, null=True)), - ("notified", models.BooleanField(db_index=True, default=False, null=True)), + ( + "notified", + models.BooleanField(db_index=True, default=False, null=True), + ), ( "release", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -5813,7 +6631,8 @@ class Migration(CheckedMigration): ( "artifact_bundle", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.artifactbundle" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.artifactbundle", ), ), ], @@ -5834,12 +6653,20 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("order", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ( + "order", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ( "commit", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" + db_constraint=False, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.commit", ), ), ( @@ -5862,7 +6689,10 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), ("first_seen", models.DateTimeField(default=django.utils.timezone.now)), ( "last_seen", @@ -5910,7 +6740,10 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), + ( + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), ( "release_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), @@ -5923,6 +6756,13 @@ class Migration(CheckedMigration): db_index=True, null=True ), ), + ( + "date_accessed", + models.DateTimeField( + db_default=django.db.models.functions.datetime.Now(), + default=django.utils.timezone.now, + ), + ), ( "artifact_count", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -5953,11 +6793,16 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("repository_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "repository_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ( "commit", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" + db_constraint=False, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.commit", ), ), ( @@ -6010,7 +6855,9 @@ class Migration(CheckedMigration): model_name="release", name="projects", field=models.ManyToManyField( - related_name="releases", through="sentry.ReleaseProject", to="sentry.project" + related_name="releases", + through="sentry.ReleaseProject", + to="sentry.project", ), ), migrations.CreateModel( @@ -6042,7 +6889,8 @@ class Migration(CheckedMigration): ( "environment", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.environment" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.environment", ), ), ( @@ -6071,8 +6919,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("threshold_type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("trigger_type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "threshold_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "trigger_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("value", models.IntegerField()), ("window_in_seconds", models.PositiveIntegerField()), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), @@ -6106,9 +6960,18 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("creator_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ( + "creator_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("owner_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), ( "uuid", @@ -6132,15 +6995,27 @@ class Migration(CheckedMigration): ), ), ("status", models.SmallIntegerField(default=0)), - ("scheduled_pause_at_step", models.SmallIntegerField(default=None, null=True)), - ("scheduled_cancel_at_step", models.SmallIntegerField(default=None, null=True)), + ( + "scheduled_pause_at_step", + models.SmallIntegerField(default=None, null=True), + ), + ( + "scheduled_cancel_at_step", + models.SmallIntegerField(default=None, null=True), + ), ("want_org_slugs", models.JSONField(default=list)), ("want_usernames", models.JSONField(null=True)), ("latest_notified", models.SmallIntegerField(default=None, null=True)), - ("latest_unclaimed_emails_sent_at", models.DateTimeField(default=None, null=True)), + ( + "latest_unclaimed_emails_sent_at", + models.DateTimeField(default=None, null=True), + ), ("latest_task", models.CharField(default="", max_length=64)), ("latest_task_attempts", models.SmallIntegerField(default=0)), - ("failure_reason", models.CharField(default=None, max_length=256, null=True)), + ( + "failure_reason", + models.CharField(default=None, max_length=256, null=True), + ), ], options={ "db_table": "sentry_relocation", @@ -6173,9 +7048,16 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("kind", models.SmallIntegerField()), + ("bucket_path", models.CharField(null=True)), ( "file", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -6185,7 +7067,8 @@ class Migration(CheckedMigration): ( "relocation", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.relocation" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.relocation", ), ), ], @@ -6202,14 +7085,21 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("status", models.SmallIntegerField(default=0)), ("attempts", models.SmallIntegerField(default=0)), ( "relocation", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.relocation" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.relocation", ), ), ], @@ -6226,8 +7116,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("status", models.SmallIntegerField(default=0)), ( "build_id", @@ -6238,7 +7134,8 @@ class Migration(CheckedMigration): ( "relocation", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.relocation" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.relocation", ), ), ( @@ -6266,11 +7163,14 @@ class Migration(CheckedMigration): "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("name", models.CharField(max_length=200)), - ("url", models.URLField(null=True)), + ("name", models.CharField(max_length=500)), + ("url", models.URLField(max_length=512, null=True)), ("provider", models.CharField(max_length=64, null=True)), ("external_id", models.CharField(max_length=64, null=True)), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ( + "config", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), + ), ( "status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField( @@ -6284,13 +7184,112 @@ class Migration(CheckedMigration): db_index=True, null=True ), ), - ("languages", sentry.db.models.fields.array.ArrayField(null=True)), + ( + "languages", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ], options={ "db_table": "sentry_repository", "unique_together": {("organization_id", "provider", "external_id")}, }, ), + migrations.CreateModel( + name="ProjectRepository", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("source", models.SmallIntegerField(default=0)), + ( + "project", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + ), + ), + ( + "repository", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.repository", + ), + ), + ], + options={ + "db_table": "sentry_projectrepository", + }, + ), + migrations.CreateModel( + name="CodeReviewEvent", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("pr_number", models.IntegerField(null=True)), + ("pr_title", models.TextField(null=True)), + ("pr_author", models.TextField(null=True)), + ("pr_url", models.TextField(null=True)), + ("pr_state", models.CharField(max_length=16, null=True)), + ("raw_event_type", models.CharField(max_length=64)), + ("raw_event_action", models.CharField(max_length=64)), + ("trigger_id", models.CharField(max_length=64, null=True)), + ("trigger", models.CharField(max_length=64, null=True)), + ("trigger_user", models.TextField(null=True)), + ("trigger_at", models.DateTimeField(default=django.utils.timezone.now)), + ("target_commit_sha", models.CharField(max_length=64, null=True)), + ( + "status", + models.CharField( + default=sentry.models.code_review_event.CodeReviewEventStatus[ + "WEBHOOK_RECEIVED" + ], + max_length=32, + ), + ), + ("denial_reason", models.TextField(null=True)), + ("webhook_received_at", models.DateTimeField(null=True)), + ("preflight_completed_at", models.DateTimeField(null=True)), + ("task_enqueued_at", models.DateTimeField(null=True)), + ("sent_to_seer_at", models.DateTimeField(null=True)), + ("review_started_at", models.DateTimeField(null=True)), + ("review_completed_at", models.DateTimeField(null=True)), + ("seer_run_id", models.CharField(max_length=64, null=True)), + ( + "comments_posted", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("review_result", models.JSONField(null=True)), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ( + "repository", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.repository", + ), + ), + ], + options={ + "db_table": "sentry_code_review_event", + }, + ), migrations.CreateModel( name="RepositoryProjectPathConfig", fields=[ @@ -6300,35 +7299,42 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "organization_integration_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.OrganizationIntegration", db_index=True, on_delete="CASCADE" + "sentry.OrganizationIntegration", + db_index=True, + on_delete="CASCADE", ), ), ( "organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("integration_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "integration_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("stack_root", models.TextField()), ("source_root", models.TextField()), ("default_branch", models.TextField(null=True)), - ("automatically_generated", models.BooleanField(db_default=False, default=False)), ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.project", - ), + "automatically_generated", + models.BooleanField(db_default=False, default=False), ), ( - "repository", + "project_repository", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.repository" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.projectrepository", ), ), ], @@ -6347,8 +7353,12 @@ class Migration(CheckedMigration): ), ("raw", models.TextField()), ("schema", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ("date_synced", models.DateTimeField(null=True)), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -6371,7 +7381,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="RollbackOrganization", + name="RepositorySettings", fields=[ ( "id", @@ -6379,22 +7389,41 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("data", models.JSONField(default=None, null=True)), + ("enabled_code_review", models.BooleanField(default=False)), ( - "organization", + "code_review_triggers", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=32), + default=list, + size=None, + ), + ), + ( + "date_added", + models.DateTimeField(db_default=django.db.models.functions.datetime.Now()), + ), + ( + "date_updated", + models.DateTimeField( + auto_now=True, + db_default=django.db.models.functions.datetime.Now(), + ), + ), + ( + "repository", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.repository", + unique=True, ), ), ], options={ - "db_table": "sentry_rollbackorganization", + "db_table": "sentry_repositorysettings", }, ), migrations.CreateModel( - name="RollbackUser", + name="RollbackOrganization", fields=[ ( "id", @@ -6404,29 +7433,21 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "user_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, on_delete="CASCADE" - ), - ), - ("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), - ("share_uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), ("data", models.JSONField(default=None, null=True)), - ("share_data", models.JSONField(default=None, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], options={ - "db_table": "sentry_rollbackuser", + "db_table": "sentry_rollbackorganization", }, ), migrations.CreateModel( - name="Rule", + name="RollbackUser", fields=[ ( "id", @@ -6434,75 +7455,38 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), ( - "environment_id", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("label", models.CharField(max_length=256)), - ("data", sentry.db.models.fields.gzippeddict.GzippedDictField()), - ( - "status", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_index=True, default=0 - ), - ), - ( - "source", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=sentry.models.rule.RuleSource["ISSUE"], - default=sentry.models.rule.RuleSource["ISSUE"], - ), - ), - ( - "owner_user_id", + "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", db_index=True, on_delete="CASCADE" ), ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), + "uuid", + models.UUIDField(default=uuid.uuid4, editable=False, unique=True), ), - ], - options={ - "db_table": "sentry_rule", - }, - ), - migrations.CreateModel( - name="NeglectedRule", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), + "share_uuid", + models.UUIDField(default=uuid.uuid4, editable=False, unique=True), ), - ("disable_date", models.DateTimeField()), - ("opted_out", models.BooleanField(default=False)), - ("sent_initial_email_date", models.DateTimeField(null=True)), - ("sent_final_email_date", models.DateTimeField(null=True)), + ("data", models.JSONField(default=None, null=True)), + ("share_data", models.JSONField(default=None, null=True)), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ( - "rule", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.rule" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], options={ - "abstract": False, + "db_table": "sentry_rollbackuser", }, ), migrations.CreateModel( - name="GroupRuleStatus", + name="Rule", fields=[ ( "id", @@ -6510,62 +7494,48 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("status", models.PositiveSmallIntegerField(default=0)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("last_active", models.DateTimeField(null=True)), ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), + "environment_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), ), + ("label", models.CharField(max_length=256)), ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), + "data", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), ), - ( - "rule", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.rule" + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_index=True, default=0 ), ), - ], - options={ - "db_table": "sentry_grouprulestatus", - }, - ), - migrations.CreateModel( - name="RuleActivity", - fields=[ ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False + "source", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=sentry.models.rule.RuleSource["ISSUE"], + default=sentry.models.rule.RuleSource["ISSUE"], ), ), ( - "user_id", + "owner_user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), - ("type", models.IntegerField()), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "rule", + "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.rule" + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" ), ), ], options={ - "db_table": "sentry_ruleactivity", + "db_table": "sentry_rule", }, ), migrations.CreateModel( - name="RuleFireHistory", + name="GroupRuleStatus", fields=[ ( "id", @@ -6573,26 +7543,19 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("event_id", sentry.db.models.fields.text.CharField(max_length=32, null=True)), - ( - "date_added", - models.DateTimeField(db_index=True, default=django.utils.timezone.now), - ), - ("notification_uuid", models.UUIDField(null=True)), + ("status", models.PositiveSmallIntegerField(default=0)), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ("last_active", models.DateTimeField(null=True)), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", + on_delete=django.db.models.deletion.CASCADE, to="sentry.group" ), ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.project", + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" ), ), ( @@ -6603,11 +7566,11 @@ class Migration(CheckedMigration): ), ], options={ - "db_table": "sentry_rulefirehistory", + "db_table": "sentry_grouprulestatus", }, ), migrations.CreateModel( - name="NotificationMessage", + name="RuleActivity", fields=[ ( "id", @@ -6615,54 +7578,23 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("error_details", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ("error_code", models.IntegerField(db_index=True, null=True)), - ("message_identifier", sentry.db.models.fields.text.CharField(null=True)), - ( - "rule_action_uuid", - sentry.db.models.fields.text.CharField(db_index=True, null=True), - ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("open_period_start", models.DateTimeField(null=True)), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - ( - "incident", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.incident" - ), - ), - ( - "parent_notification_message", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.notificationmessage", - ), - ), ( - "trigger_action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.alertruletriggeraction", + "user_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), + ("type", models.IntegerField()), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( - "rule_fire_history", + "rule", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.rulefirehistory", + on_delete=django.db.models.deletion.CASCADE, to="sentry.rule" ), ), ], options={ - "db_table": "sentry_notificationmessage", + "db_table": "sentry_ruleactivity", }, ), migrations.CreateModel( @@ -6699,7 +7631,9 @@ class Migration(CheckedMigration): ( "rule", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.rule" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.rule", ), ), ], @@ -6728,7 +7662,10 @@ class Migration(CheckedMigration): ), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("is_global", models.BooleanField(db_index=True, default=False, null=True)), + ( + "is_global", + models.BooleanField(db_index=True, default=False, null=True), + ), ( "owner_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -6776,8 +7713,11 @@ class Migration(CheckedMigration): default=sentry.deletions.models.scheduleddeletion.default_date_schedule ), ), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default={})), + ( + "actor_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ("data", models.JSONField(default=dict)), ("in_progress", models.BooleanField(default=False)), ], options={ @@ -6818,6 +7758,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -6860,16 +7802,25 @@ class Migration(CheckedMigration): ("redirect_url", models.URLField(null=True)), ("webhook_url", models.URLField(max_length=512, null=True)), ("is_alertable", models.BooleanField(default=False)), + ("is_disabled", models.BooleanField(db_default=False, default=False)), ("verify_install", models.BooleanField(default=True)), - ("events", sentry.db.models.fields.array.ArrayField(null=True)), + ( + "events", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ("overview", models.TextField(null=True)), - ("schema", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("schema", models.JSONField(default=dict)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_published", models.DateTimeField(blank=True, null=True)), ("creator_label", models.TextField(null=True)), ("popularity", models.PositiveSmallIntegerField(default=1, null=True)), - ("metadata", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("metadata", models.JSONField(default=dict)), ( "application", models.OneToOneField( @@ -6947,7 +7898,7 @@ class Migration(CheckedMigration): ), ), ("type", models.CharField(max_length=64)), - ("schema", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("schema", models.JSONField()), ( "sentry_app", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -6991,7 +7942,10 @@ class Migration(CheckedMigration): ), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "api_grant", models.OneToOneField( @@ -7032,8 +7986,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -7065,7 +8025,8 @@ class Migration(CheckedMigration): ( "api_token", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.apitoken" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.apitoken", ), ), ( @@ -7096,7 +8057,8 @@ class Migration(CheckedMigration): ( "service_hook", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.servicehook" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.servicehook", ), ), ], @@ -7116,9 +8078,17 @@ class Migration(CheckedMigration): ("type", models.SmallIntegerField()), ("dataset", models.TextField()), ("query", models.TextField()), + ( + "group_by", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=200), null=True, size=100 + ), + ), ("aggregate", models.TextField()), ("time_window", models.IntegerField()), ("resolution", models.IntegerField()), + ("extrapolation_mode", models.IntegerField(db_default=0, default=0)), + ("query_snapshot", models.JSONField(null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "environment", @@ -7147,7 +8117,9 @@ class Migration(CheckedMigration): model_name="alertrule", name="snuba_query", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.snubaquery", unique=True + on_delete=django.db.models.deletion.CASCADE, + to="sentry.snubaquery", + unique=True, ), ), migrations.CreateModel( @@ -7163,7 +8135,8 @@ class Migration(CheckedMigration): ( "snuba_query", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.snubaquery" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.snubaquery", ), ), ], @@ -7181,7 +8154,10 @@ class Migration(CheckedMigration): ), ), ("string", models.CharField(max_length=200)), - ("organization_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "last_seen", @@ -7209,13 +8185,23 @@ class Migration(CheckedMigration): ), ("slug", sentry.db.models.fields.slug.SentrySlugField()), ("name", models.CharField(max_length=64)), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), - ("idp_provisioned", models.BooleanField(db_default=False, default=False)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "idp_provisioned", + models.BooleanField(db_default=False, default=False), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -7227,7 +8213,9 @@ class Migration(CheckedMigration): model_name="rule", name="owner_team", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.team", ), ), migrations.CreateModel( @@ -7272,12 +8260,13 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("is_active", models.BooleanField(default=True)), + ("is_active", models.BooleanField(db_default=True)), ("role", models.CharField(blank=True, max_length=32, null=True)), ( "organizationmember", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organizationmember" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organizationmember", ), ), ( @@ -7316,7 +8305,8 @@ class Migration(CheckedMigration): ( "member", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organizationmember" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organizationmember", ), ), ( @@ -7346,8 +8336,14 @@ class Migration(CheckedMigration): ), ), ("is_active", models.BooleanField(default=True)), - ("reason", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "reason", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -7367,7 +8363,9 @@ class Migration(CheckedMigration): ( "team", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.team", ), ), ], @@ -7385,7 +8383,10 @@ class Migration(CheckedMigration): ), ), ("type", models.PositiveSmallIntegerField()), - ("context", sentry.db.models.fields.jsonfield.JSONField(null=True)), + ( + "context", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), ( "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -7420,7 +8421,9 @@ class Migration(CheckedMigration): ( "team", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.team", ), ), ], @@ -7443,7 +8446,10 @@ class Migration(CheckedMigration): "sentry.User", db_index=True, null=True, on_delete="SET_NULL" ), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("prev_history_date", models.DateTimeField(null=True)), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( @@ -7454,14 +8460,6 @@ class Migration(CheckedMigration): to="sentry.group", ), ), - ( - "prev_history", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.grouphistory", - ), - ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -7490,7 +8488,9 @@ class Migration(CheckedMigration): ( "team", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.team", ), ), ], @@ -7554,8 +8554,14 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -7568,19 +8574,29 @@ class Migration(CheckedMigration): "sentry.Integration", db_index=True, on_delete="CASCADE" ), ), - ("provider", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "provider", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("external_name", models.TextField()), ("external_id", models.TextField(null=True)), + ( + "source", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( "team", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.team", ), ), ], @@ -7626,9 +8642,40 @@ class Migration(CheckedMigration): model_name="alertrule", name="team", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.team" + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.team", ), ), + migrations.CreateModel( + name="TeamAvatar", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("ident", models.CharField(db_index=True, max_length=32, unique=True)), + ( + "file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True, unique=True), + ), + ("avatar_type", models.PositiveSmallIntegerField(default=0)), + ( + "team", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="avatar", + to="sentry.team", + unique=True, + ), + ), + ], + options={ + "db_table": "sentry_teamavatar", + }, + ), migrations.CreateModel( name="TeamKeyTransaction", fields=[ @@ -7642,7 +8689,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( @@ -7681,7 +8729,10 @@ class Migration(CheckedMigration): ), ("slug", models.SlugField()), ("name", models.CharField(max_length=64)), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ("org_role", models.CharField(max_length=32, null=True)), ], @@ -7728,14 +8779,18 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("email", models.EmailField(max_length=75)), + ("email", models.EmailField(max_length=200)), ( "validation_hash", models.CharField( - default=sentry.utils.security.hash.get_secure_token, max_length=32 + default=sentry.utils.security.hash.get_secure_token, + max_length=32, ), ), - ("date_hash_added", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_hash_added", + models.DateTimeField(default=django.utils.timezone.now), + ), ("is_verified", models.BooleanField(default=False)), ( "user", @@ -7767,12 +8822,50 @@ class Migration(CheckedMigration): ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "db_table": "sentry_userip", + }, + ), + migrations.CreateModel( + name="UserMergeVerificationCode", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "token", + models.CharField( + default=sentry.users.models.user_merge_verification_code.generate_token, + max_length=64, + ), + ), + ( + "expires_at", + models.DateTimeField( + default=sentry.users.models.user_merge_verification_code.generate_expires_at + ), + ), + ( + "user", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + unique=True, ), ), ], options={ - "db_table": "sentry_userip", + "db_table": "sentry_user_verification_codes_temp", }, ), migrations.CreateModel( @@ -7793,15 +8886,19 @@ class Migration(CheckedMigration): ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, null=True, on_delete="CASCADE" + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", ), ), ("key", models.CharField(max_length=64)), - ("value", sentry.db.models.fields.picklefield.PickledObjectField(editable=False)), + ("value", models.JSONField(null=True)), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -7822,7 +8919,8 @@ class Migration(CheckedMigration): ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -7869,10 +8967,12 @@ class Migration(CheckedMigration): "db_table": "sentry_userreport", "indexes": [ models.Index( - fields=["project_id", "event_id"], name="sentry_user_project_cbfd59_idx" + fields=["project_id", "event_id"], + name="sentry_user_project_cbfd59_idx", ), models.Index( - fields=["project_id", "date_added"], name="sentry_user_project_b8faaf_idx" + fields=["project_id", "date_added"], + name="sentry_user_project_b8faaf_idx", ), ], "unique_together": {("project_id", "event_id")}, @@ -7887,18 +8987,26 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ( "role", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.userrole" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.userrole", ), ), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -7946,6 +9054,8 @@ class Migration(CheckedMigration): "alerts:read", "alerts:write", "member:invite", + "project:distribution", + "org:ci", ], default=None, ), @@ -7960,7 +9070,10 @@ class Migration(CheckedMigration): ( "organization_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, null=True, on_delete="CASCADE" + "sentry.Organization", + db_index=True, + null=True, + on_delete="CASCADE", ), ), ( @@ -7974,7 +9087,8 @@ class Migration(CheckedMigration): ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -8012,7 +9126,8 @@ class Migration(CheckedMigration): ( "artifact_bundle", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.artifactbundle" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.artifactbundle", ), ), ], @@ -8020,7 +9135,8 @@ class Migration(CheckedMigration): "db_table": "sentry_artifactbundleindex", "indexes": [ models.Index( - fields=["url", "artifact_bundle"], name="sentry_arti_url_7e628a_idx" + fields=["url", "artifact_bundle"], + name="sentry_arti_url_7e628a_idx", ) ], }, @@ -8034,14 +9150,18 @@ class Migration(CheckedMigration): primary_key=True, serialize=False ), ), - ("guide_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), + ( + "guide_id", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), ("viewed_ts", models.DateTimeField(null=True)), ("dismissed_ts", models.DateTimeField(null=True)), ("useful", models.BooleanField(null=True)), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -8070,9 +9190,15 @@ class Migration(CheckedMigration): "target_object", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), - ("event", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("ip_address", models.GenericIPAddressField(null=True, unpack_ipv4=True)), - ("data", sentry.db.models.fields.gzippeddict.GzippedDictField()), + ( + "event", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "ip_address", + models.GenericIPAddressField(null=True, unpack_ipv4=True), + ), + ("data", sentry.db.models.fields.jsonfield.LegacyTextJSONField()), ("datetime", models.DateTimeField(default=django.utils.timezone.now)), ( "actor", @@ -8130,11 +9256,12 @@ class Migration(CheckedMigration): ("created_at", models.DateTimeField(default=django.utils.timezone.now)), ("last_used_at", models.DateTimeField(null=True)), ("type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("config", sentry.users.models.authenticator.AuthenticatorConfig(editable=False)), + ("config", sentry.users.models.authenticator.AuthenticatorConfig()), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -8155,20 +9282,28 @@ class Migration(CheckedMigration): ), ), ("ident", models.CharField(max_length=128)), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("last_verified", models.DateTimeField(default=django.utils.timezone.now)), - ("last_synced", models.DateTimeField(default=django.utils.timezone.now)), + ("data", models.JSONField(default=dict)), + ( + "last_verified", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "last_synced", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ( "auth_provider", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.authprovider" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.authprovider", ), ), ], @@ -8177,7 +9312,10 @@ class Migration(CheckedMigration): "indexes": [ models.Index(fields=["last_synced"], name="auth_identity_last_synced_idx") ], - "unique_together": {("auth_provider", "ident"), ("auth_provider", "user")}, + "unique_together": { + ("auth_provider", "ident"), + ("auth_provider", "user"), + }, }, ), migrations.CreateModel( @@ -8193,13 +9331,15 @@ class Migration(CheckedMigration): ( "broadcast", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.broadcast" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.broadcast", ), ), ( "user", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -8211,7 +9351,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="commit", index=models.Index( - fields=["repository_id", "date_added"], name="sentry_comm_reposit_da31f2_idx" + fields=["repository_id", "date_added"], + name="sentry_comm_reposit_da31f2_idx", ), ), migrations.AddIndex( @@ -8223,16 +9364,43 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="commit", index=models.Index( - fields=["organization_id", "date_added"], name="sentry_comm_organiz_7be514_idx" + fields=["organization_id", "date_added"], + name="sentry_comm_organiz_7be514_idx", ), ), migrations.AlterUniqueTogether( name="commit", unique_together={("repository_id", "key")}, ), - migrations.AlterUniqueTogether( - name="commitfilechange", - unique_together={("commit", "filename")}, + migrations.AddIndex( + model_name="commitcomparison", + index=models.Index( + fields=["organization_id", "head_repo_name", "head_sha"], + name="sentry_comm_organiz_d9bea9_idx", + ), + ), + migrations.AddIndex( + model_name="commitcomparison", + index=models.Index( + fields=["organization_id", "head_repo_name", "base_sha"], + name="sentry_comm_organiz_2c6634_idx", + ), + ), + migrations.AddConstraint( + model_name="commitcomparison", + constraint=models.UniqueConstraint( + condition=models.Q(("base_sha__isnull", False)), + fields=("organization_id", "head_repo_name", "head_sha", "base_sha"), + name="sentry_commitcomparison_org_comparison_uniq", + ), + ), + migrations.AddConstraint( + model_name="commitcomparison", + constraint=models.UniqueConstraint( + condition=models.Q(("base_sha__isnull", True)), + fields=("organization_id", "head_repo_name", "head_sha"), + name="sentry_commitcomparison_org_commit_uniq", + ), ), migrations.AlterUniqueTogether( name="controlfileblobindex", @@ -8242,22 +9410,29 @@ class Migration(CheckedMigration): name="controlfileblobowner", unique_together={("blob", "organization_id")}, ), + migrations.AddIndex( + model_name="dashboardrevision", + index=models.Index( + fields=["dashboard", "-date_added"], name="sentry_dashrev_dash_date_idx" + ), + ), migrations.AlterUniqueTogether( - name="dashboardfavoriteuser", - unique_together={("user_id", "dashboard")}, + name="dashboardwidgetquery", + unique_together={("widget", "order")}, ), migrations.AlterUniqueTogether( - name="dashboardwidget", - unique_together={("dashboard", "order")}, + name="dashboardfieldlink", + unique_together={("dashboard_widget_query", "field")}, ), migrations.AlterUniqueTogether( - name="dashboardwidgetquery", - unique_together={("widget", "order")}, + name="dataaccessgrant", + unique_together={("organization_id", "grant_type", "ticket_id")}, ), migrations.AddIndex( model_name="debugidartifactbundle", index=models.Index( - fields=["debug_id", "artifact_bundle"], name="sentry_debu_debug_i_8c6c44_idx" + fields=["debug_id", "artifact_bundle"], + name="sentry_debu_debug_i_8c6c44_idx", ), ), migrations.AlterUniqueTogether( @@ -8276,55 +9451,28 @@ class Migration(CheckedMigration): name="groupmeta", unique_together={("group", "key")}, ), - migrations.AlterUniqueTogether( - name="identity", - unique_together={("idp", "external_id"), ("idp", "user")}, - ), migrations.AddIndex( - model_name="incidenttrigger", + model_name="groupopenperiodactivity", index=models.Index( - fields=["alert_rule_trigger", "incident_id"], name="sentry_inci_alert_r_33da01_idx" + fields=["group_open_period", "type", "event_id"], + name="sentry_grou_group_o_4c2b45_idx", ), ), - migrations.AlterUniqueTogether( - name="incidenttrigger", - unique_together={("incident", "alert_rule_trigger")}, - ), - migrations.AlterUniqueTogether( - name="alertruletrigger", - unique_together={("alert_rule", "label")}, + migrations.AddIndex( + model_name="groupopenperiodactivity", + index=models.Index(fields=["event_id"], name="sentry_grou_event_i_9c9778_idx"), ), - migrations.AddConstraint( - model_name="notificationsettingoption", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q(("team_id__isnull", False), ("user_id__isnull", True)), - models.Q(("team_id__isnull", True), ("user_id__isnull", False)), - _connector="OR", - ), - name="notification_setting_option_team_or_user_check", - ), + migrations.AddIndex( + model_name="groupopenperiodactivity", + index=models.Index(fields=["date_added"], name="sentry_grou_date_ad_e242e5_idx"), ), migrations.AlterUniqueTogether( - name="notificationsettingoption", - unique_together={("scope_type", "scope_identifier", "user_id", "team_id", "type")}, - ), - migrations.AddConstraint( - model_name="notificationsettingprovider", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q(("team_id__isnull", False), ("user_id__isnull", True)), - models.Q(("team_id__isnull", True), ("user_id__isnull", False)), - _connector="OR", - ), - name="notification_setting_provider_team_or_user_check", - ), + name="groupredirect", + unique_together={("organization_id", "previous_short_id", "previous_project_slug")}, ), migrations.AlterUniqueTogether( - name="notificationsettingprovider", - unique_together={ - ("scope_type", "scope_identifier", "user_id", "team_id", "provider", "type") - }, + name="identity", + unique_together={("idp", "external_id"), ("idp", "user")}, ), migrations.AddConstraint( model_name="groupsearchviewstarred", @@ -8349,9 +9497,34 @@ class Migration(CheckedMigration): name="externalissue", unique_together={("organization", "integration_id", "key")}, ), - migrations.AlterUniqueTogether( - name="dashboardtombstone", - unique_together={("organization", "slug")}, + migrations.AddConstraint( + model_name="dashboardfavoriteuser", + constraint=models.UniqueConstraint( + fields=("user_id", "dashboard"), + name="sentry_dashboardfavoriteuser_user_id_dashboard_id_2c7267a5_uniq", + ), + ), + migrations.AddConstraint( + model_name="dashboardfavoriteuser", + constraint=models.UniqueConstraint( + deferrable=django.db.models.constraints.Deferrable["DEFERRED"], + fields=("user_id", "organization_id", "position"), + name="sentry_dashboardfavoriteuser_user_org_position_uniq_deferred", + ), + ), + migrations.AddIndex( + model_name="organizationcontributors", + index=models.Index( + fields=["organization_id", "date_updated"], + name="sentry_oc_org_date_upd_idx", + ), + ), + migrations.AddConstraint( + model_name="organizationcontributors", + constraint=models.UniqueConstraint( + fields=("organization_id", "integration_id", "external_identifier"), + name="sentry_orgcont_unique_org_cont", + ), ), migrations.AlterUniqueTogether( name="organizationintegration", @@ -8364,13 +9537,15 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="organizationmembermapping", index=models.Index( - fields=["organization_id", "user"], name="sentry_orga_organiz_ae9fe7_idx" + fields=["organization_id", "user"], + name="sentry_orga_organiz_ae9fe7_idx", ), ), migrations.AddIndex( model_name="organizationmembermapping", index=models.Index( - fields=["organization_id", "email"], name="sentry_orga_organiz_7de26b_idx" + fields=["organization_id", "email"], + name="sentry_orga_organiz_7de26b_idx", ), ), migrations.AlterUniqueTogether( @@ -8401,12 +9576,64 @@ class Migration(CheckedMigration): name="groupsearchviewproject", unique_together={("group_search_view", "project")}, ), + migrations.AddConstraint( + model_name="groupreaction", + constraint=models.CheckConstraint( + condition=models.Q( + ("commit__isnull", True), ("group__isnull", True), _negated=True + ), + name="commit_or_group_required", + ), + ), + migrations.AddConstraint( + model_name="groupreaction", + constraint=models.UniqueConstraint( + condition=models.Q( + ("commit__isnull", False), + ("group__isnull", False), + ("user_id__isnull", False), + ), + fields=("project", "commit", "group", "user_id"), + name="unique_user_commit_group_reaction", + ), + ), + migrations.AddConstraint( + model_name="groupreaction", + constraint=models.UniqueConstraint( + condition=models.Q( + ("commit__isnull", False), + ("group__isnull", True), + ("user_id__isnull", False), + ), + fields=("project", "commit", "user_id"), + name="unique_user_project_commit_reaction", + ), + ), + migrations.AddConstraint( + model_name="groupreaction", + constraint=models.UniqueConstraint( + condition=models.Q( + ("commit__isnull", True), + ("group__isnull", False), + ("user_id__isnull", False), + ), + fields=("project", "group", "user_id"), + name="unique_user_group_exclusion_reaction", + ), + ), migrations.AddIndex( model_name="groupopenperiod", index=models.Index( fields=["group", "date_started"], name="sentry_grou_group_i_4bffd0_idx" ), ), + migrations.AddIndex( + model_name="groupopenperiod", + index=models.Index( + models.F("data__pending_incident_detector_id"), + name="data__pend_inc_detector_id_idx", + ), + ), # would be nice but it doesn't support hints :( # django.contrib.postgres.operations.BtreeGistExtension(), SafeRunSQL( @@ -8423,12 +9650,14 @@ class Migration(CheckedMigration): sentry.models.groupopenperiod.TsTzRange( "date_started", "date_ended", - django.contrib.postgres.fields.ranges.RangeBoundary(), + django.contrib.postgres.fields.ranges.RangeBoundary( + inclusive_lower=True, inclusive_upper=True + ), ), "&&", ), ], - name="exclude_overlapping_start_end", + name="exclude_overlapping_date_start_end", ), ), migrations.AddIndex( @@ -8438,6 +9667,13 @@ class Migration(CheckedMigration): name="sentry_grou_project_dd3e95_idx", ), ), + migrations.AddIndex( + model_name="grouplink", + index=models.Index( + fields=["linked_id", "linked_type"], + name="sentry_grou_linked__ee54de_idx", + ), + ), migrations.AlterUniqueTogether( name="grouplink", unique_together={("group", "linked_type", "linked_id")}, @@ -8458,6 +9694,10 @@ class Migration(CheckedMigration): fields=["date", "project", "id"], name="sentry_grou_date_d4eb5a_idx" ), ), + migrations.AddIndex( + model_name="groupemailthread", + index=models.Index(fields=["project", "date"], name="sentry_grou_project_56b6ae_idx"), + ), migrations.AlterUniqueTogether( name="groupemailthread", unique_together={("email", "group"), ("email", "msgid")}, @@ -8475,47 +9715,42 @@ class Migration(CheckedMigration): unique_together={("organization_id", "name")}, ), migrations.AlterUniqueTogether( - name="discoversavedqueryproject", - unique_together={("project", "discover_saved_query")}, + name="dataforwarderproject", + unique_together={("data_forwarder", "project")}, ), - migrations.AddConstraint( - model_name="discoversavedquery", - constraint=models.UniqueConstraint( - condition=models.Q(("is_homepage", True)), - fields=("organization", "created_by_id", "is_homepage"), - name="unique_user_homepage_query", - ), + migrations.AlterUniqueTogether( + name="dataforwarder", + unique_together={("organization", "provider")}, ), migrations.AlterUniqueTogether( name="dashboardproject", unique_together={("project", "dashboard")}, ), - migrations.AlterUniqueTogether( - name="dashboard", - unique_together={("organization", "title")}, - ), - migrations.AlterUniqueTogether( - name="customdynamicsamplingruleproject", - unique_together={("custom_dynamic_sampling_rule", "project")}, - ), - migrations.AddIndex( - model_name="customdynamicsamplingrule", - index=models.Index( - condition=models.Q(("is_active", True)), fields=["organization"], name="org_idx" + migrations.AddConstraint( + model_name="dashboard", + constraint=models.UniqueConstraint( + condition=models.Q(("prebuilt_id__isnull", True)), + fields=("organization", "title"), + name="sentry_dashboard_organization_title_uniq", ), ), - migrations.AddIndex( - model_name="customdynamicsamplingrule", - index=models.Index( - condition=models.Q(("is_active", True)), fields=["end_date"], name="end_date_idx" + migrations.AddConstraint( + model_name="dashboard", + constraint=models.UniqueConstraint( + condition=models.Q(("prebuilt_id__isnull", False)), + fields=("organization", "prebuilt_id"), + name="sentry_dashboard_organization_prebuilt_id_uniq", ), ), - migrations.AddIndex( - model_name="customdynamicsamplingrule", - index=models.Index( - condition=models.Q(("is_active", True)), - fields=["condition_hash"], - name="condition_hash_idx", + migrations.AddConstraint( + model_name="dashboard", + constraint=models.CheckConstraint( + condition=models.Q( + ("prebuilt_id__isnull", True), + ("created_by_id__isnull", True), + _connector="OR", + ), + name="sentry_dashboard_prebuilt_null_created_by", ), ), migrations.AlterUniqueTogether( @@ -8528,10 +9763,15 @@ class Migration(CheckedMigration): fields=["project", "datetime"], name="sentry_acti_project_cd8457_idx" ), ), + migrations.AddIndex( + model_name="activity", + index=models.Index(fields=["project", "type"], name="sentry_acti_project_4b71f8_idx"), + ), migrations.AddIndex( model_name="projectartifactbundle", index=models.Index( - fields=["project_id", "artifact_bundle"], name="sentry_proj_project_f73d36_idx" + fields=["project_id", "artifact_bundle"], + name="sentry_proj_project_f73d36_idx", ), ), migrations.AlterUniqueTogether( @@ -8570,16 +9810,6 @@ class Migration(CheckedMigration): name="projectsdk", unique_together={("project", "event_type", "sdk_name")}, ), - migrations.AddConstraint( - model_name="projecttemplate", - constraint=models.UniqueConstraint( - fields=("name", "organization"), name="unique_projecttemplate_name_per_org" - ), - ), - migrations.AlterUniqueTogether( - name="projecttemplateoption", - unique_together={("project_template", "key")}, - ), migrations.AlterUniqueTogether( name="projecttransactionthresholdoverride", unique_together={("project", "transaction")}, @@ -8587,7 +9817,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="pullrequest", index=models.Index( - fields=["repository_id", "date_added"], name="sentry_pull_reposit_c429a4_idx" + fields=["repository_id", "date_added"], + name="sentry_pull_reposit_c429a4_idx", ), ), migrations.AddIndex( @@ -8597,10 +9828,36 @@ class Migration(CheckedMigration): name="sentry_pull_organiz_8aabcf_idx", ), ), + migrations.AddIndex( + model_name="pullrequest", + index=models.Index( + fields=["organization_id", "head_commit_sha"], + name="sentry_pull_organiz_502705_idx", + ), + ), migrations.AlterUniqueTogether( name="pullrequest", unique_together={("repository_id", "key")}, ), + migrations.AddIndex( + model_name="pullrequestactivity", + index=models.Index( + fields=["pull_request", "date_added"], + name="sentry_pull_pull_re_bb8fc7_idx", + ), + ), + migrations.AddIndex( + model_name="pullrequestactivity", + index=models.Index(fields=["date_added"], name="sentry_pull_date_ad_577efd_idx"), + ), + migrations.AlterUniqueTogether( + name="pullrequestactivity", + unique_together={("pull_request", "webhook_id")}, + ), + migrations.AlterUniqueTogether( + name="pullrequestattribution", + unique_together={("pull_request", "signal_type", "source")}, + ), migrations.AlterUniqueTogether( name="pullrequestcomment", unique_together={("pull_request", "comment_type")}, @@ -8612,7 +9869,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="incident", index=models.Index( - fields=["alert_rule", "type", "status"], name="sentry_inci_alert_r_24a457_idx" + fields=["alert_rule", "type", "status"], + name="sentry_inci_alert_r_24a457_idx", ), ), migrations.AlterUniqueTogether( @@ -8623,6 +9881,13 @@ class Migration(CheckedMigration): name="recentsearch", unique_together={("user_id", "organization", "type", "query_hash")}, ), + migrations.AddIndex( + model_name="groupresolution", + index=models.Index( + fields=["type", "status", "future_release_version"], + name="groupres_future_release_idx", + ), + ), migrations.AddIndex( model_name="groupenvironment", index=models.Index( @@ -8637,7 +9902,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="group", index=models.Index( - fields=["project", "first_release"], name="sentry_grou_project_4662d9_idx" + fields=["project", "first_release"], + name="sentry_grou_project_4662d9_idx", ), ), migrations.AddIndex( @@ -8682,13 +9948,15 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="group", index=models.Index( - fields=["status", "substatus", "id"], name="sentry_grou_status_48b516_idx" + fields=["status", "substatus", "id"], + name="sentry_grou_status_48b516_idx", ), ), migrations.AddIndex( model_name="group", index=models.Index( - fields=["status", "substatus", "first_seen"], name="sentry_grou_status_e07f40_idx" + fields=["status", "substatus", "first_seen"], + name="sentry_grou_status_e07f40_idx", ), ), migrations.AddIndex( @@ -8709,7 +9977,12 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="releaseartifactbundle", index=models.Index( - fields=["organization_id", "release_name", "dist_name", "artifact_bundle"], + fields=[ + "organization_id", + "release_name", + "dist_name", + "artifact_bundle", + ], name="sentry_rele_organiz_291018_idx", ), ), @@ -8750,7 +10023,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="releaseproject", index=models.Index( - fields=["project", "first_seen_transaction"], name="sentry_rele_project_3143eb_idx" + fields=["project", "first_seen_transaction"], + name="sentry_rele_project_3143eb_idx", ), ), migrations.AlterUniqueTogether( @@ -8775,7 +10049,8 @@ class Migration(CheckedMigration): models.OrderBy(models.F("patch"), descending=True), models.OrderBy(models.F("revision"), descending=True), models.OrderBy( - models.Case(models.When(prerelease="", then=1), default=0), descending=True + models.Case(models.When(prerelease="", then=1), default=0), + descending=True, ), models.OrderBy(models.F("prerelease"), descending=True), name="sentry_release_semver_by_package_idx", @@ -8790,7 +10065,8 @@ class Migration(CheckedMigration): models.OrderBy(models.F("patch"), descending=True), models.OrderBy(models.F("revision"), descending=True), models.OrderBy( - models.Case(models.When(prerelease="", then=1), default=0), descending=True + models.Case(models.When(prerelease="", then=1), default=0), + descending=True, ), models.OrderBy(models.F("prerelease"), descending=True), name="sentry_release_semver_idx", @@ -8799,19 +10075,22 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="release", index=models.Index( - fields=["organization", "build_code"], name="sentry_rele_organiz_ffeeb2_idx" + fields=["organization", "build_code"], + name="sentry_rele_organiz_ffeeb2_idx", ), ), migrations.AddIndex( model_name="release", index=models.Index( - fields=["organization", "build_number"], name="sentry_rele_organiz_6b035f_idx" + fields=["organization", "build_number"], + name="sentry_rele_organiz_6b035f_idx", ), ), migrations.AddIndex( model_name="release", index=models.Index( - fields=["organization", "date_added"], name="sentry_rele_organiz_4ed947_idx" + fields=["organization", "date_added"], + name="sentry_rele_organiz_4ed947_idx", ), ), migrations.AddIndex( @@ -8827,7 +10106,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="releaseprojectenvironment", index=models.Index( - fields=["project", "adopted", "environment"], name="sentry_rele_project_4bea8e_idx" + fields=["project", "adopted", "environment"], + name="sentry_rele_project_4bea8e_idx", ), ), migrations.AddIndex( @@ -8846,57 +10126,63 @@ class Migration(CheckedMigration): unique_together={("relocation", "file"), ("relocation", "kind")}, ), migrations.AlterUniqueTogether( - name="repositoryprojectpathconfig", - unique_together={("project", "stack_root")}, + name="projectrepository", + unique_together={("project", "repository")}, ), - migrations.AddConstraint( - model_name="rollbackorganization", - constraint=models.UniqueConstraint(fields=("organization_id",), name="unique_org"), + migrations.AddIndex( + model_name="codereviewevent", + index=models.Index(fields=["date_added"], name="sentry_code_date_ad_a2451c_idx"), ), - migrations.AddConstraint( - model_name="rollbackuser", - constraint=models.UniqueConstraint( - fields=("user_id", "organization_id"), name="unique_user_org" + migrations.AddIndex( + model_name="codereviewevent", + index=models.Index( + fields=["organization", "trigger_at"], + name="sentry_code_organiz_4f4b09_idx", ), ), - migrations.AlterUniqueTogether( - name="grouprulestatus", - unique_together={("rule", "group")}, + migrations.AddIndex( + model_name="codereviewevent", + index=models.Index( + fields=["organization", "repository", "trigger_at"], + name="sentry_code_organiz_7ba32c_idx", + ), ), migrations.AddIndex( - model_name="rulefirehistory", + model_name="codereviewevent", index=models.Index( - fields=["rule", "date_added"], name="sentry_rule_rule_id_015b9e_idx" + fields=["organization", "repository", "pr_number"], + name="sentry_code_organiz_76bbd1_idx", ), ), migrations.AddConstraint( - model_name="notificationmessage", + model_name="codereviewevent", constraint=models.UniqueConstraint( - condition=models.Q( - ("error_code__isnull", True), - ("incident__isnull", False), - ("parent_notification_message__isnull", True), - ("trigger_action__isnull", False), - ), - fields=("incident", "trigger_action"), - name="singular_parent_message_per_incident_and_trigger_action", + condition=models.Q(("trigger_id__isnull", False)), + fields=("organization", "repository", "trigger_id"), + name="unique_org_repo_trigger_id", ), ), migrations.AddConstraint( - model_name="notificationmessage", + model_name="repositoryprojectpathconfig", constraint=models.UniqueConstraint( - models.F("rule_fire_history"), - models.F("rule_action_uuid"), - django.db.models.functions.comparison.Coalesce( - "open_period_start", - models.Value(datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC)), - ), - condition=models.Q( - ("error_code__isnull", True), ("parent_notification_message__isnull", True) - ), - name="singular_parent_message_per_rule_fire_history_rule_action_open_", + fields=("project_repository", "stack_root", "source_root"), + name="sentry_repositoryproject_project_repository_id_st_b55e4224_uniq", + ), + ), + migrations.AddConstraint( + model_name="rollbackorganization", + constraint=models.UniqueConstraint(fields=("organization_id",), name="unique_org"), + ), + migrations.AddConstraint( + model_name="rollbackuser", + constraint=models.UniqueConstraint( + fields=("user_id", "organization_id"), name="unique_user_org" ), ), + migrations.AlterUniqueTogether( + name="grouprulestatus", + unique_together={("rule", "group")}, + ), migrations.AddConstraint( model_name="rulesnooze", constraint=models.CheckConstraint( @@ -8967,13 +10253,15 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="rule", index=models.Index( - fields=["project", "status", "owner_team"], name="sentry_rule_project_cce776_idx" + fields=["project", "status", "owner_team"], + name="sentry_rule_project_cce776_idx", ), ), migrations.AddIndex( model_name="rule", index=models.Index( - fields=["project", "status", "owner_user_id"], name="sentry_rule_project_6e9491_idx" + fields=["project", "status", "owner_user_id"], + name="sentry_rule_project_6e9491_idx", ), ), migrations.AddConstraint( @@ -9042,7 +10330,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="grouphistory", index=models.Index( - fields=["project", "status", "release"], name="sentry_grou_project_bbcf30_idx" + fields=["project", "status", "release"], + name="sentry_grou_project_bbcf30_idx", ), ), migrations.AddIndex( @@ -9063,7 +10352,9 @@ class Migration(CheckedMigration): model_name="externalactor", constraint=models.CheckConstraint( condition=models.Q( - ("user_id__isnull", False), ("team_id__isnull", False), _connector="OR" + ("user_id__isnull", False), + ("team_id__isnull", False), + _connector="OR", ), name="external_actor_team_or_user", ), @@ -9093,7 +10384,10 @@ class Migration(CheckedMigration): ), migrations.AlterUniqueTogether( name="useroption", - unique_together={("user", "organization_id", "key"), ("user", "project_id", "key")}, + unique_together={ + ("user", "organization_id", "key"), + ("user", "project_id", "key"), + }, ), migrations.AlterUniqueTogether( name="userpermission", diff --git a/src/sentry/migrations/0905_fix_workflow_engine_cycle.py b/src/sentry/migrations/0905_fix_workflow_engine_cycle.py deleted file mode 100644 index 17e8ffd9ecdb..000000000000 --- a/src/sentry/migrations/0905_fix_workflow_engine_cycle.py +++ /dev/null @@ -1,77 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:31 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - replaces = [ - ("sentry", "0815_add_action_cols_to_threads_model"), - ("sentry", "0817_update_notificationmessage_constraints_for_action_group_open_period"), - ] - - dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), - ("workflow_engine", "0001_squashed_0065_add_status_to_detector_and_workflow"), - ] - - operations = [ - migrations.AddField( - model_name="notificationmessage", - name="action", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" - ), - ), - migrations.AddConstraint( - model_name="notificationmessage", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q( - ("incident__isnull", False), - ("trigger_action__isnull", False), - ("rule_action_uuid__isnull", True), - ("rule_fire_history__isnull", True), - ("action__isnull", True), - ("group__isnull", True), - ("open_period_start__isnull", True), - ), - models.Q( - ("incident__isnull", True), - ("trigger_action__isnull", True), - ("rule_action_uuid__isnull", False), - ("rule_fire_history__isnull", False), - ("action__isnull", True), - ("group__isnull", True), - ), - models.Q( - ("incident__isnull", True), - ("trigger_action__isnull", True), - ("rule_action_uuid__isnull", True), - ("rule_fire_history__isnull", True), - ("action__isnull", False), - ("group__isnull", False), - ), - _connector="OR", - ), - name="notification_type_mutual_exclusivity", - ), - ), - ] diff --git a/src/sentry/migrations/0906_django_arrayfield_users.py b/src/sentry/migrations/0906_django_arrayfield_users.py deleted file mode 100644 index efddabc8405e..000000000000 --- a/src/sentry/migrations/0906_django_arrayfield_users.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 20:20 - -import django.contrib.postgres.fields -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0905_fix_workflow_engine_cycle"), - ] - - operations = [ - migrations.AlterField( - model_name="identity", - name="scopes", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="userrole", - name="permissions", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - ] diff --git a/src/sentry/migrations/0907_sentry_apps_array.py b/src/sentry/migrations/0907_sentry_apps_array.py deleted file mode 100644 index 71c32086f31b..000000000000 --- a/src/sentry/migrations/0907_sentry_apps_array.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 20:57 - -import django.contrib.postgres.fields -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0906_django_arrayfield_users"), - ] - - operations = [ - migrations.AlterField( - model_name="sentryapp", - name="events", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="servicehook", - name="events", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - ] diff --git a/src/sentry/migrations/0908_increase_email_field_length.py b/src/sentry/migrations/0908_increase_email_field_length.py deleted file mode 100644 index d08bea186bbc..000000000000 --- a/src/sentry/migrations/0908_increase_email_field_length.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 21:42 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0907_sentry_apps_array"), - ] - - operations = [ - migrations.AlterField( - model_name="user", - name="email", - field=models.EmailField(blank=True, max_length=200), - ), - ] diff --git a/src/sentry/migrations/0909_django_array_field_not_release.py b/src/sentry/migrations/0909_django_array_field_not_release.py deleted file mode 100644 index 60331d9a17e4..000000000000 --- a/src/sentry/migrations/0909_django_array_field_not_release.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-22 13:49 - -import django.contrib.postgres.fields -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0908_increase_email_field_length"), - ] - - operations = [ - migrations.AlterField( - model_name="apiapplication", - name="scopes", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="dashboardwidgetquery", - name="fields", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="dashboardwidgetqueryondemand", - name="spec_hashes", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="datasecrecywaiver", - name="zendesk_tickets", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="groupsearchview", - name="environments", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - migrations.AlterField( - model_name="repository", - name="languages", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - ] diff --git a/src/sentry/migrations/0910_make_organizationmemberteam_is_active_default.py b/src/sentry/migrations/0910_make_organizationmemberteam_is_active_default.py deleted file mode 100644 index a0c365eebb45..000000000000 --- a/src/sentry/migrations/0910_make_organizationmemberteam_is_active_default.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 20:55 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0909_django_array_field_not_release"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationmemberteam", - name="is_active", - field=models.BooleanField(db_default=True), - ), - ] diff --git a/src/sentry/migrations/0911_increase_email_model_email_field_length.py b/src/sentry/migrations/0911_increase_email_model_email_field_length.py deleted file mode 100644 index d60fd010621e..000000000000 --- a/src/sentry/migrations/0911_increase_email_model_email_field_length.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 23:05 - -from django.db import migrations, models - -import sentry.db.models.fields.citext -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - # Disabled: this migration changes the length of indexed columns, which our - # safety framework now blocks. The migration has already been applied in - # production, so it is safe to skip the check here. - checked = False - - dependencies = [ - ("sentry", "0910_make_organizationmemberteam_is_active_default"), - ] - - operations = [ - migrations.AlterField( - model_name="email", - name="email", - field=sentry.db.models.fields.citext.CIEmailField(max_length=200, unique=True), - ), - migrations.AlterField( - model_name="useremail", - name="email", - field=models.EmailField(max_length=200), - ), - ] diff --git a/src/sentry/migrations/0912_make_organizationmemberteam_replica_is_active_true.py b/src/sentry/migrations/0912_make_organizationmemberteam_replica_is_active_true.py deleted file mode 100644 index c53dac3aa280..000000000000 --- a/src/sentry/migrations/0912_make_organizationmemberteam_replica_is_active_true.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-22 17:58 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0911_increase_email_model_email_field_length"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationmemberteamreplica", - name="is_active", - field=models.BooleanField(db_default=True), - ), - ] diff --git a/src/sentry/migrations/0913_split_discover_dataset_dashboards_self_hosted.py b/src/sentry/migrations/0913_split_discover_dataset_dashboards_self_hosted.py deleted file mode 100644 index da6731639608..000000000000 --- a/src/sentry/migrations/0913_split_discover_dataset_dashboards_self_hosted.py +++ /dev/null @@ -1,180 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-20 17:45 - -from enum import Enum - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps -from django.db.models import Q - -from sentry.discover.dashboard_widget_split import _get_and_save_split_decision_for_dashboard_widget -from sentry.models.dashboard_widget import TypesClass -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - - -class DashboardWidgetTypes(TypesClass): - DISCOVER = 0 - """ - Old way of accessing error events and transaction events simultaneously @deprecated. Use ERROR_EVENTS or TRANSACTION_LIKE instead. - """ - ISSUE = 1 - RELEASE_HEALTH = 2 - METRICS = 3 - ERROR_EVENTS = 100 - """ - Error side of the split from Discover. - """ - TRANSACTION_LIKE = 101 - """ - This targets transaction-like data from the split from discover. It may either use 'Transactions' events or 'PerformanceMetrics' depending on on-demand, MEP metrics, etc. - """ - SPANS = 102 - LOGS = 103 - """ - These represent the logs trace item type on the EAP dataset. - """ - - TYPES = [ - (DISCOVER, "discover"), - (ISSUE, "issue"), - ( - RELEASE_HEALTH, - "metrics", - ), - (ERROR_EVENTS, "error-events"), - (TRANSACTION_LIKE, "transaction-like"), - (SPANS, "spans"), - (LOGS, "logs"), - ] - TYPE_NAMES = [t[1] for t in TYPES] - - -class DatasetSourcesTypes(Enum): - """ - Ambiguous queries that haven't been or couldn't be categorized into a - specific dataset. - """ - - UNKNOWN = 0 - """ - Dataset inferred by either running the query or using heuristics. - """ - INFERRED = 1 - """ - Canonical dataset, user explicitly selected it. - """ - USER = 2 - """ - Was an ambiguous dataset forced to split (i.e. we picked a default) - """ - FORCED = 3 - """ - Dataset inferred by split script, version 1 - """ - SPLIT_VERSION_1 = 4 - """ - Dataset inferred by split script, version 2 - """ - SPLIT_VERSION_2 = 5 - - @classmethod - def as_choices(cls) -> tuple[tuple[int, str], ...]: - return tuple((source.value, source.name.lower()) for source in cls) - - @classmethod - def as_text_choices(cls) -> tuple[tuple[str, int], ...]: - return tuple((source.name.lower(), source.value) for source in cls) - - -class DashboardWidgetDisplayTypes(TypesClass): - LINE_CHART = 0 - AREA_CHART = 1 - STACKED_AREA_CHART = 2 - BAR_CHART = 3 - TABLE = 4 - BIG_NUMBER = 6 - TOP_N = 7 - TYPES = [ - (LINE_CHART, "line"), - (AREA_CHART, "area"), - (STACKED_AREA_CHART, "stacked_area"), - (BAR_CHART, "bar"), - (TABLE, "table"), - (BIG_NUMBER, "big_number"), - (TOP_N, "top_n"), - ] - TYPE_NAMES = [t[1] for t in TYPES] - - -def split_discover_dataset_dashboards_self_hosted( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - DashboardWidgetQuery = apps.get_model("sentry", "DashboardWidgetQuery") - catch_all_unsplit_widgets = Q( - widget__widget_type=DashboardWidgetTypes.DISCOVER, - ) & ~Q( - widget__discover_widget_split__in=[ - DashboardWidgetTypes.ERROR_EVENTS, - DashboardWidgetTypes.TRANSACTION_LIKE, - ] - ) - - queryset = DashboardWidgetQuery.objects.filter( - catch_all_unsplit_widgets, - ).select_related("widget__dashboard__organization") - - for widget_query in RangeQuerySetWrapperWithProgressBar(queryset): - try: - _get_and_save_split_decision_for_dashboard_widget(widget_query, dry_run=False) - except Exception: - widget_query.widget.discover_widget_split = DashboardWidgetTypes.ERROR_EVENTS - widget_query.widget.dataset_source = DatasetSourcesTypes.UNKNOWN.value - widget_query.widget.save() - - -def reverse_split_discover_dataset_dashboards_self_hosted( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - DashboardWidgetQuery = apps.get_model("sentry", "DashboardWidgetQuery") - all_split_widgets = Q( - widget__discover_widget_split__in=[ - DashboardWidgetTypes.ERROR_EVENTS, - DashboardWidgetTypes.TRANSACTION_LIKE, - ] - ) - - queryset = DashboardWidgetQuery.objects.filter(all_split_widgets) - - for widget_query in RangeQuerySetWrapperWithProgressBar(queryset): - widget_query.widget.discover_widget_split = None - widget_query.widget.dataset_source = DatasetSourcesTypes.UNKNOWN.value - widget_query.widget.save() - - -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 = True - - dependencies = [ - ("sentry", "0912_make_organizationmemberteam_replica_is_active_true"), - ] - - operations = [ - migrations.RunPython( - split_discover_dataset_dashboards_self_hosted, - reverse_code=reverse_split_discover_dataset_dashboards_self_hosted, - hints={"tables": ["sentry_dashboardwidget"]}, - ) - ] diff --git a/src/sentry/migrations/0914_increase_orgmember_user_email_max_length.py b/src/sentry/migrations/0914_increase_orgmember_user_email_max_length.py deleted file mode 100644 index b8327eeba39e..000000000000 --- a/src/sentry/migrations/0914_increase_orgmember_user_email_max_length.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-22 22:17 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0913_split_discover_dataset_dashboards_self_hosted"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationmember", - name="user_email", - field=models.CharField(blank=True, max_length=200, null=True), - ), - ] diff --git a/src/sentry/migrations/0915_add_user_email_unique_column.py b/src/sentry/migrations/0915_add_user_email_unique_column.py deleted file mode 100644 index 3b572cabb70b..000000000000 --- a/src/sentry/migrations/0915_add_user_email_unique_column.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-02 16:56 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0914_increase_orgmember_user_email_max_length"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="email_unique", - field=models.EmailField(null=True, max_length=200, unique=True), - ), - ] diff --git a/src/sentry/migrations/0916_delete_open_period_rows.py b/src/sentry/migrations/0916_delete_open_period_rows.py deleted file mode 100644 index 5abe5320f5e1..000000000000 --- a/src/sentry/migrations/0916_delete_open_period_rows.py +++ /dev/null @@ -1,49 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-02 20:17 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import bulk_delete_objects - -logger = logging.getLogger(__name__) - - -def delete_open_periods(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - GroupOpenPeriod = apps.get_model("sentry", "GroupOpenPeriod") - - while GroupOpenPeriod.objects.exists(): - ids = GroupOpenPeriod.objects.values_list("id", flat=True)[:10000] - bulk_delete_objects(GroupOpenPeriod, id__in=ids) - logger.info("Deleted open periods", extra={"count": len(ids)}) - - -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 = True - - dependencies = [ - ("sentry", "0915_add_user_email_unique_column"), - ] - - operations = [ - migrations.RunPython( - code=delete_open_periods, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_groupopenperiod"]}, - ), - ] diff --git a/src/sentry/migrations/0917_convert_org_saved_searches_to_views.py b/src/sentry/migrations/0917_convert_org_saved_searches_to_views.py deleted file mode 100644 index e87184230868..000000000000 --- a/src/sentry/migrations/0917_convert_org_saved_searches_to_views.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.1.7 on 2025-04-28 16:43 - - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def convert_org_saved_searches_to_views( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - # This migration had an error and was never run. - # See 0921_convert_org_saved_searches_to_views_rerevised.py for the correct migration. - return - - -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 = True - - dependencies = [ - ("sentry", "0916_delete_open_period_rows"), - ] - - operations = [ - migrations.RunPython( - convert_org_saved_searches_to_views, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_groupsearchview", "sentry_savedsearch"]}, - ) - ] diff --git a/src/sentry/migrations/0918_sentry_release_arrayfield.py b/src/sentry/migrations/0918_sentry_release_arrayfield.py deleted file mode 100644 index 8e7f6bf52c5f..000000000000 --- a/src/sentry/migrations/0918_sentry_release_arrayfield.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-03 21:20 - -import django.contrib.postgres.fields -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0917_convert_org_saved_searches_to_views"), - ] - - operations = [ - migrations.AlterField( - model_name="release", - name="authors", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, null=True, size=None - ), - ), - ] diff --git a/src/sentry/migrations/0919_project_slug_non_null.py b/src/sentry/migrations/0919_project_slug_non_null.py deleted file mode 100644 index 1199bf1ad5b8..000000000000 --- a/src/sentry/migrations/0919_project_slug_non_null.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-04 15:07 - -from django.db import migrations - -import sentry.db.models.fields.slug -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0918_sentry_release_arrayfield"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="slug", - field=sentry.db.models.fields.slug.SentrySlugField(max_length=100), - ), - ] diff --git a/src/sentry/migrations/0920_convert_org_saved_searches_to_views_revised.py b/src/sentry/migrations/0920_convert_org_saved_searches_to_views_revised.py deleted file mode 100644 index c3cf88fda38c..000000000000 --- a/src/sentry/migrations/0920_convert_org_saved_searches_to_views_revised.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-03 22:33 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def convert_org_saved_searches_to_views( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - # This migration had an error and was never run. - # See 0921_convert_org_saved_searches_to_views_rerevised.py for the correct migration. - return - - -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 = True - - dependencies = [ - ("sentry", "0919_project_slug_non_null"), - ] - - operations = [ - migrations.RunPython( - convert_org_saved_searches_to_views, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_groupsearchview", "sentry_savedsearch"]}, - ) - ] diff --git a/src/sentry/migrations/0921_convert_org_saved_searches_to_views_rerevised.py b/src/sentry/migrations/0921_convert_org_saved_searches_to_views_rerevised.py deleted file mode 100644 index 018413669cbf..000000000000 --- a/src/sentry/migrations/0921_convert_org_saved_searches_to_views_rerevised.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-04 21:35 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.models.savedsearch import Visibility -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - - -def convert_org_saved_searches_to_views( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - SavedSearch = apps.get_model("sentry", "SavedSearch") - GroupSearchView = apps.get_model("sentry", "GroupSearchView") - - org_saved_searches = SavedSearch.objects.filter( - visibility=Visibility.ORGANIZATION, owner_id__isnull=False - ) - - for saved_search in RangeQuerySetWrapperWithProgressBar(org_saved_searches): - matching_views = GroupSearchView.objects.filter( - organization=saved_search.organization, - user_id=saved_search.owner_id, - name=saved_search.name, - query=saved_search.query, - query_sort=saved_search.sort, - ) - - if matching_views.count() == 0: - GroupSearchView.objects.create( - organization=saved_search.organization, - user_id=saved_search.owner_id, - name=saved_search.name, - query=saved_search.query, - query_sort=saved_search.sort, - date_added=saved_search.date_added, - ) - - -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 = True - - dependencies = [ - ("sentry", "0920_convert_org_saved_searches_to_views_revised"), - ] - - operations = [ - migrations.RunPython( - convert_org_saved_searches_to_views, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_groupsearchview", "sentry_savedsearch"]}, - ) - ] diff --git a/src/sentry/migrations/0922_dashboard_starred_add_position_column_and_constraint.py b/src/sentry/migrations/0922_dashboard_starred_add_position_column_and_constraint.py deleted file mode 100644 index 690ed16c489b..000000000000 --- a/src/sentry/migrations/0922_dashboard_starred_add_position_column_and_constraint.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-02 19:31 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0921_convert_org_saved_searches_to_views_rerevised"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="dashboardfavoriteuser", - unique_together=set(), - ), - migrations.AddField( - model_name="dashboardfavoriteuser", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - migrations.AddField( - model_name="dashboardfavoriteuser", - name="position", - field=models.PositiveSmallIntegerField(null=True), - ), - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.AddConstraint( - model_name="dashboardfavoriteuser", - constraint=models.UniqueConstraint( - fields=("user_id", "dashboard"), - name="sentry_dashboardfavoriteuser_user_id_dashboard_id_2c7267a5_uniq", - ), - ), - ], - ), - ] diff --git a/src/sentry/migrations/0923_dashboard_starred_backfill_orgs.py b/src/sentry/migrations/0923_dashboard_starred_backfill_orgs.py deleted file mode 100644 index 536cb8e11a81..000000000000 --- a/src/sentry/migrations/0923_dashboard_starred_backfill_orgs.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-02 19:33 - -from typing import Any - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -def backfill_dashboard_organization(apps: Any, _schema_editor: Any) -> None: - """ - Backfill the organization field for DashboardFavoriteUser objects for existing favorites. - """ - DashboardFavoriteUser = apps.get_model("sentry", "DashboardFavoriteUser") - - batch_size = 1000 - favorites_to_update = [] - - for favorite in ( - DashboardFavoriteUser.objects.filter(organization__isnull=True) - .select_related("dashboard") - .iterator(chunk_size=batch_size) - ): - favorite.organization = favorite.dashboard.organization - favorites_to_update.append(favorite) - - if len(favorites_to_update) >= batch_size: - DashboardFavoriteUser.objects.bulk_update( - favorites_to_update, ["organization"], batch_size=batch_size - ) - favorites_to_update = [] - - # Update remaining items - if favorites_to_update: - DashboardFavoriteUser.objects.bulk_update( - favorites_to_update, ["organization"], batch_size=batch_size - ) - - -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 = True - - dependencies = [ - ("sentry", "0922_dashboard_starred_add_position_column_and_constraint"), - ] - - operations = [ - migrations.RunPython( - code=backfill_dashboard_organization, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_dashboardfavoriteuser"]}, - ), - ] diff --git a/src/sentry/migrations/0924_dashboard_add_unique_constraint_for_user_org_position.py b/src/sentry/migrations/0924_dashboard_add_unique_constraint_for_user_org_position.py deleted file mode 100644 index 05f7c6e66440..000000000000 --- a/src/sentry/migrations/0924_dashboard_add_unique_constraint_for_user_org_position.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-06 15:48 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0923_dashboard_starred_backfill_orgs"), - ] - - operations = [ - migrations.AlterField( - model_name="dashboardfavoriteuser", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - migrations.AddConstraint( - model_name="dashboardfavoriteuser", - constraint=models.UniqueConstraint( - fields=("user_id", "organization_id", "position"), - name="sentry_dashboardfavoriteuser_user_id_organization_id_position_uniq", - ), - ), - ] diff --git a/src/sentry/migrations/0925_backfill_open_periods.py b/src/sentry/migrations/0925_backfill_open_periods.py deleted file mode 100644 index 12c1c2397969..000000000000 --- a/src/sentry/migrations/0925_backfill_open_periods.py +++ /dev/null @@ -1,238 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-30 00:42 - -import logging -from collections import defaultdict -from datetime import datetime -from enum import Enum -from typing import Any - -from django.conf import settings -from django.db import DataError, IntegrityError, migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils import redis -from sentry.utils.iterators import chunked -from sentry.utils.query import RangeQuerySetWrapperWithProgressBarApprox - -logger = logging.getLogger(__name__) - -CHUNK_SIZE = 20 - - -# copied constants and enums -class ActivityType(Enum): - SET_REGRESSION = 6 - SET_RESOLVED = 1 - SET_RESOLVED_IN_RELEASE = 13 - SET_RESOLVED_BY_AGE = 15 - SET_RESOLVED_IN_COMMIT = 16 - SET_RESOLVED_IN_PULL_REQUEST = 21 - - -RESOLVED_ACTIVITY_TYPES = [ - ActivityType.SET_RESOLVED.value, - ActivityType.SET_RESOLVED_IN_RELEASE.value, - ActivityType.SET_RESOLVED_BY_AGE.value, - ActivityType.SET_RESOLVED_IN_COMMIT.value, - ActivityType.SET_RESOLVED_IN_PULL_REQUEST.value, -] - - -class GroupStatus: - UNRESOLVED = 0 - RESOLVED = 1 - - -# end copy - - -def get_open_periods_for_group( - apps: StateApps, - group_id: int, - status: int, - project_id: int, - first_seen: datetime, - activities: list[Any], - GroupOpenPeriod: Any, -) -> list[Any]: - # No activities means the group has been open since the first_seen date - if not activities: - return [ - GroupOpenPeriod( - group_id=group_id, - project_id=project_id, - date_started=first_seen, - ) - ] - - # Since activities can apparently exist from before the start date, we want to ensure the - # first open period starts at the first_seen date and ends at the first resolution activity after it. - start_index = 0 - activities_len = len(activities) - while ( - start_index < activities_len and activities[start_index].type not in RESOLVED_ACTIVITY_TYPES - ): - start_index += 1 - - open_periods = [] - regression_time: datetime | None = first_seen - for activity in activities[start_index:]: - if activity.type == ActivityType.SET_REGRESSION.value and regression_time is None: - regression_time = activity.datetime - - elif activity.type in RESOLVED_ACTIVITY_TYPES and regression_time is not None: - if activity.datetime < regression_time: - logger.warning( - "Open period has invalid start and end dates", - extra={ - "group_id": group_id, - "activity_datetime": activity.datetime, - "regression_time": regression_time, - }, - ) - return [] - - open_periods.append( - GroupOpenPeriod( - group_id=group_id, - project_id=project_id, - date_started=regression_time, - date_ended=activity.datetime, - resolution_activity=activity, - user_id=activity.user_id, - ) - ) - - regression_time = None - - # Handle currently open period if the group is unresolved - if status == GroupStatus.UNRESOLVED and regression_time is not None: - open_periods.append( - GroupOpenPeriod( - group_id=group_id, - project_id=project_id, - date_started=regression_time, - ) - ) - - return open_periods - - -def _backfill_group_open_periods( - apps: StateApps, group_data: list[tuple[int, datetime, int, int]] -) -> None: - GroupOpenPeriod = apps.get_model("sentry", "GroupOpenPeriod") - Activity = apps.get_model("sentry", "Activity") - - group_ids = [group_id for group_id, _, _, _ in group_data] - groups_with_open_periods = set( - GroupOpenPeriod.objects.filter(group_id__in=group_ids) - .values_list("group_id", flat=True) - .distinct() - ) - - group_ids = [group_id for group_id in group_ids if group_id not in groups_with_open_periods] - # Filter to REGRESSION and SET_RESOLVED_XX activties to find the bounds of each open period. - # The only UNRESOLVED activity we would care about is the first UNRESOLVED activity for the group creation, - # but we don't create an entry for that. - - activities = defaultdict(list) - - try: - for activity in Activity.objects.filter( - group_id__in=group_ids, - type__in=[ActivityType.SET_REGRESSION.value, *RESOLVED_ACTIVITY_TYPES], - ).order_by("datetime"): - # Skip activities before the group's first_seen date - if activity.datetime < activity.group.first_seen: - continue - - activities[activity.group_id].append(activity) - except Exception as e: - logger.exception( - "Error getting activities", - extra={"group_ids": group_ids, "error": e}, - ) - return - - open_periods = [] - for group_id, first_seen, status, project_id in group_data: - # Skip groups that already have open periods - if group_id in groups_with_open_periods: - continue - - open_periods.extend( - get_open_periods_for_group( - apps, - group_id, - status, - project_id, - first_seen, - activities[group_id], - GroupOpenPeriod, - ) - ) - - with transaction.atomic(router.db_for_write(GroupOpenPeriod)): - try: - GroupOpenPeriod.objects.bulk_create(open_periods) - except (IntegrityError, DataError) as e: - logger.exception( - "Error creating open period", - extra={"group_ids": group_ids, "error": e}, - ) - - -def backfill_group_open_periods(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Group = apps.get_model("sentry", "Group") - - backfill_key = "backfill_group_open_periods_from_activity_0702_1" - redis_client = redis.redis_clusters.get(settings.SENTRY_MONITORS_REDIS_CLUSTER) - - progress_id = int(redis_client.get(backfill_key) or 0) - for group_data in chunked( - RangeQuerySetWrapperWithProgressBarApprox( - Group.objects.filter(id__gt=progress_id).values_list( - "id", "first_seen", "status", "project_id" - ), - result_value_getter=lambda item: item[0], - ), - CHUNK_SIZE, - ): - logger.info( - "Processing batch for group open period backfill", - extra={"last_group_id": group_data[-1][0]}, - ) - _backfill_group_open_periods(apps, group_data) - # Save progress to redis in case we have to restart - redis_client.set(backfill_key, group_data[-1][0], ex=60 * 60 * 24 * 7) - - -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 = True - - dependencies = [ - ("sentry", "0924_dashboard_add_unique_constraint_for_user_org_position"), - ] - - operations = [ - migrations.RunPython( - backfill_group_open_periods, - migrations.RunPython.noop, - hints={"tables": ["sentry_groupopenperiod"]}, - ), - ] diff --git a/src/sentry/migrations/0926_dashboard_favorite_defer_position_constraint.py b/src/sentry/migrations/0926_dashboard_favorite_defer_position_constraint.py deleted file mode 100644 index 964730a90185..000000000000 --- a/src/sentry/migrations/0926_dashboard_favorite_defer_position_constraint.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-10 14:57 - -import django.db.models.constraints -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0925_backfill_open_periods"), - ] - - operations = [ - migrations.RemoveConstraint( - model_name="dashboardfavoriteuser", - name="sentry_dashboardfavoriteuser_user_id_organization_id_position_uniq", - ), - migrations.AddConstraint( - model_name="dashboardfavoriteuser", - constraint=models.UniqueConstraint( - deferrable=django.db.models.constraints.Deferrable["DEFERRED"], - fields=("user_id", "organization_id", "position"), - name="sentry_dashboardfavoriteuser_user_org_position_uniq_deferred", - ), - ), - ] diff --git a/src/sentry/migrations/0927_dashboard_add_unique_constraint_user_dashboard.py b/src/sentry/migrations/0927_dashboard_add_unique_constraint_user_dashboard.py deleted file mode 100644 index 427be648bf1f..000000000000 --- a/src/sentry/migrations/0927_dashboard_add_unique_constraint_user_dashboard.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-13 17:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0926_dashboard_favorite_defer_position_constraint"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AddConstraint( - model_name="dashboardfavoriteuser", - constraint=models.UniqueConstraint( - fields=("user_id", "dashboard_id"), - name="sentry_dashboardfavoriteuser_user_id_dashboard_id_2c7267a5_uniq", - ), - ) - ] - ) - ] diff --git a/src/sentry/migrations/0928_move_notifications_models.py b/src/sentry/migrations/0928_move_notifications_models.py deleted file mode 100644 index 1bf54f133085..000000000000 --- a/src/sentry/migrations/0928_move_notifications_models.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-14 16:22 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0927_dashboard_add_unique_constraint_user_dashboard"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RemoveField( - model_name="notificationactionproject", - name="action", - ), - migrations.RemoveField( - model_name="notificationactionproject", - name="project", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="action", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="group", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="incident", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="parent_notification_message", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="rule_fire_history", - ), - migrations.RemoveField( - model_name="notificationmessage", - name="trigger_action", - ), - migrations.AlterUniqueTogether( - name="notificationsettingoption", - unique_together=None, - ), - migrations.RemoveField( - model_name="notificationsettingoption", - name="user", - ), - migrations.AlterUniqueTogether( - name="notificationsettingprovider", - unique_together=None, - ), - migrations.RemoveField( - model_name="notificationsettingprovider", - name="user", - ), - migrations.DeleteModel( - name="NotificationAction", - ), - migrations.DeleteModel( - name="NotificationActionProject", - ), - migrations.DeleteModel( - name="NotificationMessage", - ), - migrations.DeleteModel( - name="NotificationSettingOption", - ), - migrations.DeleteModel( - name="NotificationSettingProvider", - ), - ] - ) - ] diff --git a/src/sentry/migrations/0929_no_pickle_authenticator.py b/src/sentry/migrations/0929_no_pickle_authenticator.py deleted file mode 100644 index 393cd5f46b68..000000000000 --- a/src/sentry/migrations/0929_no_pickle_authenticator.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-13 15:44 - -from typing import LiteralString - -from django.db import migrations - -import sentry.users.models.authenticator -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -def to_jsonb(table: LiteralString, column: LiteralString) -> SafeRunSQL: - return SafeRunSQL( - f""" - ALTER TABLE {table} ALTER COLUMN {column} TYPE jsonb USING {column}::jsonb; - """, - reverse_sql=f""" - ALTER TABLE {table} ALTER COLUMN {column} TYPE text; - """, - hints={"tables": [table]}, - ) - - -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 = True - - dependencies = [ - ("sentry", "0928_move_notifications_models"), - ] - - operations = [ - migrations.AlterField( - model_name="authenticator", - name="config", - field=sentry.users.models.authenticator.AuthenticatorConfig(), - ), - to_jsonb("auth_authenticator", "config"), - ] diff --git a/src/sentry/migrations/0930_make_open_period_range_boundary_inclusive.py b/src/sentry/migrations/0930_make_open_period_range_boundary_inclusive.py deleted file mode 100644 index 8a572505252a..000000000000 --- a/src/sentry/migrations/0930_make_open_period_range_boundary_inclusive.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-13 22:49 - -import django.contrib.postgres.constraints -from django.contrib.postgres.fields.ranges import RangeBoundary, RangeOperators -from django.db import migrations, models - -import sentry.models.groupopenperiod -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("sentry", "0929_no_pickle_authenticator"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - SafeRunSQL( - """\ - ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "exclude_overlapping_date_start_end" EXCLUDE USING GIST ("group_id" WITH =, (TSTZRANGE("date_started", "date_ended", '[]')) WITH &&); - """, - reverse_sql="ALTER TABLE sentry_groupopenperiod DROP CONSTRAINT IF EXISTS exclude_overlapping_date_start_end;", - hints={"tables": ["sentry_groupopenperiod"]}, - ), - ], - state_operations=[ - migrations.AddConstraint( - model_name="groupopenperiod", - constraint=django.contrib.postgres.constraints.ExclusionConstraint( - expressions=[ - (models.F("group"), RangeOperators.EQUAL), - ( - sentry.models.groupopenperiod.TsTzRange( - "date_started", - "date_ended", - RangeBoundary(inclusive_lower=True, inclusive_upper=True), - ), - RangeOperators.OVERLAPS, - ), - ], - name="exclude_overlapping_date_start_end", - ), - ), - ], - ), - migrations.RemoveConstraint( - model_name="groupopenperiod", - name="exclude_overlapping_start_end", - ), - ] diff --git a/src/sentry/migrations/0931_add_hit_counter_columns_to_grouptombstone.py b/src/sentry/migrations/0931_add_hit_counter_columns_to_grouptombstone.py deleted file mode 100644 index d95e10d54c0e..000000000000 --- a/src/sentry/migrations/0931_add_hit_counter_columns_to_grouptombstone.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-18 18:50 - -from django.db import migrations, models - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0930_make_open_period_range_boundary_inclusive"), - ] - - operations = [ - migrations.AddField( - model_name="grouptombstone", - name="last_seen", - field=models.DateTimeField(default=None, null=True), - ), - migrations.AddField( - model_name="grouptombstone", - name="times_seen", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(db_default=0), - ), - ] diff --git a/src/sentry/migrations/0932_update_grouptombstone_with_auto_now_add.py b/src/sentry/migrations/0932_update_grouptombstone_with_auto_now_add.py deleted file mode 100644 index a3b602f2a8e9..000000000000 --- a/src/sentry/migrations/0932_update_grouptombstone_with_auto_now_add.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-23 07:09 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0931_add_hit_counter_columns_to_grouptombstone"), - ] - - operations = [ - migrations.AlterField( - model_name="grouptombstone", - name="last_seen", - field=models.DateTimeField(auto_now_add=True, null=True), - ), - ] diff --git a/src/sentry/migrations/0933_add_has_agents_insights_flag.py b/src/sentry/migrations/0933_add_has_agents_insights_flag.py deleted file mode 100644 index fd680ef5d7e3..000000000000 --- a/src/sentry/migrations/0933_add_has_agents_insights_flag.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-23 12:46 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0932_update_grouptombstone_with_auto_now_add"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="flags", - field=bitfield.models.BitField( - [ - "has_releases", - "has_issue_alerts_targeting", - "has_transactions", - "has_alert_filters", - "has_sessions", - "has_profiles", - "has_replays", - "has_feedbacks", - "has_new_feedbacks", - "spike_protection_error_currently_active", - "spike_protection_transaction_currently_active", - "spike_protection_attachment_currently_active", - "has_minified_stack_trace", - "has_cron_monitors", - "has_cron_checkins", - "has_sourcemaps", - "has_custom_metrics", - "has_high_priority_alerts", - "has_insights_http", - "has_insights_db", - "has_insights_assets", - "has_insights_app_start", - "has_insights_screen_load", - "has_insights_vitals", - "has_insights_caches", - "has_insights_queues", - "has_insights_llm_monitoring", - "has_flags", - "has_insights_agent_monitoring", - ], - default=10, - null=True, - ), - ), - ] diff --git a/src/sentry/migrations/0934_options_nullable_value.py b/src/sentry/migrations/0934_options_nullable_value.py deleted file mode 100644 index 2f182c05eece..000000000000 --- a/src/sentry/migrations/0934_options_nullable_value.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-24 14:40 - -from django.db import migrations - -import sentry.db.models.fields.picklefield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0933_add_has_agents_insights_flag"), - ] - - operations = [ - migrations.AlterField( - model_name="controloption", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - migrations.AlterField( - model_name="option", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - migrations.AlterField( - model_name="organizationoption", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - migrations.AlterField( - model_name="projectoption", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - migrations.AlterField( - model_name="projecttemplateoption", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - migrations.AlterField( - model_name="useroption", - name="value", - field=sentry.db.models.fields.picklefield.PickledObjectField(editable=False, null=True), - ), - ] diff --git a/src/sentry/migrations/0935_drop_old_openperiod_exclusion_constraint.py b/src/sentry/migrations/0935_drop_old_openperiod_exclusion_constraint.py deleted file mode 100644 index c18f79df80da..000000000000 --- a/src/sentry/migrations/0935_drop_old_openperiod_exclusion_constraint.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-26 01:16 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("sentry", "0934_options_nullable_value"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - SafeRunSQL( - """\ - ALTER TABLE "sentry_groupopenperiod" DROP CONSTRAINT IF EXISTS "exclude_overlapping_start_end"; - """, - reverse_sql="ALTER TABLE sentry_groupopenperiod ADD CONSTRAINT exclude_overlapping_start_end EXCLUDE USING GIST (group_id WITH =, (TSTZRANGE(date_started, date_ended, '[)')) WITH &&);", - hints={"tables": ["sentry_groupopenperiod"]}, - ), - ], - state_operations=[ - migrations.RemoveConstraint( - model_name="groupopenperiod", - name="exclude_overlapping_start_end", - ), - ], - ), - ] diff --git a/src/sentry/migrations/0936_prompts_activity_index.py b/src/sentry/migrations/0936_prompts_activity_index.py deleted file mode 100644 index c20040b58b06..000000000000 --- a/src/sentry/migrations/0936_prompts_activity_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-26 17:34 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0935_drop_old_openperiod_exclusion_constraint"), - ] - - operations = [ - migrations.AddIndex( - model_name="promptsactivity", - index=models.Index( - fields=["feature", "organization_id", "project_id"], - name="sentry_prom_feature_56978d_idx", - ), - ), - ] diff --git a/src/sentry/migrations/0937_fix_defaults.py b/src/sentry/migrations/0937_fix_defaults.py deleted file mode 100644 index 2c6b93eadcd9..000000000000 --- a/src/sentry/migrations/0937_fix_defaults.py +++ /dev/null @@ -1,49 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-26 23:53 - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0936_prompts_activity_index"), - ] - - operations = [ - migrations.AlterField( - model_name="promptsactivity", - name="data", - field=sentry.db.models.fields.jsonfield.JSONField(default=dict), - ), - migrations.AlterField( - model_name="regionscheduleddeletion", - name="data", - field=sentry.db.models.fields.jsonfield.JSONField(default=dict), - ), - migrations.AlterField( - model_name="release", - name="data", - field=sentry.db.models.fields.jsonfield.JSONField(default=dict), - ), - migrations.AlterField( - model_name="scheduleddeletion", - name="data", - field=sentry.db.models.fields.jsonfield.JSONField(default=dict), - ), - ] diff --git a/src/sentry/migrations/0938_rm_eventattachment_fileid_part1.py b/src/sentry/migrations/0938_rm_eventattachment_fileid_part1.py deleted file mode 100644 index 5712ca8b734a..000000000000 --- a/src/sentry/migrations/0938_rm_eventattachment_fileid_part1.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-18 13:34 - -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", "0937_fix_defaults"), - ] - - operations = [ - SafeRemoveField( - model_name="eventattachment", - name="file_id", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/0939_rm_eventattachment_fileid_part2.py b/src/sentry/migrations/0939_rm_eventattachment_fileid_part2.py deleted file mode 100644 index b3a8687e72ba..000000000000 --- a/src/sentry/migrations/0939_rm_eventattachment_fileid_part2.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-18 13:34 - -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", "0938_rm_eventattachment_fileid_part1"), - ] - - operations = [ - SafeRemoveField( - model_name="eventattachment", - name="file_id", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/0940_auditlog_json_field.py b/src/sentry/migrations/0940_auditlog_json_field.py deleted file mode 100644 index 8b7526b7a15c..000000000000 --- a/src/sentry/migrations/0940_auditlog_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-27 15:57 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0939_rm_eventattachment_fileid_part2"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_auditlogentry", "data")], - state_operations=[ - migrations.AlterField( - model_name="auditlogentry", - name="data", - field=models.JSONField(), - ) - ], - ) - ] diff --git a/src/sentry/migrations/0941_create_temporary_verification_code_table.py b/src/sentry/migrations/0941_create_temporary_verification_code_table.py deleted file mode 100644 index 31a5bfdf5072..000000000000 --- a/src/sentry/migrations/0941_create_temporary_verification_code_table.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-01 20:14 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.users.models.user_merge_verification_code -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0940_auditlog_json_field"), - ] - - operations = [ - migrations.CreateModel( - name="UserMergeVerificationCode", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "token", - models.CharField( - default=sentry.users.models.user_merge_verification_code.generate_token, - max_length=64, - ), - ), - ( - "expires_at", - models.DateTimeField( - default=sentry.users.models.user_merge_verification_code.generate_expires_at - ), - ), - ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - unique=True, - ), - ), - ], - options={ - "db_table": "sentry_user_verification_codes_temp", - }, - ), - ] diff --git a/src/sentry/migrations/0942_dashboard_remove_extra_user_org_position_constraint.py b/src/sentry/migrations/0942_dashboard_remove_extra_user_org_position_constraint.py deleted file mode 100644 index 10a944e4f24a..000000000000 --- a/src/sentry/migrations/0942_dashboard_remove_extra_user_org_position_constraint.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-03 20:04 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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", "0941_create_temporary_verification_code_table"), - ] - - operations = [ - SafeRunSQL( - """ - ALTER TABLE sentry_dashboardfavoriteuser DROP CONSTRAINT IF EXISTS sentry_dashboardfavoriteuser_user_id_organization_id_position_u; - """, - hints={"tables": ["sentry_dashboardfavoriteuser"]}, - ), - ] diff --git a/src/sentry/migrations/0943_create_data_access_grant.py b/src/sentry/migrations/0943_create_data_access_grant.py deleted file mode 100644 index fdc1a7f7836e..000000000000 --- a/src/sentry/migrations/0943_create_data_access_grant.py +++ /dev/null @@ -1,81 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-07 20:49 - -import django.db.models.deletion -import django.utils.timezone -from django.conf import settings -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0942_dashboard_remove_extra_user_org_position_constraint"), - ] - - operations = [ - migrations.CreateModel( - name="DataAccessGrant", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organization_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", db_index=True, on_delete="CASCADE" - ), - ), - ("grant_type", models.CharField(max_length=24)), - ("ticket_id", models.CharField(max_length=64, null=True)), - ("grant_start", models.DateTimeField(default=django.utils.timezone.now)), - ("grant_end", models.DateTimeField(default=django.utils.timezone.now)), - ("revocation_date", models.DateTimeField(blank=True, null=True)), - ("revocation_reason", models.CharField(blank=True, max_length=20, null=True)), - ( - "granted_by_user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="granted_data_access_grants", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "revoked_by_user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="revoked_data_access_grants", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "db_table": "sentry_dataaccessgrant", - "unique_together": {("organization_id", "grant_type", "ticket_id")}, - }, - ), - ] diff --git a/src/sentry/migrations/0944_flags_not_null.py b/src/sentry/migrations/0944_flags_not_null.py deleted file mode 100644 index 667734e23acc..000000000000 --- a/src/sentry/migrations/0944_flags_not_null.py +++ /dev/null @@ -1,72 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-08 19:05 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0943_create_data_access_grant"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="flags", - field=bitfield.models.BitField( - [ - "has_releases", - "has_issue_alerts_targeting", - "has_transactions", - "has_alert_filters", - "has_sessions", - "has_profiles", - "has_replays", - "has_feedbacks", - "has_new_feedbacks", - "spike_protection_error_currently_active", - "spike_protection_transaction_currently_active", - "spike_protection_attachment_currently_active", - "has_minified_stack_trace", - "has_cron_monitors", - "has_cron_checkins", - "has_sourcemaps", - "has_custom_metrics", - "has_high_priority_alerts", - "has_insights_http", - "has_insights_db", - "has_insights_assets", - "has_insights_app_start", - "has_insights_screen_load", - "has_insights_vitals", - "has_insights_caches", - "has_insights_queues", - "has_insights_llm_monitoring", - "has_flags", - "has_insights_agent_monitoring", - ], - default=10, - ), - ), - migrations.AlterField( - model_name="user", - name="flags", - field=bitfield.models.BitField(["newsletter_consent_prompt"], default=0), - ), - ] diff --git a/src/sentry/migrations/0945_move_discover_models.py b/src/sentry/migrations/0945_move_discover_models.py deleted file mode 100644 index 168c2be62f35..000000000000 --- a/src/sentry/migrations/0945_move_discover_models.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-08 14:54 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0944_flags_not_null"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RemoveField( - model_name="discoversavedqueryproject", - name="discover_saved_query", - ), - migrations.AlterUniqueTogether( - name="discoversavedqueryproject", - unique_together=None, - ), - migrations.RemoveField( - model_name="discoversavedqueryproject", - name="project", - ), - migrations.DeleteModel( - name="DiscoverSavedQuery", - ), - migrations.DeleteModel( - name="DiscoverSavedQueryProject", - ), - ] - ) - ] diff --git a/src/sentry/migrations/0946_add_has_mcp_insights_flag.py b/src/sentry/migrations/0946_add_has_mcp_insights_flag.py deleted file mode 100644 index eeb92a744d6b..000000000000 --- a/src/sentry/migrations/0946_add_has_mcp_insights_flag.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-10 09:55 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0945_move_discover_models"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="flags", - field=bitfield.models.BitField( - [ - "has_releases", - "has_issue_alerts_targeting", - "has_transactions", - "has_alert_filters", - "has_sessions", - "has_profiles", - "has_replays", - "has_feedbacks", - "has_new_feedbacks", - "spike_protection_error_currently_active", - "spike_protection_transaction_currently_active", - "spike_protection_attachment_currently_active", - "has_minified_stack_trace", - "has_cron_monitors", - "has_cron_checkins", - "has_sourcemaps", - "has_custom_metrics", - "has_high_priority_alerts", - "has_insights_http", - "has_insights_db", - "has_insights_assets", - "has_insights_app_start", - "has_insights_screen_load", - "has_insights_vitals", - "has_insights_caches", - "has_insights_queues", - "has_insights_llm_monitoring", - "has_flags", - "has_insights_agent_monitoring", - "has_insights_mcp", - ], - default=10, - ), - ), - ] diff --git a/src/sentry/migrations/0947_add_dashboard_last_visited_model.py b/src/sentry/migrations/0947_add_dashboard_last_visited_model.py deleted file mode 100644 index 2c1de424ac48..000000000000 --- a/src/sentry/migrations/0947_add_dashboard_last_visited_model.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-14 14:23 - -import django.db.models.deletion -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0946_add_has_mcp_insights_flag"), - ] - - operations = [ - migrations.CreateModel( - name="DashboardLastVisited", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("last_visited", models.DateTimeField(default=django.utils.timezone.now)), - ( - "dashboard", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" - ), - ), - ( - "member", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organizationmember" - ), - ), - ], - options={ - "db_table": "sentry_dashboardlastvisited", - "constraints": [ - models.UniqueConstraint( - fields=("member_id", "dashboard_id"), - name="sentry_dashboardlastvisited_unique_last_visited_per_org_member", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/0948_ds_waiver_org_fk_not_db_constr.py b/src/sentry/migrations/0948_ds_waiver_org_fk_not_db_constr.py deleted file mode 100644 index 177ba374737d..000000000000 --- a/src/sentry/migrations/0948_ds_waiver_org_fk_not_db_constr.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-11 23:13 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0947_add_dashboard_last_visited_model"), - ] - - operations = [ - migrations.AlterField( - model_name="datasecrecywaiver", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - unique=True, - ), - ), - ] diff --git a/src/sentry/migrations/0949_add_dashboard_widget_snapshot_model.py b/src/sentry/migrations/0949_add_dashboard_widget_snapshot_model.py deleted file mode 100644 index 7cf379087bc3..000000000000 --- a/src/sentry/migrations/0949_add_dashboard_widget_snapshot_model.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-15 15:03 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0948_ds_waiver_org_fk_not_db_constr"), - ] - - operations = [ - migrations.CreateModel( - name="DashboardWidgetSnapshot", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("data", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ( - "widget", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboardwidget" - ), - ), - ], - options={ - "abstract": False, - }, - ), - ] diff --git a/src/sentry/migrations/0950_safe_del_dswaiver.py b/src/sentry/migrations/0950_safe_del_dswaiver.py deleted file mode 100644 index 56d95fbfb662..000000000000 --- a/src/sentry/migrations/0950_safe_del_dswaiver.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-14 18:38 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "0949_add_dashboard_widget_snapshot_model"), - ] - - operations = [ - SafeDeleteModel( - name="DataSecrecyWaiver", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/0951_delete_ds_waiver.py b/src/sentry/migrations/0951_delete_ds_waiver.py deleted file mode 100644 index a9c85718c1d1..000000000000 --- a/src/sentry/migrations/0951_delete_ds_waiver.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-15 17:17 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "0950_safe_del_dswaiver"), - ] - - operations = [ - SafeDeleteModel( - name="DataSecrecyWaiver", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/0952_fix_span_item_event_type_alerts.py b/src/sentry/migrations/0952_fix_span_item_event_type_alerts.py deleted file mode 100644 index 08d69aab15c9..000000000000 --- a/src/sentry/migrations/0952_fix_span_item_event_type_alerts.py +++ /dev/null @@ -1,87 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-16 15:08 - -from enum import Enum -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - - -class EventType(Enum): - ERROR = 0 - DEFAULT = 1 - TRANSACTION = 2 - TRACE_ITEM_SPAN = 3 - TRACE_ITEM_LOG = 4 - - -def fix_span_item_event_type_alerts( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - SnubaQuery = apps.get_model("sentry", "SnubaQuery") - SnubaQueryEventType = apps.get_model("sentry", "SnubaQueryEventType") - - for snuba_query in RangeQuerySetWrapperWithProgressBar( - SnubaQuery.objects.filter(dataset="events_analytics_platform") - ): - event_type_objects = SnubaQueryEventType.objects.filter(snuba_query=snuba_query) - - log_event_type: Any | None = None - span_event_type: Any | None = None - transaction_event_type: Any | None = None - - for event_type in event_type_objects: - if event_type.type == EventType.TRACE_ITEM_SPAN.value: - span_event_type = event_type - if event_type.type == EventType.TRACE_ITEM_LOG.value: - log_event_type = event_type - if event_type.type == EventType.TRANSACTION.value: - transaction_event_type = event_type - - # We have always explicitly set event type for logs, so if log event type - # exists, we know it's a log alert, so skip the rest of the logic. - if log_event_type is not None: - continue - - # If it's not a log alerts and dataset is events_analytics_platform, - # we know it's a span alert. - if span_event_type is None: - SnubaQueryEventType.objects.create( - snuba_query=snuba_query, type=EventType.TRACE_ITEM_SPAN.value - ) - - # Always delete transaction event type. - if transaction_event_type is not None: - transaction_event_type.delete() - - -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 = True - - dependencies = [ - ("sentry", "0951_delete_ds_waiver"), - ] - - operations = [ - migrations.RunPython( - fix_span_item_event_type_alerts, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_snubaquery", "sentry_snubaqueryeventtype"]}, - ), - ] diff --git a/src/sentry/migrations/0953_make_releasefiles_tti.py b/src/sentry/migrations/0953_make_releasefiles_tti.py deleted file mode 100644 index c9042691d6a1..000000000000 --- a/src/sentry/migrations/0953_make_releasefiles_tti.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-18 10:28 - -import django.db.models.functions.datetime -import django.utils.timezone -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0952_fix_span_item_event_type_alerts"), - ] - - operations = [ - migrations.AddField( - model_name="releasefile", - name="date_accessed", - field=models.DateTimeField( - db_default=django.db.models.functions.datetime.Now(), - default=django.utils.timezone.now, - ), - ), - ] diff --git a/src/sentry/migrations/0954_user_option_json_field.py b/src/sentry/migrations/0954_user_option_json_field.py deleted file mode 100644 index fe526e4965c8..000000000000 --- a/src/sentry/migrations/0954_user_option_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-24 08:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0953_make_releasefiles_tti"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_useroption", "value")], - state_operations=[ - migrations.AlterField( - model_name="useroption", - name="value", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0955_org_option_json_field.py b/src/sentry/migrations/0955_org_option_json_field.py deleted file mode 100644 index 9fad1bd0e94c..000000000000 --- a/src/sentry/migrations/0955_org_option_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-24 10:40 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0954_user_option_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_organizationoptions", "value")], - state_operations=[ - migrations.AlterField( - model_name="organizationoption", - name="value", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0956_add_group_by_to_snuba_query.py b/src/sentry/migrations/0956_add_group_by_to_snuba_query.py deleted file mode 100644 index c399dfdb5796..000000000000 --- a/src/sentry/migrations/0956_add_group_by_to_snuba_query.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-24 15:41 - -import django.contrib.postgres.fields -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0955_org_option_json_field"), - ] - - operations = [ - migrations.AddField( - model_name="snubaquery", - name="group_by", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=200), null=True, size=100 - ), - ), - ] diff --git a/src/sentry/migrations/0957_projecttemplateoption_json.py b/src/sentry/migrations/0957_projecttemplateoption_json.py deleted file mode 100644 index 8edf9c6c405b..000000000000 --- a/src/sentry/migrations/0957_projecttemplateoption_json.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-25 08:13 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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", "0956_add_group_by_to_snuba_query"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_projecttemplateoption", "value")], - state_operations=[ - migrations.AlterField( - model_name="projecttemplateoption", - name="value", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0958_base_option_json_field.py b/src/sentry/migrations/0958_base_option_json_field.py deleted file mode 100644 index 02109247d325..000000000000 --- a/src/sentry/migrations/0958_base_option_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-25 09:01 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 # < 2k entries - - dependencies = [ - ("sentry", "0957_projecttemplateoption_json"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_option", "value"), - mod.to_jsonb("sentry_controloption", "value"), - ], - state_operations=[ - migrations.AlterField( - model_name="controloption", - name="value", - field=models.JSONField(null=True), - ), - migrations.AlterField( - model_name="option", - name="value", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0959_add_has_logs_bit_to_project_model.py b/src/sentry/migrations/0959_add_has_logs_bit_to_project_model.py deleted file mode 100644 index 88f8c8a88994..000000000000 --- a/src/sentry/migrations/0959_add_has_logs_bit_to_project_model.py +++ /dev/null @@ -1,69 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-28 20:31 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0958_base_option_json_field"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="flags", - field=bitfield.models.BitField( - [ - "has_releases", - "has_issue_alerts_targeting", - "has_transactions", - "has_alert_filters", - "has_sessions", - "has_profiles", - "has_replays", - "has_feedbacks", - "has_new_feedbacks", - "spike_protection_error_currently_active", - "spike_protection_transaction_currently_active", - "spike_protection_attachment_currently_active", - "has_minified_stack_trace", - "has_cron_monitors", - "has_cron_checkins", - "has_sourcemaps", - "has_custom_metrics", - "has_high_priority_alerts", - "has_insights_http", - "has_insights_db", - "has_insights_assets", - "has_insights_app_start", - "has_insights_screen_load", - "has_insights_vitals", - "has_insights_caches", - "has_insights_queues", - "has_insights_llm_monitoring", - "has_flags", - "has_insights_agent_monitoring", - "has_insights_mcp", - "has_logs", - ], - default=10, - ), - ), - ] diff --git a/src/sentry/migrations/0960_project_option_json_field.py b/src/sentry/migrations/0960_project_option_json_field.py deleted file mode 100644 index 684cbd5d0196..000000000000 --- a/src/sentry/migrations/0960_project_option_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-29 18:54 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0959_add_has_logs_bit_to_project_model"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_projectoptions", "value")], - state_operations=[ - migrations.AlterField( - model_name="projectoption", - name="value", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0961_identity_json_field.py b/src/sentry/migrations/0961_identity_json_field.py deleted file mode 100644 index b8e76a332184..000000000000 --- a/src/sentry/migrations/0961_identity_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-01 14:44 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0960_project_option_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_identity", "data"), - mod.to_jsonb("sentry_identityprovider", "config"), - ], - state_operations=[ - migrations.AlterField( - model_name="identity", - name="data", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="identityprovider", - name="config", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0962_json_fields_too_big.py b/src/sentry/migrations/0962_json_fields_too_big.py deleted file mode 100644 index 082d9d7fc522..000000000000 --- a/src/sentry/migrations/0962_json_fields_too_big.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-04 19:01 -from typing import LiteralString - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -def to_text(table: LiteralString, column: LiteralString) -> SafeRunSQL: - return SafeRunSQL( - f""" - ALTER TABLE {table} ALTER COLUMN {column} TYPE text; - """, - reverse_sql=f""" - ALTER TABLE {table} ALTER COLUMN {column} TYPE jsonb USING {column}::jsonb; - """, - hints={"tables": [table]}, - ) - - -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 = True - - dependencies = [ - ("sentry", "0961_identity_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - to_text("sentry_auditlogentry", "data"), - to_text("sentry_projectoptions", "value"), - ], - state_operations=[ - migrations.AlterField( - model_name="auditlogentry", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(), - ), - migrations.AlterField( - model_name="projectoption", - name="value", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0963_scheduleddeletion_json_field.py b/src/sentry/migrations/0963_scheduleddeletion_json_field.py deleted file mode 100644 index 2b960d91e80b..000000000000 --- a/src/sentry/migrations/0963_scheduleddeletion_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-06 17:35 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0962_json_fields_too_big"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_regionscheduleddeletion", "data"), - mod.to_jsonb("sentry_scheduleddeletion", "data"), - ], - state_operations=[ - migrations.AlterField( - model_name="regionscheduleddeletion", - name="data", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="scheduleddeletion", - name="data", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0964_add_commitcomparison_table.py b/src/sentry/migrations/0964_add_commitcomparison_table.py deleted file mode 100644 index f95bec6df127..000000000000 --- a/src/sentry/migrations/0964_add_commitcomparison_table.py +++ /dev/null @@ -1,99 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-06 20:24 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0963_scheduleddeletion_json_field"), - ] - - operations = [ - migrations.CreateModel( - name="CommitComparison", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("head_sha", models.CharField(max_length=64)), - ("base_sha", models.CharField(max_length=64, null=True)), - ("provider", models.CharField(max_length=64, null=True)), - ("head_repo_name", models.CharField(max_length=255)), - ("base_repo_name", models.CharField(max_length=255, null=True)), - ("head_ref", models.CharField(max_length=255, null=True)), - ("base_ref", models.CharField(max_length=255, null=True)), - ("pr_number", models.PositiveIntegerField(null=True)), - ( - "base_commit", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="base_commit_set", - to="sentry.commit", - ), - ), - ( - "head_commit", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="head_commit_set", - to="sentry.commit", - ), - ), - ], - options={ - "db_table": "sentry_commitcomparison", - "indexes": [ - models.Index( - fields=["organization_id", "head_repo_name", "head_sha"], - name="sentry_comm_organiz_d9bea9_idx", - ), - models.Index( - fields=["organization_id", "head_repo_name", "base_sha"], - name="sentry_comm_organiz_2c6634_idx", - ), - ], - "constraints": [ - models.UniqueConstraint( - condition=models.Q(("base_sha__isnull", False)), - fields=("organization_id", "head_sha", "base_sha"), - name="unique_commit_comparison", - ), - models.UniqueConstraint( - condition=models.Q(("base_sha__isnull", True)), - fields=("organization_id", "head_sha"), - name="unique_single_commit", - ), - ], - }, - ), - ] diff --git a/src/sentry/migrations/0965_gzippeddict_big_tables.py b/src/sentry/migrations/0965_gzippeddict_big_tables.py deleted file mode 100644 index 7115417585fe..000000000000 --- a/src/sentry/migrations/0965_gzippeddict_big_tables.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-07 15:00 - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0964_add_commitcomparison_table"), - ] - - operations = [ - migrations.AlterField( - model_name="activity", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), - ), - migrations.AlterField( - model_name="group", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - migrations.AlterField( - model_name="rule", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - ] diff --git a/src/sentry/migrations/0966_groupopenperiod_data_pending_inc_detector_id_index.py b/src/sentry/migrations/0966_groupopenperiod_data_pending_inc_detector_id_index.py deleted file mode 100644 index 1decad68a2d9..000000000000 --- a/src/sentry/migrations/0966_groupopenperiod_data_pending_inc_detector_id_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-08 23:06 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0965_gzippeddict_big_tables"), - ] - - operations = [ - migrations.AddIndex( - model_name="groupopenperiod", - index=models.Index( - models.F("data__pending_incident_detector_id"), - name="data__pend_inc_detector_id_idx", - ), - ), - ] diff --git a/src/sentry/migrations/0967_large_tables_legacy_json_field.py b/src/sentry/migrations/0967_large_tables_legacy_json_field.py deleted file mode 100644 index c7ff361579b1..000000000000 --- a/src/sentry/migrations/0967_large_tables_legacy_json_field.py +++ /dev/null @@ -1,94 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-11 14:46 - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0966_groupopenperiod_data_pending_inc_detector_id_index"), - ] - - operations = [ - migrations.AlterField( - model_name="controlfile", - name="headers", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="externalissue", - name="metadata", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), - ), - migrations.AlterField( - model_name="featureadoption", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="file", - name="headers", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="grouphashmetadata", - name="hashing_metadata", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - migrations.AlterField( - model_name="groupinbox", - name="reason_details", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), - ), - migrations.AlterField( - model_name="organizationonboardingtask", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="projectdebugfile", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict, null=True), - ), - migrations.AlterField( - model_name="projectkey", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="promptsactivity", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="pullrequestcomment", - name="reactions", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - migrations.AlterField( - model_name="release", - name="data", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - migrations.AlterField( - model_name="repository", - name="config", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(default=dict), - ), - ] diff --git a/src/sentry/migrations/0968_delete_dashboardwidgetsnapshot_db_constraint.py b/src/sentry/migrations/0968_delete_dashboardwidgetsnapshot_db_constraint.py deleted file mode 100644 index 0dd7751557eb..000000000000 --- a/src/sentry/migrations/0968_delete_dashboardwidgetsnapshot_db_constraint.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-25 16:11 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0967_large_tables_legacy_json_field"), - ] - - operations = [ - migrations.AlterField( - model_name="dashboardwidgetsnapshot", - name="widget", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.dashboardwidget", - ), - ), - ] diff --git a/src/sentry/migrations/0969_safe_del_dashboardwidgetsnapshot.py b/src/sentry/migrations/0969_safe_del_dashboardwidgetsnapshot.py deleted file mode 100644 index b1a72451852a..000000000000 --- a/src/sentry/migrations/0969_safe_del_dashboardwidgetsnapshot.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-25 16:14 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "0968_delete_dashboardwidgetsnapshot_db_constraint"), - ] - - operations = [ - SafeDeleteModel( - name="DashboardWidgetSnapshot", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/0970_remove_pullrequestcommit_fk_constraint.py b/src/sentry/migrations/0970_remove_pullrequestcommit_fk_constraint.py deleted file mode 100644 index 4322929faf9d..000000000000 --- a/src/sentry/migrations/0970_remove_pullrequestcommit_fk_constraint.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-28 00:57 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0969_safe_del_dashboardwidgetsnapshot"), - ] - - operations = [ - migrations.AlterField( - model_name="pullrequestcommit", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" - ), - ), - ] diff --git a/src/sentry/migrations/0971_make_dashboard_widget_order_optional_field.py b/src/sentry/migrations/0971_make_dashboard_widget_order_optional_field.py deleted file mode 100644 index f6fb32c43fed..000000000000 --- a/src/sentry/migrations/0971_make_dashboard_widget_order_optional_field.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-03 14:44 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0970_remove_pullrequestcommit_fk_constraint"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="dashboardwidget", - unique_together=set(), - ), - migrations.AlterField( - model_name="dashboardwidget", - name="order", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ] diff --git a/src/sentry/migrations/0972_commit_comparison_drop_unique.py b/src/sentry/migrations/0972_commit_comparison_drop_unique.py deleted file mode 100644 index 46d8f2dff9de..000000000000 --- a/src/sentry/migrations/0972_commit_comparison_drop_unique.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-03 17:01 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0971_make_dashboard_widget_order_optional_field"), - ] - - operations = [ - migrations.RemoveConstraint( - model_name="commitcomparison", - name="unique_commit_comparison", - ), - migrations.RemoveConstraint( - model_name="commitcomparison", - name="unique_single_commit", - ), - ] diff --git a/src/sentry/migrations/0973_safe_del_dashboardwidgetsnapshot.py b/src/sentry/migrations/0973_safe_del_dashboardwidgetsnapshot.py deleted file mode 100644 index 7e6c6fcb73db..000000000000 --- a/src/sentry/migrations/0973_safe_del_dashboardwidgetsnapshot.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-04 15:41 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "0972_commit_comparison_drop_unique"), - ] - - operations = [ - SafeDeleteModel( - name="DashboardWidgetSnapshot", - deletion_action=DeletionAction.DELETE, - ) - ] diff --git a/src/sentry/migrations/0974_hc_json_field.py b/src/sentry/migrations/0974_hc_json_field.py deleted file mode 100644 index 0a4bef72ad1d..000000000000 --- a/src/sentry/migrations/0974_hc_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-14 15:26 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0973_safe_del_dashboardwidgetsnapshot"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_controloutbox", "payload"), - mod.to_jsonb("sentry_regionoutbox", "payload"), - ], - state_operations=[ - migrations.AlterField( - model_name="controloutbox", - name="payload", - field=models.JSONField(null=True), - ), - migrations.AlterField( - model_name="regionoutbox", - name="payload", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0975_grouplink_json_field.py b/src/sentry/migrations/0975_grouplink_json_field.py deleted file mode 100644 index 99686d843fa8..000000000000 --- a/src/sentry/migrations/0975_grouplink_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-08 18:41 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0974_hc_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_grouplink", "data")], - state_operations=[ - migrations.AlterField( - model_name="grouplink", - name="data", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0976_sentry_app_json_field.py b/src/sentry/migrations/0976_sentry_app_json_field.py deleted file mode 100644 index 0684c1e08ab8..000000000000 --- a/src/sentry/migrations/0976_sentry_app_json_field.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-09 15:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0975_grouplink_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_sentryapp", "metadata"), - mod.to_jsonb("sentry_sentryapp", "schema"), - mod.to_jsonb("sentry_sentryappcomponent", "schema"), - ], - state_operations=[ - migrations.AlterField( - model_name="sentryapp", - name="metadata", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="sentryapp", - name="schema", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="sentryappcomponent", - name="schema", - field=models.JSONField(), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0977_commitfilechange_break_commit_fk.py b/src/sentry/migrations/0977_commitfilechange_break_commit_fk.py deleted file mode 100644 index bc7b5e2f13b0..000000000000 --- a/src/sentry/migrations/0977_commitfilechange_break_commit_fk.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-09 22:25 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0976_sentry_app_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AlterField( - model_name="commitfilechange", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.commit", - ), - ) - ], - state_operations=[ - migrations.RemoveField( - model_name="commitfilechange", - name="commit", - ), - migrations.AddField( - model_name="commitfilechange", - name="commit_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - migrations.AlterUniqueTogether( - name="commitfilechange", - unique_together={("commit_id", "filename")}, - ), - ], - ), - ] diff --git a/src/sentry/migrations/0978_break_commit_fks.py b/src/sentry/migrations/0978_break_commit_fks.py deleted file mode 100644 index b90eae0d9b01..000000000000 --- a/src/sentry/migrations/0978_break_commit_fks.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-10 21:38 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0977_commitfilechange_break_commit_fk"), - ] - - operations = [ - migrations.AlterField( - model_name="commitcomparison", - name="base_commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="base_commit_set", - to="sentry.commit", - ), - ), - migrations.AlterField( - model_name="commitcomparison", - name="head_commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="head_commit_set", - to="sentry.commit", - ), - ), - migrations.AlterField( - model_name="releasecommit", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" - ), - ), - migrations.AlterField( - model_name="releaseheadcommit", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to="sentry.commit" - ), - ), - ] diff --git a/src/sentry/migrations/0979_add_apiapplication_version.py b/src/sentry/migrations/0979_add_apiapplication_version.py deleted file mode 100644 index 1d0c0ffbc49a..000000000000 --- a/src/sentry/migrations/0979_add_apiapplication_version.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - # Introduce ApiApplication.version; default for new rows set to 0 (legacy) - is_post_deployment = False - - dependencies = [ - ("sentry", "0978_break_commit_fks"), - ] - - operations = [ - migrations.AddField( - model_name="apiapplication", - name="version", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=0, db_index=True, db_default=0 - ), - ), - # Keep default for new rows as 0 (legacy). Later we will bump default to 1 when ready. - ] diff --git a/src/sentry/migrations/0980_integrations_json_field.py b/src/sentry/migrations/0980_integrations_json_field.py deleted file mode 100644 index 0c9cf65a1711..000000000000 --- a/src/sentry/migrations/0980_integrations_json_field.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-10 16:41 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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", "0979_add_apiapplication_version"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_docintegration", "metadata"), - mod.to_jsonb("sentry_integration", "metadata"), - mod.to_jsonb("sentry_organizationintegration", "config"), - ], - state_operations=[ - migrations.AlterField( - model_name="docintegration", - name="metadata", - field=models.JSONField(default=dict, null=True), - ), - migrations.AlterField( - model_name="integration", - name="metadata", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="organizationintegration", - name="config", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0981_add_dashboard_migration_fields.py b/src/sentry/migrations/0981_add_dashboard_migration_fields.py deleted file mode 100644 index f5477747bbf9..000000000000 --- a/src/sentry/migrations/0981_add_dashboard_migration_fields.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 19:20 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0980_integrations_json_field"), - ] - - operations = [ - migrations.AddField( - model_name="dashboardwidget", - name="changed_reason", - field=models.JSONField(null=True), - ), - migrations.AddField( - model_name="dashboardwidget", - name="widget_snapshot", - field=models.JSONField(null=True), - ), - ] diff --git a/src/sentry/migrations/0982_redirect_fk_and_date.py b/src/sentry/migrations/0982_redirect_fk_and_date.py deleted file mode 100644 index 91b0a60a29e6..000000000000 --- a/src/sentry/migrations/0982_redirect_fk_and_date.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 17:44 - -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0981_add_dashboard_migration_fields"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AlterField( - model_name="groupredirect", - name="group_id", - field=sentry.db.models.fields.BoundedBigIntegerField(db_index=True), - ), - migrations.AddField( - model_name="groupredirect", - name="date_added", - field=models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ], - state_operations=[ - migrations.RemoveField( - model_name="groupredirect", - name="group_id", - ), - migrations.AddField( - model_name="groupredirect", - name="date_added", - field=models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - migrations.AddField( - model_name="groupredirect", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - related_name="primary_group_of_redirect", - to="sentry.group", - ), - ), - ], - ), - ] diff --git a/src/sentry/migrations/0983_create_groupopenperiodactivity_table.py b/src/sentry/migrations/0983_create_groupopenperiodactivity_table.py deleted file mode 100644 index 57b977d49552..000000000000 --- a/src/sentry/migrations/0983_create_groupopenperiodactivity_table.py +++ /dev/null @@ -1,62 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-15 21:15 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.models.groupopenperiodactivity -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0982_redirect_fk_and_date"), - ] - - operations = [ - migrations.CreateModel( - name="GroupOpenPeriodActivity", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("type", models.IntegerField()), - ("value", models.IntegerField(null=True)), - ( - "notification_uuid", - models.UUIDField( - default=sentry.models.groupopenperiodactivity.generate_random_uuid - ), - ), - ( - "group_open_period", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.groupopenperiod" - ), - ), - ], - options={ - "db_table": "sentry_groupopenperiodactivity", - }, - ), - ] diff --git a/src/sentry/migrations/0984_authprovider_json_field.py b/src/sentry/migrations/0984_authprovider_json_field.py deleted file mode 100644 index ac00886073d0..000000000000 --- a/src/sentry/migrations/0984_authprovider_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-15 20:02 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0983_create_groupopenperiodactivity_table"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_authprovider", "config"), - mod.to_jsonb("sentry_authproviderreplica", "config"), - ], - state_operations=[ - migrations.AlterField( - model_name="authprovider", - name="config", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="authproviderreplica", - name="config", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0985_add_timestamp_to_grouphash_table.py b/src/sentry/migrations/0985_add_timestamp_to_grouphash_table.py deleted file mode 100644 index c694ffc4c242..000000000000 --- a/src/sentry/migrations/0985_add_timestamp_to_grouphash_table.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-16 16:05 - -import django.utils.timezone -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0984_authprovider_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AddField( - model_name="grouphash", - name="date_added", - field=models.DateTimeField(null=True), - ), - ], - state_operations=[ - migrations.AddField( - model_name="grouphash", - name="date_added", - field=models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ], - ), - ] diff --git a/src/sentry/migrations/0986_add_future_release_version_to_groupresolution.py b/src/sentry/migrations/0986_add_future_release_version_to_groupresolution.py deleted file mode 100644 index 54bfa5365321..000000000000 --- a/src/sentry/migrations/0986_add_future_release_version_to_groupresolution.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-16 21:55 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0985_add_timestamp_to_grouphash_table"), - ] - - operations = [ - migrations.AddField( - model_name="groupresolution", - name="future_release_version", - field=models.CharField(blank=True, max_length=250, null=True), - ), - migrations.AddIndex( - model_name="groupresolution", - index=models.Index( - fields=["type", "status", "future_release_version"], - name="groupres_future_release_idx", - ), - ), - ] diff --git a/src/sentry/migrations/0987_authidentity_json_field.py b/src/sentry/migrations/0987_authidentity_json_field.py deleted file mode 100644 index e578c9a97f0c..000000000000 --- a/src/sentry/migrations/0987_authidentity_json_field.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-17 13:49 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("sentry", "0986_add_future_release_version_to_groupresolution"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - mod.to_jsonb("sentry_authidentity", "data"), - mod.to_jsonb("sentry_authidentityreplica", "data"), - ], - state_operations=[ - migrations.AlterField( - model_name="authidentity", - name="data", - field=models.JSONField(default=dict), - ), - migrations.AlterField( - model_name="authidentityreplica", - name="data", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0988_data_forwarding.py b/src/sentry/migrations/0988_data_forwarding.py deleted file mode 100644 index 7f244f758452..000000000000 --- a/src/sentry/migrations/0988_data_forwarding.py +++ /dev/null @@ -1,103 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-17 16:03 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0987_authidentity_json_field"), - ] - - operations = [ - migrations.CreateModel( - name="DataForwarder", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("is_enabled", models.BooleanField(default=True)), - ("enroll_new_projects", models.BooleanField(default=False)), - ("provider", models.CharField(max_length=64)), - ("config", models.JSONField(default=dict)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "sentry_dataforwarder", - }, - ), - migrations.CreateModel( - name="DataForwarderProject", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("is_enabled", models.BooleanField(default=True)), - ("overrides", models.JSONField(default=dict)), - ( - "data_forwarder", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="projects", - to="sentry.dataforwarder", - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_dataforwarderproject", - "unique_together": {("data_forwarder", "project")}, - }, - ), - migrations.AddField( - model_name="dataforwarder", - name="enrolled_projects", - field=models.ManyToManyField( - related_name="data_forwarders", - through="sentry.DataForwarderProject", - to="sentry.project", - ), - ), - migrations.AlterUniqueTogether( - name="dataforwarder", - unique_together={("organization", "provider")}, - ), - ] diff --git a/src/sentry/migrations/0989_add_release_date_added_idx.py b/src/sentry/migrations/0989_add_release_date_added_idx.py deleted file mode 100644 index 0a31c3a0046b..000000000000 --- a/src/sentry/migrations/0989_add_release_date_added_idx.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-17 22:32 - -import django.utils.timezone -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0988_data_forwarding"), - ] - - operations = [ - migrations.AlterField( - model_name="release", - name="date_added", - field=models.DateTimeField(db_index=True, default=django.utils.timezone.now), - ), - ] diff --git a/src/sentry/migrations/0990_groupowner_json_field.py b/src/sentry/migrations/0990_groupowner_json_field.py deleted file mode 100644 index 3c7a816418c6..000000000000 --- a/src/sentry/migrations/0990_groupowner_json_field.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-17 17:44 - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0989_add_release_date_added_idx"), - ] - - operations = [ - migrations.AlterField( - model_name="groupowner", - name="context", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - ] diff --git a/src/sentry/migrations/0991_projectownership_json_field.py b/src/sentry/migrations/0991_projectownership_json_field.py deleted file mode 100644 index 4d9ca53f664a..000000000000 --- a/src/sentry/migrations/0991_projectownership_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-19 15:19 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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", "0990_groupowner_json_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_projectownership", "schema")], - state_operations=[ - migrations.AlterField( - model_name="projectownership", - name="schema", - field=models.JSONField(null=True), - ), - ], - ) - ] diff --git a/src/sentry/migrations/0992_latestrepoerelease_indexes.py b/src/sentry/migrations/0992_latestrepoerelease_indexes.py deleted file mode 100644 index aebca12eb168..000000000000 --- a/src/sentry/migrations/0992_latestrepoerelease_indexes.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-26 21:30 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0991_projectownership_json_field"), - ] - - operations = [ - migrations.AlterField( - model_name="latestreporeleaseenvironment", - name="commit_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True, null=True), - ), - migrations.AlterField( - model_name="latestreporeleaseenvironment", - name="environment_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - migrations.AlterField( - model_name="latestreporeleaseenvironment", - name="release_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ] diff --git a/src/sentry/migrations/0993_add_event_id_to_grouphash_metadata.py b/src/sentry/migrations/0993_add_event_id_to_grouphash_metadata.py deleted file mode 100644 index 2b817f66b1e0..000000000000 --- a/src/sentry/migrations/0993_add_event_id_to_grouphash_metadata.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-29 17:55 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0992_latestrepoerelease_indexes"), - ] - - operations = [ - migrations.AddField( - model_name="grouphashmetadata", - name="event_id", - field=models.CharField(max_length=32, null=True), - ), - ] diff --git a/src/sentry/migrations/0994_add_groupreaction_table.py b/src/sentry/migrations/0994_add_groupreaction_table.py deleted file mode 100644 index 7c536f6a4b4b..000000000000 --- a/src/sentry/migrations/0994_add_groupreaction_table.py +++ /dev/null @@ -1,112 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-29 23:51 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0993_add_event_id_to_grouphash_metadata"), - ] - - operations = [ - migrations.CreateModel( - name="GroupReaction", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("reaction", models.BooleanField()), - ( - "user_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ("source", models.PositiveSmallIntegerField()), - ( - "commit", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.commit", - ), - ), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_groupreaction", - "constraints": [ - models.CheckConstraint( - condition=models.Q( - ("commit__isnull", True), ("group__isnull", True), _negated=True - ), - name="commit_or_group_required", - ), - models.UniqueConstraint( - condition=models.Q( - ("commit__isnull", False), - ("group__isnull", False), - ("user_id__isnull", False), - ), - fields=("project", "commit", "group", "user_id"), - name="unique_user_commit_group_reaction", - ), - models.UniqueConstraint( - condition=models.Q( - ("commit__isnull", False), - ("group__isnull", True), - ("user_id__isnull", False), - ), - fields=("project", "commit", "user_id"), - name="unique_user_project_commit_reaction", - ), - models.UniqueConstraint( - condition=models.Q( - ("commit__isnull", True), - ("group__isnull", False), - ("user_id__isnull", False), - ), - fields=("project", "group", "user_id"), - name="unique_user_group_exclusion_reaction", - ), - ], - }, - ), - ] diff --git a/src/sentry/migrations/0995_add_date_updated_to_grouphash_metadata.py b/src/sentry/migrations/0995_add_date_updated_to_grouphash_metadata.py deleted file mode 100644 index dc2edb4b46c8..000000000000 --- a/src/sentry/migrations/0995_add_date_updated_to_grouphash_metadata.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-30 16:52 - -import django.utils.timezone -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0994_add_groupreaction_table"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AddField( - model_name="grouphashmetadata", - name="date_updated", - field=models.DateTimeField(null=True), - ), - ], - state_operations=[ - migrations.AddField( - model_name="grouphashmetadata", - name="date_updated", - field=models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ], - ), - ] diff --git a/src/sentry/migrations/0996_add_dashboard_field_link_model.py b/src/sentry/migrations/0996_add_dashboard_field_link_model.py deleted file mode 100644 index b78ebf919b76..000000000000 --- a/src/sentry/migrations/0996_add_dashboard_field_link_model.py +++ /dev/null @@ -1,62 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-09 18:51 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0995_add_date_updated_to_grouphash_metadata"), - ] - - operations = [ - migrations.CreateModel( - name="DashboardFieldLink", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("field", models.TextField()), - ( - "dashboard", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" - ), - ), - ( - "dashboard_widget_query", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.dashboardwidgetquery", - ), - ), - ], - options={ - "db_table": "sentry_dashboardfieldlink", - "unique_together": {("dashboard_widget_query", "field")}, - }, - ), - ] diff --git a/src/sentry/migrations/0997_add_has_trace_metrics_bit_to_project_model.py b/src/sentry/migrations/0997_add_has_trace_metrics_bit_to_project_model.py deleted file mode 100644 index 780a00401d5d..000000000000 --- a/src/sentry/migrations/0997_add_has_trace_metrics_bit_to_project_model.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-22 18:19 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0996_add_dashboard_field_link_model"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="flags", - field=bitfield.models.BitField( - [ - "has_releases", - "has_issue_alerts_targeting", - "has_transactions", - "has_alert_filters", - "has_sessions", - "has_profiles", - "has_replays", - "has_feedbacks", - "has_new_feedbacks", - "spike_protection_error_currently_active", - "spike_protection_transaction_currently_active", - "spike_protection_attachment_currently_active", - "has_minified_stack_trace", - "has_cron_monitors", - "has_cron_checkins", - "has_sourcemaps", - "has_custom_metrics", - "has_high_priority_alerts", - "has_insights_http", - "has_insights_db", - "has_insights_assets", - "has_insights_app_start", - "has_insights_screen_load", - "has_insights_vitals", - "has_insights_caches", - "has_insights_queues", - "has_insights_llm_monitoring", - "has_flags", - "has_insights_agent_monitoring", - "has_insights_mcp", - "has_logs", - "has_trace_metrics", - ], - default=10, - ), - ), - ] diff --git a/src/sentry/migrations/0998_add_prebuilt_id_to_dashboards.py b/src/sentry/migrations/0998_add_prebuilt_id_to_dashboards.py deleted file mode 100644 index ff442f544b7f..000000000000 --- a/src/sentry/migrations/0998_add_prebuilt_id_to_dashboards.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-23 15:14 - -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.hybrid_cloud_foreign_key -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0997_add_has_trace_metrics_bit_to_project_model"), - ] - - operations = [ - migrations.AddField( - model_name="dashboard", - name="prebuilt_id", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=None, null=True - ), - ), - migrations.AlterField( - model_name="dashboard", - name="created_by_id", - field=sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="CASCADE" - ), - ), - migrations.AddConstraint( - model_name="dashboard", - constraint=models.UniqueConstraint( - condition=models.Q(("prebuilt_id__isnull", False)), - fields=("organization", "prebuilt_id"), - name="sentry_dashboard_organization_prebuilt_id_uniq", - ), - ), - migrations.AddConstraint( - model_name="dashboard", - constraint=models.CheckConstraint( - condition=models.Q( - ("prebuilt_id__isnull", True), ("created_by_id__isnull", True), _connector="OR" - ), - name="sentry_dashboard_prebuilt_null_created_by", - ), - ), - ] diff --git a/src/sentry/migrations/0999_add_extrapolation_mode_to_snuba_query.py b/src/sentry/migrations/0999_add_extrapolation_mode_to_snuba_query.py deleted file mode 100644 index 19a65c0535cf..000000000000 --- a/src/sentry/migrations/0999_add_extrapolation_mode_to_snuba_query.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-23 20:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0998_add_prebuilt_id_to_dashboards"), - ] - - operations = [ - migrations.AddField( - model_name="snubaquery", - name="extrapolation_mode", - field=models.IntegerField(db_default=0, default=0), - ), - migrations.AddField( - model_name="snubaquery", - name="query_snapshot", - field=models.JSONField(null=True), - ), - ] diff --git a/src/sentry/migrations/1000_add_project_distribution_scope.py b/src/sentry/migrations/1000_add_project_distribution_scope.py deleted file mode 100644 index a0451d0809b7..000000000000 --- a/src/sentry/migrations/1000_add_project_distribution_scope.py +++ /dev/null @@ -1,149 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-27 10:46 - -from django.db import migrations - -import bitfield.models -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0999_add_extrapolation_mode_to_snuba_query"), - ] - - operations = [ - migrations.AlterField( - model_name="apiauthorization", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apikey", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apitoken", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="sentryapp", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - ], - default=None, - ), - ), - ] diff --git a/src/sentry/migrations/1001_prevent_grouphistory_infinte_recursion.py b/src/sentry/migrations/1001_prevent_grouphistory_infinte_recursion.py deleted file mode 100644 index 5356388387ef..000000000000 --- a/src/sentry/migrations/1001_prevent_grouphistory_infinte_recursion.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-31 12:18 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1000_add_project_distribution_scope"), - ] - - operations = [ - migrations.AlterField( - model_name="grouphistory", - name="prev_history", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.grouphistory" - ), - ), - ] diff --git a/src/sentry/migrations/1002_group_history_prev_history_remove_db_constraint.py b/src/sentry/migrations/1002_group_history_prev_history_remove_db_constraint.py deleted file mode 100644 index 82de4c85251e..000000000000 --- a/src/sentry/migrations/1002_group_history_prev_history_remove_db_constraint.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-04 15:02 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1001_prevent_grouphistory_infinte_recursion"), - ] - - operations = [ - migrations.AlterField( - model_name="grouphistory", - name="prev_history", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.grouphistory", - ), - ), - ] diff --git a/src/sentry/migrations/1003_group_history_prev_history_safe_removal.py b/src/sentry/migrations/1003_group_history_prev_history_safe_removal.py deleted file mode 100644 index bcf4360d991d..000000000000 --- a/src/sentry/migrations/1003_group_history_prev_history_safe_removal.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-04 15:18 - -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", "1002_group_history_prev_history_remove_db_constraint"), - ] - - operations = [ - SafeRemoveField( - model_name="grouphistory", - name="prev_history", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1004_group_history_prev_history_delete.py b/src/sentry/migrations/1004_group_history_prev_history_delete.py deleted file mode 100644 index e9187bd45b66..000000000000 --- a/src/sentry/migrations/1004_group_history_prev_history_delete.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-18 00:00 - -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", "1003_group_history_prev_history_safe_removal"), - ] - - operations = [ - SafeRemoveField( - model_name="grouphistory", - name="prev_history", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1005_add_groupemailthread_project_date_index.py b/src/sentry/migrations/1005_add_groupemailthread_project_date_index.py deleted file mode 100644 index 2169b884f4af..000000000000 --- a/src/sentry/migrations/1005_add_groupemailthread_project_date_index.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 16:02 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1004_group_history_prev_history_delete"), - ] - - operations = [ - migrations.AddIndex( - model_name="groupemailthread", - index=models.Index(fields=["project", "date"], name="sentry_grou_project_56b6ae_idx"), - ), - ] diff --git a/src/sentry/migrations/1006_drop_legacy_incidentseen_incidentsubscription.py b/src/sentry/migrations/1006_drop_legacy_incidentseen_incidentsubscription.py deleted file mode 100644 index 14d4fad42db3..000000000000 --- a/src/sentry/migrations/1006_drop_legacy_incidentseen_incidentsubscription.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-18 21:54 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("sentry", "1005_add_groupemailthread_project_date_index"), - ] - - operations = [ - SafeRunSQL( - """ - DROP TABLE IF EXISTS sentry_incidentseen CASCADE; - """, - hints={"tables": ["sentry_incidentseen"]}, - ), - SafeRunSQL( - """ - DROP TABLE IF EXISTS sentry_incidentsubscription CASCADE; - """, - hints={"tables": ["sentry_incidentsubscription"]}, - ), - ] diff --git a/src/sentry/migrations/1007_cleanup_failed_safe_deletes.py b/src/sentry/migrations/1007_cleanup_failed_safe_deletes.py deleted file mode 100644 index a8c1fd8a899a..000000000000 --- a/src/sentry/migrations/1007_cleanup_failed_safe_deletes.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 00:37 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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", "1006_drop_legacy_incidentseen_incidentsubscription"), - ] - - operations = [ - # Clean up tables that may not have been deleted due to missing - # historical_silo_assignments entries before the fix - SafeRunSQL( - sql="DROP TABLE IF EXISTS sentry_datasecrecywaiver CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["sentry_datasecrecywaiver"]}, - ), - SafeRunSQL( - sql="DROP TABLE IF EXISTS sentry_dashboardwidgetsnapshot CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["sentry_dashboardwidgetsnapshot"]}, - ), - ] diff --git a/src/sentry/migrations/1008_loosen_unique_title_contraint.py b/src/sentry/migrations/1008_loosen_unique_title_contraint.py deleted file mode 100644 index c54ef9bce22b..000000000000 --- a/src/sentry/migrations/1008_loosen_unique_title_contraint.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-26 15:37 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1007_cleanup_failed_safe_deletes"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="dashboard", - unique_together=set(), - ), - migrations.AddConstraint( - model_name="dashboard", - constraint=models.UniqueConstraint( - condition=models.Q(("prebuilt_id__isnull", True)), - fields=("organization", "title"), - name="sentry_dashboard_organization_title_uniq", - ), - ), - ] diff --git a/src/sentry/migrations/1009_add_date_updated_to_organizationmapping.py b/src/sentry/migrations/1009_add_date_updated_to_organizationmapping.py deleted file mode 100644 index cb3b483b3417..000000000000 --- a/src/sentry/migrations/1009_add_date_updated_to_organizationmapping.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-20 21:13 - -import django.db.models.functions -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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", "1008_loosen_unique_title_contraint"), - ] - - operations = [ - # This migration had to be reverted after it was merged and ran in some environments. - # Clean up the previous attempt and try again - SafeRunSQL( - sql=""" - ALTER TABLE "sentry_organizationmapping" DROP COLUMN IF EXISTS "date_updated"; - """, - reverse_sql="", - hints={"tables": ["sentry_organizationmapping"]}, - ), - migrations.AddField( - model_name="organizationmapping", - name="date_updated", - field=models.DateTimeField( - db_default=django.db.models.functions.Now(), - auto_now=True, - db_index=True, - ), - ), - ] diff --git a/src/sentry/migrations/1010_add_organizationcontributors_table.py b/src/sentry/migrations/1010_add_organizationcontributors_table.py deleted file mode 100644 index 21607490e6f6..000000000000 --- a/src/sentry/migrations/1010_add_organizationcontributors_table.py +++ /dev/null @@ -1,75 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-21 21:54 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1009_add_date_updated_to_organizationmapping"), - ] - - operations = [ - migrations.CreateModel( - name="OrganizationContributors", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "integration_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Integration", db_index=True, on_delete="CASCADE" - ), - ), - ("external_identifier", models.CharField(db_index=True, max_length=255)), - ("alias", models.CharField(blank=True, max_length=255, null=True)), - ("num_actions", sentry.db.models.fields.bounded.BoundedIntegerField(default=0)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("date_updated", models.DateTimeField(auto_now=True)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "sentry_organizationcontributors", - "indexes": [ - models.Index( - fields=["organization_id", "date_updated"], - name="sentry_oc_org_date_upd_idx", - ) - ], - "constraints": [ - models.UniqueConstraint( - fields=("organization_id", "integration_id", "external_identifier"), - name="sentry_orgcont_unique_org_cont", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1011_update_oc_integration_cascade_to_null.py b/src/sentry/migrations/1011_update_oc_integration_cascade_to_null.py deleted file mode 100644 index 7c013b78a615..000000000000 --- a/src/sentry/migrations/1011_update_oc_integration_cascade_to_null.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-02 18:18 - -from django.db import migrations - -import sentry.db.models.fields.hybrid_cloud_foreign_key -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1010_add_organizationcontributors_table"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationcontributors", - name="integration_id", - field=sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Integration", db_index=True, on_delete="DO_NOTHING" - ), - ), - ] diff --git a/src/sentry/migrations/1012_add_event_id_to_open_period.py b/src/sentry/migrations/1012_add_event_id_to_open_period.py deleted file mode 100644 index 277c091f260f..000000000000 --- a/src/sentry/migrations/1012_add_event_id_to_open_period.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-08 22:14 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1011_update_oc_integration_cascade_to_null"), - ] - - operations = [ - migrations.AddField( - model_name="groupopenperiod", - name="event_id", - field=models.CharField(max_length=32, null=True), - ), - ] diff --git a/src/sentry/migrations/1013_add_repositorysettings_table.py b/src/sentry/migrations/1013_add_repositorysettings_table.py deleted file mode 100644 index 918f25f7dd83..000000000000 --- a/src/sentry/migrations/1013_add_repositorysettings_table.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-09 22:43 - -import django.contrib.postgres.fields -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1012_add_event_id_to_open_period"), - ] - - operations = [ - migrations.CreateModel( - name="RepositorySettings", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("enabled_code_review", models.BooleanField(default=False)), - ( - "code_review_triggers", - django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), default=list, size=None - ), - ), - ( - "repository", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.repository", - unique=True, - ), - ), - ], - options={ - "db_table": "sentry_repositorysettings", - }, - ), - ] diff --git a/src/sentry/migrations/1014_add_pkce_to_apigrant.py b/src/sentry/migrations/1014_add_pkce_to_apigrant.py deleted file mode 100644 index c7c9ef40fc2c..000000000000 --- a/src/sentry/migrations/1014_add_pkce_to_apigrant.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-04 20:45 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1013_add_repositorysettings_table"), - ] - - operations = [ - migrations.AddField( - model_name="apigrant", - name="code_challenge", - field=models.CharField(max_length=128, null=True), - ), - migrations.AddField( - model_name="apigrant", - name="code_challenge_method", - field=models.CharField(max_length=10, null=True), - ), - ] diff --git a/src/sentry/migrations/1015_backfill_self_hosted_sentry_app_emails.py b/src/sentry/migrations/1015_backfill_self_hosted_sentry_app_emails.py deleted file mode 100644 index 8ee9765578e5..000000000000 --- a/src/sentry/migrations/1015_backfill_self_hosted_sentry_app_emails.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-21 20:48 - -import logging - -from django.conf import settings -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - - -def backfill_proxy_user_emails(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - if not settings.SENTRY_SELF_HOSTED: - # This operation for SaaS Sentry is handled using a script. - return - - User = apps.get_model("sentry", "User") - - proxy_users = User.objects.filter(is_sentry_app=True, email="") - - for item in proxy_users: - email = f"{item.username}@proxy-user.sentry.io" - item.email = email - item.save() - logger.info("Assigned placeholder email %s to user %s", item.email, item.id) - - -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 = True - - dependencies = [ - ("sentry", "1014_add_pkce_to_apigrant"), - ] - - operations = [ - migrations.RunPython( - backfill_proxy_user_emails, migrations.RunPython.noop, hints={"tables": ["auth_user"]} - ) - ] diff --git a/src/sentry/migrations/1016_remove_on_command_phrase_trigger.py b/src/sentry/migrations/1016_remove_on_command_phrase_trigger.py deleted file mode 100644 index 269cb5b1146a..000000000000 --- a/src/sentry/migrations/1016_remove_on_command_phrase_trigger.py +++ /dev/null @@ -1,76 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-08 18:18 - -import django.contrib.postgres.fields -from django.db import migrations, models -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def remove_on_command_phrase_from_repository_settings( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """Remove 'on_command_phrase' from RepositorySettings.code_review_triggers.""" - RepositorySettings = apps.get_model("sentry", "RepositorySettings") - - all_settings = list(RepositorySettings.objects.all()) - - updated_settings = [] - for settings in all_settings: - if ( - settings.code_review_triggers - and isinstance(settings.code_review_triggers, list) - and "on_command_phrase" in settings.code_review_triggers - ): - settings.code_review_triggers = [ - trigger - for trigger in settings.code_review_triggers - if trigger != "on_command_phrase" - ] - updated_settings.append(settings) - - if updated_settings: - RepositorySettings.objects.bulk_update(updated_settings, fields=["code_review_triggers"]) - - -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", "1015_backfill_self_hosted_sentry_app_emails"), - ] - - operations = [ - migrations.RunPython( - remove_on_command_phrase_from_repository_settings, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_repositorysettings"]}, - ), - migrations.AlterField( - model_name="repositorysettings", - name="code_review_triggers", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField( - choices=[ - ("on_new_commit", "on_new_commit"), - ("on_ready_for_review", "on_ready_for_review"), - ], - max_length=32, - ), - default=list, - ), - ), - ] diff --git a/src/sentry/migrations/1017_add_apidevicecode.py b/src/sentry/migrations/1017_add_apidevicecode.py deleted file mode 100644 index 511fccaf08dd..000000000000 --- a/src/sentry/migrations/1017_add_apidevicecode.py +++ /dev/null @@ -1,116 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-05 - -import django.contrib.postgres.fields -import django.db.models.deletion -import django.utils.timezone -from django.conf import settings -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.models.apidevicecode -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1016_remove_on_command_phrase_trigger"), - ] - - operations = [ - migrations.CreateModel( - name="ApiDeviceCode", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "device_code", - models.CharField( - default=sentry.models.apidevicecode.generate_device_code, - max_length=64, - unique=True, - ), - ), - ( - "user_code", - models.CharField( - unique=True, - default=sentry.models.apidevicecode.generate_user_code, - max_length=16, - ), - ), - ( - "application", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.apiapplication", - ), - ), - ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "organization_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", - db_index=True, - null=True, - on_delete="CASCADE", - ), - ), - ( - "scope_list", - django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), - default=list, - size=None, - ), - ), - ( - "expires_at", - models.DateTimeField( - db_index=True, - default=sentry.models.apidevicecode.default_expiration, - ), - ), - ( - "status", - models.CharField( - default="pending", - max_length=20, - ), - ), - ( - "date_added", - models.DateTimeField(default=django.utils.timezone.now), - ), - ], - options={ - "db_table": "sentry_apidevicecode", - }, - ), - ] diff --git a/src/sentry/migrations/1018_encrypt_integration_metadata.py b/src/sentry/migrations/1018_encrypt_integration_metadata.py deleted file mode 100644 index 32541abe3df7..000000000000 --- a/src/sentry/migrations/1018_encrypt_integration_metadata.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-13 10:08 - -from django.db import migrations - -import sentry.db.models.fields.encryption.encrypted_json_field -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1017_add_apidevicecode"), - ] - - operations = [ - migrations.AlterField( - model_name="integration", - name="metadata", - field=sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( - default=dict - ), - ), - ] diff --git a/src/sentry/migrations/1019_add_integration_debug_json.py b/src/sentry/migrations/1019_add_integration_debug_json.py deleted file mode 100644 index 788e8f1afecf..000000000000 --- a/src/sentry/migrations/1019_add_integration_debug_json.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-16 21:56 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1018_encrypt_integration_metadata"), - ] - - operations = [ - migrations.AddField( - model_name="integration", - name="debug_data", - field=models.JSONField(default=dict, null=True), - ), - ] diff --git a/src/sentry/migrations/1020_alter_apiapplication_client_secret_nullable.py b/src/sentry/migrations/1020_alter_apiapplication_client_secret_nullable.py deleted file mode 100644 index 6a4affc09cca..000000000000 --- a/src/sentry/migrations/1020_alter_apiapplication_client_secret_nullable.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-20 21:29 - -from django.db import migrations, models - -import sentry.models.apiapplication -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1019_add_integration_debug_json"), - ] - - operations = [ - migrations.AlterField( - model_name="apiapplication", - name="client_secret", - field=models.TextField(null=True, default=sentry.models.apiapplication.generate_token), - ), - ] diff --git a/src/sentry/migrations/1021_add_date_added_date_updated_to_repositorysettings.py b/src/sentry/migrations/1021_add_date_added_date_updated_to_repositorysettings.py deleted file mode 100644 index 483abc409b07..000000000000 --- a/src/sentry/migrations/1021_add_date_added_date_updated_to_repositorysettings.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-26 18:00 - -import django.db.models.functions.datetime -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1020_alter_apiapplication_client_secret_nullable"), - ] - - operations = [ - migrations.AddField( - model_name="repositorysettings", - name="date_added", - field=models.DateTimeField(db_default=django.db.models.functions.datetime.Now()), - ), - migrations.AddField( - model_name="repositorysettings", - name="date_updated", - field=models.DateTimeField( - auto_now=True, db_default=django.db.models.functions.datetime.Now() - ), - ), - ] diff --git a/src/sentry/migrations/1022_add_event_id_to_groupopenperiodactivity.py b/src/sentry/migrations/1022_add_event_id_to_groupopenperiodactivity.py deleted file mode 100644 index 8027ed1f5b63..000000000000 --- a/src/sentry/migrations/1022_add_event_id_to_groupopenperiodactivity.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-29 22:27 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1021_add_date_added_date_updated_to_repositorysettings"), - ] - - operations = [ - migrations.AddField( - model_name="groupopenperiodactivity", - name="event_id", - field=models.CharField(max_length=32, null=True), - ), - ] diff --git a/src/sentry/migrations/1023_add_commitcomparison_unique_constraints.py b/src/sentry/migrations/1023_add_commitcomparison_unique_constraints.py deleted file mode 100644 index 6bc4f4bfae90..000000000000 --- a/src/sentry/migrations/1023_add_commitcomparison_unique_constraints.py +++ /dev/null @@ -1,84 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-30 21:35 - -from django.db import migrations, models -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - - -def delete_duplicate_commit_comparisons( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Delete duplicate CommitComparison records, keeping the oldest (lowest ID) for each unique - combination of (organization_id, head_repo_name, head_sha, base_sha). - - Before deleting, updates PreprodArtifact foreign key references to point to the kept record. - """ - CommitComparison = apps.get_model("sentry", "CommitComparison") - PreprodArtifact = apps.get_model("preprod", "PreprodArtifact") - - key_to_kept_id: dict[tuple[int, str, str, str | None], int] = {} - duplicate_to_kept: dict[int, int] = {} - - for record in RangeQuerySetWrapperWithProgressBar(CommitComparison.objects.all()): - key = (record.organization_id, record.head_repo_name, record.head_sha, record.base_sha) - - if key in key_to_kept_id: - duplicate_to_kept[record.id] = key_to_kept_id[key] - else: - key_to_kept_id[key] = record.id - - if duplicate_to_kept: - for duplicate_id, kept_id in duplicate_to_kept.items(): - PreprodArtifact.objects.filter(commit_comparison_id=duplicate_id).update( - commit_comparison_id=kept_id - ) - CommitComparison.objects.filter(id__in=duplicate_to_kept.keys()).delete() - - -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 = True - - dependencies = [ - ("sentry", "1022_add_event_id_to_groupopenperiodactivity"), - ("preprod", "0026_add_initial_snapshot_models"), - ] - - operations = [ - migrations.RunPython( - delete_duplicate_commit_comparisons, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_commitcomparison", "sentry_preprodartifact"]}, - ), - migrations.AddConstraint( - model_name="commitcomparison", - constraint=models.UniqueConstraint( - condition=models.Q(("base_sha__isnull", False)), - fields=("organization_id", "head_repo_name", "head_sha", "base_sha"), - name="sentry_commitcomparison_org_comparison_uniq", - ), - ), - migrations.AddConstraint( - model_name="commitcomparison", - constraint=models.UniqueConstraint( - condition=models.Q(("base_sha__isnull", True)), - fields=("organization_id", "head_repo_name", "head_sha"), - name="sentry_commitcomparison_org_commit_uniq", - ), - ), - ] diff --git a/src/sentry/migrations/1024_delete_never_active_users_without_emails_self_hosted.py b/src/sentry/migrations/1024_delete_never_active_users_without_emails_self_hosted.py deleted file mode 100644 index 46298acddebb..000000000000 --- a/src/sentry/migrations/1024_delete_never_active_users_without_emails_self_hosted.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-21 23:09 - -import logging - -from django.conf import settings -from django.db import migrations, router -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.silo.safety import unguarded_write - -logger = logging.getLogger(__name__) - - -def delete_never_active_users_without_emails( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - if not settings.SENTRY_SELF_HOSTED: - # This operation for SaaS Sentry is handled using a script. - return - - User = apps.get_model("sentry", "User") - - target_users = User.objects.filter(last_active=None, email="") - - for user in target_users: - logger.info("Deleting user %s", user.id) - with unguarded_write(using=router.db_for_write(User)): - user.delete() - - -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 = True - - dependencies = [ - ("sentry", "1023_add_commitcomparison_unique_constraints"), - ] - - operations = [ - migrations.RunPython( - delete_never_active_users_without_emails, - migrations.RunPython.noop, - hints={"tables": ["auth_user"]}, - ) - ] diff --git a/src/sentry/migrations/1025_backfill_groupopenperiodactivity_event_id.py b/src/sentry/migrations/1025_backfill_groupopenperiodactivity_event_id.py deleted file mode 100644 index ba5e5f37da23..000000000000 --- a/src/sentry/migrations/1025_backfill_groupopenperiodactivity_event_id.py +++ /dev/null @@ -1,129 +0,0 @@ -# Generated by Django 5.2.8 on 2026-02-09 18:53 - -import logging -from typing import Any - -from django.db import connection, migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.iterators import chunked -from sentry.utils.query import RangeQuerySetWrapperWithProgressBarApprox - -logger = logging.getLogger(__name__) - -BATCH_SIZE = 1000 - -# OpenPeriodActivityType.OPENED -OPENED = 1 - - -def _flush_batch(cursor: Any, batch: list[tuple[int, str]]) -> None: - values_clause = ", ".join(["(%s, %s)"] * len(batch)) - params: list[int | str] = [] - for activity_id, event_id in batch: - params.extend([activity_id, event_id]) - - cursor.execute( - f""" - UPDATE sentry_groupopenperiodactivity - SET event_id = data.event_id - FROM (VALUES {values_clause}) AS data (id, event_id) - WHERE sentry_groupopenperiodactivity.id = data.id - AND sentry_groupopenperiodactivity.event_id IS NULL - """, - params, - ) - - -def backfill_event_id_to_activity(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - GroupOpenPeriod = apps.get_model("sentry", "GroupOpenPeriod") - GroupOpenPeriodActivity = apps.get_model("sentry", "GroupOpenPeriodActivity") - - cursor = connection.cursor() - total_processed = 0 - total_updated = 0 - - for chunk in chunked( - RangeQuerySetWrapperWithProgressBarApprox( - GroupOpenPeriodActivity.objects.all().values_list( - "id", "group_open_period_id", "type", "event_id" - ), - result_value_getter=lambda item: item[0], - ), - BATCH_SIZE, - ): - chunk = [ - (activity_id, open_period_id) - for activity_id, open_period_id, type_, event_id in chunk - if type_ == OPENED and event_id is None - ] - total_processed += BATCH_SIZE - if not chunk: - if total_processed % (BATCH_SIZE * 10) == 0: - logger.info( - "backfill_event_id_to_activity: processed %d rows, updated %d", - total_processed, - total_updated, - ) - continue - - open_period_ids = [open_period_id for _, open_period_id in chunk] - event_ids_by_open_period = dict( - GroupOpenPeriod.objects.filter( - id__in=open_period_ids, - event_id__isnull=False, - ).values_list("id", "event_id") - ) - - batch = [] - for activity_id, open_period_id in chunk: - event_id = event_ids_by_open_period.get(open_period_id) - if event_id is not None: - batch.append((activity_id, event_id)) - - if batch: - _flush_batch(cursor, batch) - total_updated += len(batch) - - if total_processed % (BATCH_SIZE * 10) == 0: - logger.info( - "backfill_event_id_to_activity: processed %d rows, updated %d", - total_processed, - total_updated, - ) - - logger.info( - "backfill_event_id_to_activity: complete, processed %d rows, updated %d", - total_processed, - total_updated, - ) - - -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 = True - - dependencies = [ - ("sentry", "1024_delete_never_active_users_without_emails_self_hosted"), - ] - - operations = [ - migrations.RunPython( - backfill_event_id_to_activity, - migrations.RunPython.noop, - hints={"tables": ["sentry_groupopenperiod", "sentry_groupopenperiodactivity"]}, - ), - ] diff --git a/src/sentry/migrations/1026_add_index_groupopenperiodactivity_open_period_type_event_id.py b/src/sentry/migrations/1026_add_index_groupopenperiodactivity_open_period_type_event_id.py deleted file mode 100644 index 41d7ff33ff69..000000000000 --- a/src/sentry/migrations/1026_add_index_groupopenperiodactivity_open_period_type_event_id.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-02-10 17:35 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1025_backfill_groupopenperiodactivity_event_id"), - ] - - operations = [ - migrations.AddIndex( - model_name="groupopenperiodactivity", - index=models.Index( - fields=["group_open_period", "type", "event_id"], - name="sentry_grou_group_o_4c2b45_idx", - ), - ), - ] diff --git a/src/sentry/migrations/1027_encrypt_data_forwarding_configurations.py b/src/sentry/migrations/1027_encrypt_data_forwarding_configurations.py deleted file mode 100644 index cabbcb1a347e..000000000000 --- a/src/sentry/migrations/1027_encrypt_data_forwarding_configurations.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.8 on 2026-02-10 20:02 - -from django.db import migrations - -import sentry.db.models.fields.encryption.encrypted_json_field -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1026_add_index_groupopenperiodactivity_open_period_type_event_id"), - ] - - operations = [ - migrations.AlterField( - model_name="dataforwarder", - name="config", - field=sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( - default=dict - ), - ), - migrations.AlterField( - model_name="dataforwarderproject", - name="overrides", - field=sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( - default=dict - ), - ), - ] diff --git a/src/sentry/migrations/1028_remove_group_open_period_event_id.py b/src/sentry/migrations/1028_remove_group_open_period_event_id.py deleted file mode 100644 index 5adbaef2884c..000000000000 --- a/src/sentry/migrations/1028_remove_group_open_period_event_id.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.8 on 2026-02-09 19:47 -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", "1027_encrypt_data_forwarding_configurations"), - ] - - operations = [ - SafeRemoveField( - model_name="groupopenperiod", - name="event_id", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1029_delete_group_open_period_event_id.py b/src/sentry/migrations/1029_delete_group_open_period_event_id.py deleted file mode 100644 index a0112a378f39..000000000000 --- a/src/sentry/migrations/1029_delete_group_open_period_event_id.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2026-02-09 23:27 - -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", "1028_remove_group_open_period_event_id"), - ] - - operations = [ - SafeRemoveField( - model_name="groupopenperiod", - name="event_id", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1030_add_commitcomparison_extras.py b/src/sentry/migrations/1030_add_commitcomparison_extras.py deleted file mode 100644 index b3fc1f14cb6e..000000000000 --- a/src/sentry/migrations/1030_add_commitcomparison_extras.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-14 00:57 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1029_delete_group_open_period_event_id"), - ] - - operations = [ - migrations.AddField( - model_name="commitcomparison", - name="extras", - field=models.JSONField(db_default={}, default=dict), - ), - ] diff --git a/src/sentry/migrations/1031_encrypt_identity_data_field.py b/src/sentry/migrations/1031_encrypt_identity_data_field.py deleted file mode 100644 index 37e279244367..000000000000 --- a/src/sentry/migrations/1031_encrypt_identity_data_field.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-18 09:46 - -import sentry.db.models.fields.encryption.encrypted_json_field -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1030_add_commitcomparison_extras"), - ] - - operations = [ - migrations.AlterField( - model_name="identity", - name="data", - field=sentry.db.models.fields.encryption.encrypted_json_field.EncryptedJSONField( - default=dict - ), - ), - ] diff --git a/src/sentry/migrations/1032_code_review_event.py b/src/sentry/migrations/1032_code_review_event.py deleted file mode 100644 index 7b272c364465..000000000000 --- a/src/sentry/migrations/1032_code_review_event.py +++ /dev/null @@ -1,112 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-19 18:41 - -import django.utils.timezone -import sentry.db.models.fields.bounded -import sentry.models.code_review_event -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1031_encrypt_identity_data_field"), - ] - - operations = [ - migrations.CreateModel( - name="CodeReviewEvent", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ( - "repository_id", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), - ), - ("pr_number", models.IntegerField(null=True)), - ("pr_title", models.TextField(null=True)), - ("pr_author", models.TextField(null=True)), - ("pr_url", models.TextField(null=True)), - ("pr_state", models.CharField(max_length=16, null=True)), - ("raw_event_type", models.CharField(max_length=64)), - ("raw_event_action", models.CharField(max_length=64)), - ("trigger_id", models.CharField(max_length=64, null=True)), - ("trigger", models.CharField(max_length=64, null=True)), - ("trigger_user", models.TextField(null=True)), - ("trigger_at", models.DateTimeField(default=django.utils.timezone.now)), - ("target_commit_sha", models.CharField(max_length=64, null=True)), - ( - "status", - models.CharField( - default=sentry.models.code_review_event.CodeReviewEventStatus[ - "WEBHOOK_RECEIVED" - ], - max_length=32, - ), - ), - ("denial_reason", models.TextField(null=True)), - ( - "date_added", - models.DateTimeField(db_index=True, default=django.utils.timezone.now), - ), - ("webhook_received_at", models.DateTimeField(null=True)), - ("preflight_completed_at", models.DateTimeField(null=True)), - ("task_enqueued_at", models.DateTimeField(null=True)), - ("sent_to_seer_at", models.DateTimeField(null=True)), - ("review_started_at", models.DateTimeField(null=True)), - ("review_completed_at", models.DateTimeField(null=True)), - ("seer_run_id", models.CharField(max_length=64, null=True)), - ( - "comments_posted", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("review_result", models.JSONField(null=True)), - ], - options={ - "db_table": "sentry_code_review_event", - "indexes": [ - models.Index( - fields=["organization_id", "trigger_at"], - name="sentry_code_organiz_4f4b09_idx", - ), - models.Index( - fields=["organization_id", "repository_id", "trigger_at"], - name="sentry_code_organiz_7ba32c_idx", - ), - models.Index( - fields=["organization_id", "repository_id", "pr_number"], - name="sentry_code_organiz_76bbd1_idx", - ), - ], - "constraints": [ - models.UniqueConstraint( - condition=models.Q(("trigger_id__isnull", False)), - fields=("organization_id", "repository_id", "trigger_id"), - name="unique_org_repo_trigger_id", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1033_remove_grouprelease_group_id_last_seen_idx.py b/src/sentry/migrations/1033_remove_grouprelease_group_id_last_seen_idx.py deleted file mode 100644 index 5f3afeed2dd7..000000000000 --- a/src/sentry/migrations/1033_remove_grouprelease_group_id_last_seen_idx.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-23 11:43 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1032_code_review_event"), - ] - - operations = [ - migrations.RemoveIndex( - model_name="grouprelease", - name="sentry_grou_group_i_b6e502_idx", - ), - ] diff --git a/src/sentry/migrations/1034_remove_code_review_event.py b/src/sentry/migrations/1034_remove_code_review_event.py deleted file mode 100644 index 85b15cdabea1..000000000000 --- a/src/sentry/migrations/1034_remove_code_review_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-26 00:43 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1033_remove_grouprelease_group_id_last_seen_idx"), - ] - - operations = [ - SafeDeleteModel( - name="CodeReviewEvent", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1035_delete_code_review_event.py b/src/sentry/migrations/1035_delete_code_review_event.py deleted file mode 100644 index 6d81f0372d2b..000000000000 --- a/src/sentry/migrations/1035_delete_code_review_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-26 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1034_remove_code_review_event"), - ] - - operations = [ - SafeDeleteModel( - name="CodeReviewEvent", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1036_orgmapping_date_updated_trunc_index.py b/src/sentry/migrations/1036_orgmapping_date_updated_trunc_index.py deleted file mode 100644 index 8cf5de6b5db5..000000000000 --- a/src/sentry/migrations/1036_orgmapping_date_updated_trunc_index.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-27 21:06 - -import django.db.models.functions.datetime -import sentry.db.models.indexes -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1035_delete_code_review_event"), - ] - - operations = [ - migrations.AddIndex( - model_name="organizationmapping", - index=sentry.db.models.indexes.IndexWithPostgresNameLimits( - django.db.models.functions.datetime.TruncSecond("date_updated"), - models.F("id"), - name="sentry_orgmapping_date_updated_id_idx", - ), - ), - migrations.AlterField( - model_name="organizationmapping", - name="date_updated", - field=models.DateTimeField( - auto_now=True, db_default=django.db.models.functions.datetime.Now() - ), - ), - ] diff --git a/src/sentry/migrations/1037_add_grouphashmetadata_seer_latest_training_model.py b/src/sentry/migrations/1037_add_grouphashmetadata_seer_latest_training_model.py deleted file mode 100644 index 6a5e8b32b071..000000000000 --- a/src/sentry/migrations/1037_add_grouphashmetadata_seer_latest_training_model.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-27 17:54 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1036_orgmapping_date_updated_trunc_index"), - ] - - operations = [ - migrations.AddField( - model_name="grouphashmetadata", - name="seer_latest_training_model", - field=models.CharField(null=True), - ), - ] diff --git a/src/sentry/migrations/1038_add_index_groupopenperiodactivity_event_id.py b/src/sentry/migrations/1038_add_index_groupopenperiodactivity_event_id.py deleted file mode 100644 index 1105cc3438d3..000000000000 --- a/src/sentry/migrations/1038_add_index_groupopenperiodactivity_event_id.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-27 23:35 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1037_add_grouphashmetadata_seer_latest_training_model"), - ] - - operations = [ - migrations.AddIndex( - model_name="groupopenperiodactivity", - index=models.Index(fields=["event_id"], name="sentry_grou_event_i_9c9778_idx"), - ), - ] diff --git a/src/sentry/migrations/1039_widget_description_to_textfield.py b/src/sentry/migrations/1039_widget_description_to_textfield.py deleted file mode 100644 index 752d5f87e1b4..000000000000 --- a/src/sentry/migrations/1039_widget_description_to_textfield.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-19 15:22 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1038_add_index_groupopenperiodactivity_event_id"), - ] - - operations = [ - migrations.AlterField( - model_name="dashboardwidget", - name="description", - field=models.TextField(blank=True, null=True), - ), - ] diff --git a/src/sentry/migrations/1040_drop_fk_projecttemplate.py b/src/sentry/migrations/1040_drop_fk_projecttemplate.py deleted file mode 100644 index 2e87fb9e4574..000000000000 --- a/src/sentry/migrations/1040_drop_fk_projecttemplate.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-04 16:38 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -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", "1039_widget_description_to_textfield"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="template", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.projecttemplate", - ), - ), - SafeRemoveField( - model_name="project", - name="template", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1041_projectkeymapping.py b/src/sentry/migrations/1041_projectkeymapping.py deleted file mode 100644 index a1900fecb6da..000000000000 --- a/src/sentry/migrations/1041_projectkeymapping.py +++ /dev/null @@ -1,69 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-04 20:20 - -import django.db.models.functions.datetime -import sentry.db.models.fields.bounded -import sentry.db.models.indexes -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1040_drop_fk_projecttemplate"), - ] - - operations = [ - migrations.CreateModel( - name="ProjectKeyMapping", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "project_key_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ( - "public_key", - models.CharField(db_index=True, max_length=32, unique=True), - ), - ("cell_name", models.CharField(max_length=48)), - ( - "date_updated", - models.DateTimeField( - auto_now=True, - db_default=django.db.models.functions.datetime.Now(), - ), - ), - ], - options={ - "db_table": "sentry_projectkeymapping", - "indexes": [ - sentry.db.models.indexes.IndexWithPostgresNameLimits( - models.F("cell_name"), - django.db.models.functions.datetime.TruncSecond("date_updated"), - models.F("id"), - name="sentry_projkeymapping_cell_name_date_updated_id_idx", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1042_create_code_review_event.py b/src/sentry/migrations/1042_create_code_review_event.py deleted file mode 100644 index 2c6af48f1c31..000000000000 --- a/src/sentry/migrations/1042_create_code_review_event.py +++ /dev/null @@ -1,119 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-26 00:51 - -import django.db.models.deletion -import django.utils.timezone -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.models.code_review_event -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1041_projectkeymapping"), - ] - - operations = [ - migrations.CreateModel( - name="CodeReviewEvent", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("pr_number", models.IntegerField(null=True)), - ("pr_title", models.TextField(null=True)), - ("pr_author", models.TextField(null=True)), - ("pr_url", models.TextField(null=True)), - ("pr_state", models.CharField(max_length=16, null=True)), - ("raw_event_type", models.CharField(max_length=64)), - ("raw_event_action", models.CharField(max_length=64)), - ("trigger_id", models.CharField(max_length=64, null=True)), - ("trigger", models.CharField(max_length=64, null=True)), - ("trigger_user", models.TextField(null=True)), - ("trigger_at", models.DateTimeField(default=django.utils.timezone.now)), - ("target_commit_sha", models.CharField(max_length=64, null=True)), - ( - "status", - models.CharField( - default=sentry.models.code_review_event.CodeReviewEventStatus[ - "WEBHOOK_RECEIVED" - ], - max_length=32, - ), - ), - ("denial_reason", models.TextField(null=True)), - ("webhook_received_at", models.DateTimeField(null=True)), - ("preflight_completed_at", models.DateTimeField(null=True)), - ("task_enqueued_at", models.DateTimeField(null=True)), - ("sent_to_seer_at", models.DateTimeField(null=True)), - ("review_started_at", models.DateTimeField(null=True)), - ("review_completed_at", models.DateTimeField(null=True)), - ("seer_run_id", models.CharField(max_length=64, null=True)), - ( - "comments_posted", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("review_result", models.JSONField(null=True)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - ( - "repository", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.repository", - ), - ), - ], - options={ - "db_table": "sentry_code_review_event", - "indexes": [ - models.Index(fields=["date_added"], name="sentry_code_date_ad_a2451c_idx"), - models.Index( - fields=["organization", "trigger_at"], - name="sentry_code_organiz_4f4b09_idx", - ), - models.Index( - fields=["organization", "repository", "trigger_at"], - name="sentry_code_organiz_7ba32c_idx", - ), - models.Index( - fields=["organization", "repository", "pr_number"], - name="sentry_code_organiz_76bbd1_idx", - ), - ], - "constraints": [ - models.UniqueConstraint( - condition=models.Q(("trigger_id__isnull", False)), - fields=("organization", "repository", "trigger_id"), - name="unique_org_repo_trigger_id", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1043_big_redirect_slug.py b/src/sentry/migrations/1043_big_redirect_slug.py deleted file mode 100644 index 38af87f405b3..000000000000 --- a/src/sentry/migrations/1043_big_redirect_slug.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-05 19:50 - -import sentry.db.models.fields.slug -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - # Disabled: this migration changes the length of indexed columns, which our - # safety framework now blocks. The migration has already been applied in - # production, so it is safe to skip the check here. - checked = False - - dependencies = [ - ("sentry", "1042_create_code_review_event"), - ] - - operations = [ - migrations.AlterField( - model_name="projectredirect", - name="redirect_slug", - field=sentry.db.models.fields.slug.SentrySlugField(max_length=100), - ), - ] diff --git a/src/sentry/migrations/1044_remove_projecttemplate_model.py b/src/sentry/migrations/1044_remove_projecttemplate_model.py deleted file mode 100644 index cb068407435c..000000000000 --- a/src/sentry/migrations/1044_remove_projecttemplate_model.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-04 -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1043_big_redirect_slug"), - ] - - operations = [ - migrations.AlterField( - model_name="projecttemplate", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - migrations.AlterField( - model_name="projecttemplateoption", - name="project_template", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - related_name="options", - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.projecttemplate", - ), - ), - SafeDeleteModel( - name="ProjectTemplateOption", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeDeleteModel( - name="ProjectTemplate", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1045_dashboard_favorite_user_add_starred_column.py b/src/sentry/migrations/1045_dashboard_favorite_user_add_starred_column.py deleted file mode 100644 index a5a6967be700..000000000000 --- a/src/sentry/migrations/1045_dashboard_favorite_user_add_starred_column.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-06 17:17 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1044_remove_projecttemplate_model"), - ] - - operations = [ - migrations.AddField( - model_name="dashboardfavoriteuser", - name="favorited", - field=models.BooleanField(db_default=True), - ), - ] diff --git a/src/sentry/migrations/1046_projecttemplate_cleanup.py b/src/sentry/migrations/1046_projecttemplate_cleanup.py deleted file mode 100644 index 01ad3dfa3acb..000000000000 --- a/src/sentry/migrations/1046_projecttemplate_cleanup.py +++ /dev/null @@ -1,28 +0,0 @@ -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.fields import SafeRemoveField -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1045_dashboard_favorite_user_add_starred_column"), - ] - - operations = [ - SafeRemoveField( - model_name="project", - name="template", - deletion_action=DeletionAction.DELETE, - ), - SafeDeleteModel( - name="ProjectTemplateOption", - deletion_action=DeletionAction.DELETE, - ), - SafeDeleteModel( - name="ProjectTemplate", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1047_rename_orgmapping_region_name_to_cell_name.py b/src/sentry/migrations/1047_rename_orgmapping_region_name_to_cell_name.py deleted file mode 100644 index b8fc77d11cf7..000000000000 --- a/src/sentry/migrations/1047_rename_orgmapping_region_name_to_cell_name.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-06 20:58 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1046_projecttemplate_cleanup"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationmapping", - name="region_name", - field=models.CharField(db_column="region_name", max_length=48), - ), - migrations.RenameField( - model_name="organizationmapping", - old_name="region_name", - new_name="cell_name", - ), - ] diff --git a/src/sentry/migrations/1048_organizationmapping_cell_name_idx.py b/src/sentry/migrations/1048_organizationmapping_cell_name_idx.py deleted file mode 100644 index a14f1824281e..000000000000 --- a/src/sentry/migrations/1048_organizationmapping_cell_name_idx.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-06 22:33 - -import django.db.models.functions.datetime -import sentry.db.models.indexes -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1047_rename_orgmapping_region_name_to_cell_name"), - ] - - operations = [ - migrations.AddIndex( - model_name="organizationmapping", - index=sentry.db.models.indexes.IndexWithPostgresNameLimits( - models.F("cell_name"), - django.db.models.functions.datetime.TruncSecond("date_updated"), - models.F("id"), - name="sentry_orgmapping_cell_name_date_updated_id_idx", - ), - ), - ] diff --git a/src/sentry/migrations/1049_rename_slugreservation_region_name_to_cell_name.py b/src/sentry/migrations/1049_rename_slugreservation_region_name_to_cell_name.py deleted file mode 100644 index 9f11bb59f57a..000000000000 --- a/src/sentry/migrations/1049_rename_slugreservation_region_name_to_cell_name.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-06 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1048_organizationmapping_cell_name_idx"), - ] - - operations = [ - migrations.AlterField( - model_name="organizationslugreservation", - name="region_name", - field=models.CharField(db_column="region_name", max_length=48, null=False), - ), - migrations.RenameField( - model_name="organizationslugreservation", - old_name="region_name", - new_name="cell_name", - ), - ] diff --git a/src/sentry/migrations/1050_projectkeymapping_uniq_constraint.py b/src/sentry/migrations/1050_projectkeymapping_uniq_constraint.py deleted file mode 100644 index f1ecfcacf5fd..000000000000 --- a/src/sentry/migrations/1050_projectkeymapping_uniq_constraint.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-09 18:57 - -import sentry.db.models.fields.bounded -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1049_rename_slugreservation_region_name_to_cell_name"), - ] - - operations = [ - migrations.AlterField( - model_name="projectkeymapping", - name="project_key_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(), - ), - migrations.AddConstraint( - model_name="projectkeymapping", - constraint=models.UniqueConstraint( - fields=("project_key_id", "cell_name"), - name="sentry_projectkeymapping_project_key_id_cell_name_uniq", - ), - ), - ] diff --git a/src/sentry/migrations/1051_rename_controloutbox_region_name_to_cell_name.py b/src/sentry/migrations/1051_rename_controloutbox_region_name_to_cell_name.py deleted file mode 100644 index d33c4e6ea5e1..000000000000 --- a/src/sentry/migrations/1051_rename_controloutbox_region_name_to_cell_name.py +++ /dev/null @@ -1,89 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-10 19:30 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1050_projectkeymapping_uniq_constraint"), - ] - - operations = [ - migrations.AlterField( - model_name="controloutbox", - name="region_name", - field=models.CharField(db_column="region_name", max_length=48), - ), - migrations.RenameField( - model_name="controloutbox", - old_name="region_name", - new_name="cell_name", - ), - # The indexes reference the same DB column (region_name via db_column), so - # the actual SQL is identical before and after — no drop/recreate needed. - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RemoveIndex( - model_name="controloutbox", - name="sentry_cont_region__1c1c72_idx", - ), - migrations.RemoveIndex( - model_name="controloutbox", - name="sentry_cont_region__0c4512_idx", - ), - migrations.RemoveIndex( - model_name="controloutbox", - name="sentry_cont_region__a95d82_idx", - ), - migrations.AddIndex( - model_name="controloutbox", - index=models.Index( - fields=[ - "cell_name", - "shard_scope", - "shard_identifier", - "category", - "object_identifier", - ], - name="sentry_cont_region__1c1c72_idx", - ), - ), - migrations.AddIndex( - model_name="controloutbox", - index=models.Index( - fields=[ - "cell_name", - "shard_scope", - "shard_identifier", - "scheduled_for", - ], - name="sentry_cont_region__0c4512_idx", - ), - ), - migrations.AddIndex( - model_name="controloutbox", - index=models.Index( - fields=["cell_name", "shard_scope", "shard_identifier", "id"], - name="sentry_cont_region__a95d82_idx", - ), - ), - ], - database_operations=[], - ), - ] diff --git a/src/sentry/migrations/1052_rename_regionoutbox_to_celloutbox.py b/src/sentry/migrations/1052_rename_regionoutbox_to_celloutbox.py deleted file mode 100644 index bb38ee1562a4..000000000000 --- a/src/sentry/migrations/1052_rename_regionoutbox_to_celloutbox.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-12 22:57 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1051_rename_controloutbox_region_name_to_cell_name"), - ("workflow_engine", "0106_migrate_actions_sentry_app_data"), - ] - - operations = [ - # db_table is already "sentry_regionoutbox" on CellOutbox, so no DDL needed. - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RenameModel( - old_name="RegionOutbox", - new_name="CellOutbox", - ), - ], - database_operations=[], - ), - ] diff --git a/src/sentry/migrations/1053_protect_projectdebugfile_file.py b/src/sentry/migrations/1053_protect_projectdebugfile_file.py deleted file mode 100644 index 65ac73831b00..000000000000 --- a/src/sentry/migrations/1053_protect_projectdebugfile_file.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-11 11:29 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1052_rename_regionoutbox_to_celloutbox"), - ] - - operations = [ - migrations.AlterField( - model_name="projectdebugfile", - name="file", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="sentry.file" - ), - ), - ] diff --git a/src/sentry/migrations/1054_rename_regionscheduleddeletion_to_cellscheduleddeletion.py b/src/sentry/migrations/1054_rename_regionscheduleddeletion_to_cellscheduleddeletion.py deleted file mode 100644 index cd34b7278818..000000000000 --- a/src/sentry/migrations/1054_rename_regionscheduleddeletion_to_cellscheduleddeletion.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-16 22:48 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1053_protect_projectdebugfile_file"), - ] - - operations = [ - # db_table is already "sentry_regionscheduleddeletion" on CellScheduledDeletion, so no DDL needed. - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RenameModel( - old_name="RegionScheduledDeletion", - new_name="CellScheduledDeletion", - ), - ], - database_operations=[], - ), - ] diff --git a/src/sentry/migrations/1055_rename_regiontombstone_to_celltombstone.py b/src/sentry/migrations/1055_rename_regiontombstone_to_celltombstone.py deleted file mode 100644 index 379653611f6f..000000000000 --- a/src/sentry/migrations/1055_rename_regiontombstone_to_celltombstone.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-17 20:21 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1054_rename_regionscheduleddeletion_to_cellscheduleddeletion"), - ] - - operations = [ - # db_table is already "sentry_regiontombstone" on CellTombstone, so no DDL needed. - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RenameModel( - old_name="RegionTombstone", - new_name="CellTombstone", - ), - ], - database_operations=[], - ), - ] diff --git a/src/sentry/migrations/1056_add_explorer_autofix_fields.py b/src/sentry/migrations/1056_add_explorer_autofix_fields.py deleted file mode 100644 index 11ec9fd70183..000000000000 --- a/src/sentry/migrations/1056_add_explorer_autofix_fields.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-23 22:08 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1055_rename_regiontombstone_to_celltombstone"), - ] - - operations = [ - migrations.AddField( - model_name="group", - name="seer_explorer_autofix_last_triggered", - field=models.DateTimeField(null=True), - ), - ] diff --git a/src/sentry/migrations/1057_drop_legacy_alert_rule_tables.py b/src/sentry/migrations/1057_drop_legacy_alert_rule_tables.py deleted file mode 100644 index 26d7fdb4ca37..000000000000 --- a/src/sentry/migrations/1057_drop_legacy_alert_rule_tables.py +++ /dev/null @@ -1,42 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-24 18:58 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 - - # There are only 15 rows in this table - is_post_deployment = False - - dependencies = [ - ("sentry", "1056_add_explorer_autofix_fields"), - ] - - operations = [ - # Addresses https://sentry.sentry.io/issues/7295196781/ - SafeRunSQL( - """ - DROP TABLE IF EXISTS sentry_alertruleactivationcondition CASCADE; - """, - hints={"tables": ["sentry_alertruleactivationcondition"]}, - ), - SafeRunSQL( - """ - DROP TABLE IF EXISTS sentry_alertruleactivations CASCADE; - """, - hints={"tables": ["sentry_alertruleactivations"]}, - ), - ] diff --git a/src/sentry/migrations/1058_change_code_mapping_unique_constraint.py b/src/sentry/migrations/1058_change_code_mapping_unique_constraint.py deleted file mode 100644 index 09bcd9161edd..000000000000 --- a/src/sentry/migrations/1058_change_code_mapping_unique_constraint.py +++ /dev/null @@ -1,49 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-27 11:40 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1057_drop_legacy_alert_rule_tables"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AddConstraint( - model_name="repositoryprojectpathconfig", - constraint=models.UniqueConstraint( - fields=["project", "stack_root", "source_root"], - name="sentry_repositoryproject_project_id_stack_root_so_c371dfa7_uniq", - ), - ), - migrations.AlterUniqueTogether( - name="repositoryprojectpathconfig", - unique_together=set(), - ), - ], - state_operations=[ - migrations.AlterUniqueTogether( - name="repositoryprojectpathconfig", - unique_together={("project", "stack_root", "source_root")}, - ), - ], - ), - ] diff --git a/src/sentry/migrations/1059_add_groupopenperiodactivity_date_added_index.py b/src/sentry/migrations/1059_add_groupopenperiodactivity_date_added_index.py deleted file mode 100644 index d68abbcee833..000000000000 --- a/src/sentry/migrations/1059_add_groupopenperiodactivity_date_added_index.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-31 22:06 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1058_change_code_mapping_unique_constraint"), - ] - - operations = [ - migrations.AddIndex( - model_name="groupopenperiodactivity", - index=models.Index(fields=["date_added"], name="sentry_grou_date_ad_e242e5_idx"), - ), - ] diff --git a/src/sentry/migrations/1060_eventattachment_date_expires.py b/src/sentry/migrations/1060_eventattachment_date_expires.py deleted file mode 100644 index f65eee772f4e..000000000000 --- a/src/sentry/migrations/1060_eventattachment_date_expires.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-01 07:22 - -import datetime - -import django.db.models.expressions -import django.db.models.functions.datetime -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.objectstore import default_attachment_retention - -# Initial default applies to existing attachments. New rows will be written with -# a runtime-defined default, so we follow-up with a static 30d default. -_RETENTION_DAYS = default_attachment_retention() - - -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", "1059_add_groupopenperiodactivity_date_added_index"), - ] - - operations = [ - migrations.AddField( - model_name="eventattachment", - name="date_expires", - field=models.DateTimeField( - db_default=django.db.models.expressions.CombinedExpression( - django.db.models.functions.datetime.Now(), - "+", - models.Value(datetime.timedelta(days=_RETENTION_DAYS)), - ), - ), - ), - migrations.AlterField( - model_name="eventattachment", - name="date_expires", - field=models.DateTimeField( - db_default=django.db.models.expressions.CombinedExpression( - django.db.models.functions.datetime.Now(), - "+", - models.Value(datetime.timedelta(days=30)), - ), - ), - ), - ] diff --git a/src/sentry/migrations/1061_eventattachment_date_expires_index.py b/src/sentry/migrations/1061_eventattachment_date_expires_index.py deleted file mode 100644 index 62967a337149..000000000000 --- a/src/sentry/migrations/1061_eventattachment_date_expires_index.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-01 12:13 - -import datetime - -import django.db.models.expressions -import django.db.models.functions.datetime -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1060_eventattachment_date_expires"), - ] - - operations = [ - migrations.AlterField( - model_name="eventattachment", - name="date_expires", - field=models.DateTimeField( - db_default=django.db.models.expressions.CombinedExpression( - django.db.models.functions.datetime.Now(), - "+", - models.Value(datetime.timedelta(days=30)), - ), - db_index=True, - ), - ), - ] diff --git a/src/sentry/migrations/1062_backfill_eventattachment_date_expires.py b/src/sentry/migrations/1062_backfill_eventattachment_date_expires.py deleted file mode 100644 index 379260677e4a..000000000000 --- a/src/sentry/migrations/1062_backfill_eventattachment_date_expires.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - is_post_deployment = True - - dependencies = [ - ("sentry", "1061_eventattachment_date_expires_index"), - ] - - operations = [ - migrations.RunPython( - migrations.RunPython.noop, - migrations.RunPython.noop, - hints={"tables": ["sentry_eventattachment"]}, - ), - ] diff --git a/src/sentry/migrations/1063_remove_customdynamicsamplingrule.py b/src/sentry/migrations/1063_remove_customdynamicsamplingrule.py deleted file mode 100644 index 23c3d41982f6..000000000000 --- a/src/sentry/migrations/1063_remove_customdynamicsamplingrule.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.11 on 2026-04-02 -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1062_backfill_eventattachment_date_expires"), - ] - - operations = [ - migrations.AlterField( - model_name="customdynamicsamplingruleproject", - name="custom_dynamic_sampling_rule", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.customdynamicsamplingrule", - ), - ), - migrations.AlterField( - model_name="customdynamicsamplingruleproject", - name="project", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.project", - ), - ), - migrations.AlterField( - model_name="customdynamicsamplingrule", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - SafeDeleteModel( - name="CustomDynamicSamplingRuleProject", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeDeleteModel( - name="CustomDynamicSamplingRule", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1064_eventattachment_date_expires_now.py b/src/sentry/migrations/1064_eventattachment_date_expires_now.py deleted file mode 100644 index 6355479b1014..000000000000 --- a/src/sentry/migrations/1064_eventattachment_date_expires_now.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-07 11:17 - -import datetime -import django.db.models.expressions -import django.db.models.functions.datetime -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1063_remove_customdynamicsamplingrule"), - ] - - operations = [ - migrations.AlterField( - model_name="eventattachment", - name="date_expires", - field=models.DateTimeField( - db_default=django.db.models.expressions.CombinedExpression( - django.db.models.functions.datetime.Now(), - "+", - models.Value(datetime.timedelta(days=30)), - ), - db_index=True, - ), - ), - ] diff --git a/src/sentry/migrations/1065_delete_customdynamicsamplingrule.py b/src/sentry/migrations/1065_delete_customdynamicsamplingrule.py deleted file mode 100644 index 766a2f618137..000000000000 --- a/src/sentry/migrations/1065_delete_customdynamicsamplingrule.py +++ /dev/null @@ -1,22 +0,0 @@ -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1064_eventattachment_date_expires_now"), - ] - - operations = [ - SafeDeleteModel( - name="CustomDynamicSamplingRuleProject", - deletion_action=DeletionAction.DELETE, - ), - SafeDeleteModel( - name="CustomDynamicSamplingRule", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1066_add_export_format_in_data_export_obj.py b/src/sentry/migrations/1066_add_export_format_in_data_export_obj.py deleted file mode 100644 index e701fc80426f..000000000000 --- a/src/sentry/migrations/1066_add_export_format_in_data_export_obj.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-01 19:40 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1065_delete_customdynamicsamplingrule"), - ] - - operations = [ - migrations.AddField( - model_name="exporteddata", - name="export_format", - field=models.CharField(default="csv", null=True), - ), - ] diff --git a/src/sentry/migrations/1067_add_dashboard_revision_model.py b/src/sentry/migrations/1067_add_dashboard_revision_model.py deleted file mode 100644 index 8b023c264447..000000000000 --- a/src/sentry/migrations/1067_add_dashboard_revision_model.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-14 15:38 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.db.models.fields.jsonfield -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1066_add_export_format_in_data_export_obj"), - ] - - operations = [ - migrations.CreateModel( - name="DashboardRevision", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "created_by_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("title", models.CharField(max_length=255)), - ("source", models.CharField(default="edit", max_length=32)), - ("snapshot", sentry.db.models.fields.jsonfield.JSONField(default=dict)), - ("snapshot_schema_version", models.IntegerField()), - ( - "dashboard", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.dashboard" - ), - ), - ], - options={ - "db_table": "sentry_dashboardrevision", - "indexes": [ - models.Index( - fields=["dashboard", "-date_added"], name="sentry_dashrev_dash_date_idx" - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1068_rename_relocationtransfer_region_to_cell.py b/src/sentry/migrations/1068_rename_relocationtransfer_region_to_cell.py deleted file mode 100644 index 67e8d4ed675c..000000000000 --- a/src/sentry/migrations/1068_rename_relocationtransfer_region_to_cell.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-14 23:15 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1067_add_dashboard_revision_model"), - ] - - operations = [ - migrations.AlterField( - model_name="controlrelocationtransfer", - name="exporting_region", - field=models.CharField(db_column="exporting_region"), - ), - migrations.RenameField( - model_name="controlrelocationtransfer", - old_name="exporting_region", - new_name="exporting_cell", - ), - migrations.AlterField( - model_name="controlrelocationtransfer", - name="requesting_region", - field=models.CharField(db_column="requesting_region"), - ), - migrations.RenameField( - model_name="controlrelocationtransfer", - old_name="requesting_region", - new_name="requesting_cell", - ), - migrations.AlterField( - model_name="regionrelocationtransfer", - name="exporting_region", - field=models.CharField(db_column="exporting_region"), - ), - migrations.RenameField( - model_name="regionrelocationtransfer", - old_name="exporting_region", - new_name="exporting_cell", - ), - migrations.AlterField( - model_name="regionrelocationtransfer", - name="requesting_region", - field=models.CharField(db_column="requesting_region"), - ), - migrations.RenameField( - model_name="regionrelocationtransfer", - old_name="requesting_region", - new_name="requesting_cell", - ), - ] diff --git a/src/sentry/migrations/1069_add_organization_avatar_replica.py b/src/sentry/migrations/1069_add_organization_avatar_replica.py deleted file mode 100644 index 0ce723fc81eb..000000000000 --- a/src/sentry/migrations/1069_add_organization_avatar_replica.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-16 22:06 - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.hybrid_cloud_foreign_key -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1068_rename_relocationtransfer_region_to_cell"), - ] - - operations = [ - migrations.CreateModel( - name="OrganizationAvatarReplica", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organization_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Organization", - db_index=True, - on_delete="CASCADE", - unique=True, - ), - ), - ("avatar_type", models.PositiveSmallIntegerField(default=0)), - ("avatar_ident", models.CharField(max_length=32)), - ], - options={ - "db_table": "sentry_organizationavatarreplica", - }, - ), - ] diff --git a/src/sentry/migrations/1070_increase_integration_external_id_length.py b/src/sentry/migrations/1070_increase_integration_external_id_length.py deleted file mode 100644 index 6d89ba916506..000000000000 --- a/src/sentry/migrations/1070_increase_integration_external_id_length.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-17 16:39 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - # Disabled: this migration changes the length of indexed columns, which our - # safety framework now blocks. The migration has already been applied in - # production, so it is safe to skip the check here. - checked = False - - dependencies = [ - ("sentry", "1069_add_organization_avatar_replica"), - ] - - operations = [ - migrations.AlterField( - model_name="integration", - name="external_id", - field=models.CharField(max_length=256), - ), - ] diff --git a/src/sentry/migrations/1071_add_broadcast_sync_locked.py b/src/sentry/migrations/1071_add_broadcast_sync_locked.py deleted file mode 100644 index 708b5b915e71..000000000000 --- a/src/sentry/migrations/1071_add_broadcast_sync_locked.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-20 00:00 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1070_increase_integration_external_id_length"), - ] - - operations = [ - migrations.AddField( - model_name="broadcast", - name="sync_locked", - field=models.BooleanField(default=False, db_default=False), - ), - ] diff --git a/src/sentry/migrations/1072_backfill_scm_integration_config.py b/src/sentry/migrations/1072_backfill_scm_integration_config.py deleted file mode 100644 index 22b4f2437be7..000000000000 --- a/src/sentry/migrations/1072_backfill_scm_integration_config.py +++ /dev/null @@ -1,85 +0,0 @@ -from collections import defaultdict - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -# Legacy OrganizationOption keys whose value=True needs to be carried onto -# OrganizationIntegration.config. Mirrors _SCM_BACKFILL_PROVIDER_KEYS in -# src/sentry/receivers/outbox/cell.py. -_LEGACY_KEYS = ( - "sentry:github_pr_bot", - "sentry:github_nudge_invite", - "sentry:gitlab_pr_bot", -) - -# Hardcoded values from sentry.hybridcloud.outbox.category at the time this -# migration was authored. Pinned as integers so a future enum/scope rename -# can't break replays on stale databases. -_ORGANIZATION_SCOPE = 0 -_SCM_INTEGRATION_CONFIG_BACKFILL = 46 - - -def backfill_scm_integration_config( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Emit one cell outbox per org with at least one true-valued legacy SCM - toggle. The receiver (sentry.receivers.outbox.cell) drains each outbox - on the cell silo and fans out to every ACTIVE GitHub/GitLab - OrganizationIntegration via RPC. - - The previous body did the RPC directly from the migration CLI and - failed in prod with 401 errors against the control silo. Outboxes - drain inside a worker that has a stable RPC auth context, retry on - transient failures, and run in current code -- so a replay against - drifted code is at worst a no-op (the receiver may be retired) rather - than a half-applied write. - """ - OrganizationOption = apps.get_model("sentry", "OrganizationOption") - CellOutbox = apps.get_model("sentry", "CellOutbox") - - queryset = OrganizationOption.objects.filter(key__in=_LEGACY_KEYS, value=True) - - opts_by_org: defaultdict[int, set[str]] = defaultdict(set) - for opt in queryset: - opts_by_org[opt.organization_id].add(opt.key) - - for organization_id, opts in opts_by_org.items(): - CellOutbox( - shard_scope=_ORGANIZATION_SCOPE, - shard_identifier=organization_id, - category=_SCM_INTEGRATION_CONFIG_BACKFILL, - object_identifier=organization_id, - payload={"keys": sorted(opts)}, - ).save() - - -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 = True - - dependencies = [ - ("sentry", "1071_add_broadcast_sync_locked"), - ] - - operations = [ - migrations.RunPython( - backfill_scm_integration_config, - migrations.RunPython.noop, - hints={"tables": ["sentry_organizationoptions"]}, - ), - ] diff --git a/src/sentry/migrations/1073_add_org_ci_scope.py b/src/sentry/migrations/1073_add_org_ci_scope.py deleted file mode 100644 index 6e6504abf69d..000000000000 --- a/src/sentry/migrations/1073_add_org_ci_scope.py +++ /dev/null @@ -1,153 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-22 15:30 - -import bitfield.models -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1072_backfill_scm_integration_config"), - ] - - operations = [ - migrations.AlterField( - model_name="apiauthorization", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apikey", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="apitoken", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - migrations.AlterField( - model_name="sentryapp", - name="scopes", - field=bitfield.models.BitField( - [ - "project:read", - "project:write", - "project:admin", - "project:releases", - "team:read", - "team:write", - "team:admin", - "event:read", - "event:write", - "event:admin", - "org:read", - "org:write", - "org:admin", - "member:read", - "member:write", - "member:admin", - "org:integrations", - "alerts:read", - "alerts:write", - "member:invite", - "project:distribution", - "org:ci", - ], - default=None, - ), - ), - ] diff --git a/src/sentry/migrations/1074_remove_dashboardtombstone.py b/src/sentry/migrations/1074_remove_dashboardtombstone.py deleted file mode 100644 index 3633aa7f59f7..000000000000 --- a/src/sentry/migrations/1074_remove_dashboardtombstone.py +++ /dev/null @@ -1,31 +0,0 @@ -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1073_add_org_ci_scope"), - ] - - operations = [ - migrations.AlterField( - model_name="dashboardtombstone", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - SafeDeleteModel( - name="DashboardTombstone", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1075_add_user_is_suspended.py b/src/sentry/migrations/1075_add_user_is_suspended.py deleted file mode 100644 index 5bc945c7cd50..000000000000 --- a/src/sentry/migrations/1075_add_user_is_suspended.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-29 17:22 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1074_remove_dashboardtombstone"), - ] - - operations = [ - migrations.AddField( - model_name="user", - name="is_suspended", - field=models.BooleanField(db_default=False, default=False), - ), - ] diff --git a/src/sentry/migrations/1076_delete_dashboardtombstone.py b/src/sentry/migrations/1076_delete_dashboardtombstone.py deleted file mode 100644 index ca282bac6d61..000000000000 --- a/src/sentry/migrations/1076_delete_dashboardtombstone.py +++ /dev/null @@ -1,18 +0,0 @@ -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1075_add_user_is_suspended"), - ] - - operations = [ - SafeDeleteModel( - name="DashboardTombstone", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1077_add_is_disabled_field.py b/src/sentry/migrations/1077_add_is_disabled_field.py deleted file mode 100644 index 77fdcff75939..000000000000 --- a/src/sentry/migrations/1077_add_is_disabled_field.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-29 22:27 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1076_delete_dashboardtombstone"), - ] - - operations = [ - migrations.AddField( - model_name="sentryapp", - name="is_disabled", - field=models.BooleanField(default=False, db_default=False), - ), - ] diff --git a/src/sentry/migrations/1078_drop_querysubscription_time_window.py b/src/sentry/migrations/1078_drop_querysubscription_time_window.py deleted file mode 100644 index 894556925223..000000000000 --- a/src/sentry/migrations/1078_drop_querysubscription_time_window.py +++ /dev/null @@ -1,24 +0,0 @@ -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1077_add_is_disabled_field"), - ] - - operations = [ - # The field was removed from Django model state in migration 0077 (May 2020) - # using plain RemoveField, before the SafeRemoveField two-step process existed. - # Since the field never went through MOVE_TO_PENDING, SafeRemoveField(DELETE) - # can't be used here — it would fail the pending_deletion_fields check. - SafeRunSQL( - sql=""" - ALTER TABLE "sentry_querysubscription" DROP COLUMN IF EXISTS "time_window"; - """, - reverse_sql="", - hints={"tables": ["sentry_querysubscription"]}, - ), - ] diff --git a/src/sentry/migrations/1079_purge_scm_legacy_org_options.py b/src/sentry/migrations/1079_purge_scm_legacy_org_options.py deleted file mode 100644 index fd6c4ae317f3..000000000000 --- a/src/sentry/migrations/1079_purge_scm_legacy_org_options.py +++ /dev/null @@ -1,46 +0,0 @@ -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -_LEGACY_KEYS = ( - "sentry:github_pr_bot", - "sentry:github_nudge_invite", - "sentry:gitlab_pr_bot", -) - - -def purge_scm_legacy_org_options(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - OrganizationOption = apps.get_model("sentry", "OrganizationOption") - - for opt in OrganizationOption.objects.filter(key__in=_LEGACY_KEYS): - opt.delete() - - -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 = True - - dependencies = [ - ("sentry", "1078_drop_querysubscription_time_window"), - ] - - operations = [ - migrations.RunPython( - purge_scm_legacy_org_options, - migrations.RunPython.noop, - hints={"tables": ["sentry_organizationoptions"]}, - ), - ] diff --git a/src/sentry/migrations/1080_backfill_deprecated_dashboard_widget_display_types.py b/src/sentry/migrations/1080_backfill_deprecated_dashboard_widget_display_types.py deleted file mode 100644 index c557330a2d17..000000000000 --- a/src/sentry/migrations/1080_backfill_deprecated_dashboard_widget_display_types.py +++ /dev/null @@ -1,119 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-01 15:33 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.iterators import chunked -from sentry.utils.query import RangeQuerySetWrapperWithProgressBarApprox - -logger = logging.getLogger(__name__) - -# Hardcoded values from sentry.models.dashboard_widget.DashboardWidgetDisplayTypes -# at the time this migration was authored. Pinned as integers so a future enum -# rename can't break replays on stale databases. -_AREA_CHART = 1 -_STACKED_AREA_CHART = 2 -_TOP_N = 7 - -_DEPRECATED_DISPLAY_TYPES = (_STACKED_AREA_CHART, _TOP_N) - -# top_n widgets had an implicit series limit of 5 (hardcoded TOP_N constant in -# the frontend). Once coerced to area, the dashboard serializer requires limit -# to be set on chart widgets that have group-by columns, so populate it -# explicitly where it's missing. -_TOP_N_DEFAULT_LIMIT = 5 - -BATCH_SIZE = 1000 - - -def backfill_deprecated_display_types( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Coerce widgets stored with deprecated display types to AREA, matching the - coercion the frontend already performs at render time. The builder has - rejected new top_n widgets for some time, but existing rows kept the - deprecated value, which broke the dashboard duplicate flow (the API - rejects deprecated display types on widgets without an id). - - stacked_area has no frontend rendering path at all, so widgets stored - with that value were already broken in the UI. - - For top_n rows specifically, populate `limit` to 5 where it is missing. - The dashboard serializer rejects chart widgets with group-by columns and a - null limit, and every top_n widget by definition has group-by columns, so - coercing display_type alone would just swap one rejection for another on - the duplicate flow. - """ - DashboardWidget = apps.get_model("sentry", "DashboardWidget") - - stats = {"stacked_area": 0, "top_n": 0, "limit_populated": 0} - - for chunk in chunked( - RangeQuerySetWrapperWithProgressBarApprox( - DashboardWidget.objects.filter(display_type__in=_DEPRECATED_DISPLAY_TYPES).values_list( - "id", "display_type", "limit" - ), - result_value_getter=lambda item: item[0], - ), - BATCH_SIZE, - ): - # Partition the chunk into rows that need both columns updated - # (top_n with null limit) and rows that need only display_type. - # Each row appears in exactly one .update() so its changes commit - # together; CheckedMigration runs with atomic=False, so a row split - # across two .update() calls could be left half-migrated by a crash. - top_n_null_limit_ids = [] - display_only_ids = [] - for widget_id, display_type, limit in chunk: - if display_type == _STACKED_AREA_CHART: - stats["stacked_area"] += 1 - display_only_ids.append(widget_id) - else: - stats["top_n"] += 1 - if limit is None: - top_n_null_limit_ids.append(widget_id) - stats["limit_populated"] += 1 - else: - display_only_ids.append(widget_id) - - if top_n_null_limit_ids: - DashboardWidget.objects.filter(id__in=top_n_null_limit_ids).update( - display_type=_AREA_CHART, limit=_TOP_N_DEFAULT_LIMIT - ) - if display_only_ids: - DashboardWidget.objects.filter(id__in=display_only_ids).update(display_type=_AREA_CHART) - - logger.info("backfill_deprecated_display_types: complete, %s", stats) - - -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 = True - - dependencies = [ - ("sentry", "1079_purge_scm_legacy_org_options"), - ] - - operations = [ - migrations.RunPython( - backfill_deprecated_display_types, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_dashboardwidget"]}, - ), - ] diff --git a/src/sentry/migrations/1081_remove_neglectedrule.py b/src/sentry/migrations/1081_remove_neglectedrule.py deleted file mode 100644 index 6656c25b9811..000000000000 --- a/src/sentry/migrations/1081_remove_neglectedrule.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-05 22:43 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1080_backfill_deprecated_dashboard_widget_display_types"), - ] - - operations = [ - migrations.AlterField( - model_name="neglectedrule", - name="organization", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - migrations.AlterField( - model_name="neglectedrule", - name="rule", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.rule", - ), - ), - SafeDeleteModel( - name="NeglectedRule", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1082_drop_neglectedrule_table.py b/src/sentry/migrations/1082_drop_neglectedrule_table.py deleted file mode 100644 index 9e57b69c21a2..000000000000 --- a/src/sentry/migrations/1082_drop_neglectedrule_table.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-06 16:24 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1081_remove_neglectedrule"), - ] - - operations = [ - SafeDeleteModel(name="NeglectedRule", deletion_action=DeletionAction.DELETE), - ] diff --git a/src/sentry/migrations/1083_remove_dashboardlastvisited.py b/src/sentry/migrations/1083_remove_dashboardlastvisited.py deleted file mode 100644 index 5bbecf6bfeba..000000000000 --- a/src/sentry/migrations/1083_remove_dashboardlastvisited.py +++ /dev/null @@ -1,40 +0,0 @@ -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1082_drop_neglectedrule_table"), - ] - - operations = [ - migrations.AlterField( - model_name="dashboardlastvisited", - name="dashboard", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.dashboard", - ), - ), - migrations.AlterField( - model_name="dashboardlastvisited", - name="member", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organizationmember", - ), - ), - SafeDeleteModel( - name="DashboardLastVisited", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1084_delete_dashboardlastvisited.py b/src/sentry/migrations/1084_delete_dashboardlastvisited.py deleted file mode 100644 index df2d750805cc..000000000000 --- a/src/sentry/migrations/1084_delete_dashboardlastvisited.py +++ /dev/null @@ -1,18 +0,0 @@ -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1083_remove_dashboardlastvisited"), - ] - - operations = [ - SafeDeleteModel( - name="DashboardLastVisited", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1085_add_date_synced_to_projectcodeowners.py b/src/sentry/migrations/1085_add_date_synced_to_projectcodeowners.py deleted file mode 100644 index a03c1ae4837c..000000000000 --- a/src/sentry/migrations/1085_add_date_synced_to_projectcodeowners.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-07 20:06 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1084_delete_dashboardlastvisited"), - ] - - operations = [ - migrations.AddField( - model_name="projectcodeowners", - name="date_synced", - field=models.DateTimeField(null=True), - ), - ] diff --git a/src/sentry/migrations/1086_add_source_to_external_actor.py b/src/sentry/migrations/1086_add_source_to_external_actor.py deleted file mode 100644 index 9b032f3583bf..000000000000 --- a/src/sentry/migrations/1086_add_source_to_external_actor.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-11 16:33 - -import sentry.db.models.fields.bounded -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1085_add_date_synced_to_projectcodeowners"), - ] - - operations = [ - migrations.AddField( - model_name="externalactor", - name="source", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ] diff --git a/src/sentry/migrations/1087_add_projectrepository.py b/src/sentry/migrations/1087_add_projectrepository.py deleted file mode 100644 index e0e61d06c917..000000000000 --- a/src/sentry/migrations/1087_add_projectrepository.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-11 18:17 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1086_add_source_to_external_actor"), - ] - - operations = [ - migrations.CreateModel( - name="ProjectRepository", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("source", models.SmallIntegerField(default=0)), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ( - "repository", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.repository" - ), - ), - ], - options={ - "db_table": "sentry_projectrepository", - "unique_together": {("project", "repository")}, - }, - ), - migrations.AddField( - model_name="repositoryprojectpathconfig", - name="project_repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.projectrepository", - ), - ), - ] diff --git a/src/sentry/migrations/1088_remove_rulefirehistory.py b/src/sentry/migrations/1088_remove_rulefirehistory.py deleted file mode 100644 index f6807d6f7084..000000000000 --- a/src/sentry/migrations/1088_remove_rulefirehistory.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-12 16:55 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1087_add_projectrepository"), - ("notifications", "0006_drop_issue_alert_columns_notificationmessage"), - ] - - operations = [ - migrations.AlterField( - model_name="rulefirehistory", - name="rule", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.rule", - ), - ), - SafeDeleteModel( - name="RuleFireHistory", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1089_drop_rulefirehistory.py b/src/sentry/migrations/1089_drop_rulefirehistory.py deleted file mode 100644 index 41b6578d5b9f..000000000000 --- a/src/sentry/migrations/1089_drop_rulefirehistory.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-12 18:50 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1088_remove_rulefirehistory"), - ] - - operations = [ - SafeDeleteModel( - name="RuleFireHistory", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1090_rm_triggered_incidents_alertruletrigger.py b/src/sentry/migrations/1090_rm_triggered_incidents_alertruletrigger.py deleted file mode 100644 index 526841f2740e..000000000000 --- a/src/sentry/migrations/1090_rm_triggered_incidents_alertruletrigger.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-12 22:30 - - -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", "1089_drop_rulefirehistory"), - ] - - operations = [ - SafeRemoveField( - model_name="alertruletrigger", - name="triggered_incidents", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1091_delete_triggered_incidents_alertruletrigger.py b/src/sentry/migrations/1091_delete_triggered_incidents_alertruletrigger.py deleted file mode 100644 index 3f483e91e976..000000000000 --- a/src/sentry/migrations/1091_delete_triggered_incidents_alertruletrigger.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-12 23:01 - - -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", "1090_rm_triggered_incidents_alertruletrigger"), - ] - - operations = [ - SafeRemoveField( - model_name="alertruletrigger", - name="triggered_incidents", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1092_backfill_projectrepository.py b/src/sentry/migrations/1092_backfill_projectrepository.py deleted file mode 100644 index 982d2b1ad1d8..000000000000 --- a/src/sentry/migrations/1092_backfill_projectrepository.py +++ /dev/null @@ -1,129 +0,0 @@ -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -# Mirror of ProjectRepositorySource values — we can't import the model -# in a migration because the code may change after the migration is written. -SOURCE_MANUAL = 0 -SOURCE_AUTO_EVENT = 2 -SOURCE_SEER_PREFERENCE = 4 - -# Lower number = higher priority. Used to pick the best source when -# a (project, repo) pair appears in multiple tables. -SOURCE_PRIORITY = { - SOURCE_SEER_PREFERENCE: 0, - SOURCE_MANUAL: 1, - SOURCE_AUTO_EVENT: 2, -} - - -def backfill_project_repository(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - ProjectRepository = apps.get_model("sentry", "ProjectRepository") - RepositoryProjectPathConfig = apps.get_model("sentry", "RepositoryProjectPathConfig") - SeerProjectRepository = apps.get_model("seer", "SeerProjectRepository") - - # Step 1: Collect all unique (project_id, repository_id) pairs and pick - # the best source for each. - # - # Priority: SEER_PREFERENCE (user explicitly picked repos for Seer) - # > MANUAL (user-created code mapping) > AUTO_EVENT (auto-generated). - - pair_to_source: dict[tuple[int, int], int] = {} - - def _set_if_higher_priority(key: tuple[int, int], new_source: int) -> None: - existing = pair_to_source.get(key) - if existing is None or SOURCE_PRIORITY[new_source] < SOURCE_PRIORITY[existing]: - pair_to_source[key] = new_source - - for row in RangeQuerySetWrapperWithProgressBar( - RepositoryProjectPathConfig.objects.values_list( - "id", "project_id", "repository_id", "automatically_generated" - ), - result_value_getter=lambda values: values[0], - ): - _id, project_id, repository_id, automatically_generated = row - new_source = SOURCE_AUTO_EVENT if automatically_generated else SOURCE_MANUAL - _set_if_higher_priority((project_id, repository_id), new_source) - - for row in RangeQuerySetWrapperWithProgressBar( - SeerProjectRepository.objects.values_list("id", "project_id", "repository_id"), - result_value_getter=lambda values: values[0], - ): - _id, project_id, repository_id = row - _set_if_higher_priority((project_id, repository_id), SOURCE_SEER_PREFERENCE) - - existing_pairs = set(ProjectRepository.objects.values_list("project_id", "repository_id")) - - batch: list[object] = [] - for (project_id, repository_id), source in pair_to_source.items(): - if (project_id, repository_id) in existing_pairs: - continue - batch.append( - ProjectRepository(project_id=project_id, repository_id=repository_id, source=source) - ) - if len(batch) >= 1000: - ProjectRepository.objects.bulk_create(batch, ignore_conflicts=True) - batch = [] - if batch: - ProjectRepository.objects.bulk_create(batch, ignore_conflicts=True) - - pr_lookup: dict[tuple[int, int], int] = {} - for pr_id, project_id, repository_id in ProjectRepository.objects.values_list( - "id", "project_id", "repository_id" - ): - pr_lookup[(project_id, repository_id)] = pr_id - - for config in RangeQuerySetWrapperWithProgressBar( - RepositoryProjectPathConfig.objects.filter(project_repository_id__isnull=True) - ): - pr_id = pr_lookup.get((config.project_id, config.repository_id)) - if pr_id is not None: - RepositoryProjectPathConfig.objects.filter(id=config.id).update( - project_repository_id=pr_id - ) - - for spr in RangeQuerySetWrapperWithProgressBar( - SeerProjectRepository.objects.filter(project_repository_id__isnull=True) - ): - pr_id = pr_lookup.get((spr.project_id, spr.repository_id)) - if pr_id is not None: - spr.project_repository_id = pr_id - spr.save(update_fields=["project_repository_id"]) - - -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 = True - - dependencies = [ - ("sentry", "1091_delete_triggered_incidents_alertruletrigger"), - ("seer", "0011_add_project_repository_fk_to_seer"), - ] - - operations = [ - migrations.RunPython( - backfill_project_repository, - reverse_code=migrations.RunPython.noop, - hints={ - "tables": [ - "sentry_projectrepository", - "sentry_repositoryprojectpathconfig", - "seer_projectrepository", - ] - }, - ), - ] diff --git a/src/sentry/migrations/1093_remove_incidenttrigger.py b/src/sentry/migrations/1093_remove_incidenttrigger.py deleted file mode 100644 index 530b94f10cee..000000000000 --- a/src/sentry/migrations/1093_remove_incidenttrigger.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-13 18:07 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1092_backfill_projectrepository"), - ] - - operations = [ - migrations.AlterField( - model_name="incidenttrigger", - name="alert_rule_trigger", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.alertruletrigger", - ), - ), - migrations.AlterField( - model_name="incidenttrigger", - name="incident", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - db_index=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.incident", - ), - ), - SafeDeleteModel( - name="IncidentTrigger", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1094_delete_incidenttrigger.py b/src/sentry/migrations/1094_delete_incidenttrigger.py deleted file mode 100644 index 538ecec49c4b..000000000000 --- a/src/sentry/migrations/1094_delete_incidenttrigger.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-13 18:59 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1093_remove_incidenttrigger"), - ] - - operations = [ - SafeDeleteModel( - name="IncidentTrigger", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1095_make_project_repository_fk_notnull.py b/src/sentry/migrations/1095_make_project_repository_fk_notnull.py deleted file mode 100644 index 82f1c2e6caa6..000000000000 --- a/src/sentry/migrations/1095_make_project_repository_fk_notnull.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-13 22:18 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1094_delete_incidenttrigger"), - ] - - operations = [ - migrations.AlterField( - model_name="repositoryprojectpathconfig", - name="project_repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.projectrepository" - ), - ), - ] diff --git a/src/sentry/migrations/1096_backfill_mcp_dashboard_widget_filters.py b/src/sentry/migrations/1096_backfill_mcp_dashboard_widget_filters.py deleted file mode 100644 index 08a704bf3f54..000000000000 --- a/src/sentry/migrations/1096_backfill_mcp_dashboard_widget_filters.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-13 12:00 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - -_OLD_FILTER = "span.name:mcp.server" -_NEW_FILTER = "span.op:mcp.server" - - -def backfill_mcp_dashboard_widget_filters( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - The MCP pre-built dashboards filtered spans on `span.name:mcp.server`, but - a recent Relay change corrected the `name` of MCP spans, so that filter no - longer matches. The fix in code switched to `span.op:mcp.server`, but any - widgets already saved with the old condition (from prebuilt dashboards that - were copied/customized, or from users who hand-typed the filter) are still - broken. Replace the literal substring everywhere it appears in - DashboardWidgetQuery.conditions. - """ - DashboardWidgetQuery = apps.get_model("sentry", "DashboardWidgetQuery") - - updated = 0 - rows = DashboardWidgetQuery.objects.filter(conditions__contains=_OLD_FILTER).values_list( - "id", "conditions" - ) - for row_id, conditions in rows: - new_conditions = conditions.replace(_OLD_FILTER, _NEW_FILTER) - if new_conditions == conditions: - continue - DashboardWidgetQuery.objects.filter(id=row_id).update(conditions=new_conditions) - updated += 1 - - logger.info("backfill_mcp_dashboard_widget_filters: complete, updated=%d", updated) - - -class Migration(CheckedMigration): - is_post_deployment = True - - dependencies = [ - ("sentry", "1095_make_project_repository_fk_notnull"), - ] - - operations = [ - migrations.RunPython( - backfill_mcp_dashboard_widget_filters, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_dashboardwidgetquery"]}, - ), - ] diff --git a/src/sentry/migrations/1097_add_new_unique_constraints.py b/src/sentry/migrations/1097_add_new_unique_constraints.py deleted file mode 100644 index 5a3dc763be9b..000000000000 --- a/src/sentry/migrations/1097_add_new_unique_constraints.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 19:11 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1096_backfill_mcp_dashboard_widget_filters"), - ] - - operations = [ - migrations.AddConstraint( - model_name="repositoryprojectpathconfig", - constraint=models.UniqueConstraint( - fields=("project_repository", "stack_root", "source_root"), - name="sentry_repositoryproject_project_repository_id_st_b55e4224_uniq", - ), - ), - ] diff --git a/src/sentry/migrations/1098_remove_old_fks.py b/src/sentry/migrations/1098_remove_old_fks.py deleted file mode 100644 index cc6de1933fb2..000000000000 --- a/src/sentry/migrations/1098_remove_old_fks.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 19:26 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -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", "1097_add_new_unique_constraints"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="repositoryprojectpathconfig", - unique_together=set(), - ), - migrations.AlterField( - model_name="repositoryprojectpathconfig", - name="project", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.project", - ), - ), - migrations.AlterField( - model_name="repositoryprojectpathconfig", - name="repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.repository", - ), - ), - SafeRemoveField( - model_name="repositoryprojectpathconfig", - name="project", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="repositoryprojectpathconfig", - name="repository", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1099_drop_old_fk_columns.py b/src/sentry/migrations/1099_drop_old_fk_columns.py deleted file mode 100644 index d1665036a085..000000000000 --- a/src/sentry/migrations/1099_drop_old_fk_columns.py +++ /dev/null @@ -1,36 +0,0 @@ -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", "1098_remove_old_fks"), - ] - - operations = [ - SafeRemoveField( - model_name="repositoryprojectpathconfig", - name="project", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="repositoryprojectpathconfig", - name="repository", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/migrations/1100_add_relocation_file_bucket_path.py b/src/sentry/migrations/1100_add_relocation_file_bucket_path.py deleted file mode 100644 index b4abf485eabc..000000000000 --- a/src/sentry/migrations/1100_add_relocation_file_bucket_path.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-21 17:47 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1099_drop_old_fk_columns"), - ] - - operations = [ - migrations.AddField( - model_name="relocationfile", - name="bucket_path", - field=models.CharField(null=True), - ), - ] diff --git a/src/sentry/migrations/1101_remove_email_model_pending.py b/src/sentry/migrations/1101_remove_email_model_pending.py deleted file mode 100644 index 032b402b3360..000000000000 --- a/src/sentry/migrations/1101_remove_email_model_pending.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-26 20:43 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1100_add_relocation_file_bucket_path"), - ] - - operations = [ - SafeDeleteModel(name="Email", deletion_action=DeletionAction.MOVE_TO_PENDING), - ] diff --git a/src/sentry/migrations/1102_activity_project_type_index.py b/src/sentry/migrations/1102_activity_project_type_index.py deleted file mode 100644 index 2b28408afe5d..000000000000 --- a/src/sentry/migrations/1102_activity_project_type_index.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-29 19:53 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("sentry", "1101_remove_email_model_pending"), - ] - - operations = [ - # Drop a legacy, unused index that was created manually outside of Django's - # migration state, so there is no corresponding model/state change. - SafeRunSQL( - sql="DROP INDEX CONCURRENTLY IF EXISTS sentry_activity_weekly_report_jtcunning;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["sentry_activity"]}, - use_statement_timeout=False, - ), - migrations.AddIndex( - model_name="activity", - index=models.Index(fields=["project", "type"], name="sentry_acti_project_4b71f8_idx"), - ), - ] diff --git a/src/sentry/migrations/1103_backfill_auto_link_repos_by_name.py b/src/sentry/migrations/1103_backfill_auto_link_repos_by_name.py deleted file mode 100644 index 1a6bc070a798..000000000000 --- a/src/sentry/migrations/1103_backfill_auto_link_repos_by_name.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -Backfill ProjectRepository rows by matching repo name suffix to project slug. - -This is a one-time backfill for the auto-link-repos-by-name feature. It -iterates all active organizations, and for each one matches unlinked repos -to unlinked projects by name. Respects the dry-run option -(repository.auto-link-by-name-dry-run) read directly from sentry_option. - -Safe to re-run: uses get_or_create and skips already-linked pairs. -""" - -import logging -from typing import Any - -from django.db import migrations -from django.db.models import Exists, OuterRef -from django.utils.text import slugify - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - -# source enum: AUTO_NAME_MATCH = 3 -AUTO_NAME_MATCH = 3 -ACTIVE = 0 - - -def _get_dry_run(apps: Any) -> bool: - Option = apps.get_model("sentry", "Option") - try: - opt = Option.objects.get(key="repository.auto-link-by-name-dry-run") - return bool(opt.value) - except Option.DoesNotExist: - return True - - -def _get_repo_name_candidates(repo_name: str) -> list[str]: - parts = [slugify(part.strip()) for part in repo_name.split("/") if part.strip()] - parts = [p for p in parts if p] - if not parts: - return [] - candidates = [parts[-1]] - if len(parts) > 1: - candidates.append("-".join(parts)) - return candidates - - -def backfill_auto_link_repos(apps: Any, schema_editor: Any) -> None: - Organization = apps.get_model("sentry", "Organization") - Project = apps.get_model("sentry", "Project") - Repository = apps.get_model("sentry", "Repository") - ProjectRepository = apps.get_model("sentry", "ProjectRepository") - - dry_run = _get_dry_run(apps) - total_matched = 0 - total_created = 0 - - for org in RangeQuerySetWrapperWithProgressBar(Organization.objects.filter(status=ACTIVE)): - repos = Repository.objects.filter( - organization_id=org.id, - status=ACTIVE, - ).exclude(Exists(ProjectRepository.objects.filter(repository_id=OuterRef("id")))) - if not repos.exists(): - continue - - unlinked_projects_by_slug = {} - for project_id, slug in ( - Project.objects.filter( - organization_id=org.id, - status=ACTIVE, - ) - .exclude(Exists(ProjectRepository.objects.filter(project_id=OuterRef("id")))) - .values_list("id", "slug") - ): - unlinked_projects_by_slug[slug] = (project_id, slug) - - if not unlinked_projects_by_slug: - continue - - for repo in repos: - project_id = None - project_slug = None - for candidate in _get_repo_name_candidates(repo.name): - if candidate in unlinked_projects_by_slug: - project_id, project_slug = unlinked_projects_by_slug.pop(candidate) - break - if project_id is None: - continue - - total_matched += 1 - - if dry_run: - logger.info( - "backfill_auto_link_repos.dry_run_match", - extra={ - "organization_id": org.id, - "repository_id": repo.id, - "repository_name": repo.name, - "project_id": project_id, - "project_slug": project_slug, - }, - ) - else: - _, was_created = ProjectRepository.objects.get_or_create( - project_id=project_id, - repository=repo, - defaults={"source": AUTO_NAME_MATCH}, - ) - if was_created: - total_created += 1 - logger.info( - "backfill_auto_link_repos.linked", - extra={ - "organization_id": org.id, - "repository_id": repo.id, - "repository_name": repo.name, - "project_id": project_id, - "project_slug": project_slug, - }, - ) - - if dry_run: - logger.info( - "backfill_auto_link_repos.dry_run_complete", - extra={"total_matched": total_matched}, - ) - else: - logger.info( - "backfill_auto_link_repos.complete", - extra={"total_matched": total_matched, "total_created": total_created}, - ) - - -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 = True - - dependencies = [ - ("sentry", "1102_activity_project_type_index"), - ] - - operations = [ - migrations.RunPython( - backfill_auto_link_repos, - migrations.RunPython.noop, - hints={"tables": ["sentry_projectrepository"]}, - ), - ] diff --git a/src/sentry/migrations/1104_remove_email_model_drop.py b/src/sentry/migrations/1104_remove_email_model_drop.py deleted file mode 100644 index f367eeff545a..000000000000 --- a/src/sentry/migrations/1104_remove_email_model_drop.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-01 21:10 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "1103_backfill_auto_link_repos_by_name"), - ] - - operations = [ - SafeDeleteModel(name="Email", deletion_action=DeletionAction.DELETE), - ] diff --git a/src/sentry/migrations/1105_pr_merge_metrics.py b/src/sentry/migrations/1105_pr_merge_metrics.py deleted file mode 100644 index 543165500be6..000000000000 --- a/src/sentry/migrations/1105_pr_merge_metrics.py +++ /dev/null @@ -1,168 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-03 08:52 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1104_remove_email_model_drop"), - ] - - operations = [ - migrations.CreateModel( - name="PullRequestActivity", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("event_type", models.CharField(max_length=64)), - ("webhook_id", models.CharField(max_length=255)), - ("payload", models.JSONField(default=dict)), - ( - "pull_request", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.pullrequest" - ), - ), - ], - options={ - "db_table": "sentry_pullrequest_activity", - "unique_together": {("pull_request", "webhook_id")}, - }, - ), - migrations.CreateModel( - name="PullRequestAttribution", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("signal_type", models.CharField(max_length=64)), - ("signal_details", models.JSONField(null=True)), - ("source", models.CharField(max_length=128)), - ("is_valid", models.BooleanField(default=True)), - ( - "pull_request", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.pullrequest" - ), - ), - ], - options={ - "db_table": "sentry_pullrequest_attribution", - "unique_together": {("pull_request", "signal_type", "source")}, - }, - ), - migrations.CreateModel( - name="PullRequestMetrics", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("verdict", models.CharField(max_length=64, null=True)), - ( - "additions", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "deletions", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "files_changed", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "commits_count", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "comments_count", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "participants_count", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "reviews_count", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ("is_assigned", models.BooleanField(default=False)), - ( - "pull_request", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="metrics", - to="sentry.pullrequest", - ), - ), - ], - options={ - "db_table": "sentry_pullrequest_metrics", - }, - ), - migrations.AddField( - model_name="pullrequest", - name="closed_at", - field=models.DateTimeField(null=True), - ), - migrations.AddField( - model_name="pullrequest", - name="head_commit_sha", - field=models.CharField(max_length=64, null=True), - ), - migrations.AddField( - model_name="pullrequest", - name="merged_at", - field=models.DateTimeField(null=True), - ), - migrations.AddField( - model_name="pullrequest", - name="state", - field=models.CharField(max_length=32, null=True), - ), - migrations.AddIndex( - model_name="pullrequestactivity", - index=models.Index( - fields=["pull_request", "date_added"], name="sentry_pull_pull_re_bb8fc7_idx" - ), - ), - migrations.AddIndex( - model_name="pullrequestactivity", - index=models.Index(fields=["date_added"], name="sentry_pull_date_ad_577efd_idx"), - ), - ] diff --git a/src/sentry/migrations/1106_pullrequest_head_commit_sha_index.py b/src/sentry/migrations/1106_pullrequest_head_commit_sha_index.py deleted file mode 100644 index 10d67cb4d5ff..000000000000 --- a/src/sentry/migrations/1106_pullrequest_head_commit_sha_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-03 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1105_pr_merge_metrics"), - ] - - operations = [ - migrations.AddIndex( - model_name="pullrequest", - index=models.Index( - fields=["organization_id", "head_commit_sha"], - name="sentry_pull_organiz_502705_idx", - ), - ), - ] diff --git a/src/sentry/migrations/1107_commitauthor_public_email_queried_at.py b/src/sentry/migrations/1107_commitauthor_public_email_queried_at.py deleted file mode 100644 index 90d9a6419fa8..000000000000 --- a/src/sentry/migrations/1107_commitauthor_public_email_queried_at.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-01 00:00 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1106_pullrequest_head_commit_sha_index"), - ] - - operations = [ - migrations.AddField( - model_name="commitauthor", - name="public_email_queried_at", - field=models.DateTimeField(null=True), - ), - ] diff --git a/src/sentry/migrations/1108_drop_organizationmapping_codecov_access_pending.py b/src/sentry/migrations/1108_drop_organizationmapping_codecov_access_pending.py deleted file mode 100644 index cd87838a717c..000000000000 --- a/src/sentry/migrations/1108_drop_organizationmapping_codecov_access_pending.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-03 08:17 - -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", "1107_commitauthor_public_email_queried_at"), - ] - - operations = [ - # State-only removal: drops the field from Django's model state but keeps the - # column in the database, so older app servers still running during the rolling - # deploy can continue to SELECT it. The column itself is dropped in a follow-up - # migration once this is fully deployed. - SafeRemoveField( - model_name="organizationmapping", - name="codecov_access", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/migrations/1109_add_group_action_log_entry.py b/src/sentry/migrations/1109_add_group_action_log_entry.py deleted file mode 100644 index f1bfd1b5ff1d..000000000000 --- a/src/sentry/migrations/1109_add_group_action_log_entry.py +++ /dev/null @@ -1,84 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-20 18:54 - -import django.db.models.functions.datetime -import sentry.db.models.fields.bounded -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1108_drop_organizationmapping_codecov_access_pending"), - ] - - operations = [ - migrations.CreateModel( - name="GroupActionLogEntry", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("group_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ( - "project_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(), - ), - ( - "original_group_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), - ), - ("type", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ( - "actor_type", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), - ), - ("actor_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("source", models.CharField(max_length=64)), - ("data", models.JSONField(default=dict)), - ( - "date_added", - models.DateTimeField(db_default=django.db.models.functions.datetime.Now()), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("idempotency_key", models.CharField(max_length=64, null=True)), - ], - options={ - "db_table": "sentry_groupactionlogentry", - "indexes": [ - models.Index( - fields=["group_id", "date_added", "id"], - name="sentry_grou_group_i_cc465f_idx", - ), - models.Index( - fields=["project_id", "group_id"], - name="sentry_grou_project_6ed08e_idx", - ), - ], - "constraints": [ - models.UniqueConstraint( - condition=models.Q(("idempotency_key__isnull", False)), - fields=("group_id", "idempotency_key"), - name="uniq_groupactionlogentry_group_idempotency_key", - ) - ], - }, - ), - ] diff --git a/src/sentry/migrations/1110_add_team_avatar.py b/src/sentry/migrations/1110_add_team_avatar.py deleted file mode 100644 index ff0c281cc18a..000000000000 --- a/src/sentry/migrations/1110_add_team_avatar.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-08 20:20 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1109_add_group_action_log_entry"), - ] - - operations = [ - migrations.CreateModel( - name="TeamAvatar", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("ident", models.CharField(db_index=True, max_length=32, unique=True)), - ( - "file_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True, unique=True), - ), - ("avatar_type", models.PositiveSmallIntegerField(default=0)), - ( - "team", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="avatar", - to="sentry.team", - unique=True, - ), - ), - ], - options={ - "db_table": "sentry_teamavatar", - }, - ), - ] diff --git a/src/sentry/migrations/1111_add_index_for_group_link.py b/src/sentry/migrations/1111_add_index_for_group_link.py deleted file mode 100644 index 2a33ec7793bc..000000000000 --- a/src/sentry/migrations/1111_add_index_for_group_link.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-09 17:08 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1110_add_team_avatar"), - ] - - operations = [ - migrations.AddIndex( - model_name="grouplink", - index=models.Index( - fields=["linked_id", "linked_type"], - name="sentry_grou_linked__ee54de_idx", - ), - ), - ] diff --git a/src/sentry/migrations/1112_pullrequest_metrics_fields.py b/src/sentry/migrations/1112_pullrequest_metrics_fields.py deleted file mode 100644 index 575f251d632a..000000000000 --- a/src/sentry/migrations/1112_pullrequest_metrics_fields.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-09 18:15 - -import sentry.db.models.fields.bounded -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1111_add_index_for_group_link"), - ] - - operations = [ - migrations.AddField( - model_name="pullrequest", - name="draft", - field=models.BooleanField(null=True), - ), - migrations.AddField( - model_name="pullrequest", - name="opened_at", - field=models.DateTimeField(null=True), - ), - migrations.AddField( - model_name="pullrequestmetrics", - name="review_comments_count", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ] diff --git a/src/sentry/migrations/1113_extend_repository_name_length.py b/src/sentry/migrations/1113_extend_repository_name_length.py deleted file mode 100644 index 62f78f7781d3..000000000000 --- a/src/sentry/migrations/1113_extend_repository_name_length.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-09 17:23 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1112_pullrequest_metrics_fields"), - ] - - operations = [ - migrations.AlterField( - model_name="repository", - name="name", - field=models.CharField(max_length=500), - ), - ] diff --git a/src/sentry/migrations/1114_extend_repository_url_length.py b/src/sentry/migrations/1114_extend_repository_url_length.py deleted file mode 100644 index 3c19fa708ebc..000000000000 --- a/src/sentry/migrations/1114_extend_repository_url_length.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-10 14:40 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1113_extend_repository_name_length"), - ] - - operations = [ - migrations.AlterField( - model_name="repository", - name="url", - field=models.URLField(max_length=512, null=True), - ), - ] diff --git a/src/sentry/migrations/1115_projectdebugfile_add_objectstore_columns.py b/src/sentry/migrations/1115_projectdebugfile_add_objectstore_columns.py deleted file mode 100644 index c1004654f40d..000000000000 --- a/src/sentry/migrations/1115_projectdebugfile_add_objectstore_columns.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey - -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("sentry", "1114_extend_repository_url_length"), - ] - - operations = [ - migrations.AlterField( - model_name="projectdebugfile", - name="file", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=models.PROTECT, to="sentry.file" - ), - ), - migrations.AddField( - model_name="projectdebugfile", - name="storage_path", - field=models.TextField(null=True), - ), - migrations.AddField( - model_name="projectdebugfile", - name="content_type", - field=models.TextField(null=True), - ), - migrations.AddField( - model_name="projectdebugfile", - name="file_size", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), - ), - migrations.AddField( - model_name="projectdebugfile", - name="date_created", - field=models.DateTimeField(null=True), - ), - ] diff --git a/src/sentry/migrations/1116_add_project_custom_inbound_filter.py b/src/sentry/migrations/1116_add_project_custom_inbound_filter.py deleted file mode 100644 index dbce6ca0d948..000000000000 --- a/src/sentry/migrations/1116_add_project_custom_inbound_filter.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-01 14:59 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "1115_projectdebugfile_add_objectstore_columns"), - ] - - operations = [ - migrations.CreateModel( - name="CustomInboundFilter", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("name", models.CharField(blank=True, max_length=256, null=True)), - ("active", models.BooleanField(db_default=True, default=True)), - ("conditions", models.JSONField(default=list)), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="custom_inbound_filters", - to="sentry.project", - ), - ), - ], - options={ - "db_table": "sentry_custominboundfilter", - }, - ), - ] diff --git a/src/sentry/migrations/1117_drop_organizationmapping_codecov_access_delete.py b/src/sentry/migrations/1117_drop_organizationmapping_codecov_access_delete.py deleted file mode 100644 index b5f7b6ca61ee..000000000000 --- a/src/sentry/migrations/1117_drop_organizationmapping_codecov_access_delete.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-16 12:00 - -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", "1116_add_project_custom_inbound_filter"), - ] - - operations = [ - SafeRemoveField( - model_name="organizationmapping", - name="codecov_access", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/monitors/migrations/0001_squashed_0005_record_date_in_progress_state.py b/src/sentry/monitors/migrations/0001_squashed_0013_delete_monitor_is_muted_field.py similarity index 84% rename from src/sentry/monitors/migrations/0001_squashed_0005_record_date_in_progress_state.py rename to src/sentry/monitors/migrations/0001_squashed_0013_delete_monitor_is_muted_field.py index 5292926802d5..0342bdacd9ea 100644 --- a/src/sentry/monitors/migrations/0001_squashed_0005_record_date_in_progress_state.py +++ b/src/sentry/monitors/migrations/0001_squashed_0013_delete_monitor_is_muted_field.py @@ -1,9 +1,7 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:30 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.deletion import django.utils.timezone -from django.db import migrations, models - import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key @@ -11,6 +9,8 @@ import sentry.db.models.fields.slug import sentry.db.models.fields.uuid import sentry.monitors.models +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -30,11 +30,15 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("monitors", "0001_initial"), - ("monitors", "0002_fix_drift_default_to_db_default"), - ("monitors", "0003_record_date_in_progress"), - ("monitors", "0004_record_date_in_progress_sql_only"), - ("monitors", "0005_record_date_in_progress_state"), + ("monitors", "0001_squashed_0005_record_date_in_progress_state"), + ("monitors", "0006_add_is_upserting"), + ("monitors", "0007_monitors_json_field"), + ("monitors", "0008_fix_processing_error_keys"), + ("monitors", "0009_backfill_monitor_detectors"), + ("monitors", "0010_delete_orphaned_detectors"), + ("monitors", "0011_backfill_monitor_environment_is_muted"), + ("monitors", "0012_remove_monitor_is_muted_field"), + ("monitors", "0013_delete_monitor_is_muted_field"), ] initial = True @@ -62,7 +66,10 @@ class Migration(CheckedMigration): "project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ( "guid", sentry.db.models.fields.uuid.UUIDField( @@ -70,8 +77,8 @@ class Migration(CheckedMigration): ), ), ("slug", sentry.db.models.fields.slug.SentrySlugField()), - ("is_muted", models.BooleanField(db_default=False, default=False)), ("name", models.CharField(max_length=128)), + ("is_upserting", models.BooleanField(db_default=False, default=False)), ( "owner_user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( @@ -84,26 +91,30 @@ class Migration(CheckedMigration): db_index=True, null=True ), ), - ("config", sentry.db.models.fields.jsonfield.JSONField(default=dict)), + ("config", models.JSONField(default=dict)), ], options={ "db_table": "sentry_monitor", "indexes": [ models.Index( - fields=["organization_id", "slug"], name="sentry_moni_organiz_a62466_idx" + fields=["organization_id", "slug"], + name="sentry_moni_organiz_a62466_idx", ) ], "constraints": [ models.CheckConstraint( condition=models.Q( models.Q( - ("owner_team_id__isnull", False), ("owner_user_id__isnull", True) + ("owner_team_id__isnull", False), + ("owner_user_id__isnull", True), ), models.Q( - ("owner_team_id__isnull", True), ("owner_user_id__isnull", False) + ("owner_team_id__isnull", True), + ("owner_user_id__isnull", False), ), models.Q( - ("owner_team_id__isnull", True), ("owner_user_id__isnull", True) + ("owner_team_id__isnull", True), + ("owner_user_id__isnull", True), ), _connector="OR", ), @@ -127,7 +138,10 @@ class Migration(CheckedMigration): sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ("is_muted", models.BooleanField(db_default=False, default=False)), ("next_checkin", models.DateTimeField(null=True)), ("next_checkin_latest", models.DateTimeField(null=True)), @@ -135,7 +149,8 @@ class Migration(CheckedMigration): ( "monitor", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="monitors.monitor" + on_delete=django.db.models.deletion.CASCADE, + to="monitors.monitor", ), ), ], @@ -162,7 +177,10 @@ class Migration(CheckedMigration): "project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("status", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0)), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), ( "duration", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), @@ -175,13 +193,22 @@ class Migration(CheckedMigration): "date_added", models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), ("date_clock", models.DateTimeField(null=True)), ("date_in_progress", models.DateTimeField(null=True)), ("expected_time", models.DateTimeField(null=True)), ("timeout_at", models.DateTimeField(null=True)), - ("monitor_config", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ("trace_id", sentry.db.models.fields.uuid.UUIDField(max_length=32, null=True)), + ( + "monitor_config", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), + ( + "trace_id", + sentry.db.models.fields.uuid.UUIDField(max_length=32, null=True), + ), ( "monitor", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -224,7 +251,8 @@ class Migration(CheckedMigration): ( "monitor", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="monitors.monitor" + on_delete=django.db.models.deletion.CASCADE, + to="monitors.monitor", ), ), ( @@ -267,12 +295,16 @@ class Migration(CheckedMigration): ), ), ("detection_timestamp", models.DateTimeField(auto_now_add=True)), - ("user_notified_timestamp", models.DateTimeField(db_index=True, null=True)), + ( + "user_notified_timestamp", + models.DateTimeField(db_index=True, null=True), + ), ("env_muted_timestamp", models.DateTimeField(db_index=True, null=True)), ( "monitor_incident", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="monitors.monitorincident" + on_delete=django.db.models.deletion.CASCADE, + to="monitors.monitorincident", ), ), ], @@ -283,7 +315,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="monitorenvironment", index=models.Index( - fields=["status", "next_checkin_latest"], name="sentry_moni_status_9f06fe_idx" + fields=["status", "next_checkin_latest"], + name="sentry_moni_status_9f06fe_idx", ), ), migrations.AlterUniqueTogether( @@ -293,7 +326,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="monitorcheckin", index=models.Index( - fields=["monitor", "date_added", "status"], name="sentry_moni_monitor_0a49ce_idx" + fields=["monitor", "date_added", "status"], + name="sentry_moni_monitor_0a49ce_idx", ), ), migrations.AddIndex( @@ -307,7 +341,8 @@ class Migration(CheckedMigration): migrations.AddIndex( model_name="monitorcheckin", index=models.Index( - fields=["monitor", "status", "date_added"], name="sentry_moni_monitor_7ed5ce_idx" + fields=["monitor", "status", "date_added"], + name="sentry_moni_monitor_7ed5ce_idx", ), ), migrations.AddIndex( diff --git a/src/sentry/monitors/migrations/0006_add_is_upserting.py b/src/sentry/monitors/migrations/0006_add_is_upserting.py deleted file mode 100644 index 212ea5f41a34..000000000000 --- a/src/sentry/monitors/migrations/0006_add_is_upserting.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-04 15:48 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("monitors", "0001_squashed_0005_record_date_in_progress_state"), - ] - - operations = [ - migrations.AddField( - model_name="monitor", - name="is_upserting", - field=models.BooleanField(db_default=False, default=False), - ), - ] diff --git a/src/sentry/monitors/migrations/0007_monitors_json_field.py b/src/sentry/monitors/migrations/0007_monitors_json_field.py deleted file mode 100644 index 64d3345022b8..000000000000 --- a/src/sentry/monitors/migrations/0007_monitors_json_field.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-01 15:46 - -from django.db import migrations, models - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = True - - dependencies = [ - ("monitors", "0006_add_is_upserting"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("sentry_monitor", "config")], - state_operations=[ - migrations.AlterField( - model_name="monitor", - name="config", - field=models.JSONField(default=dict), - ), - ], - ), - migrations.AlterField( - model_name="monitorcheckin", - name="monitor_config", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - ] diff --git a/src/sentry/monitors/migrations/0008_fix_processing_error_keys.py b/src/sentry/monitors/migrations/0008_fix_processing_error_keys.py deleted file mode 100644 index 8ca69688ffbb..000000000000 --- a/src/sentry/monitors/migrations/0008_fix_processing_error_keys.py +++ /dev/null @@ -1,224 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-04 21:26 - - -import uuid -from collections.abc import Sequence -from dataclasses import dataclass, field -from datetime import datetime, timedelta -from itertools import chain -from typing import Any, TypedDict - -from django.conf import settings -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps -from django.utils.functional import cached_property -from django.utils.text import slugify - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils import json, redis - -MAX_ERRORS_PER_SET = 10 -MONITOR_ERRORS_LIFETIME = timedelta(days=7) -DEFAULT_SLUG_MAX_LENGTH = 50 - - -def slugify_monitor_slug(slug: str) -> str: - return slugify(slug)[:DEFAULT_SLUG_MAX_LENGTH].strip("-") - - -@dataclass -class CheckinItem: - """ - Represents a check-in to be processed - """ - - ts: datetime - """ - The timestamp the check-in was produced into the kafka topic. This differs - from the start_time that is part of the CheckIn - """ - - partition: int - """ - The kafka partition id the check-in was produced into. - """ - - message: Any - """ - The original unpacked check-in message contents. - """ - - payload: Any - """ - The json-decoded check-in payload contained within the message. Includes - the full check-in details. - """ - - @cached_property - def valid_monitor_slug(self): - return slugify_monitor_slug(self.payload["monitor_slug"]) - - @property - def processing_key(self): - """ - This key is used to uniquely identify the check-in group this check-in - belongs to. Check-ins grouped together will never be processed in - parallel with other check-ins belonging to the same group - """ - project_id = self.message["project_id"] - env = self.payload.get("environment") - return f"{project_id}:{self.valid_monitor_slug}:{env}" - - def to_dict(self) -> dict: - return { - "ts": self.ts.isoformat(), - "partition": self.partition, - "message": self.message, - "payload": self.payload, - } - - @classmethod - def from_dict(cls, data: Any) -> "CheckinItem": - return cls( - datetime.fromisoformat(data["ts"]), - data["partition"], - data["message"], - data["payload"], - ) - - -class CheckinProcessingErrorData(TypedDict): - id: str - checkin: Any - errors: Sequence[Any] - - -@dataclass() -class CheckinProcessingError: - errors: Sequence[Any] - checkin: CheckinItem - id: uuid.UUID = field(default_factory=uuid.uuid4) - - @classmethod - def from_dict(cls, data: CheckinProcessingErrorData) -> "CheckinProcessingError": - return cls( - id=uuid.UUID(data["id"]), - checkin=CheckinItem.from_dict(data["checkin"]), - errors=data["errors"], - ) - - def to_dict(self) -> CheckinProcessingErrorData: - return { - "id": self.id.hex, - "checkin": self.checkin.to_dict(), - "errors": self.errors, - } - - -def _get_cluster() -> Any: - return redis.redis_clusters.get(settings.SENTRY_MONITORS_REDIS_CLUSTER) - - -def build_monitor_identifier(monitor_id: int) -> str: - return f"monitor:{monitor_id}" - - -def build_error_identifier(uuid: uuid.UUID) -> str: - return f"monitors.processing_errors.{uuid.hex}" - - -def build_project_identifier(project_id: str) -> str: - return f"project:{project_id}" - - -def get_uuid_from_error_identifier(error_identifier: str) -> uuid.UUID: - uuid_hex = error_identifier.split(".")[2] - return uuid.UUID(hex=uuid_hex) - - -def build_set_identifier(entity_identifier: str) -> str: - return f"monitors.processing_errors_set.{entity_identifier}" - - -def fetch_processing_errors(entity_identifier: str) -> dict[uuid.UUID, Any]: - redis = _get_cluster() - pipeline = redis.pipeline() - pipeline.zrange(build_set_identifier(entity_identifier), 0, MAX_ERRORS_PER_SET, desc=True) - processing_errors = {} - error_identifiers = [ - build_error_identifier(uuid.UUID(error_identifier)) - for error_identifier in chain(*pipeline.execute()) - ] - for error_identifier in error_identifiers: - raw_error = redis.mget(error_identifier)[0] - if raw_error is not None: - processing_errors[get_uuid_from_error_identifier(error_identifier)] = ( - CheckinProcessingError.from_dict(json.loads(raw_error)) - ) - return processing_errors - - -def fix_processing_error_keys(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Monitor = apps.get_model("monitors", "Monitor") - Project = apps.get_model("sentry", "Project") - - redis = _get_cluster() - pipeline = redis.pipeline() - - # step 1: fix all monitors - for monitor_id in Monitor.objects.values_list("id", flat=True).iterator(): - monitor_identifier = build_monitor_identifier(monitor_id) - processing_errors = fetch_processing_errors(monitor_identifier) - for error_id in processing_errors: - processing_error = processing_errors[error_id] - if processing_error.id != error_id: - processing_error.id = error_id - error_key = build_error_identifier(error_id) - pipeline.set( - error_key, json.dumps(processing_error.to_dict()), ex=MONITOR_ERRORS_LIFETIME - ) - pipeline.execute() - - # step 2: fix all projects - for project_id in Project.objects.values_list("id", flat=True).iterator(): - project_identifier = build_project_identifier(str(project_id)) - processing_errors = fetch_processing_errors(project_identifier) - for error_id in processing_errors: - processing_error = processing_errors[error_id] - if processing_error.id != error_id: - processing_error.id = error_id - error_key = build_error_identifier(error_id) - pipeline.set( - error_key, json.dumps(processing_error.to_dict()), ex=MONITOR_ERRORS_LIFETIME - ) - pipeline.execute() - - -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 = True - - dependencies = [ - ("monitors", "0007_monitors_json_field"), - ("sentry", "0964_add_commitcomparison_table"), - ] - - operations = [ - migrations.RunPython( - fix_processing_error_keys, - migrations.RunPython.noop, - hints={"tables": ["sentry_monitor"]}, - ) - ] diff --git a/src/sentry/monitors/migrations/0009_backfill_monitor_detectors.py b/src/sentry/monitors/migrations/0009_backfill_monitor_detectors.py deleted file mode 100644 index 5c60a09db550..000000000000 --- a/src/sentry/monitors/migrations/0009_backfill_monitor_detectors.py +++ /dev/null @@ -1,80 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-15 23:18 - -from django.db import migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -DATA_SOURCE_CRON_MONITOR = "cron_monitor" - - -def backfill_monitor_detectors(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Monitor = apps.get_model("monitors", "Monitor") - DataSource = apps.get_model("workflow_engine", "DataSource") - Detector = apps.get_model("workflow_engine", "Detector") - DataSourceDetector = apps.get_model("workflow_engine", "DataSourceDetector") - Project = apps.get_model("sentry", "Project") - Team = apps.get_model("sentry", "Team") - for monitor in RangeQuerySetWrapperWithProgressBar(Monitor.objects.all()): - if ( - monitor.status not in (0, 1) - or not Project.objects.filter(id=monitor.project_id).exists() - or ( - monitor.owner_team_id is not None - and not Team.objects.filter(id=monitor.owner_team_id).exists() - ) - ): - continue - - # Copied from `ensure_cron_detector` - with transaction.atomic(router.db_for_write(DataSource)): - try: - data_source, created = DataSource.objects.get_or_create( - type=DATA_SOURCE_CRON_MONITOR, - organization_id=monitor.organization_id, - source_id=str(monitor.id), - ) - except DataSource.MultipleObjectsReturned: - # If these rows already exist just skip. We shouldn't have multiple rows, but because there's no unique - # key on `type, organization_id, source_id` we can have race conditions. - continue - if created: - detector = Detector.objects.create( - # MonitorIncidentType.slug - type="monitor_check_in_failure", - project_id=monitor.project_id, - name=monitor.name, - owner_user_id=monitor.owner_user_id, - owner_team_id=monitor.owner_team_id, - ) - DataSourceDetector.objects.create(data_source=data_source, detector=detector) - - -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 = True - - dependencies = [ - ("monitors", "0008_fix_processing_error_keys"), - ] - - operations = [ - migrations.RunPython( - backfill_monitor_detectors, - migrations.RunPython.noop, - hints={"tables": ["sentry_monitor"]}, - ) - ] diff --git a/src/sentry/monitors/migrations/0010_delete_orphaned_detectors.py b/src/sentry/monitors/migrations/0010_delete_orphaned_detectors.py deleted file mode 100644 index ae8b03ee5995..000000000000 --- a/src/sentry/monitors/migrations/0010_delete_orphaned_detectors.py +++ /dev/null @@ -1,52 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 18:57 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def delete_orphaned_cron_detectors( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Monitor = apps.get_model("monitors", "Monitor") - Detector = apps.get_model("workflow_engine", "Detector") - DataSource = apps.get_model("workflow_engine", "DataSource") - - # The largest region has only 100k of these, so we should be fine bringing them into memory - for data_source in DataSource.objects.filter(type="cron_monitor"): - if Monitor.objects.filter(id=int(data_source.source_id)).exists(): - continue - for detector in Detector.objects.filter(data_sources=data_source): - detector.delete() - data_source.delete() - - -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 = True - - dependencies = [ - ("monitors", "0009_backfill_monitor_detectors"), - ("workflow_engine", "0085_crons_link_detectors_to_all_workflows"), - ] - - operations = [ - migrations.RunPython( - delete_orphaned_cron_detectors, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detectorworkflow"]}, - ), - ] diff --git a/src/sentry/monitors/migrations/0011_backfill_monitor_environment_is_muted.py b/src/sentry/monitors/migrations/0011_backfill_monitor_environment_is_muted.py deleted file mode 100644 index 6a2f01eae073..000000000000 --- a/src/sentry/monitors/migrations/0011_backfill_monitor_environment_is_muted.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-13 19:27 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - - -def backfill_monitor_environment_is_muted( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Backfill MonitorEnvironment.is_muted from Monitor.is_muted for all muted monitors. - - After this migration: - - is_muted=True monitors will have ALL environments muted - - is_muted=False monitors will have environments unchanged (some, none, or all unmuted) - - This gets us into the correct state for the dual-write implementation where: - - Monitor is muted if and only if ALL environments are muted - - Monitor is unmuted if ANY environment is unmuted - """ - Monitor = apps.get_model("monitors", "Monitor") - MonitorEnvironment = apps.get_model("monitors", "MonitorEnvironment") - - # Filter is_muted in memory to avoid query timeouts (no composite index on id, is_muted) - all_monitors = Monitor.objects.all() - - for monitor in RangeQuerySetWrapperWithProgressBar(all_monitors): - if monitor.is_muted: - MonitorEnvironment.objects.filter(monitor=monitor).update(is_muted=True) - - -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 = True - - dependencies = [ - ("monitors", "0010_delete_orphaned_detectors"), - ] - - operations = [ - migrations.RunPython( - backfill_monitor_environment_is_muted, - migrations.RunPython.noop, - hints={"tables": ["sentry_monitor", "sentry_monitorenvironment"]}, - ), - ] diff --git a/src/sentry/monitors/migrations/0012_remove_monitor_is_muted_field.py b/src/sentry/monitors/migrations/0012_remove_monitor_is_muted_field.py deleted file mode 100644 index 768f228f2924..000000000000 --- a/src/sentry/monitors/migrations/0012_remove_monitor_is_muted_field.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-13 19:47 - -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 = [ - ("monitors", "0011_backfill_monitor_environment_is_muted"), - ] - - operations = [ - SafeRemoveField( - model_name="monitor", - name="is_muted", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/monitors/migrations/0013_delete_monitor_is_muted_field.py b/src/sentry/monitors/migrations/0013_delete_monitor_is_muted_field.py deleted file mode 100644 index 768c3a424a24..000000000000 --- a/src/sentry/monitors/migrations/0013_delete_monitor_is_muted_field.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-13 22:11 - -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 = [ - ("monitors", "0012_remove_monitor_is_muted_field"), - ] - - operations = [ - SafeRemoveField( - model_name="monitor", - name="is_muted", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/notifications/migrations/0001_move_notifications_models.py b/src/sentry/notifications/migrations/0001_move_notifications_models.py deleted file mode 100644 index 09fbbe5435ea..000000000000 --- a/src/sentry/notifications/migrations/0001_move_notifications_models.py +++ /dev/null @@ -1,370 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-14 16:22 - -import datetime - -import django.db.models.deletion -import django.db.models.functions.comparison -import django.utils.timezone -from django.conf import settings -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.db.models.fields.jsonfield -import sentry.db.models.fields.text -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - initial = True - - dependencies = [ - ("sentry", "0928_move_notifications_models"), - ("workflow_engine", "0069_rename_error_detectors"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.CreateModel( - name="NotificationAction", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "integration_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Integration", - blank=True, - db_index=True, - null=True, - on_delete="CASCADE", - ), - ), - ( - "sentry_app_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.SentryApp", - blank=True, - db_index=True, - null=True, - on_delete="CASCADE", - ), - ), - ("type", models.SmallIntegerField()), - ("target_type", models.SmallIntegerField()), - ("target_identifier", models.TextField(null=True)), - ("target_display", models.TextField(null=True)), - ("trigger_type", models.SmallIntegerField()), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - ], - options={ - "db_table": "sentry_notificationaction", - }, - ), - migrations.CreateModel( - name="NotificationActionProject", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="notifications.notificationaction", - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_notificationactionproject", - }, - ), - migrations.AddField( - model_name="notificationaction", - name="projects", - field=models.ManyToManyField( - through="notifications.NotificationActionProject", to="sentry.project" - ), - ), - migrations.CreateModel( - name="NotificationMessage", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("error_details", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ("error_code", models.IntegerField(db_index=True, null=True)), - ("message_identifier", sentry.db.models.fields.text.CharField(null=True)), - ( - "rule_action_uuid", - sentry.db.models.fields.text.CharField(db_index=True, null=True), - ), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("open_period_start", models.DateTimeField(null=True)), - ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.action", - ), - ), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", - ), - ), - ( - "incident", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.incident", - ), - ), - ( - "parent_notification_message", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="notifications.notificationmessage", - ), - ), - ( - "rule_fire_history", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.rulefirehistory", - ), - ), - ( - "trigger_action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.alertruletriggeraction", - ), - ), - ], - options={ - "db_table": "sentry_notificationmessage", - "constraints": [ - models.CheckConstraint( - condition=models.Q( - models.Q( - ("incident__isnull", False), - ("trigger_action__isnull", False), - ("rule_action_uuid__isnull", True), - ("rule_fire_history__isnull", True), - ("action__isnull", True), - ("group__isnull", True), - ("open_period_start__isnull", True), - ), - models.Q( - ("incident__isnull", True), - ("trigger_action__isnull", True), - ("rule_action_uuid__isnull", False), - ("rule_fire_history__isnull", False), - ("action__isnull", True), - ("group__isnull", True), - ), - models.Q( - ("incident__isnull", True), - ("trigger_action__isnull", True), - ("rule_action_uuid__isnull", True), - ("rule_fire_history__isnull", True), - ("action__isnull", False), - ("group__isnull", False), - ), - _connector="OR", - ), - name="notification_type_mutual_exclusivity", - ), - models.UniqueConstraint( - condition=models.Q( - ("error_code__isnull", True), - ("incident__isnull", False), - ("parent_notification_message__isnull", True), - ("trigger_action__isnull", False), - ), - fields=("incident", "trigger_action"), - name="singular_parent_message_per_incident_and_trigger_action", - ), - models.UniqueConstraint( - models.F("rule_fire_history"), - models.F("rule_action_uuid"), - django.db.models.functions.comparison.Coalesce( - "open_period_start", - models.Value( - datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) - ), - ), - condition=models.Q( - ("error_code__isnull", True), - ("parent_notification_message__isnull", True), - ), - name="singular_parent_message_per_rule_fire_history_rule_action_open_", - ), - ], - }, - ), - migrations.CreateModel( - name="NotificationSettingOption", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ( - "date_added", - models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ("scope_type", models.CharField(max_length=32)), - ( - "scope_identifier", - sentry.db.models.fields.bounded.BoundedBigIntegerField(), - ), - ( - "team_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Team", db_index=True, null=True, on_delete="CASCADE" - ), - ), - ("type", models.CharField(max_length=32)), - ("value", models.CharField(max_length=32)), - ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "db_table": "sentry_notificationsettingoption", - "constraints": [ - models.CheckConstraint( - condition=models.Q( - models.Q(("team_id__isnull", False), ("user_id__isnull", True)), - models.Q(("team_id__isnull", True), ("user_id__isnull", False)), - _connector="OR", - ), - name="notification_setting_option_team_or_user_check", - ) - ], - "unique_together": { - ("scope_type", "scope_identifier", "user_id", "team_id", "type") - }, - }, - ), - migrations.CreateModel( - name="NotificationSettingProvider", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ( - "date_added", - models.DateTimeField(default=django.utils.timezone.now, null=True), - ), - ("scope_type", models.CharField(max_length=32)), - ( - "scope_identifier", - sentry.db.models.fields.bounded.BoundedBigIntegerField(), - ), - ( - "team_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Team", db_index=True, null=True, on_delete="CASCADE" - ), - ), - ("type", models.CharField(max_length=32)), - ("value", models.CharField(max_length=32)), - ("provider", models.CharField(max_length=32)), - ( - "user", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={ - "db_table": "sentry_notificationsettingprovider", - "constraints": [ - models.CheckConstraint( - condition=models.Q( - models.Q(("team_id__isnull", False), ("user_id__isnull", True)), - models.Q(("team_id__isnull", True), ("user_id__isnull", False)), - _connector="OR", - ), - name="notification_setting_provider_team_or_user_check", - ) - ], - "unique_together": { - ( - "scope_type", - "scope_identifier", - "user_id", - "team_id", - "provider", - "type", - ) - }, - }, - ), - ] - ) - ] diff --git a/src/sentry/notifications/migrations/0001_squashed_0012_drop_metric_alert_cols_notificationmessage.py b/src/sentry/notifications/migrations/0001_squashed_0012_drop_metric_alert_cols_notificationmessage.py new file mode 100644 index 000000000000..1adca2c3d0b4 --- /dev/null +++ b/src/sentry/notifications/migrations/0001_squashed_0012_drop_metric_alert_cols_notificationmessage.py @@ -0,0 +1,375 @@ +# Generated by Django 5.2.14 on 2026-06-16 19:05 + +import django.db.models.deletion +import django.utils.timezone +import sentry.db.models.fields.bounded +import sentry.db.models.fields.foreignkey +import sentry.db.models.fields.hybrid_cloud_foreign_key +import sentry.db.models.fields.jsonfield +import sentry.db.models.fields.text +from django.conf import settings +from django.db import migrations, models + +from sentry.new_migrations.migrations import CheckedMigration + + +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 = True + + replaces = [ + ("notifications", "0001_move_notifications_models"), + ("notifications", "0002_notificationmessage_jsonfield"), + ("notifications", "0003_notification_thread_models"), + ("notifications", "0004_notificationmessage_group_action_date_added_idx"), + ("notifications", "0005_remove_notifmsg_rule_fire_history_constraints"), + ("notifications", "0006_drop_issue_alert_columns_notificationmessage"), + ("notifications", "0007_delete_issue_alert_columns_notificationmessage"), + ("notifications", "0008_remove_metric_alert_constraints_notificationmessage"), + ("notifications", "0009_clean_old_notificationmessage"), + ("notifications", "0010_remove_metric_alert_columns_notificationmessage"), + ("notifications", "0011_pending_delete_metric_alert_cols_notifmsg"), + ("notifications", "0012_drop_metric_alert_cols_notificationmessage"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks + + dependencies = [ + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), + ("workflow_engine", "0001_squashed_0114_sanitize_dynamic_form_field_choices"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="NotificationAction", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "integration_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Integration", + blank=True, + db_index=True, + null=True, + on_delete="CASCADE", + ), + ), + ( + "sentry_app_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.SentryApp", + blank=True, + db_index=True, + null=True, + on_delete="CASCADE", + ), + ), + ("type", models.SmallIntegerField()), + ("target_type", models.SmallIntegerField()), + ("target_identifier", models.TextField(null=True)), + ("target_display", models.TextField(null=True)), + ("trigger_type", models.SmallIntegerField()), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ], + options={ + "db_table": "sentry_notificationaction", + }, + ), + migrations.CreateModel( + name="NotificationActionProject", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "action", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="notifications.notificationaction", + ), + ), + ( + "project", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + ), + ), + ], + options={ + "db_table": "sentry_notificationactionproject", + }, + ), + migrations.AddField( + model_name="notificationaction", + name="projects", + field=models.ManyToManyField( + through="notifications.NotificationActionProject", to="sentry.project" + ), + ), + migrations.CreateModel( + name="NotificationThread", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("thread_key", models.CharField(db_index=True, max_length=64)), + ("provider_key", models.CharField(max_length=32)), + ("target_id", models.CharField(max_length=255)), + ("thread_identifier", models.CharField(max_length=255)), + ("key_type", models.CharField(db_index=True, max_length=64)), + ("key_data", models.JSONField()), + ("provider_data", models.JSONField(default=dict)), + ], + options={ + "db_table": "notifications_notificationthread", + "constraints": [ + models.UniqueConstraint( + fields=("thread_key", "provider_key", "target_id"), + name="uniq_notification_thread_per_provider_target", + ) + ], + }, + ), + migrations.CreateModel( + name="NotificationMessage", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "error_details", + sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), + ), + ("error_code", models.IntegerField(db_index=True, null=True)), + ( + "message_identifier", + sentry.db.models.fields.text.CharField(null=True), + ), + ("date_added", models.DateTimeField(default=django.utils.timezone.now)), + ("open_period_start", models.DateTimeField(null=True)), + ( + "action", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.action", + ), + ), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + ), + ), + ( + "parent_notification_message", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="notifications.notificationmessage", + ), + ), + ], + options={ + "db_table": "sentry_notificationmessage", + "indexes": [ + models.Index( + fields=["group", "action", "date_added"], + name="idx_notifmsg_group_action_date", + ), + models.Index(fields=["date_added"], name="sentry_noti_date_ad_ac82c5_idx"), + ], + }, + ), + migrations.CreateModel( + name="NotificationSettingOption", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ("scope_type", models.CharField(max_length=32)), + ( + "scope_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "team_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Team", db_index=True, null=True, on_delete="CASCADE" + ), + ), + ("type", models.CharField(max_length=32)), + ("value", models.CharField(max_length=32)), + ( + "user", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "db_table": "sentry_notificationsettingoption", + "constraints": [ + models.CheckConstraint( + condition=models.Q( + models.Q(("team_id__isnull", False), ("user_id__isnull", True)), + models.Q(("team_id__isnull", True), ("user_id__isnull", False)), + _connector="OR", + ), + name="notification_setting_option_team_or_user_check", + ) + ], + "unique_together": { + ("scope_type", "scope_identifier", "user_id", "team_id", "type") + }, + }, + ), + migrations.CreateModel( + name="NotificationSettingProvider", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ("scope_type", models.CharField(max_length=32)), + ( + "scope_identifier", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "team_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.Team", db_index=True, null=True, on_delete="CASCADE" + ), + ), + ("type", models.CharField(max_length=32)), + ("value", models.CharField(max_length=32)), + ("provider", models.CharField(max_length=32)), + ( + "user", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "db_table": "sentry_notificationsettingprovider", + "constraints": [ + models.CheckConstraint( + condition=models.Q( + models.Q(("team_id__isnull", False), ("user_id__isnull", True)), + models.Q(("team_id__isnull", True), ("user_id__isnull", False)), + _connector="OR", + ), + name="notification_setting_provider_team_or_user_check", + ) + ], + "unique_together": { + ( + "scope_type", + "scope_identifier", + "user_id", + "team_id", + "provider", + "type", + ) + }, + }, + ), + migrations.CreateModel( + name="NotificationRecord", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("provider_key", models.CharField(max_length=32)), + ("target_id", models.CharField(max_length=255)), + ("message_id", models.CharField(db_index=True, max_length=255)), + ("error_details", models.JSONField(null=True)), + ( + "thread", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_index=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="records", + to="notifications.notificationthread", + ), + ), + ], + options={ + "db_table": "notifications_notificationrecord", + "indexes": [ + models.Index( + fields=["thread", "date_added"], + name="idx_notifrecord_thread_date", + ) + ], + }, + ), + ] diff --git a/src/sentry/notifications/migrations/0002_notificationmessage_jsonfield.py b/src/sentry/notifications/migrations/0002_notificationmessage_jsonfield.py deleted file mode 100644 index 950f615241df..000000000000 --- a/src/sentry/notifications/migrations/0002_notificationmessage_jsonfield.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-04 19:14 - -from django.db import migrations - -import sentry.db.models.fields.jsonfield -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("notifications", "0001_move_notifications_models"), - ] - - operations = [ - migrations.AlterField( - model_name="notificationmessage", - name="error_details", - field=sentry.db.models.fields.jsonfield.LegacyTextJSONField(null=True), - ), - ] diff --git a/src/sentry/notifications/migrations/0003_notification_thread_models.py b/src/sentry/notifications/migrations/0003_notification_thread_models.py deleted file mode 100644 index 15fd5c2b90b9..000000000000 --- a/src/sentry/notifications/migrations/0003_notification_thread_models.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-12 00:20 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("notifications", "0002_notificationmessage_jsonfield"), - ] - - operations = [ - migrations.CreateModel( - name="NotificationThread", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("thread_key", models.CharField(db_index=True, max_length=64)), - ("provider_key", models.CharField(max_length=32)), - ("target_id", models.CharField(max_length=255)), - ("thread_identifier", models.CharField(max_length=255)), - ("key_type", models.CharField(db_index=True, max_length=64)), - ("key_data", models.JSONField()), - ("provider_data", models.JSONField(default=dict)), - ], - options={ - "db_table": "notifications_notificationthread", - "constraints": [ - models.UniqueConstraint( - fields=("thread_key", "provider_key", "target_id"), - name="uniq_notification_thread_per_provider_target", - ) - ], - }, - ), - migrations.CreateModel( - name="NotificationRecord", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("provider_key", models.CharField(max_length=32)), - ("target_id", models.CharField(max_length=255)), - ("message_id", models.CharField(db_index=True, max_length=255)), - ("error_details", models.JSONField(null=True)), - ( - "thread", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_index=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="records", - to="notifications.notificationthread", - ), - ), - ], - options={ - "db_table": "notifications_notificationrecord", - "indexes": [ - models.Index( - fields=["thread", "date_added"], name="idx_notifrecord_thread_date" - ) - ], - }, - ), - ] diff --git a/src/sentry/notifications/migrations/0004_notificationmessage_group_action_date_added_idx.py b/src/sentry/notifications/migrations/0004_notificationmessage_group_action_date_added_idx.py deleted file mode 100644 index 039a3f451f43..000000000000 --- a/src/sentry/notifications/migrations/0004_notificationmessage_group_action_date_added_idx.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-24 10:57 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("notifications", "0003_notification_thread_models"), - ("sentry", "1033_remove_grouprelease_group_id_last_seen_idx"), - ("workflow_engine", "0107_fix_email_action_fallthrough_type"), - ] - - operations = [ - migrations.AddIndex( - model_name="notificationmessage", - index=models.Index( - fields=["group", "action", "date_added"], - name="idx_notifmsg_group_action_date", - ), - ), - ] diff --git a/src/sentry/notifications/migrations/0005_remove_notifmsg_rule_fire_history_constraints.py b/src/sentry/notifications/migrations/0005_remove_notifmsg_rule_fire_history_constraints.py deleted file mode 100644 index 962c454e26fc..000000000000 --- a/src/sentry/notifications/migrations/0005_remove_notifmsg_rule_fire_history_constraints.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-08 20:11 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("notifications", "0004_notificationmessage_group_action_date_added_idx"), - ("sentry", "1085_add_date_synced_to_projectcodeowners"), - ("workflow_engine", "0113_migrate_data_conditions_categories"), - ] - - operations = [ - migrations.AddConstraint( - model_name="notificationmessage", - constraint=models.CheckConstraint( - condition=models.Q( - models.Q( - ("action__isnull", True), - ("group__isnull", True), - ("incident__isnull", False), - ("trigger_action__isnull", False), - ), - models.Q( - ("action__isnull", False), - ("group__isnull", False), - ("incident__isnull", True), - ("trigger_action__isnull", True), - ), - _connector="OR", - ), - name="notifmsg_metric_or_workflow_exclusive", - ), - ), - migrations.RemoveConstraint( - model_name="notificationmessage", - name="notification_type_mutual_exclusivity", - ), - migrations.RemoveConstraint( - model_name="notificationmessage", - name="singular_parent_message_per_rule_fire_history_rule_action_open_", - ), - ] diff --git a/src/sentry/notifications/migrations/0006_drop_issue_alert_columns_notificationmessage.py b/src/sentry/notifications/migrations/0006_drop_issue_alert_columns_notificationmessage.py deleted file mode 100644 index fc84fccc44dc..000000000000 --- a/src/sentry/notifications/migrations/0006_drop_issue_alert_columns_notificationmessage.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-11 17:19 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -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 = [ - ("notifications", "0005_remove_notifmsg_rule_fire_history_constraints"), - ("sentry", "1085_add_date_synced_to_projectcodeowners"), - ] - - operations = [ - migrations.AlterField( - model_name="notificationmessage", - name="rule_fire_history", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.rulefirehistory", - ), - ), - SafeRemoveField( - model_name="notificationmessage", - name="rule_action_uuid", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="notificationmessage", - name="rule_fire_history", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/notifications/migrations/0007_delete_issue_alert_columns_notificationmessage.py b/src/sentry/notifications/migrations/0007_delete_issue_alert_columns_notificationmessage.py deleted file mode 100644 index db8528dcf15a..000000000000 --- a/src/sentry/notifications/migrations/0007_delete_issue_alert_columns_notificationmessage.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-11 20:59 - - -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 = [ - ("notifications", "0006_drop_issue_alert_columns_notificationmessage"), - ] - - operations = [ - SafeRemoveField( - model_name="notificationmessage", - name="rule_action_uuid", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="notificationmessage", - name="rule_fire_history", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/notifications/migrations/0008_remove_metric_alert_constraints_notificationmessage.py b/src/sentry/notifications/migrations/0008_remove_metric_alert_constraints_notificationmessage.py deleted file mode 100644 index a5a8d4eac88d..000000000000 --- a/src/sentry/notifications/migrations/0008_remove_metric_alert_constraints_notificationmessage.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-13 22:41 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("notifications", "0007_delete_issue_alert_columns_notificationmessage"), - ] - - operations = [ - migrations.RemoveConstraint( - model_name="notificationmessage", - name="singular_parent_message_per_incident_and_trigger_action", - ), - migrations.RemoveConstraint( - model_name="notificationmessage", - name="notifmsg_metric_or_workflow_exclusive", - ), - ] diff --git a/src/sentry/notifications/migrations/0009_clean_old_notificationmessage.py b/src/sentry/notifications/migrations/0009_clean_old_notificationmessage.py deleted file mode 100644 index f00621f59919..000000000000 --- a/src/sentry/notifications/migrations/0009_clean_old_notificationmessage.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 16:23 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -import logging - -logger = logging.getLogger(__name__) - - -def delete_old_rows_metric_alerts(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - NotificationMessage = apps.get_model("notifications", "NotificationMessage") - - while True: - ids = list( - NotificationMessage.objects.filter(action__isnull=True).values_list("id", flat=True)[ - :1000 - ] - ) - if not ids: - break - - logger.info("Deleteing NotificationMessage rows", extra={"ids": ids}) - NotificationMessage.objects.filter(id__in=ids).delete() - - -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 = True - - dependencies = [ - ("notifications", "0008_remove_metric_alert_constraints_notificationmessage"), - ("sentry", "1096_backfill_mcp_dashboard_widget_filters"), - ] - - operations = [ - migrations.RunPython( - delete_old_rows_metric_alerts, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["sentry_notificationmessage"]}, - ), - ] diff --git a/src/sentry/notifications/migrations/0010_remove_metric_alert_columns_notificationmessage.py b/src/sentry/notifications/migrations/0010_remove_metric_alert_columns_notificationmessage.py deleted file mode 100644 index d055ec5275fe..000000000000 --- a/src/sentry/notifications/migrations/0010_remove_metric_alert_columns_notificationmessage.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 20:28 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("notifications", "0009_clean_old_notificationmessage"), - ("sentry", "1096_backfill_mcp_dashboard_widget_filters"), - ("workflow_engine", "0113_migrate_data_conditions_categories"), - ] - - operations = [ - migrations.AlterField( - model_name="notificationmessage", - name="action", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" - ), - ), - migrations.SeparateDatabaseAndState( - database_operations=[ - SafeRunSQL( - sql=""" - ALTER TABLE "sentry_notificationmessage" DROP CONSTRAINT IF EXISTS "sentry_notificationmessage_group_id_notnull"; - ALTER TABLE "sentry_notificationmessage" ADD CONSTRAINT "sentry_notificationmessage_group_id_notnull" CHECK ("group_id" IS NOT NULL) NOT VALID; - """, - reverse_sql='ALTER TABLE "sentry_notificationmessage" DROP CONSTRAINT IF EXISTS "sentry_notificationmessage_group_id_notnull";', - hints={"tables": ["sentry_notificationmessage"]}, - ), - SafeRunSQL( - sql='ALTER TABLE "sentry_notificationmessage" VALIDATE CONSTRAINT "sentry_notificationmessage_group_id_notnull";', - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["sentry_notificationmessage"]}, - use_statement_timeout=False, - ), - SafeRunSQL( - sql=""" - ALTER TABLE "sentry_notificationmessage" ALTER COLUMN "group_id" SET NOT NULL; - ALTER TABLE "sentry_notificationmessage" DROP CONSTRAINT IF EXISTS "sentry_notificationmessage_group_id_notnull"; - """, - reverse_sql='ALTER TABLE "sentry_notificationmessage" ALTER COLUMN "group_id" DROP NOT NULL', - hints={"tables": ["sentry_notificationmessage"]}, - ), - ], - state_operations=[ - migrations.AlterField( - model_name="notificationmessage", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - ], - ), - migrations.AlterField( - model_name="notificationmessage", - name="incident", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.incident", - ), - ), - migrations.AlterField( - model_name="notificationmessage", - name="trigger_action", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.alertruletriggeraction", - ), - ), - ] diff --git a/src/sentry/notifications/migrations/0011_pending_delete_metric_alert_cols_notifmsg.py b/src/sentry/notifications/migrations/0011_pending_delete_metric_alert_cols_notifmsg.py deleted file mode 100644 index 3d89fb79abf2..000000000000 --- a/src/sentry/notifications/migrations/0011_pending_delete_metric_alert_cols_notifmsg.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-19 17:16 - -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 = True - - dependencies = [ - ("notifications", "0010_remove_metric_alert_columns_notificationmessage"), - ("sentry", "1099_drop_old_fk_columns"), - ("workflow_engine", "0113_migrate_data_conditions_categories"), - ] - - operations = [ - SafeRemoveField( - model_name="notificationmessage", - name="incident", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="notificationmessage", - name="trigger_action", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - migrations.AddIndex( - model_name="notificationmessage", - index=models.Index(fields=["date_added"], name="sentry_noti_date_ad_ac82c5_idx"), - ), - ] diff --git a/src/sentry/notifications/migrations/0012_drop_metric_alert_cols_notificationmessage.py b/src/sentry/notifications/migrations/0012_drop_metric_alert_cols_notificationmessage.py deleted file mode 100644 index 52a4f4d0eaba..000000000000 --- a/src/sentry/notifications/migrations/0012_drop_metric_alert_cols_notificationmessage.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-21 16:55 - - -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 = [ - ("notifications", "0011_pending_delete_metric_alert_cols_notifmsg"), - ] - - operations = [ - SafeRemoveField( - model_name="notificationmessage", - name="incident", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="notificationmessage", - name="trigger_action", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/preprod/migrations/0001_emerge_upload_models.py b/src/sentry/preprod/migrations/0001_emerge_upload_models.py deleted file mode 100644 index 286747858abc..000000000000 --- a/src/sentry/preprod/migrations/0001_emerge_upload_models.py +++ /dev/null @@ -1,171 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-28 16:49 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.jsonfield -import sentry.preprod.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - initial = True - - dependencies = [ - ("sentry", "0913_split_discover_dataset_dashboards_self_hosted"), - ] - - operations = [ - migrations.CreateModel( - name="PreprodBuildConfiguration", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("name", models.CharField(max_length=255)), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ], - options={ - "db_table": "sentry_preprodbuildconfiguration", - "unique_together": {("project", "name")}, - }, - ), - migrations.CreateModel( - name="PreprodArtifact", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "file_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - db_index=True, null=True - ), - ), - ("date_built", models.DateTimeField(null=True)), - ( - "state", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=sentry.preprod.models.PreprodArtifact.ArtifactState["UPLOADING"] - ), - ), - ( - "artifact_type", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ( - "error_code", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("error_message", models.TextField(null=True)), - ("build_version", models.CharField(max_length=255, null=True)), - ("build_number", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("extras", sentry.db.models.fields.jsonfield.JSONField(null=True)), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ( - "build_configuration", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="preprod.preprodbuildconfiguration", - ), - ), - ], - options={ - "db_table": "sentry_preprodartifact", - }, - ), - migrations.CreateModel( - name="PreprodArtifactSizeMetrics", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "metrics_artifact_type", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ( - "state", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=sentry.preprod.models.PreprodArtifactSizeMetrics.SizeAnalysisState[ - "PENDING" - ] - ), - ), - ( - "error_code", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("error_message", models.TextField(null=True)), - ("processing_version", models.CharField(max_length=255, null=True)), - ( - "min_install_size", - sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), - ), - ( - "max_install_size", - sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), - ), - ( - "min_download_size", - sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), - ), - ( - "max_download_size", - sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), - ), - ( - "preprod_artifact", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="preprod.preprodartifact" - ), - ), - ], - options={ - "db_table": "sentry_preprodartifactsizemetrics", - "unique_together": {("preprod_artifact", "metrics_artifact_type")}, - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0001_squashed_0030_add_images_errored_to_snapshot_comparison.py b/src/sentry/preprod/migrations/0001_squashed_0030_add_images_errored_to_snapshot_comparison.py new file mode 100644 index 000000000000..3027f3264aaf --- /dev/null +++ b/src/sentry/preprod/migrations/0001_squashed_0030_add_images_errored_to_snapshot_comparison.py @@ -0,0 +1,563 @@ +# Generated by Django 5.2.14 on 2026-06-16 19:05 + +import django.contrib.postgres.fields +import django.db.models.deletion +import sentry.db.models.fields.bounded +import sentry.db.models.fields.foreignkey +import sentry.db.models.fields.hybrid_cloud_foreign_key +import sentry.preprod.models +import sentry.preprod.snapshots.models +from django.db import migrations, models + +from sentry.new_migrations.migrations import CheckedMigration + + +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 = True + + replaces = [ + ("preprod", "0001_emerge_upload_models"), + ("preprod", "0002_drop_sentry_jsonfield"), + ("preprod", "0003_drop_sentry_jsonfield_actual"), + ("preprod", "0004_add_django_jsonfield"), + ("preprod", "0005_add_git_commit"), + ("preprod", "0006_add_analysis_file_id_field"), + ("preprod", "0007_add_install_file"), + ("preprod", "0008_make_preprod_analysis_file_id_in_size_metrics_table"), + ("preprod", "0009_drop_preprod_artifact_analysis_file_id_col"), + ("preprod", "0010_actual_drop_preprod_artifact_analysis_file_id_col"), + ("preprod", "0011_add_preprod_artifact_app_name_and_app_id_fields"), + ("preprod", "0012_installablepreprod"), + ("preprod", "0013_binary_uuid"), + ("preprod", "0014_commitcomparisons_fk"), + ("preprod", "0015_add_preprod_artifact_size_metrics_identifier"), + ("preprod", "0016_add_preprod_artifact_size_comparison_table"), + ("preprod", "0017_break_commit_fks"), + ("preprod", "0018_add_preprod_artifact_app_icon_id_field"), + ("preprod", "0019_add_tooling_version_fields"), + ("preprod", "0020_add_preprod_artifact_date_added_index"), + ("preprod", "0021_add_preprod_artifact_mobile_app_info"), + ("preprod", "0022_backfill_preprod_artifact_mobile_app_info"), + ("preprod", "0023_remove_deprecated_preprod_artifact_fields"), + ("preprod", "0024_delete_deprecated_preprod_artifact_fields"), + ("preprod", "0025_add_preprod_comparison_approval"), + ("preprod", "0026_add_initial_snapshot_models"), + ("preprod", "0027_add_distribution_state_fields"), + ("preprod", "0028_add_images_skipped_to_snapshot_comparison"), + ("preprod", "0029_add_snapshot_comparison_chunks_columns"), + ("preprod", "0030_add_images_errored_to_snapshot_comparison"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks + + dependencies = [ + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), + ] + + operations = [ + migrations.CreateModel( + name="PreprodArtifact", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, null=True + ), + ), + ("date_built", models.DateTimeField(null=True)), + ( + "state", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + default=sentry.preprod.models.PreprodArtifact.ArtifactState["UPLOADING"] + ), + ), + ( + "artifact_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ( + "error_code", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("error_message", models.TextField(null=True)), + ("cli_version", models.CharField(max_length=255, null=True)), + ( + "fastlane_plugin_version", + models.CharField(max_length=255, null=True), + ), + ("gradle_plugin_version", models.CharField(max_length=255, null=True)), + ("extras", models.JSONField(null=True)), + ( + "installable_app_file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, null=True + ), + ), + ("app_id", models.CharField(max_length=255, null=True)), + ( + "main_binary_identifier", + models.CharField(db_index=True, max_length=255, null=True), + ), + ( + "installable_app_error_code", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("installable_app_error_message", models.TextField(null=True)), + ( + "commit", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.commit", + ), + ), + ( + "commit_comparison", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sentry.commitcomparison", + ), + ), + ( + "project", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + ), + ), + ], + options={ + "db_table": "sentry_preprodartifact", + }, + ), + migrations.CreateModel( + name="InstallablePreprodArtifact", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "url_path", + models.CharField(db_index=True, max_length=255, unique=True), + ), + ("expiration_date", models.DateTimeField(null=True)), + ("download_count", models.PositiveIntegerField(default=0, null=True)), + ( + "preprod_artifact", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="preprod.preprodartifact", + ), + ), + ], + options={ + "db_table": "sentry_installablepreprodartifact", + }, + ), + migrations.CreateModel( + name="PreprodArtifactMobileAppInfo", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("build_version", models.CharField(max_length=255, null=True)), + ( + "build_number", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + ), + ("app_icon_id", models.CharField(max_length=255, null=True)), + ("app_name", models.CharField(max_length=255, null=True)), + ("extras", models.JSONField(null=True)), + ( + "preprod_artifact", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="mobile_app_info", + to="preprod.preprodartifact", + ), + ), + ], + options={ + "db_table": "sentry_preprodartifactmobileappinfo", + }, + ), + migrations.CreateModel( + name="PreprodArtifactSizeMetrics", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "metrics_artifact_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("identifier", models.CharField(max_length=255, null=True)), + ( + "state", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + default=sentry.preprod.models.PreprodArtifactSizeMetrics.SizeAnalysisState[ + "PENDING" + ] + ), + ), + ( + "error_code", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("error_message", models.TextField(null=True)), + ("processing_version", models.CharField(max_length=255, null=True)), + ( + "min_install_size", + sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), + ), + ( + "max_install_size", + sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), + ), + ( + "min_download_size", + sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), + ), + ( + "max_download_size", + sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(null=True), + ), + ( + "analysis_file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, null=True + ), + ), + ( + "preprod_artifact", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="preprod.preprodartifact", + ), + ), + ], + options={ + "db_table": "sentry_preprodartifactsizemetrics", + }, + ), + migrations.CreateModel( + name="PreprodArtifactSizeComparison", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), + ), + ( + "file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + db_index=True, null=True + ), + ), + ( + "state", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + default=sentry.preprod.models.PreprodArtifactSizeComparison.State["PENDING"] + ), + ), + ( + "error_code", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("error_message", models.TextField(null=True)), + ( + "base_size_analysis", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="size_comparisons_base_size_analysis", + to="preprod.preprodartifactsizemetrics", + ), + ), + ( + "head_size_analysis", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="size_comparisons_head_size_analysis", + to="preprod.preprodartifactsizemetrics", + ), + ), + ], + options={ + "db_table": "sentry_preprodartifactsizecomparison", + }, + ), + migrations.CreateModel( + name="PreprodBuildConfiguration", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("name", models.CharField(max_length=255)), + ( + "project", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.project" + ), + ), + ], + options={ + "db_table": "sentry_preprodbuildconfiguration", + }, + ), + migrations.AddField( + model_name="preprodartifact", + name="build_configuration", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="preprod.preprodbuildconfiguration", + ), + ), + migrations.CreateModel( + name="PreprodComparisonApproval", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "preprod_feature_type", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), + ), + ( + "approval_status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + default=sentry.preprod.models.PreprodComparisonApproval.ApprovalStatus[ + "NEEDS_APPROVAL" + ] + ), + ), + ("approved_at", models.DateTimeField(null=True)), + ( + "approved_by_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.User", db_index=True, null=True, on_delete="SET_NULL" + ), + ), + ("extras", models.JSONField(null=True)), + ( + "preprod_artifact", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="preprod.preprodartifact", + ), + ), + ], + options={ + "db_table": "sentry_preprodcomparisonapproval", + }, + ), + migrations.CreateModel( + name="PreprodSnapshotMetrics", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "image_count", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ("is_selective", models.BooleanField(db_default=False, default=False)), + ("extras", models.JSONField(null=True)), + ( + "preprod_artifact", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="preprod.preprodartifact", + ), + ), + ], + options={ + "db_table": "sentry_preprodsnapshotmetrics", + }, + ), + migrations.CreateModel( + name="PreprodSnapshotComparison", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "state", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + default=sentry.preprod.snapshots.models.PreprodSnapshotComparison.State[ + "PENDING" + ] + ), + ), + ( + "error_code", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ("error_message", models.TextField(null=True)), + ( + "images_added", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "images_removed", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "images_changed", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "images_unchanged", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "images_renamed", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + ), + ( + "images_skipped", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, default=0 + ), + ), + ( + "images_errored", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField( + db_default=0, default=0 + ), + ), + ( + "chunks_total", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), + ), + ( + "chunks_done_indices", + django.contrib.postgres.fields.ArrayField( + base_field=models.IntegerField(), + db_default=[], + default=list, + size=None, + ), + ), + ("extras", models.JSONField(null=True)), + ( + "base_snapshot_metrics", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="snapshot_comparisons_base_metrics", + to="preprod.preprodsnapshotmetrics", + ), + ), + ( + "head_snapshot_metrics", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="snapshot_comparisons_head_metrics", + to="preprod.preprodsnapshotmetrics", + ), + ), + ], + options={ + "db_table": "sentry_preprodsnapshotcomparison", + }, + ), + migrations.AddConstraint( + model_name="preprodartifactsizemetrics", + constraint=models.UniqueConstraint( + condition=models.Q(("identifier__isnull", False)), + fields=("preprod_artifact", "metrics_artifact_type", "identifier"), + name="preprod_artifact_size_metrics_unique", + ), + ), + migrations.AddConstraint( + model_name="preprodartifactsizemetrics", + constraint=models.UniqueConstraint( + condition=models.Q(("identifier__isnull", True)), + fields=("preprod_artifact", "metrics_artifact_type"), + name="preprod_artifact_size_metrics_unique_no_identifier", + ), + ), + migrations.AlterUniqueTogether( + name="preprodartifactsizecomparison", + unique_together={("organization_id", "head_size_analysis", "base_size_analysis")}, + ), + migrations.AlterUniqueTogether( + name="preprodbuildconfiguration", + unique_together={("project", "name")}, + ), + migrations.AddIndex( + model_name="preprodartifact", + index=models.Index( + fields=["project", "date_added"], name="sentry_prep_project_c6742d_idx" + ), + ), + migrations.AlterUniqueTogether( + name="preprodsnapshotcomparison", + unique_together={("head_snapshot_metrics", "base_snapshot_metrics")}, + ), + ] diff --git a/src/sentry/preprod/migrations/0002_drop_sentry_jsonfield.py b/src/sentry/preprod/migrations/0002_drop_sentry_jsonfield.py deleted file mode 100644 index c327bf479be6..000000000000 --- a/src/sentry/preprod/migrations/0002_drop_sentry_jsonfield.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-11 22:44 - -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 = [ - ("preprod", "0001_emerge_upload_models"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="extras", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/preprod/migrations/0003_drop_sentry_jsonfield_actual.py b/src/sentry/preprod/migrations/0003_drop_sentry_jsonfield_actual.py deleted file mode 100644 index 9a604f2f60fe..000000000000 --- a/src/sentry/preprod/migrations/0003_drop_sentry_jsonfield_actual.py +++ /dev/null @@ -1,31 +0,0 @@ -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 = [ - ("preprod", "0002_drop_sentry_jsonfield"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="extras", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/preprod/migrations/0004_add_django_jsonfield.py b/src/sentry/preprod/migrations/0004_add_django_jsonfield.py deleted file mode 100644 index 490c4d211f7a..000000000000 --- a/src/sentry/preprod/migrations/0004_add_django_jsonfield.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-12 21:29 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0003_drop_sentry_jsonfield_actual"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="extras", - field=models.JSONField(null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0005_add_git_commit.py b/src/sentry/preprod/migrations/0005_add_git_commit.py deleted file mode 100644 index 0dc846b52475..000000000000 --- a/src/sentry/preprod/migrations/0005_add_git_commit.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-16 20:52 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0004_add_django_jsonfield"), - ("sentry", "0929_no_pickle_authenticator"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.commit" - ), - ), - ] diff --git a/src/sentry/preprod/migrations/0006_add_analysis_file_id_field.py b/src/sentry/preprod/migrations/0006_add_analysis_file_id_field.py deleted file mode 100644 index 7e9d0b53df9d..000000000000 --- a/src/sentry/preprod/migrations/0006_add_analysis_file_id_field.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-18 16:10 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0005_add_git_commit"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="analysis_file_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0007_add_install_file.py b/src/sentry/preprod/migrations/0007_add_install_file.py deleted file mode 100644 index f961d1ef26c8..000000000000 --- a/src/sentry/preprod/migrations/0007_add_install_file.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-30 19:46 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0006_add_analysis_file_id_field"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="installable_app_file_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0008_make_preprod_analysis_file_id_in_size_metrics_table.py b/src/sentry/preprod/migrations/0008_make_preprod_analysis_file_id_in_size_metrics_table.py deleted file mode 100644 index 28200285afd2..000000000000 --- a/src/sentry/preprod/migrations/0008_make_preprod_analysis_file_id_in_size_metrics_table.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-30 20:25 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0007_add_install_file"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifactsizemetrics", - name="analysis_file_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0009_drop_preprod_artifact_analysis_file_id_col.py b/src/sentry/preprod/migrations/0009_drop_preprod_artifact_analysis_file_id_col.py deleted file mode 100644 index a64ec23edd95..000000000000 --- a/src/sentry/preprod/migrations/0009_drop_preprod_artifact_analysis_file_id_col.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-30 20:48 - -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 = [ - ("preprod", "0008_make_preprod_analysis_file_id_in_size_metrics_table"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="analysis_file_id", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/preprod/migrations/0010_actual_drop_preprod_artifact_analysis_file_id_col.py b/src/sentry/preprod/migrations/0010_actual_drop_preprod_artifact_analysis_file_id_col.py deleted file mode 100644 index 765b1cbcfb14..000000000000 --- a/src/sentry/preprod/migrations/0010_actual_drop_preprod_artifact_analysis_file_id_col.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-30 20:48 - -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 = [ - ("preprod", "0009_drop_preprod_artifact_analysis_file_id_col"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="analysis_file_id", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/preprod/migrations/0011_add_preprod_artifact_app_name_and_app_id_fields.py b/src/sentry/preprod/migrations/0011_add_preprod_artifact_app_name_and_app_id_fields.py deleted file mode 100644 index 80eb2798f6db..000000000000 --- a/src/sentry/preprod/migrations/0011_add_preprod_artifact_app_name_and_app_id_fields.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-15 18:24 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0010_actual_drop_preprod_artifact_analysis_file_id_col"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="app_id", - field=models.CharField(max_length=255, null=True), - ), - migrations.AddField( - model_name="preprodartifact", - name="app_name", - field=models.CharField(max_length=255, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0012_installablepreprod.py b/src/sentry/preprod/migrations/0012_installablepreprod.py deleted file mode 100644 index af6165532d55..000000000000 --- a/src/sentry/preprod/migrations/0012_installablepreprod.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-16 20:13 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0011_add_preprod_artifact_app_name_and_app_id_fields"), - ] - - operations = [ - migrations.CreateModel( - name="InstallablePreprodArtifact", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("url_path", models.CharField(db_index=True, max_length=255, unique=True)), - ("expiration_date", models.DateTimeField(null=True)), - ("download_count", models.PositiveIntegerField(default=0, null=True)), - ( - "preprod_artifact", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="preprod.preprodartifact" - ), - ), - ], - options={ - "db_table": "sentry_installablepreprodartifact", - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0013_binary_uuid.py b/src/sentry/preprod/migrations/0013_binary_uuid.py deleted file mode 100644 index 982f25dd484b..000000000000 --- a/src/sentry/preprod/migrations/0013_binary_uuid.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-25 14:16 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0012_installablepreprod"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="main_binary_identifier", - field=models.CharField(db_index=True, max_length=255, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0014_commitcomparisons_fk.py b/src/sentry/preprod/migrations/0014_commitcomparisons_fk.py deleted file mode 100644 index e10419ce5a5a..000000000000 --- a/src/sentry/preprod/migrations/0014_commitcomparisons_fk.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-06 22:08 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0013_binary_uuid"), - ("sentry", "0964_add_commitcomparison_table"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="commit_comparison", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.commitcomparison", - ), - ), - ] diff --git a/src/sentry/preprod/migrations/0015_add_preprod_artifact_size_metrics_identifier.py b/src/sentry/preprod/migrations/0015_add_preprod_artifact_size_metrics_identifier.py deleted file mode 100644 index 8290163c275e..000000000000 --- a/src/sentry/preprod/migrations/0015_add_preprod_artifact_size_metrics_identifier.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-27 23:39 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0014_commitcomparisons_fk"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="preprodartifactsizemetrics", - unique_together=set(), - ), - migrations.AddField( - model_name="preprodartifactsizemetrics", - name="identifier", - field=models.CharField(max_length=255, null=True), - ), - migrations.AddConstraint( - model_name="preprodartifactsizemetrics", - constraint=models.UniqueConstraint( - condition=models.Q(("identifier__isnull", False)), - fields=("preprod_artifact", "metrics_artifact_type", "identifier"), - name="preprod_artifact_size_metrics_unique", - ), - ), - migrations.AddConstraint( - model_name="preprodartifactsizemetrics", - constraint=models.UniqueConstraint( - condition=models.Q(("identifier__isnull", True)), - fields=("preprod_artifact", "metrics_artifact_type"), - name="preprod_artifact_size_metrics_unique_no_identifier", - ), - ), - ] diff --git a/src/sentry/preprod/migrations/0016_add_preprod_artifact_size_comparison_table.py b/src/sentry/preprod/migrations/0016_add_preprod_artifact_size_comparison_table.py deleted file mode 100644 index 14a0c2cc3ed3..000000000000 --- a/src/sentry/preprod/migrations/0016_add_preprod_artifact_size_comparison_table.py +++ /dev/null @@ -1,88 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-04 20:28 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.preprod.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0015_add_preprod_artifact_size_metrics_identifier"), - ] - - operations = [ - migrations.CreateModel( - name="PreprodArtifactSizeComparison", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ( - "file_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField( - db_index=True, null=True - ), - ), - ( - "state", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=sentry.preprod.models.PreprodArtifactSizeComparison.State["PENDING"] - ), - ), - ( - "error_code", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("error_message", models.TextField(null=True)), - ( - "base_size_analysis", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="size_comparisons_base_size_analysis", - to="preprod.preprodartifactsizemetrics", - ), - ), - ( - "head_size_analysis", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="size_comparisons_head_size_analysis", - to="preprod.preprodartifactsizemetrics", - ), - ), - ], - options={ - "db_table": "sentry_preprodartifactsizecomparison", - "unique_together": { - ("organization_id", "head_size_analysis", "base_size_analysis") - }, - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0017_break_commit_fks.py b/src/sentry/preprod/migrations/0017_break_commit_fks.py deleted file mode 100644 index ffef4eb8e760..000000000000 --- a/src/sentry/preprod/migrations/0017_break_commit_fks.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-10 21:50 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0016_add_preprod_artifact_size_comparison_table"), - ("sentry", "0978_break_commit_fks"), - ] - - operations = [ - migrations.AlterField( - model_name="preprodartifact", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.commit", - ), - ), - ] diff --git a/src/sentry/preprod/migrations/0018_add_preprod_artifact_app_icon_id_field.py b/src/sentry/preprod/migrations/0018_add_preprod_artifact_app_icon_id_field.py deleted file mode 100644 index 9f8dbcd9f656..000000000000 --- a/src/sentry/preprod/migrations/0018_add_preprod_artifact_app_icon_id_field.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-23 22:57 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0017_break_commit_fks"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="app_icon_id", - field=models.CharField(max_length=255, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0019_add_tooling_version_fields.py b/src/sentry/preprod/migrations/0019_add_tooling_version_fields.py deleted file mode 100644 index 0021061b6e27..000000000000 --- a/src/sentry/preprod/migrations/0019_add_tooling_version_fields.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-10 10:27 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0018_add_preprod_artifact_app_icon_id_field"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="cli_version", - field=models.CharField(max_length=255, null=True), - ), - migrations.AddField( - model_name="preprodartifact", - name="fastlane_plugin_version", - field=models.CharField(max_length=255, null=True), - ), - migrations.AddField( - model_name="preprodartifact", - name="gradle_plugin_version", - field=models.CharField(max_length=255, null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0020_add_preprod_artifact_date_added_index.py b/src/sentry/preprod/migrations/0020_add_preprod_artifact_date_added_index.py deleted file mode 100644 index b71d89bfe38c..000000000000 --- a/src/sentry/preprod/migrations/0020_add_preprod_artifact_date_added_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-07 16:33 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0019_add_tooling_version_fields"), - ("sentry", "1015_backfill_self_hosted_sentry_app_emails"), - ] - - operations = [ - migrations.AddIndex( - model_name="preprodartifact", - index=models.Index( - fields=["project", "date_added"], name="sentry_prep_project_c6742d_idx" - ), - ), - ] diff --git a/src/sentry/preprod/migrations/0021_add_preprod_artifact_mobile_app_info.py b/src/sentry/preprod/migrations/0021_add_preprod_artifact_mobile_app_info.py deleted file mode 100644 index c17986eff9b9..000000000000 --- a/src/sentry/preprod/migrations/0021_add_preprod_artifact_mobile_app_info.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-07 17:40 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0020_add_preprod_artifact_date_added_index"), - ] - - operations = [ - migrations.CreateModel( - name="PreprodArtifactMobileAppInfo", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("build_version", models.CharField(max_length=255, null=True)), - ("build_number", sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True)), - ("app_icon_id", models.CharField(max_length=255, null=True)), - ("app_name", models.CharField(max_length=255, null=True)), - ("extras", models.JSONField(null=True)), - ( - "preprod_artifact", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - related_name="mobile_app_info", - to="preprod.preprodartifact", - ), - ), - ], - options={ - "db_table": "sentry_preprodartifactmobileappinfo", - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0022_backfill_preprod_artifact_mobile_app_info.py b/src/sentry/preprod/migrations/0022_backfill_preprod_artifact_mobile_app_info.py deleted file mode 100644 index ef78cbebea68..000000000000 --- a/src/sentry/preprod/migrations/0022_backfill_preprod_artifact_mobile_app_info.py +++ /dev/null @@ -1,103 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-07 10:40 - -import logging - -from django.db import IntegrityError, migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - - -def backfill_preprod_artifact_mobile_app_info( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - PreprodArtifact = apps.get_model("preprod", "PreprodArtifact") - PreprodArtifactMobileAppInfo = apps.get_model("preprod", "PreprodArtifactMobileAppInfo") - - all_artifacts = PreprodArtifact.objects.all() - mobile_app_info_to_create = [] - - # Batch up the query for existing PreprodArtifactMobileAppInfo entries to avoid N+1 queries. - # Fetch all artifact IDs that already have a PreprodArtifactMobileAppInfo - existing_mobile_app_info_artifact_ids = set( - PreprodArtifactMobileAppInfo.objects.values_list("preprod_artifact_id", flat=True) - ) - - # Loop through all artifacts, but skip if already exists - for artifact in RangeQuerySetWrapperWithProgressBar(all_artifacts): - if artifact.id in existing_mobile_app_info_artifact_ids: - logger.info( - "Skipping artifact %s because it already has a PreprodArtifactMobileAppInfo entry", - artifact.id, - ) - continue - - # Only create if there's at least one mobile app field with data - has_mobile_app_data = any( - [ - artifact.build_version, - artifact.build_number is not None, - artifact.app_name, - artifact.app_icon_id, - ] - ) - - if has_mobile_app_data: - mobile_app_info_to_create.append( - PreprodArtifactMobileAppInfo( - preprod_artifact_id=artifact.id, - build_version=artifact.build_version, - build_number=artifact.build_number, - app_name=artifact.app_name, - app_icon_id=artifact.app_icon_id, - ) - ) - - with transaction.atomic(router.db_for_write(PreprodArtifactMobileAppInfo)): - try: - PreprodArtifactMobileAppInfo.objects.bulk_create( - mobile_app_info_to_create, - ignore_conflicts=True, - ) - except IntegrityError as e: - logger.exception( - "Error bulk creating preprod artifact mobile app info", - extra={ - "mobile_app_info_to_create": len(mobile_app_info_to_create), - "error": e, - }, - ) - - -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 - - # This migration is safe to run after the code has deployed as the total amount of PreprodArtifacts is small (~6k records) - is_post_deployment = False - - dependencies = [ - ("preprod", "0021_add_preprod_artifact_mobile_app_info"), - ] - - operations = [ - migrations.RunPython( - backfill_preprod_artifact_mobile_app_info, - reverse_code=migrations.RunPython.noop, - elidable=True, - hints={"tables": ["sentry_preprodartifact", "sentry_preprodartifactmobileappinfo"]}, - ), - ] diff --git a/src/sentry/preprod/migrations/0023_remove_deprecated_preprod_artifact_fields.py b/src/sentry/preprod/migrations/0023_remove_deprecated_preprod_artifact_fields.py deleted file mode 100644 index fbfb74da5d01..000000000000 --- a/src/sentry/preprod/migrations/0023_remove_deprecated_preprod_artifact_fields.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-20 - -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 = [ - ("preprod", "0022_backfill_preprod_artifact_mobile_app_info"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="build_version", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="preprodartifact", - name="build_number", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="preprodartifact", - name="app_name", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="preprodartifact", - name="app_icon_id", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/preprod/migrations/0024_delete_deprecated_preprod_artifact_fields.py b/src/sentry/preprod/migrations/0024_delete_deprecated_preprod_artifact_fields.py deleted file mode 100644 index b6fc57c7204f..000000000000 --- a/src/sentry/preprod/migrations/0024_delete_deprecated_preprod_artifact_fields.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-20 - -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 = [ - ("preprod", "0023_remove_deprecated_preprod_artifact_fields"), - ] - - operations = [ - SafeRemoveField( - model_name="preprodartifact", - name="build_version", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="preprodartifact", - name="build_number", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="preprodartifact", - name="app_name", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="preprodartifact", - name="app_icon_id", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/preprod/migrations/0025_add_preprod_comparison_approval.py b/src/sentry/preprod/migrations/0025_add_preprod_comparison_approval.py deleted file mode 100644 index ac973038cc02..000000000000 --- a/src/sentry/preprod/migrations/0025_add_preprod_comparison_approval.py +++ /dev/null @@ -1,75 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-21 23:48 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.preprod.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0024_delete_deprecated_preprod_artifact_fields"), - ] - - operations = [ - migrations.CreateModel( - name="PreprodComparisonApproval", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "preprod_feature_type", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(), - ), - ( - "approval_status", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=sentry.preprod.models.PreprodComparisonApproval.ApprovalStatus[ - "NEEDS_APPROVAL" - ] - ), - ), - ("approved_at", models.DateTimeField(null=True)), - ( - "approved_by_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ("extras", models.JSONField(null=True)), - ( - "preprod_artifact", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="preprod.preprodartifact" - ), - ), - ], - options={ - "db_table": "sentry_preprodcomparisonapproval", - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0027_add_distribution_state_fields.py b/src/sentry/preprod/migrations/0027_add_distribution_state_fields.py deleted file mode 100644 index cb8147b52b7d..000000000000 --- a/src/sentry/preprod/migrations/0027_add_distribution_state_fields.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 5.2.8 - -from django.db import migrations, models - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("preprod", "0026_add_initial_snapshot_models"), - ] - - operations = [ - migrations.AddField( - model_name="preprodartifact", - name="installable_app_error_code", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - migrations.AddField( - model_name="preprodartifact", - name="installable_app_error_message", - field=models.TextField(null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0028_add_images_skipped_to_snapshot_comparison.py b/src/sentry/preprod/migrations/0028_add_images_skipped_to_snapshot_comparison.py deleted file mode 100644 index c718aca84bbd..000000000000 --- a/src/sentry/preprod/migrations/0028_add_images_skipped_to_snapshot_comparison.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-14 21:31 - -import sentry.db.models.fields.bounded -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0027_add_distribution_state_fields"), - ] - - operations = [ - migrations.AddField( - model_name="preprodsnapshotcomparison", - name="images_skipped", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=0, db_default=0 - ), - ), - migrations.AddField( - model_name="preprodsnapshotmetrics", - name="is_selective", - field=models.BooleanField(default=False, db_default=False), - ), - ] diff --git a/src/sentry/preprod/migrations/0029_add_snapshot_comparison_chunks_columns.py b/src/sentry/preprod/migrations/0029_add_snapshot_comparison_chunks_columns.py deleted file mode 100644 index 20fcb3faecd1..000000000000 --- a/src/sentry/preprod/migrations/0029_add_snapshot_comparison_chunks_columns.py +++ /dev/null @@ -1,42 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-03 21:04 - -import django.contrib.postgres.fields -import sentry.db.models.fields.bounded -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0028_add_images_skipped_to_snapshot_comparison"), - ] - - operations = [ - migrations.AddField( - model_name="preprodsnapshotcomparison", - name="chunks_done_indices", - field=django.contrib.postgres.fields.ArrayField( - base_field=models.IntegerField(), db_default=[], default=list, size=None - ), - ), - migrations.AddField( - model_name="preprodsnapshotcomparison", - name="chunks_total", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ] diff --git a/src/sentry/preprod/migrations/0030_add_images_errored_to_snapshot_comparison.py b/src/sentry/preprod/migrations/0030_add_images_errored_to_snapshot_comparison.py deleted file mode 100644 index 166047d1f642..000000000000 --- a/src/sentry/preprod/migrations/0030_add_images_errored_to_snapshot_comparison.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-12 18:31 - -import sentry.db.models.fields.bounded -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("preprod", "0029_add_snapshot_comparison_chunks_columns"), - ] - - operations = [ - migrations.AddField( - model_name="preprodsnapshotcomparison", - name="images_errored", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - db_default=0, default=0 - ), - ), - ] diff --git a/src/sentry/releases/migrations/0001_release_models.py b/src/sentry/releases/migrations/0001_release_models.py deleted file mode 100644 index dd17623d3d48..000000000000 --- a/src/sentry/releases/migrations/0001_release_models.py +++ /dev/null @@ -1,120 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-03 18:57 - -import django.db.models.deletion -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - initial = True - - dependencies = [ - ("sentry", "0972_commit_comparison_drop_unique"), - ] - - operations = [ - migrations.CreateModel( - name="Commit", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("repository_id", sentry.db.models.fields.bounded.BoundedPositiveIntegerField()), - ("key", models.CharField(max_length=64)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now)), - ("date_created", models.DateTimeField(auto_now_add=True)), - ("message", models.TextField(null=True)), - ( - "author", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="releasecommit_set", - to="sentry.commitauthor", - ), - ), - ], - options={ - "db_table": "releases_commit", - }, - ), - migrations.CreateModel( - name="CommitFileChange", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("filename", models.TextField()), - ("type", models.CharField(max_length=1)), - ( - "commit", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="releases.commit" - ), - ), - ], - options={ - "db_table": "releases_commitfilechange", - }, - ), - migrations.AddIndex( - model_name="commit", - index=models.Index( - fields=["repository_id", "date_added"], name="releases_co_reposit_a050ba_idx" - ), - ), - migrations.AddIndex( - model_name="commit", - index=models.Index( - fields=["author", "date_added"], name="releases_co_author__3d0b29_idx" - ), - ), - migrations.AddIndex( - model_name="commit", - index=models.Index( - fields=["organization_id", "date_added"], name="releases_co_organiz_bcc54e_idx" - ), - ), - migrations.AlterUniqueTogether( - name="commit", - unique_together={("repository_id", "key")}, - ), - migrations.AlterUniqueTogether( - name="commitfilechange", - unique_together={("commit", "filename")}, - ), - ] diff --git a/src/sentry/releases/migrations/0002_delete_dual_written_commit_tables.py b/src/sentry/releases/migrations/0002_delete_dual_written_commit_tables.py deleted file mode 100644 index 68126cf1693a..000000000000 --- a/src/sentry/releases/migrations/0002_delete_dual_written_commit_tables.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-31 19:01 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("releases", "0001_release_models"), - ("sentry", "1001_prevent_grouphistory_infinte_recursion"), - ] - - operations = [ - migrations.AlterField( - model_name="commit", - name="author", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="releasecommit_set", - to="sentry.commitauthor", - ), - ), - migrations.AlterField( - model_name="commitfilechange", - name="commit", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="releases.commit", - ), - ), - SafeDeleteModel(name="Commit", deletion_action=DeletionAction.MOVE_TO_PENDING), - SafeDeleteModel(name="CommitFileChange", deletion_action=DeletionAction.MOVE_TO_PENDING), - ] diff --git a/src/sentry/releases/migrations/0003_real_delete_dual_written_commit_tables.py b/src/sentry/releases/migrations/0003_real_delete_dual_written_commit_tables.py deleted file mode 100644 index 43547e4a55df..000000000000 --- a/src/sentry/releases/migrations/0003_real_delete_dual_written_commit_tables.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-31 19:10 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("releases", "0002_delete_dual_written_commit_tables"), - ] - - operations = [ - SafeDeleteModel(name="Commit", deletion_action=DeletionAction.DELETE), - SafeDeleteModel(name="CommitFileChange", deletion_action=DeletionAction.DELETE), - ] diff --git a/src/sentry/releases/migrations/0004_cleanup_failed_safe_deletes.py b/src/sentry/releases/migrations/0004_cleanup_failed_safe_deletes.py deleted file mode 100644 index 846bfa1c01f5..000000000000 --- a/src/sentry/releases/migrations/0004_cleanup_failed_safe_deletes.py +++ /dev/null @@ -1,41 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 00:38 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = [ - ("releases", "0003_real_delete_dual_written_commit_tables"), - ] - - operations = [ - # Clean up tables that may not have been deleted due to missing - # historical_silo_assignments entries before the fix - SafeRunSQL( - sql="DROP TABLE IF EXISTS releases_commit CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["releases_commit"]}, - ), - SafeRunSQL( - sql="DROP TABLE IF EXISTS releases_commitfilechange CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["releases_commitfilechange"]}, - ), - ] diff --git a/src/sentry/replays/migrations/0001_squashed_0005_drop_replay_index.py b/src/sentry/replays/migrations/0001_squashed_0005_drop_replay_index.py deleted file mode 100644 index b49d69adfbf4..000000000000 --- a/src/sentry/replays/migrations/0001_squashed_0005_drop_replay_index.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:28 - -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - replaces = [ - ("replays", "0001_init_replays"), - ("replays", "0002_rename_to_segment_id"), - ("replays", "0003_add_size_to_recording_segment"), - ("replays", "0004_index_together"), - ("replays", "0005_drop_replay_index"), - ] - - initial = True - - checked = False # This is an initial migration and can take locks - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="ReplayRecordingSegment", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("project_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ("replay_id", models.CharField(db_index=True, max_length=32)), - ("file_id", sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True)), - ( - "segment_id", - sentry.db.models.fields.bounded.BoundedIntegerField(db_column="sequence_id"), - ), - ( - "date_added", - models.DateTimeField(db_index=True, default=django.utils.timezone.now), - ), - ("size", sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True)), - ], - options={ - "db_table": "replays_replayrecordingsegment", - "unique_together": { - ("project_id", "replay_id", "file_id"), - ("project_id", "replay_id", "segment_id"), - }, - }, - ), - ] diff --git a/src/sentry/preprod/migrations/0026_add_initial_snapshot_models.py b/src/sentry/replays/migrations/0001_squashed_0007_organizationmember_replay_access.py similarity index 50% rename from src/sentry/preprod/migrations/0026_add_initial_snapshot_models.py rename to src/sentry/replays/migrations/0001_squashed_0007_organizationmember_replay_access.py index 9e662f7a19f5..b726c7804b5e 100644 --- a/src/sentry/preprod/migrations/0026_add_initial_snapshot_models.py +++ b/src/sentry/replays/migrations/0001_squashed_0007_organizationmember_replay_access.py @@ -1,11 +1,12 @@ -# Generated by Django 5.2.8 on 2026-01-23 18:09 +# Generated by Django 5.2.14 on 2026-06-16 19:05 +import django.contrib.postgres.fields import django.db.models.deletion -from django.db import migrations, models - +import django.utils.timezone import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey -import sentry.preprod.snapshots.models +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -22,15 +23,25 @@ class Migration(CheckedMigration): # 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 + is_post_deployment = True + + replaces = [ + ("replays", "0001_squashed_0005_drop_replay_index"), + ("replays", "0006_add_bulk_delete_job"), + ("replays", "0007_organizationmember_replay_access"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks dependencies = [ - ("preprod", "0025_add_preprod_comparison_approval"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ migrations.CreateModel( - name="PreprodSnapshotMetrics", + name="ReplayDeletionJobModel", fields=[ ( "id", @@ -40,24 +51,32 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), + ("range_start", models.DateTimeField()), + ("range_end", models.DateTimeField()), + ( + "environments", + django.contrib.postgres.fields.ArrayField( + base_field=models.TextField(), default=list, size=None + ), + ), ( - "image_count", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + "organization_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), - ("extras", models.JSONField(null=True)), ( - "preprod_artifact", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, to="preprod.preprodartifact" - ), + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), + ("status", models.CharField(default="pending")), + ("query", models.TextField()), + ("offset", models.IntegerField(default=0)), ], options={ - "db_table": "sentry_preprodsnapshotmetrics", + "db_table": "replays_replaydeletionjob", }, ), migrations.CreateModel( - name="PreprodSnapshotComparison", + name="OrganizationMemberReplayAccess", fields=[ ( "id", @@ -68,59 +87,56 @@ class Migration(CheckedMigration): ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), ( - "state", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField( - default=sentry.preprod.snapshots.models.PreprodSnapshotComparison.State[ - "PENDING" - ] + "organizationmember", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="replay_access", + to="sentry.organizationmember", + unique=True, ), ), + ], + options={ + "db_table": "sentry_organizationmemberreplayaccess", + }, + ), + migrations.CreateModel( + name="ReplayRecordingSegment", + fields=[ ( - "error_code", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), - ), - ("error_message", models.TextField(null=True)), - ( - "images_added", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), - ), - ( - "images_removed", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), ), ( - "images_changed", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + "project_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), ), + ("replay_id", models.CharField(db_index=True, max_length=32)), ( - "images_unchanged", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + "file_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), ), ( - "images_renamed", - sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=0), + "segment_id", + sentry.db.models.fields.bounded.BoundedIntegerField(db_column="sequence_id"), ), - ("extras", models.JSONField(null=True)), ( - "base_snapshot_metrics", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="snapshot_comparisons_base_metrics", - to="preprod.preprodsnapshotmetrics", - ), + "date_added", + models.DateTimeField(db_index=True, default=django.utils.timezone.now), ), ( - "head_snapshot_metrics", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="snapshot_comparisons_head_metrics", - to="preprod.preprodsnapshotmetrics", - ), + "size", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(null=True), ), ], options={ - "db_table": "sentry_preprodsnapshotcomparison", - "unique_together": {("head_snapshot_metrics", "base_snapshot_metrics")}, + "db_table": "replays_replayrecordingsegment", + "unique_together": { + ("project_id", "replay_id", "file_id"), + ("project_id", "replay_id", "segment_id"), + }, }, ), ] diff --git a/src/sentry/replays/migrations/0006_add_bulk_delete_job.py b/src/sentry/replays/migrations/0006_add_bulk_delete_job.py deleted file mode 100644 index e9848fbe2e8e..000000000000 --- a/src/sentry/replays/migrations/0006_add_bulk_delete_job.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-20 15:54 - -import django.contrib.postgres.fields -from django.db import migrations, models - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("replays", "0001_squashed_0005_drop_replay_index"), - ] - - operations = [ - migrations.CreateModel( - name="ReplayDeletionJobModel", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("range_start", models.DateTimeField()), - ("range_end", models.DateTimeField()), - ( - "environments", - django.contrib.postgres.fields.ArrayField( - base_field=models.TextField(), default=list, size=None - ), - ), - ( - "organization_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ( - "project_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(db_index=True), - ), - ("status", models.CharField(default="pending")), - ("query", models.TextField()), - ("offset", models.IntegerField(default=0)), - ], - options={ - "db_table": "replays_replaydeletionjob", - }, - ), - ] diff --git a/src/sentry/replays/migrations/0007_organizationmember_replay_access.py b/src/sentry/replays/migrations/0007_organizationmember_replay_access.py deleted file mode 100644 index 95c5813d13bd..000000000000 --- a/src/sentry/replays/migrations/0007_organizationmember_replay_access.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 5.2.8 on 2025-12-02 12:31 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("replays", "0006_add_bulk_delete_job"), - ("sentry", "1011_update_oc_integration_cascade_to_null"), - ] - - operations = [ - migrations.CreateModel( - name="OrganizationMemberReplayAccess", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "organizationmember", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="replay_access", - to="sentry.organizationmember", - unique=True, - ), - ), - ], - options={ - "db_table": "sentry_organizationmemberreplayaccess", - }, - ), - ] diff --git a/src/sentry/seer/migrations/0001_add_seerorganizationsettings.py b/src/sentry/seer/migrations/0001_add_seerorganizationsettings.py deleted file mode 100644 index 6dbaeefb449a..000000000000 --- a/src/sentry/seer/migrations/0001_add_seerorganizationsettings.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-25 19:12 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 - - initial = True - - dependencies = [ - ("sentry", "1033_remove_grouprelease_group_id_last_seen_idx"), - ] - - operations = [ - migrations.CreateModel( - name="SeerOrganizationSettings", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "default_coding_agent_integration_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.Integration", - blank=True, - db_index=True, - null=True, - on_delete="SET_NULL", - ), - ), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - unique=True, - ), - ), - ], - options={ - "db_table": "seer_organizationsettings", - }, - ), - ] diff --git a/src/sentry/seer/migrations/0001_squashed_0018_backfill_seer_agent_run_group_id.py b/src/sentry/seer/migrations/0001_squashed_0018_backfill_seer_agent_run_group_id.py new file mode 100644 index 000000000000..6c012fd276be --- /dev/null +++ b/src/sentry/seer/migrations/0001_squashed_0018_backfill_seer_agent_run_group_id.py @@ -0,0 +1,368 @@ +# Generated by Django 5.2.14 on 2026-06-16 19:05 + +import django.db.models.deletion +import sentry.db.models.fields.bounded +import sentry.db.models.fields.foreignkey +import sentry.db.models.fields.hybrid_cloud_foreign_key +import uuid +from django.db import migrations, models + +from sentry.new_migrations.migrations import CheckedMigration + + +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 = True + + replaces = [ + ("seer", "0001_add_seerorganizationsettings"), + ("seer", "0002_add_default_coding_agent"), + ("seer", "0003_add_seerprojectrepository"), + ("seer", "0004_pending_delete_seerorganizationsettings"), + ("seer", "0005_delete_seerorganizationsettings"), + ("seer", "0006_add_night_shift_models"), + ("seer", "0007_add_extras_to_nightshiftrun"), + ("seer", "0008_add_seer_run_models"), + ("seer", "0009_genericize_night_shift_results"), + ("seer", "0010_drop_legacy_columns"), + ("seer", "0011_add_project_repository_fk_to_seer"), + ("seer", "0012_make_project_repository_fk_notnull"), + ("seer", "0013_add_workflow_config"), + ("seer", "0014_add_new_unique_constraints"), + ("seer", "0015_add_seer_run_fks"), + ("seer", "0016_remove_old_fks"), + ("seer", "0017_drop_old_fk_columns"), + ("seer", "0018_backfill_seer_agent_run_group_id"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks + + dependencies = [ + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), + ] + + operations = [ + migrations.CreateModel( + name="SeerNightShiftRun", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("extras", models.JSONField(db_default={}, default=dict)), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ], + options={ + "db_table": "seer_nightshiftrun", + }, + ), + migrations.CreateModel( + name="SeerProjectRepository", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("branch_name", models.TextField(blank=True, null=True)), + ("instructions", models.TextField(blank=True, null=True)), + ( + "project_repository", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.projectrepository", + unique=True, + ), + ), + ], + options={ + "db_table": "seer_projectrepository", + }, + ), + migrations.CreateModel( + name="SeerRun", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "user_id", + sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( + "sentry.User", db_index=True, null=True, on_delete="SET_NULL" + ), + ), + ( + "uuid", + models.UUIDField(default=uuid.uuid4, editable=False, unique=True), + ), + ( + "seer_run_state_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True, unique=True), + ), + ("type", models.CharField(max_length=256)), + ( + "mirror_status", + models.CharField(db_default="pending", default="pending", max_length=256), + ), + ("last_triggered_at", models.DateTimeField()), + ("extras", models.JSONField(db_default={}, default=dict)), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ], + options={ + "db_table": "seer_seerrun", + }, + ), + migrations.CreateModel( + name="SeerNightShiftRunResult", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("kind", models.CharField(max_length=256)), + ("seer_run_id", models.TextField(null=True)), + ("extras", models.JSONField(db_default={}, default=dict)), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sentry.group", + ), + ), + ( + "run", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="results", + to="seer.seernightshiftrun", + ), + ), + ( + "result_seer_run", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="seer.seerrun", + ), + ), + ], + options={ + "db_table": "seer_nightshiftrunissue", + }, + ), + migrations.AddField( + model_name="seernightshiftrun", + name="seer_run", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="seer.seerrun", + ), + ), + migrations.CreateModel( + name="SeerAgentRun", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("title", models.CharField(max_length=256)), + ("source", models.CharField(max_length=256)), + ("extras", models.JSONField(db_default={}, default=dict)), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="sentry.group", + ), + ), + ( + "project", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="sentry.project", + ), + ), + ( + "run", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="agent", + to="seer.seerrun", + ), + ), + ], + options={ + "db_table": "seer_seeragentrun", + }, + ), + migrations.CreateModel( + name="SeerWorkflowConfig", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("strategy", models.CharField(max_length=256)), + ("enabled", models.BooleanField(default=False)), + ("schedule", models.CharField(default="daily", max_length=256)), + ("extras", models.JSONField(db_default={}, default=dict)), + ( + "organization", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", + ), + ), + ], + options={ + "db_table": "seer_workflowconfig", + }, + ), + migrations.AddField( + model_name="seernightshiftrun", + name="workflow_config", + field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="seer.seerworkflowconfig", + ), + ), + migrations.CreateModel( + name="SeerProjectRepositoryBranchOverride", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("tag_name", models.TextField()), + ("tag_value", models.TextField()), + ("branch_name", models.TextField()), + ( + "seer_project_repository", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="branch_overrides", + to="seer.seerprojectrepository", + ), + ), + ], + options={ + "db_table": "seer_projectrepositorybranchoverride", + "unique_together": {("seer_project_repository", "tag_name", "tag_value")}, + }, + ), + migrations.AddIndex( + model_name="seerrun", + index=models.Index( + fields=["organization", "-last_triggered_at"], + name="seer_seerru_organiz_c90199_idx", + ), + ), + migrations.AddIndex( + model_name="seerrun", + index=models.Index( + fields=["organization", "user_id", "-last_triggered_at"], + name="seer_seerru_organiz_8b7357_idx", + ), + ), + migrations.AddIndex( + model_name="seerrun", + index=models.Index( + fields=["organization", "type", "-last_triggered_at"], + name="seer_seerru_organiz_eb75f1_idx", + ), + ), + migrations.AddIndex( + model_name="seerrun", + index=models.Index(fields=["last_triggered_at"], name="seer_seerru_last_tr_9581cc_idx"), + ), + migrations.AddIndex( + model_name="seernightshiftrunresult", + index=models.Index(fields=["run", "kind"], name="seer_nights_run_id_d5406e_idx"), + ), + migrations.AddConstraint( + model_name="seerworkflowconfig", + constraint=models.UniqueConstraint( + fields=("organization", "strategy"), + name="seer_workflowconfig_org_strategy_uniq", + ), + ), + migrations.AddIndex( + model_name="seernightshiftrun", + index=models.Index( + fields=["organization", "date_added"], + name="seer_nights_organiz_6ebf9f_idx", + ), + ), + migrations.AddIndex( + model_name="seernightshiftrun", + index=models.Index(fields=["date_added"], name="seer_nights_date_ad_1d7b62_idx"), + ), + migrations.AddIndex( + model_name="seernightshiftrun", + index=models.Index( + fields=["workflow_config", "date_added"], + name="seer_nights_workflo_e31f62_idx", + ), + ), + ] diff --git a/src/sentry/seer/migrations/0002_add_default_coding_agent.py b/src/sentry/seer/migrations/0002_add_default_coding_agent.py deleted file mode 100644 index 7d86b74d078b..000000000000 --- a/src/sentry/seer/migrations/0002_add_default_coding_agent.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-25 21:08 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0001_add_seerorganizationsettings"), - ] - - operations = [ - migrations.AddField( - model_name="seerorganizationsettings", - name="default_coding_agent", - field=models.CharField(default="seer", max_length=32, null=True), - ), - ] diff --git a/src/sentry/seer/migrations/0003_add_seerprojectrepository.py b/src/sentry/seer/migrations/0003_add_seerprojectrepository.py deleted file mode 100644 index c301ec032f14..000000000000 --- a/src/sentry/seer/migrations/0003_add_seerprojectrepository.py +++ /dev/null @@ -1,92 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-12 20:44 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0002_add_default_coding_agent"), - ("sentry", "1051_rename_controloutbox_region_name_to_cell_name"), - ] - - operations = [ - migrations.CreateModel( - name="SeerProjectRepository", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("branch_name", models.TextField(blank=True, null=True)), - ("instructions", models.TextField(blank=True, null=True)), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ( - "repository", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.repository", - ), - ), - ], - options={ - "db_table": "seer_projectrepository", - "unique_together": {("project", "repository")}, - }, - ), - migrations.CreateModel( - name="SeerProjectRepositoryBranchOverride", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("tag_name", models.TextField()), - ("tag_value", models.TextField()), - ("branch_name", models.TextField()), - ( - "seer_project_repository", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="branch_overrides", - to="seer.seerprojectrepository", - ), - ), - ], - options={ - "db_table": "seer_projectrepositorybranchoverride", - "unique_together": {("seer_project_repository", "tag_name", "tag_value")}, - }, - ), - ] diff --git a/src/sentry/seer/migrations/0004_pending_delete_seerorganizationsettings.py b/src/sentry/seer/migrations/0004_pending_delete_seerorganizationsettings.py deleted file mode 100644 index 5cbc34e4ee23..000000000000 --- a/src/sentry/seer/migrations/0004_pending_delete_seerorganizationsettings.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-13 - -from django.db import migrations -from django.db.models import deletion - -from sentry.db.models.fields.foreignkey import FlexibleForeignKey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("seer", "0003_add_seerprojectrepository"), - ] - - operations = [ - migrations.AlterField( - model_name="seerorganizationsettings", - name="organization", - field=FlexibleForeignKey( - db_constraint=False, - on_delete=deletion.CASCADE, - to="sentry.organization", - unique=True, - ), - ), - SafeDeleteModel( - name="SeerOrganizationSettings", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/seer/migrations/0005_delete_seerorganizationsettings.py b/src/sentry/seer/migrations/0005_delete_seerorganizationsettings.py deleted file mode 100644 index ae0f99873e87..000000000000 --- a/src/sentry/seer/migrations/0005_delete_seerorganizationsettings.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.2.12 on 2026-03-13 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.state import DeletionAction - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("seer", "0004_pending_delete_seerorganizationsettings"), - ] - - operations = [ - SafeDeleteModel( - name="SeerOrganizationSettings", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/seer/migrations/0006_add_night_shift_models.py b/src/sentry/seer/migrations/0006_add_night_shift_models.py deleted file mode 100644 index 18c2cc943253..000000000000 --- a/src/sentry/seer/migrations/0006_add_night_shift_models.py +++ /dev/null @@ -1,102 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-13 02:45 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0005_delete_seerorganizationsettings"), - ("sentry", "1066_add_export_format_in_data_export_obj"), - ] - - operations = [ - migrations.CreateModel( - name="SeerNightShiftRun", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("triage_strategy", models.CharField(max_length=64)), - ("error_message", models.TextField(null=True)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.organization", - ), - ), - ], - options={ - "db_table": "seer_nightshiftrun", - }, - ), - migrations.CreateModel( - name="SeerNightShiftRunIssue", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("action", models.CharField(max_length=32)), - ("seer_run_id", models.TextField(null=True)), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", - ), - ), - ( - "run", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="issues", - to="seer.seernightshiftrun", - ), - ), - ], - options={ - "db_table": "seer_nightshiftrunissue", - }, - ), - migrations.AddIndex( - model_name="seernightshiftrun", - index=models.Index( - fields=["organization", "date_added"], - name="seer_nights_organiz_6ebf9f_idx", - ), - ), - migrations.AddIndex( - model_name="seernightshiftrun", - index=models.Index(fields=["date_added"], name="seer_nights_date_ad_1d7b62_idx"), - ), - ] diff --git a/src/sentry/seer/migrations/0007_add_extras_to_nightshiftrun.py b/src/sentry/seer/migrations/0007_add_extras_to_nightshiftrun.py deleted file mode 100644 index 6565ecfd9d56..000000000000 --- a/src/sentry/seer/migrations/0007_add_extras_to_nightshiftrun.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-16 15:55 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0006_add_night_shift_models"), - ] - - operations = [ - migrations.AddField( - model_name="seernightshiftrun", - name="extras", - field=models.JSONField(db_default={}, default=dict), - ), - ] diff --git a/src/sentry/seer/migrations/0009_genericize_night_shift_results.py b/src/sentry/seer/migrations/0009_genericize_night_shift_results.py deleted file mode 100644 index 2a10bcfa3186..000000000000 --- a/src/sentry/seer/migrations/0009_genericize_night_shift_results.py +++ /dev/null @@ -1,204 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-04 21:41 - -import logging - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations, models -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.fields import SafeRemoveField -from sentry.new_migrations.monkey.state import DeletionAction -from sentry.utils.query import RangeQuerySetWrapperWithProgressBarApprox - -logger = logging.getLogger(__name__) - - -def backfill_action_to_extras(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - """Move SeerNightShiftRunResult.action into extras["action"]. Idempotent.""" - SeerNightShiftRunResult = apps.get_model("seer", "SeerNightShiftRunResult") - - total_processed = 0 - total_updated = 0 - - for row in RangeQuerySetWrapperWithProgressBarApprox(SeerNightShiftRunResult.objects.all()): - total_processed += 1 - if row.action is None: - continue - existing = row.extras or {} - if "action" in existing: - continue - existing["action"] = row.action - row.extras = existing - row.save(update_fields=["extras"]) - total_updated += 1 - - logger.info( - "backfill_action_to_extras: complete, processed %d rows, updated %d", - total_processed, - total_updated, - ) - - -def restore_action_from_extras(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - """Reverse: copy extras["action"] back into the action column.""" - SeerNightShiftRunResult = apps.get_model("seer", "SeerNightShiftRunResult") - - for row in RangeQuerySetWrapperWithProgressBarApprox(SeerNightShiftRunResult.objects.all()): - if not row.extras: - continue - action = row.extras.get("action") - if action is None: - continue - row.action = action - row.save(update_fields=["action"]) - - -def backfill_error_message_to_extras( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """Move SeerNightShiftRun.error_message into extras["error_message"]. Idempotent.""" - SeerNightShiftRun = apps.get_model("seer", "SeerNightShiftRun") - - total_processed = 0 - total_updated = 0 - - for run in RangeQuerySetWrapperWithProgressBarApprox( - SeerNightShiftRun.objects.exclude(error_message__isnull=True) - ): - total_processed += 1 - existing = run.extras or {} - if "error_message" in existing: - continue - existing["error_message"] = run.error_message - run.extras = existing - run.save(update_fields=["extras"]) - total_updated += 1 - - logger.info( - "backfill_error_message_to_extras: complete, processed %d rows, updated %d", - total_processed, - total_updated, - ) - - -def restore_error_message_from_extras( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """Reverse: copy extras["error_message"] back into the error_message column.""" - SeerNightShiftRun = apps.get_model("seer", "SeerNightShiftRun") - - for run in RangeQuerySetWrapperWithProgressBarApprox(SeerNightShiftRun.objects.all()): - if not run.extras: - continue - error_message = run.extras.get("error_message") - if error_message is None: - continue - run.error_message = error_message - run.save(update_fields=["error_message"]) - - -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 = [ - ("seer", "0008_add_seer_run_models"), - ("sentry", "1079_purge_scm_legacy_org_options"), - ] - - operations = [ - # db_table is preserved on SeerNightShiftRunResult, so no DDL needed. - migrations.SeparateDatabaseAndState( - state_operations=[ - migrations.RenameModel( - old_name="SeerNightShiftRunIssue", - new_name="SeerNightShiftRunResult", - ), - ], - database_operations=[], - ), - migrations.AlterField( - model_name="seernightshiftrunresult", - name="run", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="results", - to="seer.seernightshiftrun", - ), - ), - migrations.AddField( - model_name="seernightshiftrunresult", - name="kind", - field=models.CharField(db_default="agentic_triage", max_length=256), - ), - migrations.AddField( - model_name="seernightshiftrunresult", - name="extras", - field=models.JSONField(db_default={}, default=dict), - ), - migrations.AlterField( - model_name="seernightshiftrunresult", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", - ), - ), - migrations.AlterField( - model_name="seernightshiftrunresult", - name="action", - field=models.CharField(max_length=32, null=True), - ), - migrations.AlterField( - model_name="seernightshiftrun", - name="triage_strategy", - field=models.CharField(max_length=64, null=True), - ), - migrations.AddIndex( - model_name="seernightshiftrunresult", - index=models.Index(fields=["run", "kind"], name="seer_nights_run_id_d5406e_idx"), - ), - migrations.RunPython( - backfill_action_to_extras, - restore_action_from_extras, - elidable=True, - hints={"tables": ["seer_nightshiftrunissue"]}, - ), - SafeRemoveField( - model_name="seernightshiftrunresult", - name="action", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="seernightshiftrun", - name="triage_strategy", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - migrations.RunPython( - backfill_error_message_to_extras, - restore_error_message_from_extras, - elidable=True, - hints={"tables": ["seer_nightshiftrun"]}, - ), - SafeRemoveField( - model_name="seernightshiftrun", - name="error_message", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/seer/migrations/0010_drop_legacy_columns.py b/src/sentry/seer/migrations/0010_drop_legacy_columns.py deleted file mode 100644 index 6d25006d8801..000000000000 --- a/src/sentry/seer/migrations/0010_drop_legacy_columns.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-05 02:03 - -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 = [ - ("seer", "0009_genericize_night_shift_results"), - ] - - operations = [ - SafeRemoveField( - model_name="seernightshiftrunresult", - name="action", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="seernightshiftrun", - name="triage_strategy", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="seernightshiftrun", - name="error_message", - deletion_action=DeletionAction.DELETE, - ), - migrations.AlterField( - model_name="seernightshiftrunresult", - name="kind", - field=models.CharField(max_length=256), - ), - ] diff --git a/src/sentry/seer/migrations/0011_add_project_repository_fk_to_seer.py b/src/sentry/seer/migrations/0011_add_project_repository_fk_to_seer.py deleted file mode 100644 index 2793707add31..000000000000 --- a/src/sentry/seer/migrations/0011_add_project_repository_fk_to_seer.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-11 21:32 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0010_drop_legacy_columns"), - ("sentry", "1087_add_projectrepository"), - ] - - operations = [ - migrations.AddField( - model_name="seerprojectrepository", - name="project_repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.projectrepository", - ), - ), - ] diff --git a/src/sentry/seer/migrations/0012_make_project_repository_fk_notnull.py b/src/sentry/seer/migrations/0012_make_project_repository_fk_notnull.py deleted file mode 100644 index 1e0188049e21..000000000000 --- a/src/sentry/seer/migrations/0012_make_project_repository_fk_notnull.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-13 22:18 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0011_add_project_repository_fk_to_seer"), - ("sentry", "1095_make_project_repository_fk_notnull"), - ] - - operations = [ - migrations.AlterField( - model_name="seerprojectrepository", - name="project_repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.projectrepository" - ), - ), - ] diff --git a/src/sentry/seer/migrations/0013_add_workflow_config.py b/src/sentry/seer/migrations/0013_add_workflow_config.py deleted file mode 100644 index 870a371aa178..000000000000 --- a/src/sentry/seer/migrations/0013_add_workflow_config.py +++ /dev/null @@ -1,79 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 01:27 - -import django.db.models.deletion -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0012_make_project_repository_fk_notnull"), - ("sentry", "1096_backfill_mcp_dashboard_widget_filters"), - ] - - operations = [ - migrations.CreateModel( - name="SeerWorkflowConfig", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("strategy", models.CharField(max_length=256)), - ("enabled", models.BooleanField(default=False)), - ("schedule", models.CharField(default="daily", max_length=256)), - ("extras", models.JSONField(db_default={}, default=dict)), - ( - "organization", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ], - options={ - "db_table": "seer_workflowconfig", - }, - ), - migrations.AddField( - model_name="seernightshiftrun", - name="workflow_config", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="seer.seerworkflowconfig", - ), - ), - migrations.AddIndex( - model_name="seernightshiftrun", - index=models.Index( - fields=["workflow_config", "date_added"], name="seer_nights_workflo_e31f62_idx" - ), - ), - migrations.AddConstraint( - model_name="seerworkflowconfig", - constraint=models.UniqueConstraint( - fields=("organization", "strategy"), name="seer_workflowconfig_org_strategy_uniq" - ), - ), - ] diff --git a/src/sentry/seer/migrations/0014_add_new_unique_constraints.py b/src/sentry/seer/migrations/0014_add_new_unique_constraints.py deleted file mode 100644 index 51842efbd4aa..000000000000 --- a/src/sentry/seer/migrations/0014_add_new_unique_constraints.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 19:11 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("seer", "0013_add_workflow_config"), - ("sentry", "1097_add_new_unique_constraints"), - ] - - operations = [ - migrations.AlterField( - model_name="seerprojectrepository", - name="project_repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="sentry.projectrepository", - unique=True, - ), - ), - ] diff --git a/src/sentry/seer/migrations/0015_add_seer_run_fks.py b/src/sentry/seer/migrations/0015_add_seer_run_fks.py deleted file mode 100644 index 3d840bb1178d..000000000000 --- a/src/sentry/seer/migrations/0015_add_seer_run_fks.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 23:33 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("seer", "0014_add_new_unique_constraints"), - ] - - operations = [ - migrations.AddField( - model_name="seernightshiftrun", - name="seer_run", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="seer.seerrun", - ), - ), - migrations.AddField( - model_name="seernightshiftrunresult", - name="result_seer_run", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="seer.seerrun", - ), - ), - ] diff --git a/src/sentry/seer/migrations/0016_remove_old_fks.py b/src/sentry/seer/migrations/0016_remove_old_fks.py deleted file mode 100644 index 1dd02f926639..000000000000 --- a/src/sentry/seer/migrations/0016_remove_old_fks.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 5.2.14 on 2026-05-15 19:26 - -import django.db.models.deletion -import sentry.db.models.fields.foreignkey -from django.db import migrations - -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 = [ - ("seer", "0015_add_seer_run_fks"), - ("sentry", "1098_remove_old_fks"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="seerprojectrepository", - unique_together=set(), - ), - migrations.AlterField( - model_name="seerprojectrepository", - name="project", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.project", - ), - ), - migrations.AlterField( - model_name="seerprojectrepository", - name="repository", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.repository", - ), - ), - SafeRemoveField( - model_name="seerprojectrepository", - name="project", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="seerprojectrepository", - name="repository", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/seer/migrations/0017_drop_old_fk_columns.py b/src/sentry/seer/migrations/0017_drop_old_fk_columns.py deleted file mode 100644 index 79a5cfd7b100..000000000000 --- a/src/sentry/seer/migrations/0017_drop_old_fk_columns.py +++ /dev/null @@ -1,36 +0,0 @@ -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 = [ - ("seer", "0016_remove_old_fks"), - ] - - operations = [ - SafeRemoveField( - model_name="seerprojectrepository", - name="project", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="seerprojectrepository", - name="repository", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/seer/migrations/0018_backfill_seer_agent_run_group_id.py b/src/sentry/seer/migrations/0018_backfill_seer_agent_run_group_id.py deleted file mode 100644 index ea6950325b3b..000000000000 --- a/src/sentry/seer/migrations/0018_backfill_seer_agent_run_group_id.py +++ /dev/null @@ -1,127 +0,0 @@ -# Generated by Django 5.2.14 on 2026-06-12 17:07 -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.numbers import validate_bigint -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - - -def _parse_group_id(value: object) -> int | None: - # str.isdigit() is unsafe here — it accepts unicode digits int() rejects — so - # parse with int() and bounds-check that it fits the bigint group_id column. - if not isinstance(value, str): - return None - try: - group_id = int(value) - except ValueError: - return None - return group_id if validate_bigint(group_id) else None - - -def backfill_seer_agent_run_group_id( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - SeerAgentRun = apps.get_model("seer", "SeerAgentRun") - Group = apps.get_model("sentry", "Group") - - # For autofix runs extras["category_value"] is the stringified group id, set - # only recently — recover it for historical rows, but only link a group that - # belongs to the run's own org (never trust the value across the tenant - # boundary). (agent_run_id, run_org_id, candidate_group_id) per row. - candidates: list[tuple[int, int, int]] = [] - skipped_bad_value = 0 - - # Only autofix rows store a group id in category_value; other sources (e.g. - # dashboard_generate) put unrelated ids there, so this filter is load-bearing. - queryset = SeerAgentRun.objects.filter( - source="autofix", - group_id__isnull=True, - ).values_list("id", "run__organization_id", "extras") - - for agent_run_id, run_org_id, extras in RangeQuerySetWrapperWithProgressBar( - queryset, result_value_getter=lambda values: values[0] - ): - group_id = _parse_group_id((extras or {}).get("category_value")) - if group_id is None: - skipped_bad_value += 1 - continue - candidates.append((agent_run_id, run_org_id, group_id)) - - group_org: dict[int, int] = {} - candidate_group_ids = sorted({group_id for _, _, group_id in candidates}) - for i in range(0, len(candidate_group_ids), 5000): - chunk = candidate_group_ids[i : i + 5000] - for group_id, org_id in Group.objects.filter(id__in=chunk).values_list( - "id", "project__organization_id" - ): - group_org[group_id] = org_id - - batch: list[object] = [] - skipped_missing_group = 0 - skipped_org_mismatch = 0 - linked = 0 - - for agent_run_id, run_org_id, group_id in candidates: - org_id = group_org.get(group_id) - if org_id is None: - skipped_missing_group += 1 - continue - if org_id != run_org_id: - skipped_org_mismatch += 1 - continue - - batch.append(SeerAgentRun(id=agent_run_id, group_id=group_id)) - linked += 1 - - if len(batch) >= 1000: - SeerAgentRun.objects.bulk_update(batch, ["group_id"]) - batch = [] - - if batch: - SeerAgentRun.objects.bulk_update(batch, ["group_id"]) - - logger.info( - "backfill_seer_agent_run_group_id.done", - extra={ - "linked": linked, - "skipped_bad_value": skipped_bad_value, - "skipped_missing_group": skipped_missing_group, - "skipped_org_mismatch": skipped_org_mismatch, - }, - ) - - -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 = True - - dependencies = [ - ("seer", "0017_drop_old_fk_columns"), - # Reads sentry.Group (and Project for org) to validate tenant ownership. - ("sentry", "1114_extend_repository_url_length"), - ] - - operations = [ - migrations.RunPython( - backfill_seer_agent_run_group_id, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["seer_seeragentrun"]}, - ), - ] diff --git a/src/sentry/tempest/migrations/0001_squashed_0003_use_encrypted_char_field.py b/src/sentry/tempest/migrations/0001_squashed_0003_use_encrypted_char_field.py index cdbfb02d7273..4c2326376299 100644 --- a/src/sentry/tempest/migrations/0001_squashed_0003_use_encrypted_char_field.py +++ b/src/sentry/tempest/migrations/0001_squashed_0003_use_encrypted_char_field.py @@ -35,7 +35,7 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "1103_backfill_auto_link_repos_by_name"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ diff --git a/src/sentry/uptime/migrations/0001_squashed_0042_extra_uptime_indexes.py b/src/sentry/uptime/migrations/0001_squashed_0042_extra_uptime_indexes.py deleted file mode 100644 index f572d21b7d87..000000000000 --- a/src/sentry/uptime/migrations/0001_squashed_0042_extra_uptime_indexes.py +++ /dev/null @@ -1,244 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:30 - -import django.db.models.deletion -import django.db.models.functions.datetime -import django.utils.timezone -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -import sentry.db.models.fields.hybrid_cloud_foreign_key -import sentry.db.models.fields.jsonfield -import sentry.uptime.models -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - replaces = [ - ("uptime", "0001_uptime_subscriptions"), - ("uptime", "0002_remove_separate_remote_subscription"), - ("uptime", "0003_drop_remote_subscription"), - ("uptime", "0004_projectuptimesubscription_mode"), - ("uptime", "0005_uptime_status"), - ("uptime", "0006_projectuptimesubscription_name_owner"), - ("uptime", "0007_update_detected_subscription_interval"), - ("uptime", "0008_uptime_url_suffix"), - ("uptime", "0009_better_name_for_uptime_rdap_columns"), - ("uptime", "0010_remove_uptime_whois_columns_state"), - ("uptime", "0011_remove_uptime_whois_columns_db"), - ("uptime", "0012_uptime_subscription_request_fields"), - ("uptime", "0013_uptime_subscription_new_unique"), - ("uptime", "0014_add_uptime_enviromnet"), - ("uptime", "0015_headers_deafult_empty_list"), - ("uptime", "0016_translate_uptime_object_headers_to_lists"), - ("uptime", "0017_unique_on_timeout"), - ("uptime", "0018_add_trace_sampling_field_to_uptime"), - ("uptime", "0019_uptime_region"), - ("uptime", "0020_drop_region"), - ("uptime", "0021_drop_region_table_col"), - ("uptime", "0022_add_trace_sampling_to_uptime_monitors"), - ("uptime", "0023_translate_uptime_object_headers_to_lists_take_two"), - ("uptime", "0024_add_status_to_project_uptime_subscription"), - ("uptime", "0025_uptime_migrate_constraint"), - ("uptime", "0026_region_mode_col"), - ("uptime", "0027_remove_migrated_and_unique_constraint"), - ("uptime", "0028_drop_migrated_column"), - ("uptime", "0029_uptime_subscription_index_domain_cols"), - ("uptime", "0030_status_update_date"), - ("uptime", "0031_translate_uptime_object_headers_to_lists_take_three"), - ("uptime", "0032_stats_on_subscription"), - ("uptime", "0033_uptime_backfill_to_detectors"), - ("uptime", "0034_uptime_backfill_uptime_status"), - ("uptime", "0035_uptime_backfill_detector_enabled"), - ("uptime", "0036_uptime_status_indexes"), - ("uptime", "0037_fix_drift_default_to_db_default"), - ("uptime", "0038_uptime_drop_project_subscription_uptime_status"), - ("uptime", "0039_uptime_drop_project_subscription_uptime_status_db"), - ("uptime", "0040_uptime_backfill_detector_conditions"), - ("uptime", "0041_uptime_backfill_detector_grouphash"), - ("uptime", "0042_extra_uptime_indexes"), - ] - - initial = True - - checked = False # This is an initial migration and can take locks - - dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), - ] - - operations = [ - migrations.CreateModel( - name="UptimeSubscription", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ("type", models.TextField()), - ("status", models.SmallIntegerField(db_default=0, default=0)), - ("subscription_id", models.TextField(null=True, unique=True)), - ("url", models.CharField(max_length=255)), - ("url_domain", models.CharField(db_default="", default="", max_length=255)), - ("url_domain_suffix", models.CharField(db_default="", default="", max_length=255)), - ("host_provider_id", models.CharField(db_index=True, max_length=255, null=True)), - ("host_provider_name", models.CharField(db_index=True, max_length=255, null=True)), - ("interval_seconds", models.IntegerField()), - ("timeout_ms", models.IntegerField()), - ("method", models.CharField(db_default="GET", max_length=20)), - ( - "headers", - sentry.db.models.fields.jsonfield.JSONField(db_default=[], default=dict), - ), - ("body", models.TextField(null=True)), - ("trace_sampling", models.BooleanField(db_default=False, default=False)), - ("uptime_status", models.PositiveSmallIntegerField(db_default=1)), - ( - "uptime_status_update_date", - models.DateTimeField(db_default=django.db.models.functions.datetime.Now()), - ), - ], - options={ - "db_table": "uptime_uptimesubscription", - "indexes": [ - models.Index( - fields=["url_domain_suffix", "url_domain"], - name="uptime_upti_url_dom_ead522_idx", - ), - models.Index( - fields=["uptime_status", "uptime_status_update_date"], - name="uptime_upti_uptime__546c70_idx", - ), - ], - }, - ), - migrations.CreateModel( - name="ProjectUptimeSubscription", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(default=django.utils.timezone.now)), - ("date_added", models.DateTimeField(default=django.utils.timezone.now, null=True)), - ( - "status", - sentry.db.models.fields.bounded.BoundedPositiveBigIntegerField(db_default=0), - ), - ("mode", models.SmallIntegerField(db_default=1, default=1)), - ("name", models.TextField()), - ( - "owner_user_id", - sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", db_index=True, null=True, on_delete="SET_NULL" - ), - ), - ( - "environment", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.environment", - ), - ), - ( - "owner_team", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to="sentry.team" - ), - ), - ( - "project", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.project" - ), - ), - ( - "uptime_subscription", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="uptime.uptimesubscription" - ), - ), - ], - options={ - "db_table": "uptime_projectuptimesubscription", - "indexes": [ - models.Index(fields=["project", "mode"], name="uptime_proj_project_30b94a_idx") - ], - "constraints": [ - models.UniqueConstraint( - condition=models.Q(("mode", 1)), - fields=("project_id", "uptime_subscription"), - name="uptime_projectuptimesubscription_unique_manual_project_subscription", - ), - models.UniqueConstraint( - condition=models.Q(("mode__in", (2, 3))), - fields=("project_id", "uptime_subscription"), - name="uptime_projectuptimesubscription_unique_auto_project_subscription", - ), - ], - }, - ), - migrations.CreateModel( - name="UptimeSubscriptionRegion", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("region_slug", models.CharField(db_default="", db_index=True, max_length=255)), - ( - "mode", - models.CharField( - db_default=sentry.uptime.models.UptimeSubscriptionRegion.RegionMode[ - "ACTIVE" - ], - max_length=32, - ), - ), - ( - "uptime_subscription", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="regions", - to="uptime.uptimesubscription", - ), - ), - ], - options={ - "db_table": "uptime_uptimesubscriptionregion", - "constraints": [ - models.UniqueConstraint( - models.F("uptime_subscription"), - models.F("region_slug"), - name="uptime_uptimesubscription_region_slug_unique", - ) - ], - }, - ), - ] diff --git a/src/sentry/uptime/migrations/0001_squashed_0055_backfill_2xx_status_assertion.py b/src/sentry/uptime/migrations/0001_squashed_0055_backfill_2xx_status_assertion.py new file mode 100644 index 000000000000..b726380987a7 --- /dev/null +++ b/src/sentry/uptime/migrations/0001_squashed_0055_backfill_2xx_status_assertion.py @@ -0,0 +1,198 @@ +# Generated by Django 5.2.14 on 2026-06-16 19:05 + +import django.db.models.deletion +import django.utils.timezone +import sentry.db.models.fields.bounded +import sentry.db.models.fields.foreignkey +import sentry.uptime.models +from django.db import migrations, models + +from sentry.new_migrations.migrations import CheckedMigration + + +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 = True + + replaces = [ + ("uptime", "0001_squashed_0042_extra_uptime_indexes"), + ("uptime", "0043_uptime_django_json_field"), + ("uptime", "0044_remove_project_uptime_subscription"), + ("uptime", "0045_backfill_detector_thresholds"), + ("uptime", "0046_delete_project_uptime_subscription_table"), + ("uptime", "0047_remove_uptime_status_columns"), + ("uptime", "0048_delete_uptime_status_columns"), + ("uptime", "0049_cleanup_failed_safe_deletes"), + ("uptime", "0050_response_capture"), + ("uptime", "0051_add_assertion"), + ("uptime", "0052_add_date_added_index_to_uptimeresponsecapture"), + ("uptime", "0053_add_response_capture_enabled"), + ("uptime", "0054_delete_bad_assertions"), + ("uptime", "0055_backfill_2xx_status_assertion"), + ] + + initial = True + + checked = False # This is an initial migration and can take locks + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="UptimeSubscription", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ( + "date_updated", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "date_added", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), + ("type", models.TextField()), + ("status", models.SmallIntegerField(db_default=0, default=0)), + ("subscription_id", models.TextField(null=True, unique=True)), + ("url", models.CharField(max_length=255)), + ( + "url_domain", + models.CharField(db_default="", default="", max_length=255), + ), + ( + "url_domain_suffix", + models.CharField(db_default="", default="", max_length=255), + ), + ( + "host_provider_id", + models.CharField(db_index=True, max_length=255, null=True), + ), + ( + "host_provider_name", + models.CharField(db_index=True, max_length=255, null=True), + ), + ("interval_seconds", models.IntegerField()), + ("timeout_ms", models.IntegerField()), + ("method", models.CharField(db_default="GET", max_length=20)), + ("headers", models.JSONField(db_default=[])), + ("body", models.TextField(null=True)), + ( + "trace_sampling", + models.BooleanField(db_default=False, default=False), + ), + ( + "response_capture_enabled", + models.BooleanField(db_default=True, default=True), + ), + ( + "capture_response_on_failure", + models.BooleanField(db_default=True, default=True), + ), + ("assertion", models.JSONField(null=True)), + ], + options={ + "db_table": "uptime_uptimesubscription", + "indexes": [ + models.Index( + fields=["url_domain_suffix", "url_domain"], + name="uptime_upti_url_dom_ead522_idx", + ) + ], + }, + ), + migrations.CreateModel( + name="UptimeResponseCapture", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ("file_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), + ( + "scheduled_check_time_ms", + sentry.db.models.fields.bounded.BoundedBigIntegerField(), + ), + ( + "uptime_subscription", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="response_captures", + to="uptime.uptimesubscription", + ), + ), + ], + options={ + "db_table": "uptime_uptimeresponsecapture", + "indexes": [ + models.Index( + fields=["uptime_subscription", "scheduled_check_time_ms"], + name="uptime_upti_uptime__aa1fbe_idx", + ), + models.Index(fields=["date_added"], name="uptime_upti_date_ad_d591fd_idx"), + ], + }, + ), + migrations.CreateModel( + name="UptimeSubscriptionRegion", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "region_slug", + models.CharField(db_default="", db_index=True, max_length=255), + ), + ( + "mode", + models.CharField( + db_default=sentry.uptime.models.UptimeSubscriptionRegion.RegionMode[ + "ACTIVE" + ], + max_length=32, + ), + ), + ( + "uptime_subscription", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="regions", + to="uptime.uptimesubscription", + ), + ), + ], + options={ + "db_table": "uptime_uptimesubscriptionregion", + "constraints": [ + models.UniqueConstraint( + models.F("uptime_subscription"), + models.F("region_slug"), + name="uptime_uptimesubscription_region_slug_unique", + ) + ], + }, + ), + ] diff --git a/src/sentry/uptime/migrations/0043_uptime_django_json_field.py b/src/sentry/uptime/migrations/0043_uptime_django_json_field.py deleted file mode 100644 index c934359e9f0f..000000000000 --- a/src/sentry/uptime/migrations/0043_uptime_django_json_field.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-06 16:59 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = True - - dependencies = [ - ("uptime", "0001_squashed_0042_extra_uptime_indexes"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - SafeRunSQL( - """ - ALTER TABLE uptime_uptimesubscription - ALTER COLUMN headers DROP DEFAULT, - ALTER COLUMN headers TYPE jsonb USING headers::jsonb, - ALTER COLUMN headers SET DEFAULT '[]'::jsonb; - """, - reverse_sql=""" - ALTER TABLE uptime_uptimesubscription - ALTER COLUMN headers DROP DEFAULT, - ALTER COLUMN headers TYPE text - ALTER COLUMN headers SET DEFAULT '[]'; - """, - hints={"tables": ["uptime_uptimesubscription"]}, - ) - ], - state_operations=[ - migrations.AlterField( - model_name="uptimesubscription", - name="headers", - field=models.JSONField(db_default=[]), - ), - ], - ) - ] diff --git a/src/sentry/uptime/migrations/0044_remove_project_uptime_subscription.py b/src/sentry/uptime/migrations/0044_remove_project_uptime_subscription.py deleted file mode 100644 index bf8af845fba9..000000000000 --- a/src/sentry/uptime/migrations/0044_remove_project_uptime_subscription.py +++ /dev/null @@ -1,64 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-12 23:27 - -from django.db.migrations import AlterField -from django.db.models import deletion - -from sentry.db.models.fields.foreignkey import FlexibleForeignKey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("uptime", "0043_uptime_django_json_field"), - ] - - operations = [ - AlterField( - model_name="projectuptimesubscription", - name="owner_team", - field=FlexibleForeignKey( - db_constraint=False, - null=True, - on_delete=deletion.SET_NULL, - to="sentry.team", - ), - ), - AlterField( - model_name="projectuptimesubscription", - name="project", - field=FlexibleForeignKey( - db_constraint=False, - on_delete=deletion.CASCADE, - to="sentry.project", - ), - ), - AlterField( - model_name="projectuptimesubscription", - name="uptime_subscription", - field=FlexibleForeignKey( - db_constraint=False, - on_delete=deletion.PROTECT, - to="uptime.uptimesubscription", - ), - ), - SafeDeleteModel( - name="ProjectUptimeSubscription", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/uptime/migrations/0045_backfill_detector_thresholds.py b/src/sentry/uptime/migrations/0045_backfill_detector_thresholds.py deleted file mode 100644 index 63b4c3f7ca37..000000000000 --- a/src/sentry/uptime/migrations/0045_backfill_detector_thresholds.py +++ /dev/null @@ -1,64 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-17 17:50 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE = "uptime_domain_failure" -DEFAULT_RECOVERY_THRESHOLD = 1 -DEFAULT_DOWNTIME_THRESHOLD = 3 - - -def backfill_detector_thresholds(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - """ - Backfill recovery_threshold and downtime_threshold in uptime detector configs. - - This migration adds the new threshold fields to all existing uptime detectors - so that the UptimeDetectorHandler can start using config values instead of - global hardcoded options. - """ - Detector = apps.get_model("workflow_engine", "Detector") - - # Query all uptime detectors - uptime_detectors = Detector.objects.filter( - type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, - ) - - for detector in RangeQuerySetWrapperWithProgressBar(uptime_detectors): - # Only update detectors that don't already have threshold values - config = detector.config or {} - needs_update = False - - if "recovery_threshold" not in config: - config["recovery_threshold"] = DEFAULT_RECOVERY_THRESHOLD - needs_update = True - - if "downtime_threshold" not in config: - config["downtime_threshold"] = DEFAULT_DOWNTIME_THRESHOLD - needs_update = True - - if needs_update: - detector.config = config - detector.save(update_fields=["config"]) - - -class Migration(CheckedMigration): - # This is a data migration that can take a while on large deployments - # and should be run manually after code deployment - is_post_deployment = True - - dependencies = [ - ("uptime", "0044_remove_project_uptime_subscription"), - ("workflow_engine", "0085_crons_link_detectors_to_all_workflows"), - ] - - operations = [ - migrations.RunPython( - backfill_detector_thresholds, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detector"]}, - ) - ] diff --git a/src/sentry/uptime/migrations/0046_delete_project_uptime_subscription_table.py b/src/sentry/uptime/migrations/0046_delete_project_uptime_subscription_table.py deleted file mode 100644 index a07837404224..000000000000 --- a/src/sentry/uptime/migrations/0046_delete_project_uptime_subscription_table.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-22 19:44 - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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 = [ - ("uptime", "0045_backfill_detector_thresholds"), - ] - - operations = [ - SafeDeleteModel( - name="ProjectUptimeSubscription", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/uptime/migrations/0047_remove_uptime_status_columns.py b/src/sentry/uptime/migrations/0047_remove_uptime_status_columns.py deleted file mode 100644 index 26b51b9109b1..000000000000 --- a/src/sentry/uptime/migrations/0047_remove_uptime_status_columns.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-08 16:26 - -from django.db import migrations - -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 = [ - ("uptime", "0046_delete_project_uptime_subscription_table"), - ] - - operations = [ - migrations.RemoveIndex( - model_name="uptimesubscription", - name="uptime_upti_uptime__546c70_idx", - ), - SafeRemoveField( - model_name="uptimesubscription", - name="uptime_status", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - SafeRemoveField( - model_name="uptimesubscription", - name="uptime_status_update_date", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/uptime/migrations/0048_delete_uptime_status_columns.py b/src/sentry/uptime/migrations/0048_delete_uptime_status_columns.py deleted file mode 100644 index be8f9350c61e..000000000000 --- a/src/sentry/uptime/migrations/0048_delete_uptime_status_columns.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-22 18:59 - - -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 = [ - ("uptime", "0047_remove_uptime_status_columns"), - ] - - operations = [ - SafeRemoveField( - model_name="uptimesubscription", - name="uptime_status", - deletion_action=DeletionAction.DELETE, - ), - SafeRemoveField( - model_name="uptimesubscription", - name="uptime_status_update_date", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/uptime/migrations/0049_cleanup_failed_safe_deletes.py b/src/sentry/uptime/migrations/0049_cleanup_failed_safe_deletes.py deleted file mode 100644 index 754d86151aec..000000000000 --- a/src/sentry/uptime/migrations/0049_cleanup_failed_safe_deletes.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 00:38 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = [ - ("uptime", "0048_delete_uptime_status_columns"), - ] - - operations = [ - # Clean up table that may not have been deleted due to missing - # historical_silo_assignments entry before the fix - SafeRunSQL( - sql="DROP TABLE IF EXISTS uptime_projectuptimesubscription CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["uptime_projectuptimesubscription"]}, - ), - ] diff --git a/src/sentry/uptime/migrations/0050_response_capture.py b/src/sentry/uptime/migrations/0050_response_capture.py deleted file mode 100644 index eeb7f661c6bc..000000000000 --- a/src/sentry/uptime/migrations/0050_response_capture.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-16 20:02 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("uptime", "0049_cleanup_failed_safe_deletes"), - ] - - operations = [ - migrations.AddField( - model_name="uptimesubscription", - name="capture_response_on_failure", - field=models.BooleanField(db_default=True, default=True), - ), - migrations.CreateModel( - name="UptimeResponseCapture", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ("file_id", sentry.db.models.fields.bounded.BoundedBigIntegerField()), - ( - "scheduled_check_time_ms", - sentry.db.models.fields.bounded.BoundedBigIntegerField(), - ), - ( - "uptime_subscription", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="response_captures", - to="uptime.uptimesubscription", - ), - ), - ], - options={ - "db_table": "uptime_uptimeresponsecapture", - "indexes": [ - models.Index( - fields=["uptime_subscription", "scheduled_check_time_ms"], - name="uptime_upti_uptime__aa1fbe_idx", - ) - ], - }, - ), - ] diff --git a/src/sentry/uptime/migrations/0051_add_assertion.py b/src/sentry/uptime/migrations/0051_add_assertion.py deleted file mode 100644 index 9d6e1bf9a3f7..000000000000 --- a/src/sentry/uptime/migrations/0051_add_assertion.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-23 14:44 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("uptime", "0050_response_capture"), - ] - - operations = [ - migrations.AddField( - model_name="uptimesubscription", - name="assertion", - field=models.JSONField(null=True), - ), - ] diff --git a/src/sentry/uptime/migrations/0052_add_date_added_index_to_uptimeresponsecapture.py b/src/sentry/uptime/migrations/0052_add_date_added_index_to_uptimeresponsecapture.py deleted file mode 100644 index 5f54383a412f..000000000000 --- a/src/sentry/uptime/migrations/0052_add_date_added_index_to_uptimeresponsecapture.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-27 18:12 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("uptime", "0051_add_assertion"), - ] - - operations = [ - migrations.AddIndex( - model_name="uptimeresponsecapture", - index=models.Index(fields=["date_added"], name="uptime_upti_date_ad_d591fd_idx"), - ), - ] diff --git a/src/sentry/uptime/migrations/0053_add_response_capture_enabled.py b/src/sentry/uptime/migrations/0053_add_response_capture_enabled.py deleted file mode 100644 index 0235dbab5734..000000000000 --- a/src/sentry/uptime/migrations/0053_add_response_capture_enabled.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-27 20:06 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("uptime", "0052_add_date_added_index_to_uptimeresponsecapture"), - ] - - operations = [ - migrations.AddField( - model_name="uptimesubscription", - name="response_capture_enabled", - field=models.BooleanField(db_default=True, default=True), - ), - ] diff --git a/src/sentry/uptime/migrations/0054_delete_bad_assertions.py b/src/sentry/uptime/migrations/0054_delete_bad_assertions.py deleted file mode 100644 index 259b94a46a0a..000000000000 --- a/src/sentry/uptime/migrations/0054_delete_bad_assertions.py +++ /dev/null @@ -1,51 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-30 19:34 -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - - -def backfill_delete_assertions(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - UptimeSubscription = apps.get_model("uptime", "UptimeSubscription") - - # Query all uptime detectors - subscriptions = UptimeSubscription.objects.filter(assertion__isnull=False) - - for subscription in subscriptions: - subscription.assertion = None - subscription.save(update_fields=["assertion"]) - id = f"{subscription.id}" - logger.info("0054_delete_bad_assertions %s", id) - - -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 = [ - ("uptime", "0053_add_response_capture_enabled"), - ] - - operations = [ - migrations.RunPython( - backfill_delete_assertions, - migrations.RunPython.noop, - hints={"tables": ["uptime_uptimesubscription"]}, - ) - ] diff --git a/src/sentry/uptime/migrations/0055_backfill_2xx_status_assertion.py b/src/sentry/uptime/migrations/0055_backfill_2xx_status_assertion.py deleted file mode 100644 index 27a7798a31e7..000000000000 --- a/src/sentry/uptime/migrations/0055_backfill_2xx_status_assertion.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-20 10:53 -import copy -import logging -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - -DEFAULT_STATUS_CODE_CHECKS = [ - {"op": "status_code_check", "operator": {"cmp": "greater_than"}, "value": 199}, - {"op": "status_code_check", "operator": {"cmp": "less_than"}, "value": 300}, -] - - -def _has_any_status_code_check(node: dict[str, Any]) -> bool: - op = node.get("op") - if op == "status_code_check": - return True - elif op in ("and", "or"): - return any(_has_any_status_code_check(child) for child in node.get("children", [])) - elif op == "not": - operand = node.get("operand") - return _has_any_status_code_check(operand) if operand else False - return False - - -def ensure_2xx_status_checks( - assertion: dict[str, Any] | None, -) -> tuple[dict[str, Any], bool]: - """ - Ensure the assertion contains at least one status_code_check. If none exists, - add the default >199 and <300 pair. Returns (assertion, was_modified). - """ - if not assertion or not assertion.get("root"): - return {"root": {"op": "and", "children": copy.deepcopy(DEFAULT_STATUS_CODE_CHECKS)}}, True - - root = assertion["root"] - if _has_any_status_code_check(root): - return assertion, False - - # No status code check found — add the pair - if root.get("op") == "and": - new_children = list(root.get("children", [])) + copy.deepcopy(DEFAULT_STATUS_CODE_CHECKS) - return {"root": {**root, "children": new_children}}, True - else: - # Root is not an "and" group — wrap it - return { - "root": {"op": "and", "children": [root, *copy.deepcopy(DEFAULT_STATUS_CODE_CHECKS)]} - }, True - - -def backfill_2xx_status_assertion(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - UptimeSubscription = apps.get_model("uptime", "UptimeSubscription") - - subscriptions = UptimeSubscription.objects.all() - - for subscription in RangeQuerySetWrapperWithProgressBar(subscriptions): - new_assertion, was_modified = ensure_2xx_status_checks(subscription.assertion) - if was_modified: - subscription.assertion = new_assertion - subscription.save(update_fields=["assertion"]) - - -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 = True - - dependencies = [ - ("uptime", "0054_delete_bad_assertions"), - ] - - operations = [ - migrations.RunPython( - backfill_2xx_status_assertion, - migrations.RunPython.noop, - hints={"tables": ["uptime_uptimesubscription"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0001_squashed_0065_add_status_to_detector_and_workflow.py b/src/sentry/workflow_engine/migrations/0001_squashed_0114_sanitize_dynamic_form_field_choices.py similarity index 72% rename from src/sentry/workflow_engine/migrations/0001_squashed_0065_add_status_to_detector_and_workflow.py rename to src/sentry/workflow_engine/migrations/0001_squashed_0114_sanitize_dynamic_form_field_choices.py index e4b75d9613ea..c802bdf36661 100644 --- a/src/sentry/workflow_engine/migrations/0001_squashed_0065_add_status_to_detector_and_workflow.py +++ b/src/sentry/workflow_engine/migrations/0001_squashed_0114_sanitize_dynamic_form_field_choices.py @@ -1,9 +1,8 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:30 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.deletion +import django.db.models.expressions import django.db.models.functions.comparison -from django.db import migrations, models - import sentry.db.models.fields.bounded import sentry.db.models.fields.foreignkey import sentry.db.models.fields.hybrid_cloud_foreign_key @@ -12,6 +11,8 @@ import sentry.workflow_engine.models.data_condition import sentry.workflow_engine.models.data_condition_group import sentry.workflow_engine.types +from django.db import migrations, models + from sentry.new_migrations.migrations import CheckedMigration @@ -31,71 +32,56 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("workflow_engine", "0001_workflow_table"), - ("workflow_engine", "0002_data_source"), - ("workflow_engine", "0003_detector"), - ("workflow_engine", "0004_workflowactions"), - ("workflow_engine", "0005_data_source_detector"), - ("workflow_engine", "0006_data_conditions"), - ("workflow_engine", "0007_loosen_workflow_action_relationship"), - ("workflow_engine", "0008_detector_state"), - ("workflow_engine", "0009_detector_type"), - ("workflow_engine", "0010_detector_state_unique_group"), - ("workflow_engine", "0011_action_updates"), - ("workflow_engine", "0012_data_source_type_change"), - ("workflow_engine", "0013_related_name_conditions_on_dcg"), - ("workflow_engine", "0014_model_additions_for_milestones"), - ("workflow_engine", "0015_create_rule_lookup_tables"), - ("workflow_engine", "0016_refactor_action_model"), - ("workflow_engine", "0017_ref_data_condition"), - ("workflow_engine", "0018_rm_data_condition_condition"), - ("workflow_engine", "0019_drop_dataconditions_condition"), - ("workflow_engine", "0020_rm_legacy_notification_type"), - ("workflow_engine", "0021_drop_legacy_notification_type"), - ("workflow_engine", "0022_add_action_group_status_model"), - ("workflow_engine", "0023_create_action_trigger_action_table"), - ("workflow_engine", "0024_drop_trigger_data_condition_p1"), - ("workflow_engine", "0025_drop_trigger_data_condition_p2"), - ("workflow_engine", "0026_rm_org_detector_req_action_cols"), - ("workflow_engine", "0027_drop_org_detector_req_action"), - ("workflow_engine", "0028_wfe_change_query_id_to_source_id"), - ("workflow_engine", "0029_ds_query_id_to_pending"), - ("workflow_engine", "0030_allow_blank_workflow_owner_fks"), - ("workflow_engine", "0031_make_detector_project_non_nullable"), - ("workflow_engine", "0032_remove_data_source_query_id"), - ("workflow_engine", "0033_workflow_name_256_char"), - ("workflow_engine", "0034_action_cleanup_1"), - ("workflow_engine", "0035_action_model_drop_legacy_fields"), - ("workflow_engine", "0036_action_remove_legacy_fields"), - ("workflow_engine", "0037_rm_workflow_name_unique_constraint"), - ("workflow_engine", "0038_add_detector_workflow_unique_together"), - ("workflow_engine", "0039_workflow_fire_history_table"), - ("workflow_engine", "0040_break_lookup_fks"), - ("workflow_engine", "0041_datacondition_alertruletrigger_lookup_table"), - ("workflow_engine", "0042_workflow_fire_history_add_fired_actions_bool"), - ("workflow_engine", "0043_create_incidentgroupopenperiod_lookup_table"), - ("workflow_engine", "0044_rm_detector_name_unique_constraint"), - ("workflow_engine", "0045_add_unique_constraint_alert_rule_detector"), - ("workflow_engine", "0046_drop_metric_alert_fire_detectors"), - ("workflow_engine", "0047_migrate_issue_alerts"), - ("workflow_engine", "0048_fix_some_drift"), - ("workflow_engine", "0049_migrate_metric_alerts"), - ("workflow_engine", "0050_remove_orphaned_rule_workflows"), - ("workflow_engine", "0051_migrate_remaining_issue_alerts"), - ("workflow_engine", "0052_migrate_errored_metric_alerts"), - ("workflow_engine", "0053_add_legacy_rule_indices"), - ("workflow_engine", "0054_clean_up_orphaned_metric_alert_objects"), - ("workflow_engine", "0055_datasource_define_indexes"), - ("workflow_engine", "0056_workflow_fire_history_passed_filters_column"), - ("workflow_engine", "0057_workflowengine_rename_column"), - ("workflow_engine", "0058_add_inc_identifier_incidentgroupopenperiod"), - ("workflow_engine", "0059_fix_high_priority_condition_triggers"), - ("workflow_engine", "0060_rename_azure_devops_action_to_vsts"), - ("workflow_engine", "0061_backfill_metric_alert_resolution_action_filters"), - ("workflow_engine", "0062_workflow_engine_missing_indexes"), - ("workflow_engine", "0063_drop_rollout_workflowfirehistory_columns"), - ("workflow_engine", "0064_delete_rollout_workflowfirehistory_columns"), - ("workflow_engine", "0065_add_status_to_detector_and_workflow"), + ("workflow_engine", "0001_squashed_0065_add_status_to_detector_and_workflow"), + ("workflow_engine", "0066_workflow_action_group_status_table"), + ("workflow_engine", "0067_workflow_action_group_status_group_db_constraint"), + ("workflow_engine", "0068_migrate_anomaly_detection_alerts"), + ("workflow_engine", "0069_rename_error_detectors"), + ("workflow_engine", "0070_migrate_remaining_anomaly_detection_alerts"), + ("workflow_engine", "0071_migrate_remaining_metric_alerts"), + ("workflow_engine", "0072_add_detector_to_workflowfirehistory"), + ("workflow_engine", "0073_safe_pending_delete_actiongroupstatus"), + ("workflow_engine", "0074_safe_delete_actiongroupstatus"), + ("workflow_engine", "0075_add_index_to_dcg_action"), + ("workflow_engine", "0076_add_detector_group_table"), + ("workflow_engine", "0077_add_wfh_single_write_col"), + ("workflow_engine", "0078_workflow_fire_history_date_index"), + ("workflow_engine", "0079_add_unique_constraint_to_detector_group"), + ("workflow_engine", "0080_update_metric_detector_config_fields"), + ("workflow_engine", "0081_add_unique_constraint_to_detector_group"), + ("workflow_engine", "0082_disconnect_error_detector_cron_workflows"), + ("workflow_engine", "0083_add_status_to_action"), + ("workflow_engine", "0084_crons_dedupe_workflows"), + ("workflow_engine", "0085_crons_link_detectors_to_all_workflows"), + ("workflow_engine", "0086_fix_cron_to_cron_workflow_links"), + ("workflow_engine", "0087_relink_crons_to_compatible_issue_workflows"), + ("workflow_engine", "0088_remove_monitor_slug_conditions"), + ("workflow_engine", "0089_update_cron_workflow_names"), + ("workflow_engine", "0090_add_detectorgroup_detector_date_index"), + ("workflow_engine", "0091_fix_email_notification_names"), + ("workflow_engine", "0092_repair_workflow_cron_conditions"), + ("workflow_engine", "0093_add_action_config_index"), + ("workflow_engine", "0094_backfill_issue_stream_detector_workflows"), + ("workflow_engine", "0095_unique_detectorgroup_group"), + ("workflow_engine", "0096_delete_non_single_written_fire_history"), + ("workflow_engine", "0097_add_unique_constraint_to_datasource"), + ("workflow_engine", "0098_detectorgroup_detector_set_null"), + ("workflow_engine", "0099_backfill_metric_issue_detectorgroup"), + ("workflow_engine", "0100_move_is_single_written_to_pending"), + ("workflow_engine", "0101_remove_is_single_written_field"), + ("workflow_engine", "0102_cleanup_failed_safe_deletes"), + ("workflow_engine", "0103_add_unique_constraint"), + ("workflow_engine", "0104_action_data_fallthrough_type"), + ("workflow_engine", "0105_add_incident_identifer_index"), + ("workflow_engine", "0106_migrate_actions_sentry_app_data"), + ("workflow_engine", "0107_fix_email_action_fallthrough_type"), + ("workflow_engine", "0108_remove_sentry_app_identifier_from_action"), + ("workflow_engine", "0109_add_detector_state_triggered_date_index"), + ("workflow_engine", "0110_owner_team_break_fk"), + ("workflow_engine", "0111_add_workflowfirehistory_date_added_index"), + ("workflow_engine", "0112_drop_redundant_error_detector_workflows"), + ("workflow_engine", "0113_migrate_data_conditions_categories"), + ("workflow_engine", "0114_sanitize_dynamic_form_field_choices"), ] initial = True @@ -103,7 +89,7 @@ class Migration(CheckedMigration): checked = False # This is an initial migration and can take locks dependencies = [ - ("sentry", "0001_squashed_0904_onboarding_task_project_id_idx"), + ("sentry", "0001_squashed_1117_drop_organizationmapping_codecov_access_delete"), ] operations = [ @@ -131,9 +117,20 @@ class Migration(CheckedMigration): on_delete="CASCADE", ), ), + ( + "status", + sentry.db.models.fields.bounded.BoundedPositiveIntegerField(db_default=0), + ), ], options={ - "abstract": False, + "indexes": [ + models.Index( + models.F("type"), + django.db.models.expressions.RawSQL("config->>'target_identifier'", []), + condition=models.Q(("type", "sentry_app")), + name="sentry_app_lookup_action", + ) + ], }, ), migrations.CreateModel( @@ -154,7 +151,8 @@ class Migration(CheckedMigration): ( "action", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.action", ), ), ], @@ -185,7 +183,8 @@ class Migration(CheckedMigration): ( "organization", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -226,35 +225,6 @@ class Migration(CheckedMigration): "abstract": False, }, ), - migrations.CreateModel( - name="DataConditionGroupAction", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" - ), - ), - ( - "condition_group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.dataconditiongroup", - ), - ), - ], - options={ - "abstract": False, - }, - ), migrations.CreateModel( name="DataSource", fields=[ @@ -271,7 +241,8 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ], @@ -290,7 +261,8 @@ class Migration(CheckedMigration): ( "data_source", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.datasource" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.datasource", ), ), ], @@ -310,7 +282,17 @@ class Migration(CheckedMigration): ( "owner_user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", + ), + ), + ( + "owner_team_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + blank=True, db_index=True, null=True ), ), ("name", models.CharField(max_length=200)), @@ -331,15 +313,6 @@ class Migration(CheckedMigration): to="workflow_engine.datasource", ), ), - ( - "owner_team", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.team", - ), - ), ( "project", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -365,14 +338,16 @@ class Migration(CheckedMigration): model_name="datasourcedetector", name="detector", field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.detector" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.detector", ), ), migrations.AddField( model_name="datasource", name="detectors", field=models.ManyToManyField( - through="workflow_engine.DataSourceDetector", to="workflow_engine.detector" + through="workflow_engine.DataSourceDetector", + to="workflow_engine.detector", ), ), migrations.CreateModel( @@ -401,7 +376,8 @@ class Migration(CheckedMigration): ( "detector", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.detector" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.detector", ), ), ], @@ -409,6 +385,36 @@ class Migration(CheckedMigration): "db_table": "workflow_engine_alertruledetector", }, ), + migrations.CreateModel( + name="DetectorGroup", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "detector", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="workflow_engine.detector", + ), + ), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + ), + ), + ], + options={ + "db_table": "workflow_engine_detectorgroup", + }, + ), migrations.CreateModel( name="DetectorState", fields=[ @@ -420,8 +426,14 @@ class Migration(CheckedMigration): ), ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), - ("detector_group_key", models.CharField(blank=True, max_length=200, null=True)), - ("is_triggered", models.BooleanField(db_column="active", default=False)), + ( + "detector_group_key", + models.CharField(blank=True, max_length=200, null=True), + ), + ( + "is_triggered", + models.BooleanField(db_column="active", default=False), + ), ( "state", models.CharField( @@ -432,7 +444,8 @@ class Migration(CheckedMigration): ( "detector", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.detector" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.detector", ), ), ], @@ -481,7 +494,17 @@ class Migration(CheckedMigration): ( "owner_user_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", + ), + ), + ( + "owner_team_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField( + blank=True, db_index=True, null=True ), ), ("name", models.CharField(max_length=256)), @@ -490,7 +513,11 @@ class Migration(CheckedMigration): ( "created_by_id", sentry.db.models.fields.hybrid_cloud_foreign_key.HybridCloudForeignKey( - "sentry.User", blank=True, db_index=True, null=True, on_delete="SET_NULL" + "sentry.User", + blank=True, + db_index=True, + null=True, + on_delete="SET_NULL", ), ), ( @@ -505,22 +532,15 @@ class Migration(CheckedMigration): ( "organization", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.organization" - ), - ), - ( - "owner_team", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.team", + on_delete=django.db.models.deletion.CASCADE, + to="sentry.organization", ), ), ( "when_condition_group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( blank=True, + db_index=False, null=True, on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.dataconditiongroup", @@ -545,13 +565,15 @@ class Migration(CheckedMigration): ( "detector", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.detector" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.detector", ), ), ( "workflow", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.workflow" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.workflow", ), ), ], @@ -582,7 +604,8 @@ class Migration(CheckedMigration): ( "workflow", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.workflow" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.workflow", ), ), ], @@ -590,6 +613,39 @@ class Migration(CheckedMigration): "db_table": "workflow_engine_alertruleworkflow", }, ), + migrations.CreateModel( + name="WorkflowActionGroupStatus", + fields=[ + ( + "id", + sentry.db.models.fields.bounded.BoundedBigAutoField( + primary_key=True, serialize=False + ), + ), + ("date_updated", models.DateTimeField(auto_now=True)), + ("date_added", models.DateTimeField(auto_now_add=True)), + ( + "action", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.action", + ), + ), + ( + "group", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + ), + ), + ( + "workflow", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.workflow", + ), + ), + ], + ), migrations.CreateModel( name="WorkflowDataConditionGroup", fields=[ @@ -612,7 +668,8 @@ class Migration(CheckedMigration): ( "workflow", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.workflow" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.workflow", ), ), ], @@ -638,6 +695,14 @@ class Migration(CheckedMigration): editable=False, max_length=32, unique=True ), ), + ( + "detector", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="workflow_engine.detector", + ), + ), ( "group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( @@ -649,7 +714,8 @@ class Migration(CheckedMigration): ( "workflow", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.workflow" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.workflow", ), ), ], @@ -658,7 +724,7 @@ class Migration(CheckedMigration): }, ), migrations.CreateModel( - name="ActionGroupStatus", + name="DataConditionAlertRuleTrigger", fields=[ ( "id", @@ -669,28 +735,29 @@ class Migration(CheckedMigration): ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" - ), + "alert_rule_trigger_id", + sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), ), ( - "group", + "data_condition", sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.datacondition", ), ), ], options={ + "db_table": "workflow_engine_dataconditionalertruletrigger", "constraints": [ models.UniqueConstraint( - fields=("action", "group"), name="workflow_engine_uniq_action_group" + fields=("alert_rule_trigger_id", "data_condition"), + name="workflow_engine_uniq_datacondition_alertruletrigger", ) ], }, ), migrations.CreateModel( - name="DataConditionAlertRuleTrigger", + name="DataConditionGroupAction", fields=[ ( "id", @@ -701,23 +768,25 @@ class Migration(CheckedMigration): ("date_updated", models.DateTimeField(auto_now=True)), ("date_added", models.DateTimeField(auto_now_add=True)), ( - "alert_rule_trigger_id", - sentry.db.models.fields.bounded.BoundedBigIntegerField(null=True), + "action", + sentry.db.models.fields.foreignkey.FlexibleForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="workflow_engine.action", + ), ), ( - "data_condition", + "condition_group", sentry.db.models.fields.foreignkey.FlexibleForeignKey( on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.datacondition", + to="workflow_engine.dataconditiongroup", ), ), ], options={ - "db_table": "workflow_engine_dataconditionalertruletrigger", - "constraints": [ - models.UniqueConstraint( - fields=("alert_rule_trigger_id", "data_condition"), - name="workflow_engine_uniq_datacondition_alertruletrigger", + "indexes": [ + models.Index( + fields=["condition_group", "action"], + name="cond_group_action_idx", ) ], }, @@ -726,9 +795,15 @@ class Migration(CheckedMigration): model_name="detector", constraint=models.CheckConstraint( condition=models.Q( - models.Q(("owner_team__isnull", False), ("owner_user_id__isnull", True)), - models.Q(("owner_team__isnull", True), ("owner_user_id__isnull", False)), - models.Q(("owner_team__isnull", True), ("owner_user_id__isnull", True)), + models.Q( + ("owner_team_id__isnull", False), + ("owner_user_id__isnull", True), + ), + models.Q( + ("owner_team_id__isnull", True), + ("owner_user_id__isnull", False), + ), + models.Q(("owner_team_id__isnull", True), ("owner_user_id__isnull", True)), _connector="OR", ), name="workflow_engine_detector_owner_constraints", @@ -737,17 +812,21 @@ class Migration(CheckedMigration): migrations.AddConstraint( model_name="datasourcedetector", constraint=models.UniqueConstraint( - fields=("data_source", "detector"), name="workflow_engine_uniq_datasource_detector" + fields=("data_source", "detector"), + name="workflow_engine_uniq_datasource_detector", ), ), migrations.AddIndex( model_name="datasource", - index=models.Index(fields=["type", "source_id"], name="workflow_en_type_66eafc_idx"), + index=models.Index( + fields=["organization", "type", "source_id"], + name="workflow_en_organiz_d71f4a_idx", + ), ), - migrations.AddIndex( + migrations.AddConstraint( model_name="datasource", - index=models.Index( - fields=["organization", "type", "source_id"], name="workflow_en_organiz_d71f4a_idx" + constraint=models.UniqueConstraint( + fields=("type", "source_id"), name="unique_type_source_id" ), ), migrations.AddConstraint( @@ -771,6 +850,24 @@ class Migration(CheckedMigration): name="alertruledetector", unique_together={("detector", "alert_rule_id"), ("detector", "rule_id")}, ), + migrations.AddIndex( + model_name="detectorgroup", + index=models.Index( + fields=["detector", "-date_added"], name="detectorgroup_det_date_idx" + ), + ), + migrations.AlterUniqueTogether( + name="detectorgroup", + unique_together={("group",)}, + ), + migrations.AddIndex( + model_name="detectorstate", + index=models.Index( + condition=models.Q(("is_triggered", True)), + fields=["is_triggered", "date_updated"], + name="detector_state_triggered_date", + ), + ), migrations.AddConstraint( model_name="detectorstate", constraint=models.UniqueConstraint( @@ -781,19 +878,36 @@ class Migration(CheckedMigration): name="detector_state_unique_group_key", ), ), + migrations.AddIndex( + model_name="incidentgroupopenperiod", + index=models.Index( + fields=["incident_identifier"], name="workflow_en_inciden_2450f4_idx" + ), + ), migrations.AddConstraint( model_name="incidentgroupopenperiod", constraint=models.CheckConstraint( condition=models.Q( models.Q( - ("incident_identifier__isnull", False), ("incident_id__isnull", False) + ("incident_identifier__isnull", False), + ("incident_id__isnull", False), + ), + models.Q( + ("incident_identifier__isnull", True), + ("incident_id__isnull", True), ), - models.Q(("incident_identifier__isnull", True), ("incident_id__isnull", True)), _connector="OR", ), name="inc_id_inc_identifier_together", ), ), + migrations.AddConstraint( + model_name="workflow", + constraint=models.UniqueConstraint( + fields=("when_condition_group_id",), + name="workflow_engine_workflow_when_condition_group_id_11d9ba05_uniq", + ), + ), migrations.AlterUniqueTogether( name="detectorworkflow", unique_together={("detector", "workflow")}, @@ -821,4 +935,21 @@ class Migration(CheckedMigration): name="alertruleworkflow", unique_together={("workflow", "alert_rule_id"), ("workflow", "rule_id")}, ), + migrations.AddConstraint( + model_name="workflowactiongroupstatus", + constraint=models.UniqueConstraint( + fields=("workflow", "action", "group"), + name="workflow_engine_uniq_workflow_action_group", + ), + ), + migrations.AddIndex( + model_name="workflowfirehistory", + index=models.Index( + fields=["workflow", "date_added"], name="workflow_en_workflo_270fe2_idx" + ), + ), + migrations.AddIndex( + model_name="workflowfirehistory", + index=models.Index(fields=["date_added"], name="workflow_en_date_ad_1986f8_idx"), + ), ] diff --git a/src/sentry/workflow_engine/migrations/0066_workflow_action_group_status_table.py b/src/sentry/workflow_engine/migrations/0066_workflow_action_group_status_table.py deleted file mode 100644 index 6553f9cacf76..000000000000 --- a/src/sentry/workflow_engine/migrations/0066_workflow_action_group_status_table.py +++ /dev/null @@ -1,79 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-29 18:55 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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", "0913_split_discover_dataset_dashboards_self_hosted"), - ("workflow_engine", "0001_squashed_0065_add_status_to_detector_and_workflow"), - ] - - operations = [ - SafeRunSQL( - """DROP TABLE IF EXISTS workflow_engine_workflowactiongroupstatus;""", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["workflow_engine_workflowactiongroupstatus"]}, - ), # this migration was successfully run in S4S and DE, partially succeeded in US - migrations.CreateModel( - name="WorkflowActionGroupStatus", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "action", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.action" - ), - ), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", - ), - ), - ( - "workflow", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="workflow_engine.workflow" - ), - ), - ], - options={ - "constraints": [ - models.UniqueConstraint( - fields=("workflow", "action", "group"), - name="workflow_engine_uniq_workflow_action_group", - ) - ], - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0067_workflow_action_group_status_group_db_constraint.py b/src/sentry/workflow_engine/migrations/0067_workflow_action_group_status_group_db_constraint.py deleted file mode 100644 index 3f9d88ac9d62..000000000000 --- a/src/sentry/workflow_engine/migrations/0067_workflow_action_group_status_group_db_constraint.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-05-30 16:12 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0914_increase_orgmember_user_email_max_length"), - ("workflow_engine", "0066_workflow_action_group_status_table"), - ] - - operations = [ - migrations.AlterField( - model_name="workflowactiongroupstatus", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0068_migrate_anomaly_detection_alerts.py b/src/sentry/workflow_engine/migrations/0068_migrate_anomaly_detection_alerts.py deleted file mode 100644 index a7e3d9ad52c3..000000000000 --- a/src/sentry/workflow_engine/migrations/0068_migrate_anomaly_detection_alerts.py +++ /dev/null @@ -1,898 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-03 21:44 - -import dataclasses -import logging -from enum import Enum, IntEnum, StrEnum -from typing import Any - -import sentry_sdk -from attr import dataclass -from django.apps.registry import Apps -from django.db import migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from jsonschema import ValidationError, validate - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -class PriorityLevel(IntEnum): - LOW = 25 - MEDIUM = 50 - HIGH = 75 - - -class DetectorPriorityLevel(IntEnum): - OK = 0 - LOW = PriorityLevel.LOW - MEDIUM = PriorityLevel.MEDIUM - HIGH = PriorityLevel.HIGH - - -class IncidentStatus(Enum): - OPEN = 1 - CLOSED = 2 - WARNING = 10 - CRITICAL = 20 - - -class IncidentType(Enum): - DETECTED = 0 - ALERT_TRIGGERED = 2 - - -class AlertRuleStatus(Enum): - PENDING = 0 - SNAPSHOT = 4 - DISABLED = 5 - NOT_ENOUGH_DATA = 6 - - -class AlertRuleThresholdType(Enum): - ABOVE = 0 - BELOW = 1 - ABOVE_AND_BELOW = 2 - - -class Condition(StrEnum): - ANOMALY_DETECTION = "anomaly_detection" - ISSUE_PRIORITY_GREATER_OR_EQUAL = "issue_priority_greater_or_equal" - ISSUE_PRIORITY_DEESCALATING = "issue_priority_deescalating" - - -class AlertRuleActivityType(Enum): - CREATED = 1 - DELETED = 2 - UPDATED = 3 - ENABLED = 4 - DISABLED = 5 - SNAPSHOT = 6 - ACTIVATED = 7 - DEACTIVATED = 8 - - -class AlertRuleTriggerActionType(Enum): - EMAIL = 0 - PAGERDUTY = 1 - SLACK = 2 - MSTEAMS = 3 - SENTRY_APP = 4 - SENTRY_NOTIFICATION = 5 # Use personal notification platform (src/sentry/notifications) - OPSGENIE = 6 - DISCORD = 7 - - -MAX_ACTIONS = 3 - -ACTION_TYPE_TO_STRING = { - AlertRuleTriggerActionType.PAGERDUTY.value: "PagerDuty", - AlertRuleTriggerActionType.SLACK.value: "Slack", - AlertRuleTriggerActionType.MSTEAMS.value: "Microsoft Teams", - AlertRuleTriggerActionType.OPSGENIE.value: "Opsgenie", -} - - -class ActionTarget(IntEnum): - """ - Explains the contents of target_identifier - """ - - # The target_identifier is a direct reference used by the service (e.g. email address, slack channel id) - SPECIFIC = 0 - # The target_identifier is an id from the User model in Sentry - USER = 1 - # The target_identifier is an id from the Team model in Sentry - TEAM = 2 - # The target_identifier is an id from the SentryApp model in Sentry - SENTRY_APP = 3 - # There is no target_identifier, but we want to send notifications to the issue owners - ISSUE_OWNERS = 4 - - -class ActionType(StrEnum): - SLACK = "slack" - MSTEAMS = "msteams" - DISCORD = "discord" - - PAGERDUTY = "pagerduty" - OPSGENIE = "opsgenie" - - EMAIL = "email" - SENTRY_APP = "sentry_app" - - -class SentryAppIdentifier(StrEnum): - """ - SentryAppIdentifier is an enum that represents the identifier for a Sentry app. - """ - - SENTRY_APP_INSTALLATION_UUID = "sentry_app_installation_uuid" - SENTRY_APP_SLUG = "sentry_app_slug" - SENTRY_APP_ID = "sentry_app_id" - - -FIELDS_TO_DETECTOR_FIELDS = { - "name": "name", - "description": "description", - "user_id": "owner_user_id", - "team_id": "owner_team_id", -} - -TYPE_TO_PROVIDER = { - 0: "email", - 1: "pagerduty", - 2: "slack", - 3: "msteams", - 4: "sentry_app", - 6: "opsgenie", - 7: "discord", -} - -PRIORITY_MAP = { - "warning": DetectorPriorityLevel.MEDIUM, # not actually used for anomaly detection alerts - "critical": DetectorPriorityLevel.HIGH, -} - - -OPSGENIE_DEFAULT_PRIORITY = "P3" -PAGERDUTY_DEFAULT_SEVERITY = "default" - - -class PagerdutySeverity(StrEnum): - DEFAULT = "default" - CRITICAL = "critical" - WARNING = "warning" - ERROR = "error" - INFO = "info" - - -@dataclass -class ActionSchemas: - config_schema: dict[str, Any] | None = None - data_schema: dict[str, Any] | None = None - - -@dataclasses.dataclass -class SentryAppFormConfigDataBlob: - """ - SentryAppFormConfigDataBlob represents a single form config field for a Sentry App. - name is the name of the form field, and value is the value of the form field. - """ - - @classmethod - def from_dict(cls, data: dict[str, Any]) -> "SentryAppFormConfigDataBlob": - if not isinstance(data.get("name"), str) or not isinstance( - data.get("value"), (str, type(None)) - ): - raise ValueError("Sentry app config must contain name and value keys") - return cls(name=data["name"], value=data["value"], label=data.get("label")) - - name: str = "" - value: str = "" - label: str | None = None - - -@dataclasses.dataclass -class SentryAppDataBlob: - """ - Represents a Sentry App notification action. - """ - - settings: list[SentryAppFormConfigDataBlob] = dataclasses.field(default_factory=list) - - @classmethod - def from_list(cls, data: list[dict[str, Any]] | None) -> "SentryAppDataBlob": - if data is None: - return cls() - return cls(settings=[SentryAppFormConfigDataBlob.from_dict(setting) for setting in data]) - - -@dataclasses.dataclass -class OnCallDataBlob: - """ - OnCallDataBlob is a specific type that represents the data blob for a PagerDuty or Opsgenie notification action. - """ - - priority: str = "" - - -action_schema_mapping: dict[str, ActionSchemas] = { - ActionType.EMAIL: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for an email Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string", "null"]}, - "target_display": {"type": ["null"]}, - "target_type": { - "type": ["integer"], - "enum": [*ActionTarget], - }, - }, - "required": ["target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.PAGERDUTY: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [0]}, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the pagerduty action", - "enum": [*PagerdutySeverity], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.SLACK: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.MSTEAMS: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.SENTRY_APP: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Sentry App Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [3]}, - "sentry_app_identifier": {"type": ["string"], "enum": [*SentryAppIdentifier]}, - }, - "required": ["target_type", "target_identifier", "sentry_app_identifier"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": {"settings": {"type": ["array", "object"]}}, - "additionalProperties": False, - }, - ), - ActionType.OPSGENIE: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the opsgenie action", - "enum": ["P1", "P2", "P3", "P4", "P5"], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.DISCORD: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Discord Action", - "type": "object", - "properties": { - "target_identifier": {"type": "string"}, - "target_display": { - "type": ["string", "null"], - }, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), -} - - -def _enforce_action_json_schema(action: Any) -> None: - schemas = action_schema_mapping.get(action.type) - if not schemas: - logger.error( - "No schema found for action type", - extra={"action_type": action.type}, - ) - return - config_schema = schemas.config_schema - data_schema = schemas.data_schema - - if config_schema is not None: - try: - validate(action.config, config_schema) - except ValidationError as e: - raise ValidationError(f"Invalid config: {e.message}") - - if data_schema is not None: - try: - validate(action.data, data_schema) - except ValidationError as e: - raise ValidationError(f"Invalid data: {e.message}") - - -def _get_trigger_action_target(apps: Apps, trigger_action: Any) -> Any: - OrganizationMember = apps.get_model("sentry", "OrganizationMember") - Team = apps.get_model("sentry", "Team") - - if trigger_action.target_identifier is None: - return None - - if trigger_action.target_type == ActionTarget.USER.value: - try: - return OrganizationMember.objects.get( - user_id=int(trigger_action.target_identifier), - organization=trigger_action.alert_rule_trigger.alert_rule.organization_id, - ) - except OrganizationMember.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.TEAM.value: - try: - return Team.objects.get(id=int(trigger_action.target_identifier)) - except Team.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.SPECIFIC.value: - return trigger_action.target_identifier - return None - - -def _get_action_description(apps: Apps, action: Any) -> str: - """ - Returns a human readable action description - """ - if action.type == AlertRuleTriggerActionType.EMAIL.value: - target = _get_trigger_action_target(apps, action) - if target: - if action.target_type == ActionTarget.USER.value: - action_target_user = target - return "Email " + action_target_user.user_email - elif action.target_type == ActionTarget.TEAM.value: - action_target_team = target - return "Email #" + action_target_team.slug - elif action.type == AlertRuleTriggerActionType.SENTRY_APP.value: - return f"Notify {action.target_display}" - - return f"Notify {action.target_display} via {ACTION_TYPE_TO_STRING[action.type]}" - - -def _get_workflow_name(apps: Apps, alert_rule: Any) -> str: - """ - Generate a workflow name like 'Slack @michelle.fu, Email michelle.fu@sentry.io...(+3)' if there is only a critical trigger - or with priority label: 'Critical - Slack @michelle.fu, Warning email michelle.fu@sentry.io...(+3)'' - """ - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - - name = "" - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id).order_by("label") - include_label = False if triggers.count() == 1 else True - - actions = AlertRuleTriggerAction.objects.filter( - alert_rule_trigger_id__in=[trigger.id for trigger in triggers], status=0 - ) - actions_counter = 0 - - for trigger in triggers: - name += f"{trigger.label.title()} - " if include_label else "" - for action in actions.filter(alert_rule_trigger_id=trigger.id): - description = _get_action_description(apps, action) + ", " - - if actions_counter < MAX_ACTIONS: - name += description - actions_counter += 1 - else: - remaining_actions = actions.count() - actions_counter - name = name[:-2] - name += f"...(+{remaining_actions})" - break - - if name[-2:] == ", ": - name = name[:-2] # chop off the trailing comma - - return name - - -def _migrate_trigger(apps: Apps, trigger: Any, detector: Any, workflow: Any) -> None: - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - WorkflowDataConditionGroup = apps.get_model("workflow_engine", "WorkflowDataConditionGroup") - DataConditionAlertRuleTrigger = apps.get_model( - "workflow_engine", "DataConditionAlertRuleTrigger" - ) - - alert_rule = trigger.alert_rule - condition_result = PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH) - # create detector trigger - detector_trigger = DataCondition.objects.create( - type=Condition.ANOMALY_DETECTION, - comparison={ - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "threshold_type": alert_rule.threshold_type, - }, - condition_result=condition_result, - condition_group=detector.workflow_condition_group, - ) - DataConditionAlertRuleTrigger.objects.create( - data_condition=detector_trigger, - alert_rule_trigger_id=trigger.id, - ) - # create action filter - data_condition_group = DataConditionGroup.objects.create( - organization_id=alert_rule.organization_id - ) - WorkflowDataConditionGroup.objects.create( - condition_group=data_condition_group, - workflow=workflow, - ) - action_filter = DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_GREATER_OR_EQUAL, - condition_group=data_condition_group, - ) - - # resolve action filter - DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_DEESCALATING, - condition_group=data_condition_group, - ) - - trigger_actions = AlertRuleTriggerAction.objects.filter(alert_rule_trigger=trigger) - for trigger_action in trigger_actions: - # 0 is active status - if trigger_action.status != 0: - continue - _migrate_trigger_action(apps, trigger_action, action_filter.condition_group.id) - - -def _migrate_trigger_action(apps: Apps, trigger_action: Any, condition_group_id: int) -> None: - DataConditionGroupAction = apps.get_model("workflow_engine", "DataConditionGroupAction") - Action = apps.get_model("workflow_engine", "Action") - ActionAlertRuleTriggerAction = apps.get_model("workflow_engine", "ActionAlertRuleTriggerAction") - if trigger_action.sentry_app_id: - action_type = ActionType.SENTRY_APP - - elif trigger_action.integration_id: - try: - action_type = ActionType(TYPE_TO_PROVIDER[trigger_action.type]) - except Exception: - logger.info( - "could not find a matching action type for the trigger action", - extra={"trigger_action_id": trigger_action.id}, - ) - raise - else: - action_type = ActionType.EMAIL - - # build data blob - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_config: - data = {} - else: - settings = ( - [trigger_action.sentry_app_config] - if isinstance(trigger_action.sentry_app_config, dict) - else trigger_action.sentry_app_config - ) - data = dataclasses.asdict(SentryAppDataBlob.from_list(settings)) - elif action_type in (ActionType.OPSGENIE, ActionType.PAGERDUTY): - default_priority = ( - OPSGENIE_DEFAULT_PRIORITY - if action_type == ActionType.OPSGENIE - else PAGERDUTY_DEFAULT_SEVERITY - ) - - if not trigger_action.sentry_app_config: - data = {"priority": default_priority} - else: - # Ensure sentry_app_config is a dict before accessing - config = trigger_action.sentry_app_config - if not isinstance(config, dict): - data = {"priority": default_priority} - else: - priority = config.get("priority", default_priority) - data = dataclasses.asdict(OnCallDataBlob(priority=priority)) - else: - data = {} - - # get target identifier - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_id: - logger.info( - "trigger action missing sentry app ID", - extra={"trigger_action_id": trigger_action.id}, - ) - raise Exception("Trigger action missing Sentry app ID") - target_identifier = str(trigger_action.sentry_app_id) - else: - target_identifier = trigger_action.target_identifier - - # build config - target_type = trigger_action.target_type - config = { - "target_display": trigger_action.target_display, - "target_identifier": target_identifier, - "target_type": target_type, - } - if target_type == ActionTarget.SENTRY_APP.value: - config["sentry_app_identifier"] = SentryAppIdentifier.SENTRY_APP_ID - - # create the models - action = Action.objects.create( - type=action_type, - data=data, - integration_id=trigger_action.integration_id, - config=config, - ) - - _enforce_action_json_schema(action) - - DataConditionGroupAction.objects.create( - condition_group_id=condition_group_id, - action_id=action.id, - ) - ActionAlertRuleTriggerAction.objects.create( - action_id=action.id, - alert_rule_trigger_action_id=trigger_action.id, - ) - - -def _create_data_source(apps: Apps, alert_rule: Any) -> Any: - DataSource = apps.get_model("workflow_engine", "DataSource") - QuerySubscription = apps.get_model("sentry", "QuerySubscription") - - snuba_query = alert_rule.snuba_query - if not snuba_query: - logger.info("alert rule missing snuba query", extra={"alert_rule_id": alert_rule.id}) - raise Exception("Alert rule missing snuba query") - try: - query_subscription = QuerySubscription.objects.get(snuba_query=snuba_query.id) - except QuerySubscription.DoesNotExist: - logger.info( - "query subscription does not exist", - extra={"snuba_query_id": snuba_query.id}, - ) - raise Exception("Query subscription does not exist") - data_source = DataSource.objects.create( - organization_id=alert_rule.organization_id, - source_id=str(query_subscription.id), - type="snuba_query_subscription", - ) - return data_source - - -def _create_detector( - apps: Apps, - alert_rule: Any, - project: Any, - data_condition_group: Any, - create_activity: Any, - enabled: bool, -) -> Any: - Detector = apps.get_model("workflow_engine", "Detector") - detector = Detector.objects.create( - project_id=project.id, - enabled=enabled, - created_by_id=create_activity.user_id if create_activity else None, - name=alert_rule.name if len(alert_rule.name) < 200 else alert_rule.name[:197] + "...", - workflow_condition_group=data_condition_group, - type="metric_issue", - description=alert_rule.description, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={ - "threshold_period": alert_rule.threshold_period, - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "comparison_delta": alert_rule.comparison_delta, - "detection_type": alert_rule.detection_type, - }, - ) - Detector.objects.filter(id=detector.id).update(date_added=alert_rule.date_added) - return detector - - -def _create_detector_state(apps: Apps, alert_rule: Any, project: Any, detector: Any) -> None: - Incident = apps.get_model("sentry", "Incident") - DetectorState = apps.get_model("workflow_engine", "DetectorState") - - incident_query = Incident.objects.filter( - type=IncidentType.ALERT_TRIGGERED.value, - alert_rule=alert_rule, - projects=project, - ) - open_incident = ( - incident_query.exclude(status=IncidentStatus.CLOSED.value).order_by("-date_added").first() - ) - if open_incident: - state = ( - DetectorPriorityLevel.MEDIUM - if open_incident.status == IncidentStatus.WARNING.value - else DetectorPriorityLevel.HIGH - ) - else: - state = DetectorPriorityLevel.OK - # create detector state - DetectorState.objects.create( - detector=detector, - is_triggered=True if open_incident else False, - state=state, - ) - - -def _update_migrated_detector_triggers(apps: Apps, alert_rule: Any, detector: Any) -> None: - Detector = apps.get_model("workflow_engine", "Detector") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - if DataCondition.objects.filter( - condition_group=detector.workflow_condition_group, type=Condition.ANOMALY_DETECTION - ).exists(): - # data conditions are correctly formed - return - - try: - with transaction.atomic(router.db_for_write(Detector)): - critical_detector_trigger = DataCondition.objects.get( - condition_group=detector.workflow_condition_group, - condition_result=DetectorPriorityLevel.HIGH, - ) - critical_detector_trigger.type = Condition.ANOMALY_DETECTION - critical_detector_trigger.comparison = { - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "threshold_type": alert_rule.threshold_type, - } - critical_detector_trigger.save() - - resolve_detector_trigger = DataCondition.objects.get( - condition_group=detector.workflow_condition_group, - condition_result=DetectorPriorityLevel.OK, - ) - resolve_detector_trigger.delete() - logger.info( - "Updated migrated detector triggers", extra={"alert_rule_id": alert_rule.id} - ) - except Exception as e: - logger.info( - "error when updating detector triggers", - extra={"error": str(e), "alert_rule_id": alert_rule.id}, - ) - sentry_sdk.capture_exception(e) - - -def migrate_anomaly_detection_alerts(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: - AlertRule = apps.get_model("sentry", "AlertRule") - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleActivity = apps.get_model("sentry", "AlertRuleActivity") - Organization = apps.get_model("sentry", "Organization") - RuleSnooze = apps.get_model("sentry", "RuleSnooze") - - AlertRuleDetector = apps.get_model("workflow_engine", "AlertRuleDetector") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - Workflow = apps.get_model("workflow_engine", "Workflow") - - # MAIN MIGRATION LOOP STARTS HERE - for organization in RangeQuerySetWrapper(Organization.objects.all()): - organization_id = organization.id - - with transaction.atomic(router.db_for_write(AlertRule)): - alert_rules = AlertRule.objects_with_snapshots.select_for_update().filter( - organization=organization, - status__in=[AlertRuleStatus.PENDING.value, AlertRuleStatus.NOT_ENOUGH_DATA.value], - detection_type="dynamic", - ) - for alert_rule in RangeQuerySetWrapper(alert_rules): - if AlertRuleDetector.objects.filter(alert_rule_id=alert_rule.id).exists(): - # this alert was changed to an anomaly detection alert after the initial migration - # we should update this rule's detector triggers - logger.info( - "Alert rule already migrated", - extra={"alert_rule_id": alert_rule.id}, - ) - detector = AlertRuleDetector.objects.get(alert_rule_id=alert_rule.id).detector - _update_migrated_detector_triggers(apps, alert_rule, detector) - continue - - try: - with transaction.atomic(router.db_for_write(AlertRule)): - project = alert_rule.projects.first() - if not project: - logger.info( - "alert rule missing project, skipping", - extra={"alert_rule_id": alert_rule.id}, - ) - continue - snoozed = None - try: - snoozed = RuleSnooze.objects.get( - alert_rule_id=alert_rule.id, user_id=None - ) - except RuleSnooze.DoesNotExist: - pass - enabled = True if snoozed is None else False - - create_activity = AlertRuleActivity.objects.filter( - alert_rule_id=alert_rule.id, type=AlertRuleActivityType.CREATED.value - ).first() - - # create data source - data_source = _create_data_source(apps, alert_rule) - - # create detector DCG - data_condition_group = DataConditionGroup.objects.create( - organization_id=organization_id, - ) - # create detector - detector = _create_detector( - apps, - alert_rule, - project, - data_condition_group, - create_activity, - enabled, - ) - # create workflow - workflow = Workflow.objects.create( - name=_get_workflow_name(apps, alert_rule), - organization_id=organization_id, - when_condition_group=None, - enabled=True, - created_by_id=create_activity.user_id if create_activity else None, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={}, - ) - Workflow.objects.filter(id=workflow.id).update( - date_added=alert_rule.date_added - ) - - data_source.detectors.set([detector]) - - # create detector state - _create_detector_state(apps, alert_rule, project, detector) - # create lookup tables - AlertRuleDetector.objects.create( - alert_rule_id=alert_rule.id, detector=detector - ) - AlertRuleWorkflow.objects.create( - alert_rule_id=alert_rule.id, workflow=workflow - ) - DetectorWorkflow.objects.create(detector=detector, workflow=workflow) - - # migrate triggers - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id) - for trigger in triggers: - # anomaly detection alerts only have critical triggers - # migrates the trigger and its associated actions - _migrate_trigger(apps, trigger, detector, workflow) - - logger.info( - "Successfully migrated alert rule", - extra={"alert_rule_id": alert_rule.id}, - ) - except Exception as e: - logger.info( - "error when migrating alert rule", - extra={"error": str(e), "alert_rule_id": alert_rule.id}, - ) - sentry_sdk.capture_exception(e) - - -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 = True - - dependencies = [ - ("workflow_engine", "0067_workflow_action_group_status_group_db_constraint"), - ] - - operations = [ - migrations.RunPython( - migrate_anomaly_detection_alerts, - migrations.RunPython.noop, - hints={"tables": ["sentry_alertrule"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0069_rename_error_detectors.py b/src/sentry/workflow_engine/migrations/0069_rename_error_detectors.py deleted file mode 100644 index b9af9456e478..000000000000 --- a/src/sentry/workflow_engine/migrations/0069_rename_error_detectors.py +++ /dev/null @@ -1,47 +0,0 @@ -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapperWithProgressBar - -logger = logging.getLogger(__name__) - - -def rename_error_detectors(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Detector = apps.get_model("workflow_engine", "Detector") - - for detector in RangeQuerySetWrapperWithProgressBar(Detector.objects.all()): - if detector.type == "error": - detector.name = "Error Monitor" - detector.save() - - -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 = True - - dependencies = [ - ("workflow_engine", "0068_migrate_anomaly_detection_alerts"), - ] - - operations = [ - migrations.RunPython( - code=rename_error_detectors, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detector"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0070_migrate_remaining_anomaly_detection_alerts.py b/src/sentry/workflow_engine/migrations/0070_migrate_remaining_anomaly_detection_alerts.py deleted file mode 100644 index a3c0f2f051f9..000000000000 --- a/src/sentry/workflow_engine/migrations/0070_migrate_remaining_anomaly_detection_alerts.py +++ /dev/null @@ -1,843 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-03 21:44 - -import dataclasses -import logging -from enum import Enum, IntEnum, StrEnum -from typing import Any - -import sentry_sdk -from attr import dataclass -from django.apps.registry import Apps -from django.db import migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.models import Exists, OuterRef -from jsonschema import ValidationError, validate - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -class PriorityLevel(IntEnum): - LOW = 25 - MEDIUM = 50 - HIGH = 75 - - -class DetectorPriorityLevel(IntEnum): - OK = 0 - LOW = PriorityLevel.LOW - MEDIUM = PriorityLevel.MEDIUM - HIGH = PriorityLevel.HIGH - - -class IncidentStatus(Enum): - OPEN = 1 - CLOSED = 2 - WARNING = 10 - CRITICAL = 20 - - -class IncidentType(Enum): - DETECTED = 0 - ALERT_TRIGGERED = 2 - - -class AlertRuleStatus(Enum): - PENDING = 0 - SNAPSHOT = 4 - DISABLED = 5 - NOT_ENOUGH_DATA = 6 - - -class AlertRuleThresholdType(Enum): - ABOVE = 0 - BELOW = 1 - ABOVE_AND_BELOW = 2 - - -class Condition(StrEnum): - ANOMALY_DETECTION = "anomaly_detection" - ISSUE_PRIORITY_GREATER_OR_EQUAL = "issue_priority_greater_or_equal" - ISSUE_PRIORITY_DEESCALATING = "issue_priority_deescalating" - - -class AlertRuleActivityType(Enum): - CREATED = 1 - DELETED = 2 - UPDATED = 3 - ENABLED = 4 - DISABLED = 5 - SNAPSHOT = 6 - ACTIVATED = 7 - DEACTIVATED = 8 - - -class AlertRuleTriggerActionType(Enum): - EMAIL = 0 - PAGERDUTY = 1 - SLACK = 2 - MSTEAMS = 3 - SENTRY_APP = 4 - SENTRY_NOTIFICATION = 5 # Use personal notification platform (src/sentry/notifications) - OPSGENIE = 6 - DISCORD = 7 - - -MAX_ACTIONS = 3 - -ACTION_TYPE_TO_STRING = { - AlertRuleTriggerActionType.PAGERDUTY.value: "PagerDuty", - AlertRuleTriggerActionType.SLACK.value: "Slack", - AlertRuleTriggerActionType.MSTEAMS.value: "Microsoft Teams", - AlertRuleTriggerActionType.OPSGENIE.value: "Opsgenie", - AlertRuleTriggerActionType.DISCORD.value: "Discord", -} - - -class ActionTarget(IntEnum): - """ - Explains the contents of target_identifier - """ - - # The target_identifier is a direct reference used by the service (e.g. email address, slack channel id) - SPECIFIC = 0 - # The target_identifier is an id from the User model in Sentry - USER = 1 - # The target_identifier is an id from the Team model in Sentry - TEAM = 2 - # The target_identifier is an id from the SentryApp model in Sentry - SENTRY_APP = 3 - # There is no target_identifier, but we want to send notifications to the issue owners - ISSUE_OWNERS = 4 - - -class ActionType(StrEnum): - SLACK = "slack" - MSTEAMS = "msteams" - DISCORD = "discord" - - PAGERDUTY = "pagerduty" - OPSGENIE = "opsgenie" - - EMAIL = "email" - SENTRY_APP = "sentry_app" - - -class SentryAppIdentifier(StrEnum): - """ - SentryAppIdentifier is an enum that represents the identifier for a Sentry app. - """ - - SENTRY_APP_INSTALLATION_UUID = "sentry_app_installation_uuid" - SENTRY_APP_SLUG = "sentry_app_slug" - SENTRY_APP_ID = "sentry_app_id" - - -FIELDS_TO_DETECTOR_FIELDS = { - "name": "name", - "description": "description", - "user_id": "owner_user_id", - "team_id": "owner_team_id", -} - -TYPE_TO_PROVIDER = { - 0: "email", - 1: "pagerduty", - 2: "slack", - 3: "msteams", - 4: "sentry_app", - 6: "opsgenie", - 7: "discord", -} - -PRIORITY_MAP = { - "warning": DetectorPriorityLevel.MEDIUM, # not actually used for anomaly detection alerts - "critical": DetectorPriorityLevel.HIGH, -} - - -OPSGENIE_DEFAULT_PRIORITY = "P3" -PAGERDUTY_DEFAULT_SEVERITY = "default" - - -class PagerdutySeverity(StrEnum): - DEFAULT = "default" - CRITICAL = "critical" - WARNING = "warning" - ERROR = "error" - INFO = "info" - - -@dataclass -class ActionSchemas: - config_schema: dict[str, Any] | None = None - data_schema: dict[str, Any] | None = None - - -@dataclasses.dataclass -class SentryAppFormConfigDataBlob: - """ - SentryAppFormConfigDataBlob represents a single form config field for a Sentry App. - name is the name of the form field, and value is the value of the form field. - """ - - @classmethod - def from_dict(cls, data: dict[str, Any]) -> "SentryAppFormConfigDataBlob": - if not isinstance(data.get("name"), str) or not isinstance( - data.get("value"), (str, type(None)) - ): - raise ValueError("Sentry app config must contain name and value keys") - return cls(name=data["name"], value=data["value"], label=data.get("label")) - - name: str = "" - value: str = "" - label: str | None = None - - -@dataclasses.dataclass -class SentryAppDataBlob: - """ - Represents a Sentry App notification action. - """ - - settings: list[SentryAppFormConfigDataBlob] = dataclasses.field(default_factory=list) - - @classmethod - def from_list(cls, data: list[dict[str, Any]] | None) -> "SentryAppDataBlob": - if data is None: - return cls() - return cls(settings=[SentryAppFormConfigDataBlob.from_dict(setting) for setting in data]) - - -@dataclasses.dataclass -class OnCallDataBlob: - """ - OnCallDataBlob is a specific type that represents the data blob for a PagerDuty or Opsgenie notification action. - """ - - priority: str = "" - - -action_schema_mapping: dict[str, ActionSchemas] = { - ActionType.EMAIL: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for an email Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string", "null"]}, - "target_display": {"type": ["null"]}, - "target_type": { - "type": ["integer"], - "enum": [*ActionTarget], - }, - }, - "required": ["target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.PAGERDUTY: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [0]}, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the pagerduty action", - "enum": [*PagerdutySeverity], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.SLACK: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.MSTEAMS: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.SENTRY_APP: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Sentry App Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [3]}, - "sentry_app_identifier": {"type": ["string"], "enum": [*SentryAppIdentifier]}, - }, - "required": ["target_type", "target_identifier", "sentry_app_identifier"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": {"settings": {"type": ["array", "object"]}}, - "additionalProperties": False, - }, - ), - ActionType.OPSGENIE: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the opsgenie action", - "enum": ["P1", "P2", "P3", "P4", "P5"], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.DISCORD: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Discord Action", - "type": "object", - "properties": { - "target_identifier": {"type": "string"}, - "target_display": { - "type": ["string", "null"], - }, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), -} - - -def _enforce_action_json_schema(action: Any) -> None: - schemas = action_schema_mapping.get(action.type) - if not schemas: - logger.error( - "No schema found for action type", - extra={"action_type": action.type}, - ) - return - config_schema = schemas.config_schema - data_schema = schemas.data_schema - - if config_schema is not None: - try: - validate(action.config, config_schema) - except ValidationError as e: - raise ValidationError(f"Invalid config: {e.message}") - - if data_schema is not None: - try: - validate(action.data, data_schema) - except ValidationError as e: - raise ValidationError(f"Invalid data: {e.message}") - - -def _get_trigger_action_target(apps: Apps, trigger_action: Any) -> Any: - OrganizationMember = apps.get_model("sentry", "OrganizationMember") - Team = apps.get_model("sentry", "Team") - - if trigger_action.target_identifier is None: - return None - - if trigger_action.target_type == ActionTarget.USER.value: - try: - return OrganizationMember.objects.get( - user_id=int(trigger_action.target_identifier), - organization=trigger_action.alert_rule_trigger.alert_rule.organization_id, - ) - except OrganizationMember.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.TEAM.value: - try: - return Team.objects.get(id=int(trigger_action.target_identifier)) - except Team.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.SPECIFIC.value: - return trigger_action.target_identifier - return None - - -def _get_action_description(apps: Apps, action: Any) -> str: - """ - Returns a human readable action description - """ - if action.type == AlertRuleTriggerActionType.EMAIL.value: - target = _get_trigger_action_target(apps, action) - if target: - if action.target_type == ActionTarget.USER.value: - action_target_user = target - return "Email " + action_target_user.user_email - elif action.target_type == ActionTarget.TEAM.value: - action_target_team = target - return "Email #" + action_target_team.slug - else: - return "Email [removed]" - elif action.type == AlertRuleTriggerActionType.SENTRY_APP.value: - return f"Notify {action.target_display}" - - return f"Notify {action.target_display} via {ACTION_TYPE_TO_STRING[action.type]}" - - -def _get_workflow_name(apps: Apps, alert_rule: Any) -> str: - """ - Generate a workflow name like 'Slack @michelle.fu, Email michelle.fu@sentry.io...(+3)' if there is only a critical trigger - or with priority label: 'Critical - Slack @michelle.fu, Warning email michelle.fu@sentry.io...(+3)'' - """ - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - - name = "" - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id).order_by("label") - include_label = False if triggers.count() == 1 else True - - actions = AlertRuleTriggerAction.objects.filter( - alert_rule_trigger_id__in=[trigger.id for trigger in triggers], status=0 - ) - actions_counter = 0 - - for trigger in triggers: - name += f"{trigger.label.title()} - " if include_label else "" - for action in actions.filter(alert_rule_trigger_id=trigger.id): - description = _get_action_description(apps, action) + ", " - - if actions_counter < MAX_ACTIONS: - name += description - actions_counter += 1 - else: - remaining_actions = actions.count() - actions_counter - name = name[:-2] - name += f"...(+{remaining_actions})" - break - - if name[-2:] == ", ": - name = name[:-2] # chop off the trailing comma - - return name - - -def _migrate_trigger(apps: Apps, trigger: Any, detector: Any, workflow: Any) -> None: - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - WorkflowDataConditionGroup = apps.get_model("workflow_engine", "WorkflowDataConditionGroup") - DataConditionAlertRuleTrigger = apps.get_model( - "workflow_engine", "DataConditionAlertRuleTrigger" - ) - - alert_rule = trigger.alert_rule - condition_result = PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH) - # create detector trigger - detector_trigger = DataCondition.objects.create( - type=Condition.ANOMALY_DETECTION, - comparison={ - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "threshold_type": alert_rule.threshold_type, - }, - condition_result=condition_result, - condition_group=detector.workflow_condition_group, - ) - DataConditionAlertRuleTrigger.objects.create( - data_condition=detector_trigger, - alert_rule_trigger_id=trigger.id, - ) - # create action filter - data_condition_group = DataConditionGroup.objects.create( - organization_id=alert_rule.organization_id - ) - WorkflowDataConditionGroup.objects.create( - condition_group=data_condition_group, - workflow=workflow, - ) - action_filter = DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_GREATER_OR_EQUAL, - condition_group=data_condition_group, - ) - - # resolve action filter - DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_DEESCALATING, - condition_group=data_condition_group, - ) - - trigger_actions = AlertRuleTriggerAction.objects.filter(alert_rule_trigger=trigger) - for trigger_action in trigger_actions: - # 0 is active status - if trigger_action.status != 0: - continue - _migrate_trigger_action(apps, trigger_action, action_filter.condition_group.id) - - -def _migrate_trigger_action(apps: Apps, trigger_action: Any, condition_group_id: int) -> None: - DataConditionGroupAction = apps.get_model("workflow_engine", "DataConditionGroupAction") - Action = apps.get_model("workflow_engine", "Action") - ActionAlertRuleTriggerAction = apps.get_model("workflow_engine", "ActionAlertRuleTriggerAction") - if trigger_action.sentry_app_id: - action_type = ActionType.SENTRY_APP - - elif trigger_action.integration_id: - try: - action_type = ActionType(TYPE_TO_PROVIDER[trigger_action.type]) - except Exception: - logger.info( - "could not find a matching action type for the trigger action", - extra={"trigger_action_id": trigger_action.id}, - ) - raise - else: - action_type = ActionType.EMAIL - - # build data blob - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_config: - data = {} - else: - settings = ( - [trigger_action.sentry_app_config] - if isinstance(trigger_action.sentry_app_config, dict) - else trigger_action.sentry_app_config - ) - data = dataclasses.asdict(SentryAppDataBlob.from_list(settings)) - elif action_type in (ActionType.OPSGENIE, ActionType.PAGERDUTY): - default_priority = ( - OPSGENIE_DEFAULT_PRIORITY - if action_type == ActionType.OPSGENIE - else PAGERDUTY_DEFAULT_SEVERITY - ) - - if not trigger_action.sentry_app_config: - data = {"priority": default_priority} - else: - # Ensure sentry_app_config is a dict before accessing - config = trigger_action.sentry_app_config - if not isinstance(config, dict): - data = {"priority": default_priority} - else: - priority = config.get("priority", default_priority) - data = dataclasses.asdict(OnCallDataBlob(priority=priority)) - else: - data = {} - - # get target identifier - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_id: - logger.info( - "trigger action missing sentry app ID", - extra={"trigger_action_id": trigger_action.id}, - ) - raise Exception("Trigger action missing Sentry app ID") - target_identifier = str(trigger_action.sentry_app_id) - else: - target_identifier = trigger_action.target_identifier - - # build config - target_type = trigger_action.target_type - config = { - "target_display": trigger_action.target_display, - "target_identifier": target_identifier, - "target_type": target_type, - } - if target_type == ActionTarget.SENTRY_APP.value: - config["sentry_app_identifier"] = SentryAppIdentifier.SENTRY_APP_ID - - # create the models - action = Action.objects.create( - type=action_type, - data=data, - integration_id=trigger_action.integration_id, - config=config, - ) - - _enforce_action_json_schema(action) - - DataConditionGroupAction.objects.create( - condition_group_id=condition_group_id, - action_id=action.id, - ) - ActionAlertRuleTriggerAction.objects.create( - action_id=action.id, - alert_rule_trigger_action_id=trigger_action.id, - ) - - -def _create_data_source(apps: Apps, alert_rule: Any) -> Any: - DataSource = apps.get_model("workflow_engine", "DataSource") - QuerySubscription = apps.get_model("sentry", "QuerySubscription") - - snuba_query = alert_rule.snuba_query - if not snuba_query: - logger.info("alert rule missing snuba query", extra={"alert_rule_id": alert_rule.id}) - raise Exception("Alert rule missing snuba query") - try: - query_subscription = QuerySubscription.objects.get(snuba_query=snuba_query.id) - except QuerySubscription.DoesNotExist: - logger.info( - "query subscription does not exist", - extra={"snuba_query_id": snuba_query.id}, - ) - raise Exception("Query subscription does not exist") - data_source = DataSource.objects.create( - organization_id=alert_rule.organization_id, - source_id=str(query_subscription.id), - type="snuba_query_subscription", - ) - return data_source - - -def _create_detector( - apps: Apps, - alert_rule: Any, - project: Any, - data_condition_group: Any, - create_activity: Any, - enabled: bool, -) -> Any: - Detector = apps.get_model("workflow_engine", "Detector") - detector = Detector.objects.create( - project_id=project.id, - enabled=enabled, - created_by_id=create_activity.user_id if create_activity else None, - name=alert_rule.name if len(alert_rule.name) < 200 else alert_rule.name[:197] + "...", - workflow_condition_group=data_condition_group, - type="metric_issue", - description=alert_rule.description, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={ - "threshold_period": alert_rule.threshold_period, - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "comparison_delta": alert_rule.comparison_delta, - "detection_type": alert_rule.detection_type, - }, - ) - Detector.objects.filter(id=detector.id).update(date_added=alert_rule.date_added) - return detector - - -def _create_detector_state(apps: Apps, alert_rule: Any, project: Any, detector: Any) -> None: - Incident = apps.get_model("sentry", "Incident") - DetectorState = apps.get_model("workflow_engine", "DetectorState") - - incident_query = Incident.objects.filter( - type=IncidentType.ALERT_TRIGGERED.value, - alert_rule=alert_rule, - projects=project, - ) - open_incident = ( - incident_query.exclude(status=IncidentStatus.CLOSED.value).order_by("-date_added").first() - ) - if open_incident: - state = ( - DetectorPriorityLevel.MEDIUM - if open_incident.status == IncidentStatus.WARNING.value - else DetectorPriorityLevel.HIGH - ) - else: - state = DetectorPriorityLevel.OK - # create detector state - DetectorState.objects.create( - detector=detector, - is_triggered=True if open_incident else False, - state=state, - ) - - -def migrate_anomaly_detection_alerts(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: - AlertRule = apps.get_model("sentry", "AlertRule") - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleActivity = apps.get_model("sentry", "AlertRuleActivity") - RuleSnooze = apps.get_model("sentry", "RuleSnooze") - - AlertRuleDetector = apps.get_model("workflow_engine", "AlertRuleDetector") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - Workflow = apps.get_model("workflow_engine", "Workflow") - - # MAIN MIGRATION LOOP STARTS HERE - alert_rules = AlertRule.objects_with_snapshots.filter( - status__in=[ - AlertRuleStatus.PENDING.value, - AlertRuleStatus.NOT_ENOUGH_DATA.value, - ], - detection_type="dynamic", - ).filter(~Exists(AlertRuleDetector.objects.filter(alert_rule_id=OuterRef("id")))) - - for alert_rule in RangeQuerySetWrapper(alert_rules): - organization_id = alert_rule.organization.id - try: - with transaction.atomic(router.db_for_write(AlertRule)): - project = alert_rule.projects.first() - if not project: - logger.info( - "alert rule missing project, skipping", - extra={"alert_rule_id": alert_rule.id}, - ) - continue - snoozed = None - try: - snoozed = RuleSnooze.objects.get(alert_rule_id=alert_rule.id, user_id=None) - except RuleSnooze.DoesNotExist: - pass - enabled = True if snoozed is None else False - - create_activity = AlertRuleActivity.objects.filter( - alert_rule_id=alert_rule.id, type=AlertRuleActivityType.CREATED.value - ).first() - - # create data source - data_source = _create_data_source(apps, alert_rule) - - # create detector DCG - data_condition_group = DataConditionGroup.objects.create( - organization_id=organization_id, - ) - # create detector - detector = _create_detector( - apps, - alert_rule, - project, - data_condition_group, - create_activity, - enabled, - ) - # create workflow - workflow = Workflow.objects.create( - name=_get_workflow_name(apps, alert_rule), - organization_id=organization_id, - when_condition_group=None, - enabled=True, - created_by_id=create_activity.user_id if create_activity else None, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={}, - ) - Workflow.objects.filter(id=workflow.id).update(date_added=alert_rule.date_added) - - data_source.detectors.set([detector]) - - # create detector state - _create_detector_state(apps, alert_rule, project, detector) - # create lookup tables - AlertRuleDetector.objects.create(alert_rule_id=alert_rule.id, detector=detector) - AlertRuleWorkflow.objects.create(alert_rule_id=alert_rule.id, workflow=workflow) - DetectorWorkflow.objects.create(detector=detector, workflow=workflow) - - # migrate triggers - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id) - for trigger in triggers: - # anomaly detection alerts only have critical triggers - # migrates the trigger and its associated actions - _migrate_trigger(apps, trigger, detector, workflow) - - logger.info( - "Successfully migrated alert rule", - extra={"alert_rule_id": alert_rule.id}, - ) - except Exception as e: - logger.info( - "error when migrating alert rule", - extra={"error": str(e), "alert_rule_id": alert_rule.id}, - ) - sentry_sdk.capture_exception(e) - - -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 = True - - dependencies = [ - ("workflow_engine", "0069_rename_error_detectors"), - ] - - operations = [ - migrations.RunPython( - migrate_anomaly_detection_alerts, - migrations.RunPython.noop, - hints={"tables": ["sentry_alertrule"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0071_migrate_remaining_metric_alerts.py b/src/sentry/workflow_engine/migrations/0071_migrate_remaining_metric_alerts.py deleted file mode 100644 index 1732be4985b3..000000000000 --- a/src/sentry/workflow_engine/migrations/0071_migrate_remaining_metric_alerts.py +++ /dev/null @@ -1,915 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-03 21:44 - -import dataclasses -import logging -from enum import Enum, IntEnum, StrEnum -from typing import Any - -import sentry_sdk -from attr import dataclass -from django.apps.registry import Apps -from django.db import migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.models import Exists, OuterRef -from jsonschema import ValidationError, validate - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -class PriorityLevel(IntEnum): - LOW = 25 - MEDIUM = 50 - HIGH = 75 - - -class DetectorPriorityLevel(IntEnum): - OK = 0 - LOW = PriorityLevel.LOW - MEDIUM = PriorityLevel.MEDIUM - HIGH = PriorityLevel.HIGH - - -class IncidentStatus(Enum): - OPEN = 1 - CLOSED = 2 - WARNING = 10 - CRITICAL = 20 - - -class IncidentType(Enum): - DETECTED = 0 - ALERT_TRIGGERED = 2 - - -class AlertRuleStatus(Enum): - PENDING = 0 - SNAPSHOT = 4 - DISABLED = 5 - NOT_ENOUGH_DATA = 6 - - -class AlertRuleThresholdType(Enum): - ABOVE = 0 - BELOW = 1 - ABOVE_AND_BELOW = 2 - - -class Condition(StrEnum): - EQUAL = "eq" - GREATER_OR_EQUAL = "gte" - GREATER = "gt" - LESS_OR_EQUAL = "lte" - LESS = "lt" - ISSUE_PRIORITY_GREATER_OR_EQUAL = "issue_priority_greater_or_equal" - ISSUE_PRIORITY_DEESCALATING = "issue_priority_deescalating" - ANOMALY_DETECTION = "anomaly_detection" - - -class AlertRuleActivityType(Enum): - CREATED = 1 - DELETED = 2 - UPDATED = 3 - ENABLED = 4 - DISABLED = 5 - SNAPSHOT = 6 - ACTIVATED = 7 - DEACTIVATED = 8 - - -class AlertRuleTriggerActionType(Enum): - EMAIL = 0 - PAGERDUTY = 1 - SLACK = 2 - MSTEAMS = 3 - SENTRY_APP = 4 - SENTRY_NOTIFICATION = 5 # Use personal notification platform (src/sentry/notifications) - OPSGENIE = 6 - DISCORD = 7 - - -MAX_ACTIONS = 3 - -ACTION_TYPE_TO_STRING = { - AlertRuleTriggerActionType.PAGERDUTY.value: "PagerDuty", - AlertRuleTriggerActionType.SLACK.value: "Slack", - AlertRuleTriggerActionType.MSTEAMS.value: "Microsoft Teams", - AlertRuleTriggerActionType.OPSGENIE.value: "Opsgenie", - AlertRuleTriggerActionType.DISCORD.value: "Discord", -} - - -class ActionTarget(IntEnum): - """ - Explains the contents of target_identifier - """ - - # The target_identifier is a direct reference used by the service (e.g. email address, slack channel id) - SPECIFIC = 0 - # The target_identifier is an id from the User model in Sentry - USER = 1 - # The target_identifier is an id from the Team model in Sentry - TEAM = 2 - # The target_identifier is an id from the SentryApp model in Sentry - SENTRY_APP = 3 - # There is no target_identifier, but we want to send notifications to the issue owners - ISSUE_OWNERS = 4 - - -class ActionType(StrEnum): - SLACK = "slack" - MSTEAMS = "msteams" - DISCORD = "discord" - - PAGERDUTY = "pagerduty" - OPSGENIE = "opsgenie" - - EMAIL = "email" - SENTRY_APP = "sentry_app" - - -class SentryAppIdentifier(StrEnum): - """ - SentryAppIdentifier is an enum that represents the identifier for a Sentry app. - """ - - SENTRY_APP_INSTALLATION_UUID = "sentry_app_installation_uuid" - SENTRY_APP_SLUG = "sentry_app_slug" - SENTRY_APP_ID = "sentry_app_id" - - -FIELDS_TO_DETECTOR_FIELDS = { - "name": "name", - "description": "description", - "user_id": "owner_user_id", - "team_id": "owner_team_id", -} - -TYPE_TO_PROVIDER = { - 0: "email", - 1: "pagerduty", - 2: "slack", - 3: "msteams", - 4: "sentry_app", - 6: "opsgenie", - 7: "discord", -} - -PRIORITY_MAP = { - "warning": DetectorPriorityLevel.MEDIUM, - "critical": DetectorPriorityLevel.HIGH, -} - - -OPSGENIE_DEFAULT_PRIORITY = "P3" -PAGERDUTY_DEFAULT_SEVERITY = "default" - - -class PagerdutySeverity(StrEnum): - DEFAULT = "default" - CRITICAL = "critical" - WARNING = "warning" - ERROR = "error" - INFO = "info" - - -@dataclass -class ActionSchemas: - config_schema: dict[str, Any] | None = None - data_schema: dict[str, Any] | None = None - - -@dataclasses.dataclass -class SentryAppFormConfigDataBlob: - """ - SentryAppFormConfigDataBlob represents a single form config field for a Sentry App. - name is the name of the form field, and value is the value of the form field. - """ - - @classmethod - def from_dict(cls, data: dict[str, Any]) -> "SentryAppFormConfigDataBlob": - if not isinstance(data.get("name"), str) or not isinstance( - data.get("value"), (str, type(None)) - ): - raise ValueError("Sentry app config must contain name and value keys") - return cls(name=data["name"], value=data["value"], label=data.get("label")) - - name: str = "" - value: str = "" - label: str | None = None - - -@dataclasses.dataclass -class SentryAppDataBlob: - """ - Represents a Sentry App notification action. - """ - - settings: list[SentryAppFormConfigDataBlob] = dataclasses.field(default_factory=list) - - @classmethod - def from_list(cls, data: list[dict[str, Any]] | None) -> "SentryAppDataBlob": - if data is None: - return cls() - return cls(settings=[SentryAppFormConfigDataBlob.from_dict(setting) for setting in data]) - - -@dataclasses.dataclass -class OnCallDataBlob: - """ - OnCallDataBlob is a specific type that represents the data blob for a PagerDuty or Opsgenie notification action. - """ - - priority: str = "" - - -action_schema_mapping: dict[str, ActionSchemas] = { - ActionType.EMAIL: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for an email Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string", "null"]}, - "target_display": {"type": ["null"]}, - "target_type": { - "type": ["integer"], - "enum": [*ActionTarget], - }, - }, - "required": ["target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.PAGERDUTY: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [0]}, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the pagerduty action", - "enum": [*PagerdutySeverity], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.SLACK: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.MSTEAMS: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Messaging Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_display", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), - ActionType.SENTRY_APP: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Sentry App Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": {"type": ["integer"], "enum": [3]}, - "sentry_app_identifier": {"type": ["string"], "enum": [*SentryAppIdentifier]}, - }, - "required": ["target_type", "target_identifier", "sentry_app_identifier"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": {"settings": {"type": ["array", "object"]}}, - "additionalProperties": False, - }, - ), - ActionType.OPSGENIE: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a on-call Action", - "type": "object", - "properties": { - "target_identifier": {"type": ["string"]}, - "target_display": {"type": ["string", "null"]}, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "priority": { - "type": "string", - "description": "The priority of the opsgenie action", - "enum": ["P1", "P2", "P3", "P4", "P5"], - }, - "additionalProperties": False, - }, - }, - ), - ActionType.DISCORD: ActionSchemas( - config_schema={ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "The configuration schema for a Discord Action", - "type": "object", - "properties": { - "target_identifier": {"type": "string"}, - "target_display": { - "type": ["string", "null"], - }, - "target_type": { - "type": ["integer"], - "enum": [ActionTarget.SPECIFIC.value], - }, - }, - "required": ["target_identifier", "target_type"], - "additionalProperties": False, - }, - data_schema={}, - ), -} - - -def _enforce_action_json_schema(action: Any) -> None: - schemas = action_schema_mapping.get(action.type) - if not schemas: - logger.error( - "No schema found for action type", - extra={"action_type": action.type}, - ) - return - config_schema = schemas.config_schema - data_schema = schemas.data_schema - - if config_schema is not None: - try: - validate(action.config, config_schema) - except ValidationError as e: - raise ValidationError(f"Invalid config: {e.message}") - - if data_schema is not None: - try: - validate(action.data, data_schema) - except ValidationError as e: - raise ValidationError(f"Invalid data: {e.message}") - - -def _get_trigger_action_target(apps: Apps, trigger_action: Any) -> Any: - OrganizationMember = apps.get_model("sentry", "OrganizationMember") - Team = apps.get_model("sentry", "Team") - - if trigger_action.target_identifier is None: - return None - - if trigger_action.target_type == ActionTarget.USER.value: - try: - return OrganizationMember.objects.get( - user_id=int(trigger_action.target_identifier), - organization=trigger_action.alert_rule_trigger.alert_rule.organization_id, - ) - except OrganizationMember.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.TEAM.value: - try: - return Team.objects.get(id=int(trigger_action.target_identifier)) - except Team.DoesNotExist: - pass - - elif trigger_action.target_type == ActionTarget.SPECIFIC.value: - return trigger_action.target_identifier - return None - - -def _get_action_description(apps: Apps, action: Any) -> str: - """ - Returns a human readable action description - """ - if action.type == AlertRuleTriggerActionType.EMAIL.value: - target = _get_trigger_action_target(apps, action) - if target: - if action.target_type == ActionTarget.USER.value: - action_target_user = target - return "Email " + action_target_user.user_email - elif action.target_type == ActionTarget.TEAM.value: - action_target_team = target - return "Email #" + action_target_team.slug - else: - return "Email [removed]" - elif action.type == AlertRuleTriggerActionType.SENTRY_APP.value: - return f"Notify {action.target_display}" - - return f"Notify {action.target_display} via {ACTION_TYPE_TO_STRING[action.type]}" - - -def _get_workflow_name(apps: Apps, alert_rule: Any) -> str: - """ - Generate a workflow name like 'Slack @michelle.fu, Email michelle.fu@sentry.io...(+3)' if there is only a critical trigger - or with priority label: 'Critical - Slack @michelle.fu, Warning email michelle.fu@sentry.io...(+3)'' - """ - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - - name = "" - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id).order_by("label") - include_label = False if triggers.count() == 1 else True - - actions = AlertRuleTriggerAction.objects.filter( - alert_rule_trigger_id__in=[trigger.id for trigger in triggers], status=0 - ) - actions_counter = 0 - - for trigger in triggers: - name += f"{trigger.label.title()} - " if include_label else "" - for action in actions.filter(alert_rule_trigger_id=trigger.id): - description = _get_action_description(apps, action) + ", " - - if actions_counter < MAX_ACTIONS: - name += description - actions_counter += 1 - else: - remaining_actions = actions.count() - actions_counter - name = name[:-2] - name += f"...(+{remaining_actions})" - break - - if name[-2:] == ", ": - name = name[:-2] # chop off the trailing comma - - return name - - -def _migrate_trigger(apps: Apps, trigger: Any, detector: Any, workflow: Any) -> None: - AlertRuleTriggerAction = apps.get_model("sentry", "AlertRuleTriggerAction") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - WorkflowDataConditionGroup = apps.get_model("workflow_engine", "WorkflowDataConditionGroup") - DataConditionAlertRuleTrigger = apps.get_model( - "workflow_engine", "DataConditionAlertRuleTrigger" - ) - - alert_rule = trigger.alert_rule - condition_result = PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH) - threshold_type = ( - Condition.GREATER - if alert_rule.threshold_type == AlertRuleThresholdType.ABOVE.value - else Condition.LESS - ) - # create detector trigger - if alert_rule.detection_type == "dynamic": - detector_trigger = DataCondition.objects.create( - type=Condition.ANOMALY_DETECTION, - comparison={ - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "threshold_type": alert_rule.threshold_type, - }, - condition_result=condition_result, - condition_group=detector.workflow_condition_group, - ) - else: - detector_trigger = DataCondition.objects.create( - comparison=trigger.alert_threshold, - condition_result=condition_result, - type=threshold_type, - condition_group=detector.workflow_condition_group, - ) - DataConditionAlertRuleTrigger.objects.create( - data_condition=detector_trigger, - alert_rule_trigger_id=trigger.id, - ) - # create action filter - data_condition_group = DataConditionGroup.objects.create( - organization_id=alert_rule.organization_id - ) - WorkflowDataConditionGroup.objects.create( - condition_group=data_condition_group, - workflow=workflow, - ) - action_filter = DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_GREATER_OR_EQUAL, - condition_group=data_condition_group, - ) - - # resolve action filter - DataCondition.objects.create( - comparison=PRIORITY_MAP.get(trigger.label, DetectorPriorityLevel.HIGH), - condition_result=True, - type=Condition.ISSUE_PRIORITY_DEESCALATING, - condition_group=data_condition_group, - ) - - trigger_actions = AlertRuleTriggerAction.objects.filter(alert_rule_trigger=trigger) - for trigger_action in trigger_actions: - # 0 is active status - if trigger_action.status != 0: - continue - _migrate_trigger_action(apps, trigger_action, action_filter.condition_group.id) - - -def _migrate_trigger_action(apps: Apps, trigger_action: Any, condition_group_id: int) -> None: - DataConditionGroupAction = apps.get_model("workflow_engine", "DataConditionGroupAction") - Action = apps.get_model("workflow_engine", "Action") - ActionAlertRuleTriggerAction = apps.get_model("workflow_engine", "ActionAlertRuleTriggerAction") - if trigger_action.sentry_app_id: - action_type = ActionType.SENTRY_APP - - elif trigger_action.integration_id: - try: - action_type = ActionType(TYPE_TO_PROVIDER[trigger_action.type]) - except Exception: - logger.info( - "could not find a matching action type for the trigger action", - extra={"trigger_action_id": trigger_action.id}, - ) - raise - else: - action_type = ActionType.EMAIL - - # build data blob - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_config: - data = {} - else: - settings = ( - [trigger_action.sentry_app_config] - if isinstance(trigger_action.sentry_app_config, dict) - else trigger_action.sentry_app_config - ) - data = dataclasses.asdict(SentryAppDataBlob.from_list(settings)) - elif action_type in (ActionType.OPSGENIE, ActionType.PAGERDUTY): - default_priority = ( - OPSGENIE_DEFAULT_PRIORITY - if action_type == ActionType.OPSGENIE - else PAGERDUTY_DEFAULT_SEVERITY - ) - - if not trigger_action.sentry_app_config: - data = {"priority": default_priority} - else: - # Ensure sentry_app_config is a dict before accessing - config = trigger_action.sentry_app_config - if not isinstance(config, dict): - data = {"priority": default_priority} - else: - priority = config.get("priority", default_priority) - data = dataclasses.asdict(OnCallDataBlob(priority=priority)) - else: - data = {} - - # get target identifier - if action_type == ActionType.SENTRY_APP: - if not trigger_action.sentry_app_id: - logger.info( - "trigger action missing sentry app ID", - extra={"trigger_action_id": trigger_action.id}, - ) - raise Exception("Trigger action missing Sentry app ID") - target_identifier = str(trigger_action.sentry_app_id) - else: - target_identifier = trigger_action.target_identifier - - # build config - target_type = trigger_action.target_type - config = { - "target_display": trigger_action.target_display, - "target_identifier": target_identifier, - "target_type": target_type, - } - if target_type == ActionTarget.SENTRY_APP.value: - config["sentry_app_identifier"] = SentryAppIdentifier.SENTRY_APP_ID - - # create the models - action = Action.objects.create( - type=action_type, - data=data, - integration_id=trigger_action.integration_id, - config=config, - ) - - _enforce_action_json_schema(action) - - DataConditionGroupAction.objects.create( - condition_group_id=condition_group_id, - action_id=action.id, - ) - ActionAlertRuleTriggerAction.objects.create( - action_id=action.id, - alert_rule_trigger_action_id=trigger_action.id, - ) - - -def _create_data_source(apps: Apps, alert_rule: Any) -> Any: - DataSource = apps.get_model("workflow_engine", "DataSource") - QuerySubscription = apps.get_model("sentry", "QuerySubscription") - - snuba_query = alert_rule.snuba_query - if not snuba_query: - logger.info("alert rule missing snuba query", extra={"alert_rule_id": alert_rule.id}) - raise Exception("Alert rule missing snuba query") - try: - query_subscription = QuerySubscription.objects.get(snuba_query=snuba_query.id) - except QuerySubscription.DoesNotExist: - logger.info( - "query subscription does not exist", - extra={"snuba_query_id": snuba_query.id}, - ) - raise Exception("Query subscription does not exist") - data_source = DataSource.objects.create( - organization_id=alert_rule.organization_id, - source_id=str(query_subscription.id), - type="snuba_query_subscription", - ) - return data_source - - -def _create_detector( - apps: Apps, - alert_rule: Any, - project: Any, - data_condition_group: Any, - create_activity: Any, - enabled: bool, -) -> Any: - Detector = apps.get_model("workflow_engine", "Detector") - detector = Detector.objects.create( - project_id=project.id, - enabled=enabled, - created_by_id=create_activity.user_id if create_activity else None, - name=alert_rule.name if len(alert_rule.name) < 200 else alert_rule.name[:197] + "...", - workflow_condition_group=data_condition_group, - type="metric_issue", - description=alert_rule.description, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={ - "threshold_period": alert_rule.threshold_period, - "sensitivity": alert_rule.sensitivity, - "seasonality": alert_rule.seasonality, - "comparison_delta": alert_rule.comparison_delta, - "detection_type": alert_rule.detection_type, - }, - ) - Detector.objects.filter(id=detector.id).update(date_added=alert_rule.date_added) - return detector - - -def _create_detector_state(apps: Apps, alert_rule: Any, project: Any, detector: Any) -> None: - Incident = apps.get_model("sentry", "Incident") - DetectorState = apps.get_model("workflow_engine", "DetectorState") - - incident_query = Incident.objects.filter( - type=IncidentType.ALERT_TRIGGERED.value, - alert_rule=alert_rule, - projects=project, - ) - open_incident = ( - incident_query.exclude(status=IncidentStatus.CLOSED.value).order_by("-date_added").first() - ) - if open_incident: - state = ( - DetectorPriorityLevel.MEDIUM - if open_incident.status == IncidentStatus.WARNING.value - else DetectorPriorityLevel.HIGH - ) - else: - state = DetectorPriorityLevel.OK - # create detector state - DetectorState.objects.create( - detector=detector, - is_triggered=True if open_incident else False, - state=state, - ) - - -def _migrate_resolve_threshold(apps: Apps, alert_rule: Any, detector: Any) -> None: - DataCondition = apps.get_model("workflow_engine", "DataCondition") - - resolve_threshold_type = ( - Condition.LESS_OR_EQUAL - if alert_rule.threshold_type == AlertRuleThresholdType.ABOVE.value - else Condition.GREATER_OR_EQUAL - ) - if alert_rule.resolve_threshold is not None: - resolve_threshold = alert_rule.resolve_threshold - else: - detector_triggers = DataCondition.objects.filter( - condition_group=detector.workflow_condition_group - ) - warning_data_condition = detector_triggers.filter( - condition_result=DetectorPriorityLevel.MEDIUM - ).first() - if warning_data_condition is not None: - resolve_threshold = warning_data_condition.comparison - else: - critical_data_condition = detector_triggers.filter( - condition_result=DetectorPriorityLevel.HIGH - ).first() - if critical_data_condition is None: - logger.info( - "no critical or warning data conditions exist for detector data condition group", - extra={"detector_data_condition_group": detector_triggers}, - ) - raise Exception( - "No critical or warning data conditions exist for detector data condition group" - ) - else: - resolve_threshold = critical_data_condition.comparison - DataCondition.objects.create( - comparison=resolve_threshold, - condition_result=DetectorPriorityLevel.OK, - type=resolve_threshold_type, - condition_group=detector.workflow_condition_group, - ) - - -def migrate_metric_alerts(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: - AlertRule = apps.get_model("sentry", "AlertRule") - AlertRuleTrigger = apps.get_model("sentry", "AlertRuleTrigger") - AlertRuleActivity = apps.get_model("sentry", "AlertRuleActivity") - AlertRuleProjects = apps.get_model("sentry", "AlertRuleProjects") - RuleSnooze = apps.get_model("sentry", "RuleSnooze") - - AlertRuleDetector = apps.get_model("workflow_engine", "AlertRuleDetector") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - Workflow = apps.get_model("workflow_engine", "Workflow") - - # MAIN MIGRATION LOOP STARTS HERE - alert_rules = ( - AlertRule.objects_with_snapshots.filter( - status__in=[ - AlertRuleStatus.PENDING.value, - AlertRuleStatus.DISABLED.value, - AlertRuleStatus.NOT_ENOUGH_DATA.value, - ] - ) - .filter(~Exists(AlertRuleDetector.objects.filter(alert_rule_id=OuterRef("id")))) - .filter(Exists(AlertRuleProjects.objects.filter(alert_rule_id=OuterRef("id")))) - ) - - for alert_rule in RangeQuerySetWrapper(alert_rules): - organization_id = alert_rule.organization.id - try: - with transaction.atomic(router.db_for_write(AlertRule)): - project = alert_rule.projects.first() - if not project: - # we will not hit this, but just to be extra sure - logger.info( - "alert rule missing project, skipping", - extra={"alert_rule_id": alert_rule.id}, - ) - continue - snoozed = None - try: - snoozed = RuleSnooze.objects.get(alert_rule_id=alert_rule.id, user_id=None) - except RuleSnooze.DoesNotExist: - pass - enabled = ( - True - if snoozed is None and alert_rule.status == AlertRuleStatus.PENDING.value - else False - ) - - create_activity = AlertRuleActivity.objects.filter( - alert_rule_id=alert_rule.id, type=AlertRuleActivityType.CREATED.value - ).first() - - # create data source - data_source = _create_data_source(apps, alert_rule) - - # create detector DCG - data_condition_group = DataConditionGroup.objects.create( - organization_id=organization_id, - ) - # create detector - detector = _create_detector( - apps, - alert_rule, - project, - data_condition_group, - create_activity, - enabled, - ) - # create workflow - workflow = Workflow.objects.create( - name=_get_workflow_name(apps, alert_rule), - organization_id=organization_id, - when_condition_group=None, - enabled=True, - created_by_id=create_activity.user_id if create_activity else None, - owner_user_id=alert_rule.user_id, - owner_team=alert_rule.team, - config={}, - ) - Workflow.objects.filter(id=workflow.id).update(date_added=alert_rule.date_added) - - data_source.detectors.set([detector]) - - # create detector state - _create_detector_state(apps, alert_rule, project, detector) - # create lookup tables - AlertRuleDetector.objects.create(alert_rule_id=alert_rule.id, detector=detector) - AlertRuleWorkflow.objects.create(alert_rule_id=alert_rule.id, workflow=workflow) - DetectorWorkflow.objects.create(detector=detector, workflow=workflow) - - # migrate triggers - triggers = AlertRuleTrigger.objects.filter(alert_rule_id=alert_rule.id) - for trigger in triggers: - # migrates the trigger and its associated actions - _migrate_trigger(apps, trigger, detector, workflow) - - # migrate resolve threshold - if alert_rule.detection_type != "dynamic": - _migrate_resolve_threshold(apps, alert_rule, detector) - - logger.info( - "Successfully migrated alert rule", - extra={"alert_rule_id": alert_rule.id}, - ) - except Exception as e: - logger.info( - "error when migrating alert rule", - extra={"error": str(e), "alert_rule_id": alert_rule.id}, - ) - sentry_sdk.capture_exception(e) - - -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 = True - - dependencies = [ - ("workflow_engine", "0070_migrate_remaining_anomaly_detection_alerts"), - ] - - operations = [ - migrations.RunPython( - migrate_metric_alerts, - migrations.RunPython.noop, - hints={"tables": ["sentry_alertrule"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0072_add_detector_to_workflowfirehistory.py b/src/sentry/workflow_engine/migrations/0072_add_detector_to_workflowfirehistory.py deleted file mode 100644 index 96dec267bbe2..000000000000 --- a/src/sentry/workflow_engine/migrations/0072_add_detector_to_workflowfirehistory.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-23 20:48 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("workflow_engine", "0071_migrate_remaining_metric_alerts"), - ] - - operations = [ - migrations.AddField( - model_name="workflowfirehistory", - name="detector", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="workflow_engine.detector", - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0073_safe_pending_delete_actiongroupstatus.py b/src/sentry/workflow_engine/migrations/0073_safe_pending_delete_actiongroupstatus.py deleted file mode 100644 index 6a1b2b6191a1..000000000000 --- a/src/sentry/workflow_engine/migrations/0073_safe_pending_delete_actiongroupstatus.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-23 20:13 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -from sentry.new_migrations.monkey.special import SafeRunSQL -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 = True - - dependencies = [ - ("sentry", "0932_update_grouptombstone_with_auto_now_add"), - ("workflow_engine", "0072_add_detector_to_workflowfirehistory"), - ] - - operations = [ - migrations.AlterField( - model_name="actiongroupstatus", - name="action", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.action", - ), - ), - migrations.AlterField( - model_name="actiongroupstatus", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - SafeRunSQL( - sql="ALTER TABLE workflow_engine_actiongroupstatus DROP CONSTRAINT IF EXISTS workflow_engine_acti_action_id_e5b33d82_fk_workflow_;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["workflow_engine_actiongroupstatus"]}, - ), - SafeDeleteModel(name="ActionGroupStatus", deletion_action=DeletionAction.MOVE_TO_PENDING), - ] diff --git a/src/sentry/workflow_engine/migrations/0074_safe_delete_actiongroupstatus.py b/src/sentry/workflow_engine/migrations/0074_safe_delete_actiongroupstatus.py deleted file mode 100644 index acff14a0468c..000000000000 --- a/src/sentry/workflow_engine/migrations/0074_safe_delete_actiongroupstatus.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-23 20:13 - - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.models import SafeDeleteModel -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", "0932_update_grouptombstone_with_auto_now_add"), - ("workflow_engine", "0073_safe_pending_delete_actiongroupstatus"), - ] - - operations = [ - SafeDeleteModel(name="ActionGroupStatus", deletion_action=DeletionAction.DELETE), - ] diff --git a/src/sentry/workflow_engine/migrations/0075_add_index_to_dcg_action.py b/src/sentry/workflow_engine/migrations/0075_add_index_to_dcg_action.py deleted file mode 100644 index ad5f21b58dd9..000000000000 --- a/src/sentry/workflow_engine/migrations/0075_add_index_to_dcg_action.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-26 21:04 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("workflow_engine", "0074_safe_delete_actiongroupstatus"), - ] - - operations = [ - migrations.AddIndex( - model_name="dataconditiongroupaction", - index=models.Index(fields=["condition_group", "action"], name="cond_group_action_idx"), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0076_add_detector_group_table.py b/src/sentry/workflow_engine/migrations/0076_add_detector_group_table.py deleted file mode 100644 index 7d70aa0ea1da..000000000000 --- a/src/sentry/workflow_engine/migrations/0076_add_detector_group_table.py +++ /dev/null @@ -1,69 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-09 17:43 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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", "0943_create_data_access_grant"), - ("workflow_engine", "0075_add_index_to_dcg_action"), - ] - - operations = [ - SafeRunSQL( - """DROP TABLE IF EXISTS "workflow_engine_detectorgroup";""", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["workflow_engine_detectorgroup"]}, - ), # this migration was successfully run in S4S and DE, failed in US - migrations.CreateModel( - name="DetectorGroup", - fields=[ - ( - "id", - sentry.db.models.fields.bounded.BoundedBigAutoField( - primary_key=True, serialize=False - ), - ), - ("date_updated", models.DateTimeField(auto_now=True)), - ("date_added", models.DateTimeField(auto_now_add=True)), - ( - "detector", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.detector", - ), - ), - ( - "group", - sentry.db.models.fields.foreignkey.FlexibleForeignKey( - db_constraint=False, - on_delete=django.db.models.deletion.CASCADE, - to="sentry.group", - ), - ), - ], - options={ - "db_table": "workflow_engine_detectorgroup", - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0077_add_wfh_single_write_col.py b/src/sentry/workflow_engine/migrations/0077_add_wfh_single_write_col.py deleted file mode 100644 index 3f57a767d75a..000000000000 --- a/src/sentry/workflow_engine/migrations/0077_add_wfh_single_write_col.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-15 20:00 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("workflow_engine", "0076_add_detector_group_table"), - ] - - operations = [ - migrations.AddField( - model_name="workflowfirehistory", - name="is_single_written", - field=models.BooleanField(db_default=False, db_index=True), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0078_workflow_fire_history_date_index.py b/src/sentry/workflow_engine/migrations/0078_workflow_fire_history_date_index.py deleted file mode 100644 index ec99e8bd4f6d..000000000000 --- a/src/sentry/workflow_engine/migrations/0078_workflow_fire_history_date_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-16 20:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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", "0952_fix_span_item_event_type_alerts"), - ("workflow_engine", "0077_add_wfh_single_write_col"), - ] - - operations = [ - migrations.AddIndex( - model_name="workflowfirehistory", - index=models.Index( - fields=["workflow", "date_added"], name="workflow_en_workflo_270fe2_idx" - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0079_add_unique_constraint_to_detector_group.py b/src/sentry/workflow_engine/migrations/0079_add_unique_constraint_to_detector_group.py deleted file mode 100644 index c55b63a8bdc8..000000000000 --- a/src/sentry/workflow_engine/migrations/0079_add_unique_constraint_to_detector_group.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-17 17:52 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0952_fix_span_item_event_type_alerts"), - ("workflow_engine", "0078_workflow_fire_history_date_index"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="detectorgroup", - unique_together={("detector", "group")}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0080_update_metric_detector_config_fields.py b/src/sentry/workflow_engine/migrations/0080_update_metric_detector_config_fields.py deleted file mode 100644 index 473bf80257d6..000000000000 --- a/src/sentry/workflow_engine/migrations/0080_update_metric_detector_config_fields.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-05 18:39 - -from django.apps.registry import Apps -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - - -def update_metric_detector_config_fields( - apps: Apps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Detector = apps.get_model("workflow_engine", "Detector") - - metric_detectors = Detector.objects.filter(type="metric_issue") - - for detector in RangeQuerySetWrapper(metric_detectors): - config = detector.config - new_config = { - "comparison_delta": config.get("comparison_delta"), - "detection_type": config.get("detection_type"), - } - detector.config = new_config - detector.save() - - -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 = True - - dependencies = [ - ("workflow_engine", "0079_add_unique_constraint_to_detector_group"), - ] - - operations = [ - migrations.RunPython( - update_metric_detector_config_fields, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detector"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0081_add_unique_constraint_to_detector_group.py b/src/sentry/workflow_engine/migrations/0081_add_unique_constraint_to_detector_group.py deleted file mode 100644 index 8cde8de11272..000000000000 --- a/src/sentry/workflow_engine/migrations/0081_add_unique_constraint_to_detector_group.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-17 21:07 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0952_fix_span_item_event_type_alerts"), - ("workflow_engine", "0080_update_metric_detector_config_fields"), - ] - - operations = [ - migrations.AlterField( - model_name="detectorgroup", - name="group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="sentry.group" - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0082_disconnect_error_detector_cron_workflows.py b/src/sentry/workflow_engine/migrations/0082_disconnect_error_detector_cron_workflows.py deleted file mode 100644 index ea03049064fe..000000000000 --- a/src/sentry/workflow_engine/migrations/0082_disconnect_error_detector_cron_workflows.py +++ /dev/null @@ -1,64 +0,0 @@ -# Generated by Django 5.2.1 on 2025-07-24 21:44 - -import logging - -from django.apps.registry import Apps -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - - -def disconnect_error_detector_cron_workflows( - apps: Apps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Rule = apps.get_model("sentry", "Rule") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - - for rule in Rule.objects.filter(source=1): - arw = AlertRuleWorkflow.objects.filter(rule_id=rule.id).select_related("workflow").first() - if not arw: - logger.info( - "No AlertRuleWorkflow found for rule, skipping", - extra={"rule_id": rule.id}, - ) - continue - - workflow = arw.workflow - # delete all DetectorWorkflow entries for this workflow, it should only be connected to error detectors - DetectorWorkflow.objects.filter(workflow=workflow).delete() - logger.info( - "Disconnected cron workflow from error detectors", - extra={"rule_id": rule.id, "workflow_id": workflow.id}, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0081_add_unique_constraint_to_detector_group"), - ] - - operations = [ - migrations.RunPython( - disconnect_error_detector_cron_workflows, - migrations.RunPython.noop, - hints={"tables": ["sentry_rule"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0083_add_status_to_action.py b/src/sentry/workflow_engine/migrations/0083_add_status_to_action.py deleted file mode 100644 index a068186f8b95..000000000000 --- a/src/sentry/workflow_engine/migrations/0083_add_status_to_action.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-07 14:30 - -from django.db import migrations - -import sentry.db.models.fields.bounded -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("workflow_engine", "0082_disconnect_error_detector_cron_workflows"), - ] - - operations = [ - migrations.AddField( - model_name="action", - name="status", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(db_default=0), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0084_crons_dedupe_workflows.py b/src/sentry/workflow_engine/migrations/0084_crons_dedupe_workflows.py deleted file mode 100644 index 2baecd29abfc..000000000000 --- a/src/sentry/workflow_engine/migrations/0084_crons_dedupe_workflows.py +++ /dev/null @@ -1,107 +0,0 @@ -# Generated by Django 5.2.1 on 2025-08-26 17:43 -import json # noqa: S003 -from collections import defaultdict -from copy import deepcopy - -from django.db import migrations, router, transaction -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def dedupe_cron_shadow_workflows(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Monitor = apps.get_model("monitors", "Monitor") - Rule = apps.get_model("sentry", "Rule") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataSourceDetector = apps.get_model("workflow_engine", "DataSourceDetector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - rules_by_org = defaultdict(list) - for rule in Rule.objects.filter(source=1): - rules_by_org[rule.project.organization_id].append(rule) - - for organization_id, rules in rules_by_org.items(): - links = AlertRuleWorkflow.objects.filter(rule_id__in=[r.id for r in rules]).select_related( - "workflow" - ) - rule_workflows = {link.rule_id: link.workflow for link in links} - # We filter out rules with no links here - if we re-run the script, we don't need to reprocess rules that - # have already been de-duped - rules = [r for r in rules if r.id in rule_workflows] - - monitors = Monitor.objects.filter(organization_id=organization_id) - rule_monitors = { - int(m.config["alert_rule_id"]): m for m in monitors if "alert_rule_id" in m.config - } - data_source_links = DataSourceDetector.objects.filter( - data_source__organization_id=organization_id, - data_source__type="cron_monitor", - ).select_related("data_source", "detector") - monitor_id_to_detector = { - int(dsl.data_source.source_id): dsl.detector for dsl in data_source_links - } - rule_hashes = defaultdict(list) - for rule in rules: - data = deepcopy(rule.data) - # Clean up the data so that it's easy to compare - for action in data.get("actions", []): - action.pop("uuid", None) - new_conditions = [] - for condition in data.get("conditions", []): - # Filter out the condition that we use to restrict this to specific cron monitors, so that we can - # compare for identical rules across the whole org - if ( - condition.get("id") == "sentry.rules.filters.tagged_event.TaggedEventFilter" - and condition.get("key") == "monitor.slug" - ): - continue - new_conditions.append(condition) - data["conditions"] = new_conditions - data["environment_id"] = rule.environment_id - data["owner_user_id"] = rule.owner_user_id - data["owner_team_id"] = rule.owner_team_id - rule_hashes[json.dumps(data, sort_keys=True)].append(rule.id) - - for rule_ids in rule_hashes.values(): - with transaction.atomic(router.db_for_write(Rule)): - primary_workflow = rule_workflows[rule_ids[0]] - rule_ids_to_remove = rule_ids[1:] - for rule_id_to_remove in rule_ids_to_remove: - if rule_id_to_remove in rule_workflows: - rule_workflows[rule_id_to_remove].delete() - - for rule_id in rule_ids: - if rule_id in rule_monitors: - detector = monitor_id_to_detector[rule_monitors[rule_id].id] - DetectorWorkflow.objects.get_or_create( - detector=detector, workflow=primary_workflow - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0083_add_status_to_action"), - ("monitors", "0009_backfill_monitor_detectors"), - ] - - operations = [ - migrations.RunPython( - dedupe_cron_shadow_workflows, - migrations.RunPython.noop, - hints={"tables": ["sentry_rule"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0085_crons_link_detectors_to_all_workflows.py b/src/sentry/workflow_engine/migrations/0085_crons_link_detectors_to_all_workflows.py deleted file mode 100644 index e1d3e6405fe2..000000000000 --- a/src/sentry/workflow_engine/migrations/0085_crons_link_detectors_to_all_workflows.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 5.2.1 -from collections import defaultdict - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - - -def link_cron_detectors_to_all_workflows( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - For all detectors with type="monitor_check_in_failure" (cron monitors), - create DetectorWorkflow entries linking them to all workflows associated with - the same project (via AlertRuleWorkflow). - - This mimics the previous behavior where cron issues would fire all alert rules - for a project. - """ - Detector = apps.get_model("workflow_engine", "Detector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - Rule = apps.get_model("sentry", "Rule") - Workflow = apps.get_model("workflow_engine", "Workflow") - - cron_detectors = Detector.objects.filter(type="monitor_check_in_failure") - - detectors_by_project = defaultdict(list) - for detector in cron_detectors: - detectors_by_project[detector.project_id].append(detector) - - # For each project, link all cron detectors to all workflows from that project - for project_id, detectors in detectors_by_project.items(): - rule_ids = Rule.objects.filter(project_id=project_id).values_list("id", flat=True) - project_workflows = Workflow.objects.filter( - alertruleworkflow__rule_id__in=rule_ids - ).distinct() - - for detector in detectors: - for workflow in project_workflows: - DetectorWorkflow.objects.get_or_create(detector=detector, workflow=workflow) - - -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 = True - - dependencies = [ - ("workflow_engine", "0084_crons_dedupe_workflows"), - ("monitors", "0009_backfill_monitor_detectors"), - ] - - operations = [ - migrations.RunPython( - link_cron_detectors_to_all_workflows, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detectorworkflow"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0086_fix_cron_to_cron_workflow_links.py b/src/sentry/workflow_engine/migrations/0086_fix_cron_to_cron_workflow_links.py deleted file mode 100644 index 4867c715645c..000000000000 --- a/src/sentry/workflow_engine/migrations/0086_fix_cron_to_cron_workflow_links.py +++ /dev/null @@ -1,212 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-19 17:27 -import json # noqa: S003 -import logging -from collections import defaultdict -from copy import deepcopy - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.iterators import chunked -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) -BATCH_SIZE = 1000 - - -def unlink_monitors_without_alert_rules(apps: StateApps) -> None: - """ - Unlink all workflows from monitors that don't have alert_rule_id. - These monitors shouldn't be linked to any workflows. - """ - - Monitor = apps.get_model("monitors", "Monitor") - DataSource = apps.get_model("workflow_engine", "DataSource") - DataSourceDetector = apps.get_model("workflow_engine", "DataSourceDetector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - - data_sources = list(DataSource.objects.filter(type="cron_monitor")) - if not data_sources: - return - monitor_id_to_data_source = {int(ds.source_id): ds for ds in data_sources} - - for monitor_batch in chunked(RangeQuerySetWrapper(Monitor.objects.all()), BATCH_SIZE): - monitor_ids_to_unlink = [] - for monitor in monitor_batch: - if "alert_rule_id" not in monitor.config: - monitor_ids_to_unlink.append(monitor.id) - - if monitor_ids_to_unlink: - data_source_ids = [] - for monitor_id in monitor_ids_to_unlink: - if monitor_id in monitor_id_to_data_source: - data_source_ids.append(monitor_id_to_data_source[monitor_id].id) - - if data_source_ids: - detector_ids = DataSourceDetector.objects.filter( - data_source_id__in=data_source_ids - ).values_list("detector_id", flat=True) - if detector_ids: - DetectorWorkflow.objects.filter(detector_id__in=detector_ids).delete() - - -def fix_cron_to_cron_workflow_links( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Fix the over-linking from migration 0085 where every cron detector was linked - to every workflow in a project. This migration: - - 1. For monitors with alert_rule_id: Keep ONLY the link to their deduped workflow - 2. For monitors without alert_rule_id: Remove ALL workflow links - 3. Issue workflows will be re-linked in the next migration - """ - Monitor = apps.get_model("monitors", "Monitor") - Rule = apps.get_model("sentry", "Rule") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataSourceDetector = apps.get_model("workflow_engine", "DataSourceDetector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - - # Handle all monitors without alert_rule_id - they should have no workflows - unlink_monitors_without_alert_rules(apps) - - # Handle monitors with alert_rule_id based on their deduped workflows - rules_by_org = defaultdict(list) - for rule in Rule.objects.filter(source=1): - rules_by_org[rule.project.organization_id].append(rule) - - for organization_id, rules in rules_by_org.items(): - links = AlertRuleWorkflow.objects.filter(rule_id__in=[r.id for r in rules]).select_related( - "workflow" - ) - rule_workflows = {link.rule_id: link.workflow for link in links} - - # Process ALL rules, not just those with workflows - # Rules without workflows need to be mapped to the primary workflow of their hash group - if not rules: - continue - - rule_hashes = defaultdict(list) - for rule in rules: - data = deepcopy(rule.data) - for action in data.get("actions", []): - action.pop("uuid", None) - new_conditions = [] - for condition in data.get("conditions", []): - if ( - condition.get("id") == "sentry.rules.filters.tagged_event.TaggedEventFilter" - and condition.get("key") == "monitor.slug" - ): - continue - new_conditions.append(condition) - data["conditions"] = new_conditions - data["environment_id"] = rule.environment_id - data["owner_user_id"] = rule.owner_user_id - data["owner_team_id"] = rule.owner_team_id - rule_hashes[json.dumps(data, sort_keys=True)].append(rule.id) - - hash_to_workflow = {} - for rule_hash, rule_ids in rule_hashes.items(): - for rule_id in rule_ids: - if rule_id in rule_workflows: - hash_to_workflow[rule_hash] = rule_workflows[rule_id] - break - else: - logger.error( - "fix_cron_to_cron_workflow_links.no_workflow_for_rule_group", - extra={ - "organization_id": organization_id, - "rule_ids": rule_ids, - "rule_count": len(rule_ids), - }, - ) - - rule_to_primary_workflow = {} - for rule_hash, rule_ids in rule_hashes.items(): - if rule_hash in hash_to_workflow: - workflow = hash_to_workflow[rule_hash] - for rule_id in rule_ids: - rule_to_primary_workflow[rule_id] = workflow.id - else: - logger.error( - "fix_cron_to_cron_workflow_links.no_workflow_mapping", - extra={ - "organization_id": organization_id, - "rule_ids": rule_ids, - "rule_count": len(rule_ids), - }, - ) - - data_source_links = DataSourceDetector.objects.filter( - data_source__organization_id=organization_id, - data_source__type="cron_monitor", - ).select_related("data_source", "detector") - - monitor_id_to_detector = { - int(dsl.data_source.source_id): dsl.detector for dsl in data_source_links - } - - monitors = list(Monitor.objects.filter(organization_id=organization_id)) - for monitor in monitors: - # Skip monitors without alert_rule_id - they were already handled above - if "alert_rule_id" not in monitor.config: - continue - - if monitor.id not in monitor_id_to_detector: - logger.error( - "fix_cron_to_cron_workflow_links.monitor_missing_detector", - extra={ - "organization_id": organization_id, - "monitor_id": monitor.id, - }, - ) - continue - - detector = monitor_id_to_detector[monitor.id] - alert_rule_id = int(monitor.config["alert_rule_id"]) - - if alert_rule_id in rule_to_primary_workflow: - correct_workflow_id = rule_to_primary_workflow[alert_rule_id] - DetectorWorkflow.objects.filter(detector=detector).exclude( - workflow_id=correct_workflow_id - ).delete() - else: - logger.error( - "fix_cron_to_cron_workflow_links.monitor_rule_missing_workflow", - extra={ - "organization_id": organization_id, - "monitor_id": monitor.id, - "alert_rule_id": alert_rule_id, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0085_crons_link_detectors_to_all_workflows"), - ("monitors", "0010_delete_orphaned_detectors"), - ] - - operations = [ - migrations.RunPython( - fix_cron_to_cron_workflow_links, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detectorworkflow"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0087_relink_crons_to_compatible_issue_workflows.py b/src/sentry/workflow_engine/migrations/0087_relink_crons_to_compatible_issue_workflows.py deleted file mode 100644 index ba574cc84f75..000000000000 --- a/src/sentry/workflow_engine/migrations/0087_relink_crons_to_compatible_issue_workflows.py +++ /dev/null @@ -1,404 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-19 19:40 -import json # noqa: S003 -import logging -from collections import defaultdict -from dataclasses import dataclass, field -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps -from django.db.models import Prefetch - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - -# Conditions that we know work with cron monitor events -# Note: assigned_to is handled specially - only allowed if it matches monitor owner -ALLOWED_CONDITIONS = { - "first_seen_event", - "regression_event", - "reappeared_event", - "every_event", - "age_comparison", - "issue_priority_equals", - "issue_priority_greater_or_equal", - "issue_priority_deescalating", - "new_high_priority_issue", - "existing_high_priority_issue", -} -CRON_GROUP_CATEGORY = 4 - - -@dataclass(frozen=True) -class ConditionData: - """Represents a condition with its type, comparison, and result.""" - - type: str - comparison: dict[str, Any] - result: bool - - def to_dict(self) -> dict[str, Any]: - return { - "type": self.type, - "comparison": self.comparison, - "result": self.result, - } - - -@dataclass(frozen=True) -class ActionData: - """Represents an action with its type and config.""" - - type: str - config: dict[str, Any] - - def to_dict(self) -> dict[str, Any]: - return { - "type": self.type, - "config": self.config, - } - - -@dataclass(frozen=True) -class ActionGroupData: - """Represents an action group with its conditions and actions.""" - - conditions: tuple[ConditionData, ...] - actions: tuple[ActionData, ...] - - def to_dict(self) -> dict[str, Any]: - return { - "conditions": [c.to_dict() for c in self.conditions], - "actions": [a.to_dict() for a in self.actions], - } - - -@dataclass -class WorkflowData: - """Represents a workflow with all its conditions and actions.""" - - workflow: Any - project_id: int - environment_id: int | None - frequency: int | None - when_conditions: tuple[ConditionData, ...] = field(default_factory=tuple) - action_groups: tuple[ActionGroupData, ...] = field(default_factory=tuple) - - def is_compatible_for_monitor(self, monitor: Any) -> bool: - """Check if all conditions are compatible with cron events for this monitor.""" - for condition in self.when_conditions: - if not self._is_condition_compatible(condition, monitor): - return False - - for group in self.action_groups: - for condition in group.conditions: - if not self._is_condition_compatible(condition, monitor): - return False - - return True - - def _is_condition_compatible(self, condition: ConditionData, monitor: Any) -> bool: - """Check if a condition is compatible with cron events for this monitor.""" - if condition.type == "assigned_to": - target_type = condition.comparison.get("target_type") - target_identifier = condition.comparison.get("target_identifier") - - if target_type == "Team" and monitor.owner_team_id: - return target_identifier == monitor.owner_team_id - elif target_type == "Member" and monitor.owner_user_id: - return target_identifier == monitor.owner_user_id - elif target_type == "Unassigned": - # Unassigned is compatible if monitor has no owner - return monitor.owner_team_id is None and monitor.owner_user_id is None - else: - return False - if condition.type == "issue_category": - return condition.comparison.get("value") == CRON_GROUP_CATEGORY - - return condition.type in ALLOWED_CONDITIONS - - def get_hash(self) -> str: - """Get a unique hash for deduplication.""" - hash_data = { - "project_id": self.project_id, - "environment_id": self.environment_id, - "frequency": self.frequency, - "when_conditions": [ - c.to_dict() - for c in sorted( - self.when_conditions, - key=lambda c: (c.type, json.dumps(c.comparison, sort_keys=True)), - ) - ], - "action_groups": [ - { - "conditions": [ - c.to_dict() - for c in sorted( - g.conditions, - key=lambda c: (c.type, json.dumps(c.comparison, sort_keys=True)), - ) - ], - "actions": [ - a.to_dict() - for a in sorted( - g.actions, key=lambda a: (a.type, json.dumps(a.config, sort_keys=True)) - ) - ], - } - for g in sorted( - self.action_groups, key=lambda g: json.dumps(g.to_dict(), sort_keys=True) - ) - ], - } - return json.dumps(hash_data, sort_keys=True) - - -def build_workflow_data( - workflow: Any, - rule_id: int, - rules_by_id: dict[int, Any], - when_conditions: list[Any], - action_groups_data: list[tuple[list[Any], list[Any]]], -) -> WorkflowData | None: - """Build a WorkflowData object from a workflow and its related data.""" - rule = rules_by_id.get(rule_id) - if not rule: - return None - when_condition_list = [] - for condition in when_conditions: - when_condition_list.append( - ConditionData( - type=condition.type, - comparison=condition.comparison, - result=condition.condition_result, - ) - ) - action_group_list = [] - for group_conditions, group_actions in action_groups_data: - conditions = tuple( - ConditionData( - type=c.type, - comparison=c.comparison, - result=c.condition_result, - ) - for c in group_conditions - ) - actions = tuple( - ActionData( - type=a.type, - config=a.config, - ) - for a in group_actions - ) - action_group_list.append(ActionGroupData(conditions=conditions, actions=actions)) - - return WorkflowData( - workflow=workflow, - project_id=rule.project_id, - environment_id=workflow.environment_id, - frequency=rule.data.get("frequency", 30), - when_conditions=tuple(when_condition_list), - action_groups=tuple(action_group_list), - ) - - -def link_crons_to_compatible_issue_workflows( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Re-link cron detectors to compatible issue workflows after migration 0086. - - This migration: - 1. Filters issue workflows to only those with compatible conditions for cron events - 2. Deduplicates workflows with identical conditions and actions - 3. Links cron detectors to the unique, compatible workflows - 4. For assigned_to conditions, only allows them if they match the monitor's owner - """ - Detector = apps.get_model("workflow_engine", "Detector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - Workflow = apps.get_model("workflow_engine", "Workflow") - Rule = apps.get_model("sentry", "Rule") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - WorkflowDataConditionGroup = apps.get_model("workflow_engine", "WorkflowDataConditionGroup") - DataConditionGroupAction = apps.get_model("workflow_engine", "DataConditionGroupAction") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - DataSourceDetector = apps.get_model("workflow_engine", "DataSourceDetector") - Monitor = apps.get_model("monitors", "Monitor") - - cron_detectors_all = Detector.objects.filter(type="monitor_check_in_failure") - detectors_by_project = defaultdict(list) - for detector in cron_detectors_all: - detectors_by_project[detector.project_id].append(detector) - - if not detectors_by_project: - logger.info("No cron detectors found, skipping migration") - return - - data_source_detectors = DataSourceDetector.objects.filter( - detector__type="monitor_check_in_failure", data_source__type="cron_monitor" - ).select_related("data_source") - - detector_to_monitor_id = {} - for dsd in data_source_detectors: - detector_to_monitor_id[dsd.detector_id] = int(dsd.data_source.source_id) - - monitors_by_id = {m.id: m for m in Monitor.objects.all()} - - total_links_created = 0 - total_projects_processed = 0 - - for project_id, cron_detectors in detectors_by_project.items(): - project_rules = list(Rule.objects.filter(project_id=project_id, source=0)) - if not project_rules: - continue - - rule_ids = [r.id for r in project_rules] - rules_by_id = {r.id: r for r in project_rules} - - issue_workflows = list( - Workflow.objects.filter(alertruleworkflow__rule_id__in=rule_ids) - .select_related("when_condition_group") - .prefetch_related( - Prefetch( - "when_condition_group__conditions", - queryset=DataCondition.objects.all(), - to_attr="prefetched_when_conditions", - ), - Prefetch( - "workflowdataconditiongroup_set", - queryset=WorkflowDataConditionGroup.objects.select_related( - "condition_group" - ).prefetch_related( - Prefetch( - "condition_group__conditions", - queryset=DataCondition.objects.all(), - to_attr="prefetched_conditions", - ), - Prefetch( - "condition_group__dataconditiongroupaction_set", - queryset=DataConditionGroupAction.objects.select_related("action"), - to_attr="prefetched_actions", - ), - ), - to_attr="prefetched_action_groups", - ), - Prefetch( - "alertruleworkflow_set", - queryset=AlertRuleWorkflow.objects.all(), - to_attr="prefetched_rule_workflows", - ), - ) - .distinct() - ) - - if not issue_workflows: - continue - - workflow_data_list = [] - for workflow in issue_workflows: - if not workflow.prefetched_rule_workflows: - continue - rule_workflow = workflow.prefetched_rule_workflows[0] - - when_conditions = [] - if workflow.when_condition_group: - when_conditions = workflow.when_condition_group.prefetched_when_conditions - - action_groups_data = [] - for wdcg in workflow.prefetched_action_groups: - group_conditions = wdcg.condition_group.prefetched_conditions - group_actions = [ga.action for ga in wdcg.condition_group.prefetched_actions] - action_groups_data.append((group_conditions, group_actions)) - - workflow_data = build_workflow_data( - workflow, rule_workflow.rule_id, rules_by_id, when_conditions, action_groups_data - ) - if workflow_data: - workflow_data_list.append(workflow_data) - - if not workflow_data_list: - continue - - # Link cron detectors to compatible workflows in this project - project_links_created = 0 - for detector in cron_detectors: - monitor_id = detector_to_monitor_id.get(detector.id) - if not monitor_id: - continue - - monitor = monitors_by_id.get(monitor_id) - if not monitor: - continue - - compatible_workflows = [] - for wd in workflow_data_list: - if wd.is_compatible_for_monitor(monitor): - compatible_workflows.append(wd) - - hash_to_workflow_data = {} - for wd in compatible_workflows: - workflow_hash = wd.get_hash() - if workflow_hash not in hash_to_workflow_data: - hash_to_workflow_data[workflow_hash] = wd - - for wd in hash_to_workflow_data.values(): - _, created = DetectorWorkflow.objects.get_or_create( - detector=detector, - workflow=wd.workflow, - ) - if created: - project_links_created += 1 - - if project_links_created > 0: - logger.info( - "Processed project", - extra={ - "project_id": project_id, - "links_created": project_links_created, - "total_workflows": len(workflow_data_list), - "cron_detectors": len(cron_detectors), - }, - ) - - total_links_created += project_links_created - total_projects_processed += 1 - - logger.info( - "Migration complete", - extra={ - "total_links_created": total_links_created, - "projects_processed": total_projects_processed, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0086_fix_cron_to_cron_workflow_links"), - ("monitors", "0009_backfill_monitor_detectors"), - ] - - operations = [ - migrations.RunPython( - link_crons_to_compatible_issue_workflows, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_detectorworkflow"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0088_remove_monitor_slug_conditions.py b/src/sentry/workflow_engine/migrations/0088_remove_monitor_slug_conditions.py deleted file mode 100644 index 1b3e34874945..000000000000 --- a/src/sentry/workflow_engine/migrations/0088_remove_monitor_slug_conditions.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 5.2.1 -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - - -def remove_monitor_slug_conditions( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Remove monitor.slug conditions from DataCondition table. - - These are tagged_event conditions with comparison like {"key":"monitor.slug","match":"eq","value":"..."} - that were used to filter events by monitor but are no longer needed after deduplication. - """ - DataCondition = apps.get_model("workflow_engine", "DataCondition") - - tagged_event_conditions = DataCondition.objects.filter(type="tagged_event") - - deleted_count = 0 - for condition in tagged_event_conditions: - comparison = condition.comparison - if isinstance(comparison, dict) and comparison.get("key") == "monitor.slug": - condition.delete() - deleted_count += 1 - - if deleted_count > 0: - logger.info( - "Removed monitor.slug tagged_event conditions", - extra={ - "deleted_count": deleted_count, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0087_relink_crons_to_compatible_issue_workflows"), - ] - - operations = [ - migrations.RunPython( - remove_monitor_slug_conditions, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_datacondition"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0089_update_cron_workflow_names.py b/src/sentry/workflow_engine/migrations/0089_update_cron_workflow_names.py deleted file mode 100644 index 960bf9ea5645..000000000000 --- a/src/sentry/workflow_engine/migrations/0089_update_cron_workflow_names.py +++ /dev/null @@ -1,177 +0,0 @@ -# Generated by Django 5.2.1 -import logging -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - -MAX_ACTIONS = 3 - -ACTION_TYPE_TO_STRING = { - "discord": "Discord", - "email": "Email", - "github": "GitHub", - "github_enterprise": "GitHub Enterprise", - "jira": "Jira", - "jira_server": "Jira Server", - "msteams": "Microsoft Teams", - "opsgenie": "Opsgenie", - "pagerduty": "PagerDuty", - "plugin": "Plugin", - "sentry_app": "Sentry App", - "slack": "Slack", - "vsts": "Azure DevOps", # Action.Type.AZURE_DEVOPS = "vsts" - "webhook": "Webhook", -} - - -def get_action_description(action: Any) -> str: - """ - Returns a human readable action description based on the action type and config - """ - action_type = action.type - if action_type == "email": - config = action.config or {} - target_type = config.get("target_type") - - if target_type == 4: # ISSUE_OWNERS - return "Email Issue Owners" - elif target_type == 2: # TEAM - target_identifier = config.get("target_identifier") - return "Email Team" if not target_identifier else f"Email Team #{target_identifier}" - elif target_type == 1: # USER - target_identifier = config.get("target_identifier") - return "Email Member" if not target_identifier else f"Email Member #{target_identifier}" - else: - return "Email" - - if action_type == "sentry_app": - config = action.config or {} - target_display = config.get("target_display") - if target_display: - return f"Notify {target_display}" - return "Sentry App" - - if action_type in ACTION_TYPE_TO_STRING: - config = action.config or {} - if action_type in ["slack", "discord", "msteams"]: - target_display = config.get("target_display") - if target_display: - return f"{ACTION_TYPE_TO_STRING[action_type]} {target_display}" - - return ACTION_TYPE_TO_STRING[action_type] - - return action_type.replace("_", " ").title() - - -def generate_workflow_name_from_actions(actions: list[Any]) -> str: - """ - Generate a workflow name based on actions like: - 'Notify: Slack #alerts, Email Issue Owners...(+3)' - """ - if not actions: - return "Notify: Workflow" - - name_parts = [] - action_count = 0 - - for action in actions[:MAX_ACTIONS]: - description = get_action_description(action) - name_parts.append(description) - action_count += 1 - - if len(actions) > MAX_ACTIONS: - remaining = len(actions) - MAX_ACTIONS - name = ", ".join(name_parts) - name += f"...(+{remaining})" - else: - name = ", ".join(name_parts) - - return f"Notify: {name}" - - -def update_cron_workflow_names(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - """ - Update workflow names for cron-linked workflows after deduplication. - - Since workflows have been deduplicated, the monitor-specific names like - "Monitor Alert: monitor-name" no longer make sense. Update them to be - based on the actions in the workflow. - """ - Workflow = apps.get_model("workflow_engine", "Workflow") - Action = apps.get_model("workflow_engine", "Action") - - cron_workflows = list( - Workflow.objects.filter( - detectorworkflow__detector__type="monitor_check_in_failure" - ).distinct() - ) - - if not cron_workflows: - logger.info("No workflows linked to cron detectors, skipping workflow name updates") - return - - workflows_updated = 0 - - for workflow in cron_workflows: - try: - if not workflow.name or not workflow.name.startswith("Monitor Alert:"): - continue - - all_actions = list( - Action.objects.filter( - dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow_id=workflow.id - ) - .distinct() - .order_by("id") - ) - - if all_actions: - new_name = generate_workflow_name_from_actions(all_actions) - if new_name != workflow.name: - workflow.name = new_name - workflow.save(update_fields=["name"]) - workflows_updated += 1 - except Exception: - logger.exception("Failed to update workflow name") - - logger.info( - "Updated workflow names", - extra={ - "workflows_updated": workflows_updated, - "total_cron_workflows": len(cron_workflows), - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0088_remove_monitor_slug_conditions"), - ] - - operations = [ - migrations.RunPython( - update_cron_workflow_names, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_workflow", "workflow_engine_datacondition"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0090_add_detectorgroup_detector_date_index.py b/src/sentry/workflow_engine/migrations/0090_add_detectorgroup_detector_date_index.py deleted file mode 100644 index 272bbfb1b8ba..000000000000 --- a/src/sentry/workflow_engine/migrations/0090_add_detectorgroup_detector_date_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-29 19:59 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "0992_latestrepoerelease_indexes"), - ("workflow_engine", "0089_update_cron_workflow_names"), - ] - - operations = [ - migrations.AddIndex( - model_name="detectorgroup", - index=models.Index( - fields=["detector", "-date_added"], name="detectorgroup_det_date_idx" - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0091_fix_email_notification_names.py b/src/sentry/workflow_engine/migrations/0091_fix_email_notification_names.py deleted file mode 100644 index 7a7ff985d22f..000000000000 --- a/src/sentry/workflow_engine/migrations/0091_fix_email_notification_names.py +++ /dev/null @@ -1,194 +0,0 @@ -# Generated by Django 5.2.1 on 2025-09-29 20:28 -import logging -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration - -logger = logging.getLogger(__name__) - -MAX_ACTIONS = 3 - - -ACTION_TYPE_TO_STRING = { - "discord": "Discord", - "email": "Email", - "github": "GitHub", - "github_enterprise": "GitHub Enterprise", - "jira": "Jira", - "jira_server": "Jira Server", - "msteams": "Microsoft Teams", - "opsgenie": "Opsgenie", - "pagerduty": "PagerDuty", - "plugin": "Plugin", - "sentry_app": "Sentry App", - "slack": "Slack", - "vsts": "Azure DevOps", - "webhook": "Webhook", -} - - -def get_action_description(action: Any, apps: StateApps) -> str: - """ - Returns a human readable action description based on the action type and config. - Fixed version that looks up actual team/user names instead of using IDs. - """ - action_type = action.type - if action_type == "email": - config = action.config or {} - target_type = config.get("target_type") - - if target_type == 4: # ISSUE_OWNERS - return "Email Issue Owners" - elif target_type == 2: # TEAM - target_identifier = config.get("target_identifier") - if target_identifier: - Team = apps.get_model("sentry", "Team") - try: - team = Team.objects.get(id=target_identifier) - return f"Email {team.name}" - except Team.DoesNotExist: - pass - return "Email Team" - elif target_type == 1: # USER - target_identifier = config.get("target_identifier") - if target_identifier: - User = apps.get_model("sentry", "User") - try: - user = User.objects.get(id=target_identifier) - display_name = user.email or user.username or f"User #{target_identifier}" - return f"Email {display_name}" - except User.DoesNotExist: - pass - return "Email Member" - else: - return "Email" - - if action_type == "sentry_app": - config = action.config or {} - target_display = config.get("target_display") - if target_display: - return f"Notify {target_display}" - return "Sentry App" - - if action_type in ACTION_TYPE_TO_STRING: - config = action.config or {} - if action_type in ["slack", "discord", "msteams"]: - target_display = config.get("target_display") - if target_display: - return f"{ACTION_TYPE_TO_STRING[action_type]} {target_display}" - - return ACTION_TYPE_TO_STRING[action_type] - - return action_type.replace("_", " ").title() - - -def generate_workflow_name_from_actions(actions: list[Any], apps: StateApps) -> str: - """ - Generate a workflow name based on actions like: - 'Notify: Email Team Name, Email Issue Owners...(+3)' - """ - if not actions: - return "Notify: Workflow" - - name_parts = [] - action_count = 0 - - for action in actions[:MAX_ACTIONS]: - description = get_action_description(action, apps) - name_parts.append(description) - action_count += 1 - - if len(actions) > MAX_ACTIONS: - remaining = len(actions) - MAX_ACTIONS - name = ", ".join(name_parts) - name += f"...(+{remaining})" - else: - name = ", ".join(name_parts) - - return f"Notify: {name}" - - -def fix_email_notification_names(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - """ - Fix workflow names that use team/user IDs instead of actual names. - Changes "Notify: Email Team #1347487" to "Notify: Email Team Name" - and "Notify: Email Member #2453577" to "Notify: Email user@email.com" - """ - Workflow = apps.get_model("workflow_engine", "Workflow") - Action = apps.get_model("workflow_engine", "Action") - - cron_workflows = list( - Workflow.objects.filter( - detectorworkflow__detector__type="monitor_check_in_failure" - ).distinct() - ) - - if not cron_workflows: - logger.info("No workflows linked to cron detectors, skipping fix") - return - - workflows_updated = 0 - - for workflow in cron_workflows: - if not workflow.name or not workflow.name.startswith("Notify: "): - continue - - if "Email Team #" not in workflow.name and "Email Member #" not in workflow.name: - continue - try: - all_actions = list( - Action.objects.filter( - dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow_id=workflow.id - ) - .distinct() - .order_by("id") - ) - - if all_actions: - new_name = generate_workflow_name_from_actions(all_actions, apps) - if new_name != workflow.name: - workflow.name = new_name - workflow.save(update_fields=["name"]) - workflows_updated += 1 - except Exception: - logger.exception("Failed to update workflow name") - - logger.info( - "Fixed email notification names", - extra={ - "workflows_updated": workflows_updated, - "total_cron_workflows": len(cron_workflows), - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0090_add_detectorgroup_detector_date_index"), - ] - - operations = [ - migrations.RunPython( - fix_email_notification_names, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_workflow", "workflow_engine_action"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0092_repair_workflow_cron_conditions.py b/src/sentry/workflow_engine/migrations/0092_repair_workflow_cron_conditions.py deleted file mode 100644 index 64b79c786d97..000000000000 --- a/src/sentry/workflow_engine/migrations/0092_repair_workflow_cron_conditions.py +++ /dev/null @@ -1,105 +0,0 @@ -# Generated by Django 5.2.1 -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -def repair_workflow_cron_conditions( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Add back the monitor.slug condition to workflows not connected to cron detectors. - """ - - Rule = apps.get_model("sentry", "Rule") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - Workflow = apps.get_model("workflow_engine", "Workflow") - DataCondition = apps.get_model("workflow_engine", "DataCondition") - WorkflowDataConditionGroup = apps.get_model("workflow_engine", "WorkflowDataConditionGroup") - - updated_rules = 0 - for rule in RangeQuerySetWrapper(Rule.objects.filter(source=0)): # RuleSource.ISSUE - conditions = rule.data.get("conditions", []) - data_conditions_to_create = [] - for condition in conditions: - if ( - condition["id"] == "sentry.rules.filters.tagged_event.TaggedEventFilter" - and condition.get("key") == "monitor.slug" - ): - data_conditions_to_create.append( - { - "key": "monitor.slug", - "match": condition["match"], - "value": condition["value"], - } - ) - - if data_conditions_to_create: - # find Workflow and WorkflowDataConditionGroup - alert_rule_workflow = AlertRuleWorkflow.objects.filter(rule_id=rule.id).first() - if not alert_rule_workflow: - logger.info( - "No AlertRuleWorkflow found for rule, skipping", - extra={"rule_id": rule.id}, - ) - continue - workflow = Workflow.objects.get(id=alert_rule_workflow.workflow_id) - data_condition_group = WorkflowDataConditionGroup.objects.get( - workflow_id=workflow.id - ).condition_group - for comparison in data_conditions_to_create: - DataCondition.objects.create( - type="tagged_event", - comparison=comparison, - condition_result=True, - condition_group_id=data_condition_group.id, - ) - updated_rules += 1 - - logger.info( - "Updated rules", - extra={ - "rules_updated": updated_rules, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0091_fix_email_notification_names"), - ] - - operations = [ - migrations.RunPython( - repair_workflow_cron_conditions, - migrations.RunPython.noop, - hints={ - "tables": [ - "workflow_engine_workflow", - "sentry_rule", - "workflow_engine_datacondition", - ] - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0093_add_action_config_index.py b/src/sentry/workflow_engine/migrations/0093_add_action_config_index.py deleted file mode 100644 index 267bac3e0748..000000000000 --- a/src/sentry/workflow_engine/migrations/0093_add_action_config_index.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-10-02 22:55 - -import django.db.models.expressions -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("workflow_engine", "0092_repair_workflow_cron_conditions"), - ] - - operations = [ - migrations.AddIndex( - model_name="action", - index=models.Index( - models.F("type"), - django.db.models.expressions.RawSQL("config->>'sentry_app_identifier'", []), - django.db.models.expressions.RawSQL("config->>'target_identifier'", []), - condition=models.Q(("type", "sentry_app")), - name="action_sentry_app_lookup", - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0094_backfill_issue_stream_detector_workflows.py b/src/sentry/workflow_engine/migrations/0094_backfill_issue_stream_detector_workflows.py deleted file mode 100644 index e2e4cc118351..000000000000 --- a/src/sentry/workflow_engine/migrations/0094_backfill_issue_stream_detector_workflows.py +++ /dev/null @@ -1,98 +0,0 @@ -# Generated by Django 5.2.1 -import logging - -from django.conf import settings -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils import redis -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - -ISSUE_STREAM_DETECTOR_NAME = "Issue Stream" - - -def backfill_issue_stream_detector_workflows( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Backfill issue stream detectors and connecting them to the error detector's workflows. - """ - Detector = apps.get_model("workflow_engine", "Detector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - - backfill_key = "backfill_issue_stream_detector_workflows" - redis_client = redis.redis_clusters.get(settings.SENTRY_MONITORS_REDIS_CLUSTER) - - progress_id = int(redis_client.get(backfill_key) or 0) - - error_detectors = Detector.objects.filter(type="error", id__gt=progress_id).prefetch_related( - "detectorworkflow_set" - ) - - count = 0 - for error_detector in RangeQuerySetWrapper(error_detectors): - issue_stream_detector, _ = Detector.objects.get_or_create( - type="issue_stream", - project_id=error_detector.project_id, - defaults={"config": {}, "name": ISSUE_STREAM_DETECTOR_NAME}, - ) - detector_workflows = error_detector.detectorworkflow_set.all() - DetectorWorkflow.objects.bulk_create( - [ - DetectorWorkflow( - detector_id=issue_stream_detector.id, workflow_id=detector_workflow.workflow_id - ) - for detector_workflow in detector_workflows - ], - ignore_conflicts=True, - ) - redis_client.set(backfill_key, error_detector.id, ex=60 * 60 * 24 * 7) - - count += 1 - - if count % 1000 == 0: - logger.info( - "Progress update", - extra={ - "count": count, - "current_detector_id": error_detector.id, - }, - ) - redis_client.set(backfill_key, error_detector.id, ex=60 * 60 * 24 * 7) - - -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 = True - - dependencies = [ - ("workflow_engine", "0093_add_action_config_index"), - ] - - operations = [ - migrations.RunPython( - backfill_issue_stream_detector_workflows, - migrations.RunPython.noop, - hints={ - "tables": [ - "workflow_engine_detector", - "workflow_engine_detectorworkflow", - ] - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0095_unique_detectorgroup_group.py b/src/sentry/workflow_engine/migrations/0095_unique_detectorgroup_group.py deleted file mode 100644 index 9f567d7b6f30..000000000000 --- a/src/sentry/workflow_engine/migrations/0095_unique_detectorgroup_group.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-10 23:25 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1003_group_history_prev_history_safe_removal"), - ("workflow_engine", "0094_backfill_issue_stream_detector_workflows"), - ] - - operations = [ - migrations.AlterUniqueTogether( - name="detectorgroup", - unique_together={("detector", "group"), ("group",)}, - ), - migrations.AlterUniqueTogether( - name="detectorgroup", - unique_together={("group",)}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0096_delete_non_single_written_fire_history.py b/src/sentry/workflow_engine/migrations/0096_delete_non_single_written_fire_history.py deleted file mode 100644 index ab2afe051f96..000000000000 --- a/src/sentry/workflow_engine/migrations/0096_delete_non_single_written_fire_history.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 5.2.1 on 2025-01-13 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import bulk_delete_objects - -logger = logging.getLogger(__name__) - - -def delete_non_single_written_fire_history( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - WorkflowFireHistory = apps.get_model("workflow_engine", "WorkflowFireHistory") - while bulk_delete_objects(WorkflowFireHistory, logger=logger, is_single_written=False): - pass - - -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 = True - - dependencies = [ - ("workflow_engine", "0095_unique_detectorgroup_group"), - ] - - operations = [ - migrations.RunPython( - code=delete_non_single_written_fire_history, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_workflowfirehistory"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0097_add_unique_constraint_to_datasource.py b/src/sentry/workflow_engine/migrations/0097_add_unique_constraint_to_datasource.py deleted file mode 100644 index 0f4063cb9159..000000000000 --- a/src/sentry/workflow_engine/migrations/0097_add_unique_constraint_to_datasource.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-13 18:53 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1003_group_history_prev_history_safe_removal"), - ("workflow_engine", "0096_delete_non_single_written_fire_history"), - ] - - operations = [ - migrations.AddConstraint( - model_name="datasource", - constraint=models.UniqueConstraint( - fields=("type", "source_id"), name="unique_type_source_id" - ), - ), - migrations.RemoveIndex( - model_name="datasource", - name="workflow_en_type_66eafc_idx", - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0098_detectorgroup_detector_set_null.py b/src/sentry/workflow_engine/migrations/0098_detectorgroup_detector_set_null.py deleted file mode 100644 index a446a4160978..000000000000 --- a/src/sentry/workflow_engine/migrations/0098_detectorgroup_detector_set_null.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.1 on 2025-11-13 23:59 - -import django.db.models.deletion -from django.db import migrations - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = [ - ("workflow_engine", "0097_add_unique_constraint_to_datasource"), - ] - - operations = [ - migrations.AlterField( - model_name="detectorgroup", - name="detector", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="workflow_engine.detector", - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0099_backfill_metric_issue_detectorgroup.py b/src/sentry/workflow_engine/migrations/0099_backfill_metric_issue_detectorgroup.py deleted file mode 100644 index 6ef66917d4dd..000000000000 --- a/src/sentry/workflow_engine/migrations/0099_backfill_metric_issue_detectorgroup.py +++ /dev/null @@ -1,163 +0,0 @@ -# Generated by Django 5.2.1 -import logging -from collections.abc import Sequence -from datetime import datetime -from enum import Enum -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps -from snuba_sdk import Column, Condition, Op - -from sentry import eventstore -from sentry.new_migrations.migrations import CheckedMigration -from sentry.snuba.dataset import Dataset - -logger = logging.getLogger(__name__) - - -class EventOrdering(Enum): - LATEST = ["project_id", "-timestamp", "-event_id"] - OLDEST = ["project_id", "timestamp", "event_id"] - RECOMMENDED = [ - "-replay.id", - "-trace.sampled", - "num_processing_errors", - "-profile.id", - "-timestamp", - "-event_id", - ] - - -def get_oldest_or_latest_event( - group: Any, - ordering: EventOrdering, - conditions: Sequence[Condition] | None = None, - start: datetime | None = None, - end: datetime | None = None, -) -> Any: - dataset = Dataset.IssuePlatform - - all_conditions = [ - Condition(Column("project_id"), Op.IN, [group.project.id]), - Condition(Column("group_id"), Op.IN, [group.id]), - ] - - if conditions: - all_conditions.extend(conditions) - - events = eventstore.backend.get_events_snql( - organization_id=group.project.organization_id, - group_id=group.id, - start=start, - end=end, - conditions=all_conditions, - limit=1, - orderby=ordering.value, - referrer="Group.get_latest", - dataset=dataset, - tenant_ids={"organization_id": group.project.organization_id}, - ) - - if events: - return events[0].for_group(group) - - return None - - -def backfill_metric_issue_detectorgroup( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Backfill the DetectorGroup table for metric issues. - """ - Group = apps.get_model("sentry", "Group") - DetectorGroup = apps.get_model("workflow_engine", "DetectorGroup") - Detector = apps.get_model("workflow_engine", "Detector") - - for group in Group.objects.filter(type=8001, detectorgroup__isnull=True).select_related( - "project" - ): # metric issues - # figure out the detector - latest_event = get_oldest_or_latest_event(group, EventOrdering.LATEST) - if not latest_event: - DetectorGroup.objects.create( - group_id=group.id, - detector_id=None, - ) - logger.info( - "No latest event found for group, creating DetectorGroup with null detector", - extra={"group_id": group.id}, - ) - continue - - occurrence = latest_event.occurrence - if not occurrence: - logger.info( - "No occurrence found for latest event", extra={"event_id": latest_event.event_id} - ) - continue - - detector_id = occurrence.evidence_data.get("detector_id") - if detector_id is None: - logger.info( - "No detector id found for occurrence", extra={"occurrence_id": occurrence.id} - ) - continue - - # try to fetch detector - detector = Detector.objects.filter(id=detector_id).first() - if detector is None: - DetectorGroup.objects.create( - group_id=group.id, - detector_id=None, - ) - logger.info( - "Creating DetectorGroup with null detector", - extra={"group_id": group.id, "detector_id": detector_id}, - ) - continue - - DetectorGroup.objects.create( - group_id=group.id, - detector_id=detector.id, - ) - logger.info( - "Creating DetectorGroup", - extra={"group_id": group.id, "detector_id": detector_id}, - ) - - -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 = True - - dependencies = [ - ("sentry", "1003_group_history_prev_history_safe_removal"), - ("workflow_engine", "0098_detectorgroup_detector_set_null"), - ] - - operations = [ - migrations.RunPython( - backfill_metric_issue_detectorgroup, - migrations.RunPython.noop, - hints={ - "tables": [ - "workflow_engine_detectorgroup", - "sentry_groupedmessage", - ] - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0100_move_is_single_written_to_pending.py b/src/sentry/workflow_engine/migrations/0100_move_is_single_written_to_pending.py deleted file mode 100644 index ee0a206c8b6f..000000000000 --- a/src/sentry/workflow_engine/migrations/0100_move_is_single_written_to_pending.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 18:22 - -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 = [ - ("workflow_engine", "0099_backfill_metric_issue_detectorgroup"), - ] - - operations = [ - SafeRemoveField( - model_name="workflowfirehistory", - name="is_single_written", - deletion_action=DeletionAction.MOVE_TO_PENDING, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0101_remove_is_single_written_field.py b/src/sentry/workflow_engine/migrations/0101_remove_is_single_written_field.py deleted file mode 100644 index 3813d48080c0..000000000000 --- a/src/sentry/workflow_engine/migrations/0101_remove_is_single_written_field.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 19:25 - -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 = [ - ("workflow_engine", "0100_move_is_single_written_to_pending"), - ] - - operations = [ - SafeRemoveField( - model_name="workflowfirehistory", - name="is_single_written", - deletion_action=DeletionAction.DELETE, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0102_cleanup_failed_safe_deletes.py b/src/sentry/workflow_engine/migrations/0102_cleanup_failed_safe_deletes.py deleted file mode 100644 index 58ba3939373d..000000000000 --- a/src/sentry/workflow_engine/migrations/0102_cleanup_failed_safe_deletes.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 00:38 - -from django.db import migrations - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.new_migrations.monkey.special import SafeRunSQL - - -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 = [ - ("workflow_engine", "0101_remove_is_single_written_field"), - ] - - operations = [ - # Clean up table that may not have been deleted due to missing - # historical_silo_assignments entry before the fix - SafeRunSQL( - sql="DROP TABLE IF EXISTS workflow_engine_actiongroupstatus CASCADE;", - reverse_sql=migrations.RunSQL.noop, - hints={"tables": ["workflow_engine_actiongroupstatus"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0103_add_unique_constraint.py b/src/sentry/workflow_engine/migrations/0103_add_unique_constraint.py deleted file mode 100644 index f02bb1e572f9..000000000000 --- a/src/sentry/workflow_engine/migrations/0103_add_unique_constraint.py +++ /dev/null @@ -1,76 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-20 21:39 - -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1007_cleanup_failed_safe_deletes"), - ("workflow_engine", "0102_cleanup_failed_safe_deletes"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - # First add the unique constraint (creates a unique index) - migrations.AddConstraint( - model_name="workflow", - constraint=models.UniqueConstraint( - fields=("when_condition_group_id",), - name="workflow_engine_workflow_when_condition_group_id_11d9ba05_uniq", - ), - ), - # Then drop the old regular index (db_index=False) - migrations.AlterField( - model_name="workflow", - name="when_condition_group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - db_index=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.dataconditiongroup", - ), - ), - ], - state_operations=[ - # Update Django's state to reflect the final model state - migrations.AlterField( - model_name="workflow", - name="when_condition_group", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - db_index=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="workflow_engine.dataconditiongroup", - ), - ), - migrations.AddConstraint( - model_name="workflow", - constraint=models.UniqueConstraint( - fields=("when_condition_group_id",), - name="workflow_engine_workflow_when_condition_group_id_11d9ba05_uniq", - ), - ), - ], - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0104_action_data_fallthrough_type.py b/src/sentry/workflow_engine/migrations/0104_action_data_fallthrough_type.py deleted file mode 100644 index 1ae640319f29..000000000000 --- a/src/sentry/workflow_engine/migrations/0104_action_data_fallthrough_type.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-24 19:57 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -def migrate_fallthrough_type(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: - Action = apps.get_model("workflow_engine", "Action") - count = 0 - for action in RangeQuerySetWrapper(Action.objects.filter(type="email")): - if "fallthroughType" in action.data: - new_data = action.data.copy() - del new_data["fallthroughType"] - new_data["fallthrough_type"] = action.data["fallthroughType"] - action.data = new_data - action.save() - count += 1 - if count % 1000 == 0: - logger.info( - "Progress update", - extra={ - "count": count, - "current_action_id": action.id, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0103_add_unique_constraint"), - ] - - operations = [ - migrations.RunPython( - code=migrate_fallthrough_type, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_action"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0105_add_incident_identifer_index.py b/src/sentry/workflow_engine/migrations/0105_add_incident_identifer_index.py deleted file mode 100644 index e0120afb311d..000000000000 --- a/src/sentry/workflow_engine/migrations/0105_add_incident_identifer_index.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-09 23:47 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("sentry", "1016_remove_on_command_phrase_trigger"), - ("workflow_engine", "0104_action_data_fallthrough_type"), - ] - - operations = [ - migrations.AddIndex( - model_name="incidentgroupopenperiod", - index=models.Index( - fields=["incident_identifier"], name="workflow_en_inciden_2450f4_idx" - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0106_migrate_actions_sentry_app_data.py b/src/sentry/workflow_engine/migrations/0106_migrate_actions_sentry_app_data.py deleted file mode 100644 index acaa3d0340db..000000000000 --- a/src/sentry/workflow_engine/migrations/0106_migrate_actions_sentry_app_data.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-28 21:26 - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - - -def migrate_action_sentry_app_data( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Action = apps.get_model("workflow_engine", "Action") - RegionOutbox = apps.get_model("sentry", "RegionOutbox") - - for action in RangeQuerySetWrapper( - Action.objects.filter( - type="sentry_app", config__sentry_app_identifier="sentry_app_installation_uuid" - ) - ): - RegionOutbox( - shard_scope=12, # OutboxScope.ACTION_SCOPE - shard_identifier=action.id, - object_identifier=action.id, - category=44, # OutboxCategory.SENTRY_APP_NORMALIZE_ACTIONS - ).save() - - -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 = True - - dependencies = [ - ("workflow_engine", "0105_add_incident_identifer_index"), - ] - - operations = [ - migrations.RunPython( - code=migrate_action_sentry_app_data, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_action"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0107_fix_email_action_fallthrough_type.py b/src/sentry/workflow_engine/migrations/0107_fix_email_action_fallthrough_type.py deleted file mode 100644 index a3e5febadf92..000000000000 --- a/src/sentry/workflow_engine/migrations/0107_fix_email_action_fallthrough_type.py +++ /dev/null @@ -1,231 +0,0 @@ -# Generated by Django 5.2.8 on 2026-01-22 18:25 - -import logging -from typing import Any - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - -EMAIL_ACTION_REGISTRY_ID = "sentry.mail.actions.NotifyEmailAction" - -# Target type mappings (from ActionTarget enum) -TARGET_TYPE_USER = 1 -TARGET_TYPE_TEAM = 2 -TARGET_TYPE_ISSUE_OWNERS = 4 - -# Maps Rule action targetType string to Action config target_type int -TARGET_TYPE_STRING_TO_INT = { - "Member": TARGET_TYPE_USER, - "Team": TARGET_TYPE_TEAM, - "IssueOwners": TARGET_TYPE_ISSUE_OWNERS, -} - -DEFAULT_FALLTHROUGH_TYPE = "ActiveMembers" - - -def translate_email_action(rule_action: dict[str, Any]) -> dict[str, Any]: - """ - Translate a Rule email action blob to Action model fields. - Returns dict with: data, config, integration_id - """ - target_type_str = rule_action.get("targetType") - if not target_type_str: - raise ValueError("targetType is required for email actions") - - target_type_int = TARGET_TYPE_STRING_TO_INT.get(target_type_str) - if target_type_int is None: - raise ValueError(f"Unknown targetType: {target_type_str}") - - # Build config - config: dict[str, Any] = { - "target_type": target_type_int, - "target_display": None, - } - - # target_identifier is only set for Member/Team, not IssueOwners - if target_type_str in ("Member", "Team"): - target_identifier = rule_action.get("targetIdentifier") - config["target_identifier"] = str(target_identifier) if target_identifier else str(None) - else: - config["target_identifier"] = None - - # Build data - only IssueOwners has fallthrough_type - data: dict[str, Any] = {} - if target_type_str == "IssueOwners": - # Check both possible keys for fallthrough type - fallthrough_type = rule_action.get("fallthrough_type") - if fallthrough_type is None: - fallthrough_type = rule_action.get("fallthroughType", DEFAULT_FALLTHROUGH_TYPE) - data["fallthrough_type"] = str(fallthrough_type) - - return { - "data": data, - "config": config, - "integration_id": None, # Email actions don't use integrations - } - - -def fix_email_action_fallthrough_type( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Fix email actions that were incorrectly migrated with missing fallthrough_type. - - This migration: - 1. Finds all Workflows that have at least 1 Action of type="email" - 2. For each workflow, fetches the Rule through AlertRuleWorkflow - 3. Gets the NotifyEmailAction actions from Rule.data["actions"] - 4. Gets the email actions for the workflow - 5. Overwrites each Action with translated data from the rule action - """ - Rule = apps.get_model("sentry", "Rule") - Workflow = apps.get_model("workflow_engine", "Workflow") - Action = apps.get_model("workflow_engine", "Action") - AlertRuleWorkflow = apps.get_model("workflow_engine", "AlertRuleWorkflow") - - # Iterate directly through workflows with email actions - workflows_with_email_actions = Workflow.objects.filter( - workflowdataconditiongroup__condition_group__dataconditiongroupaction__action__type="email" - ).distinct() - - for workflow in RangeQuerySetWrapper(workflows_with_email_actions): - try: - # Get the Rule for this workflow through AlertRuleWorkflow - alert_rule_workflow = AlertRuleWorkflow.objects.filter(workflow_id=workflow.id).first() - if not alert_rule_workflow or not alert_rule_workflow.rule_id: - logger.info( - "workflow.no_rule_link", - extra={"workflow_id": workflow.id}, - ) - continue - - try: - rule = Rule.objects.get(id=alert_rule_workflow.rule_id) - except Rule.DoesNotExist: - logger.info( - "workflow.rule_not_found", - extra={ - "workflow_id": workflow.id, - "rule_id": alert_rule_workflow.rule_id, - }, - ) - continue - - # Rule email actions - rule_actions = rule.data.get("actions", []) - rule_email_actions = [ - action for action in rule_actions if action.get("id") == EMAIL_ACTION_REGISTRY_ID - ] - - if not rule_email_actions: - logger.info( - "workflow.no_rule_email_actions", - extra={"workflow_id": workflow.id, "rule_id": rule.id}, - ) - continue - - # Workflow email actions - workflow_email_actions = list( - Action.objects.filter( - dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow_id=workflow.id, - type="email", - ) - .distinct() - .order_by("id") - ) - - if not workflow_email_actions: - logger.info( - "workflow.no_workflow_email_actions", - extra={"workflow_id": workflow.id}, - ) - continue - - # Translate rule email actions - translated_actions = [] - for rule_action in rule_email_actions: - try: - translated_actions.append(translate_email_action(rule_action)) - except ValueError: - logger.exception( - "workflow.translate_action_error", - extra={ - "workflow_id": workflow.id, - "rule_id": rule.id, - "rule_action": rule_action, - }, - ) - continue - - if len(translated_actions) != len(workflow_email_actions): - logger.warning( - "workflow.action_count_mismatch", - extra={ - "workflow_id": workflow.id, - "rule_id": rule.id, - "translated_count": len(translated_actions), - "workflow_count": len(workflow_email_actions), - }, - ) - continue - - # Overwrite each workflow action with the translated data - for i, workflow_action in enumerate(workflow_email_actions): - if i >= len(translated_actions): - break - - translated = translated_actions[i] - - workflow_action.data = translated["data"] - workflow_action.config = translated["config"] - workflow_action.integration_id = translated["integration_id"] - workflow_action.save() - - logger.info( - "workflow.actions_updated", - extra={ - "workflow_id": workflow.id, - "action_ids": [action.id for action in workflow_email_actions], - }, - ) - - except Exception: - logger.exception( - "workflow.migration_error", - extra={"workflow_id": workflow.id}, - ) - continue - - -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 = True - - dependencies = [ - ("workflow_engine", "0106_migrate_actions_sentry_app_data"), - ] - - operations = [ - migrations.RunPython( - fix_email_action_fallthrough_type, - migrations.RunPython.noop, - hints={"tables": ["workflow_engine_action", "workflow_engine_workflow", "sentry_rule"]}, - ) - ] diff --git a/src/sentry/workflow_engine/migrations/0108_remove_sentry_app_identifier_from_action.py b/src/sentry/workflow_engine/migrations/0108_remove_sentry_app_identifier_from_action.py deleted file mode 100644 index 6ec11094e0f5..000000000000 --- a/src/sentry/workflow_engine/migrations/0108_remove_sentry_app_identifier_from_action.py +++ /dev/null @@ -1,62 +0,0 @@ -# Generated by Django 5.2.11 on 2026-02-24 19:09 - -import django.db.models.expressions -from django.db import migrations, models -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - - -def remove_action_sentry_app_identifier( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Action = apps.get_model("workflow_engine", "Action") - - for action in RangeQuerySetWrapper(Action.objects.filter(type="sentry_app")): - config = action.config - config.pop("sentry_app_identifier", None) - action.config = config - action.save() - - -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 = True - - dependencies = [ - ("workflow_engine", "0107_fix_email_action_fallthrough_type"), - ] - - operations = [ - migrations.AddIndex( - model_name="action", - index=models.Index( - models.F("type"), - django.db.models.expressions.RawSQL("config->>'target_identifier'", []), - condition=models.Q(("type", "sentry_app")), - name="sentry_app_lookup_action", - ), - ), - migrations.RemoveIndex( - model_name="action", - name="action_sentry_app_lookup", - ), - migrations.RunPython( - code=remove_action_sentry_app_identifier, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_action"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0109_add_detector_state_triggered_date_index.py b/src/sentry/workflow_engine/migrations/0109_add_detector_state_triggered_date_index.py deleted file mode 100644 index b27a9dc54459..000000000000 --- a/src/sentry/workflow_engine/migrations/0109_add_detector_state_triggered_date_index.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - is_post_deployment = True - - dependencies = [ - ("workflow_engine", "0108_remove_sentry_app_identifier_from_action"), - ] - - operations = [ - migrations.AddIndex( - model_name="detectorstate", - index=models.Index( - fields=["is_triggered", "date_updated"], - condition=models.Q(is_triggered=True), - name="detector_state_triggered_date", - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0110_owner_team_break_fk.py b/src/sentry/workflow_engine/migrations/0110_owner_team_break_fk.py deleted file mode 100644 index ee192754aa75..000000000000 --- a/src/sentry/workflow_engine/migrations/0110_owner_team_break_fk.py +++ /dev/null @@ -1,88 +0,0 @@ -import django.db.models.deletion -from django.db import migrations, models - -import sentry.db.models.fields.bounded -import sentry.db.models.fields.foreignkey -from sentry.new_migrations.migrations import CheckedMigration - - -class Migration(CheckedMigration): - is_post_deployment = False - - dependencies = [ - ("workflow_engine", "0109_add_detector_state_triggered_date_index"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AlterField( - model_name="detector", - name="owner_team", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.team", - ), - ), - ], - state_operations=[ - migrations.RemoveConstraint( - model_name="detector", - name="workflow_engine_detector_owner_constraints", - ), - migrations.RemoveField( - model_name="detector", - name="owner_team", - ), - migrations.AddField( - model_name="detector", - name="owner_team_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField( - blank=True, db_index=True, null=True - ), - ), - migrations.AddConstraint( - model_name="detector", - constraint=models.CheckConstraint( - condition=( - models.Q(owner_user_id__isnull=True, owner_team_id__isnull=False) - | models.Q(owner_user_id__isnull=False, owner_team_id__isnull=True) - | models.Q(owner_user_id__isnull=True, owner_team_id__isnull=True) - ), - name="workflow_engine_detector_owner_constraints", - ), - ), - ], - ), - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.AlterField( - model_name="workflow", - name="owner_team", - field=sentry.db.models.fields.foreignkey.FlexibleForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to="sentry.team", - ), - ), - ], - state_operations=[ - migrations.RemoveField( - model_name="workflow", - name="owner_team", - ), - migrations.AddField( - model_name="workflow", - name="owner_team_id", - field=sentry.db.models.fields.bounded.BoundedBigIntegerField( - blank=True, db_index=True, null=True - ), - ), - ], - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0111_add_workflowfirehistory_date_added_index.py b/src/sentry/workflow_engine/migrations/0111_add_workflowfirehistory_date_added_index.py deleted file mode 100644 index 22c4617123d5..000000000000 --- a/src/sentry/workflow_engine/migrations/0111_add_workflowfirehistory_date_added_index.py +++ /dev/null @@ -1,33 +0,0 @@ -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - - -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 = True - - dependencies = [ - ("workflow_engine", "0110_owner_team_break_fk"), - ] - - operations = [ - migrations.AddIndex( - model_name="workflowfirehistory", - index=models.Index( - fields=["date_added"], - name="workflow_en_date_ad_1986f8_idx", - ), - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0112_drop_redundant_error_detector_workflows.py b/src/sentry/workflow_engine/migrations/0112_drop_redundant_error_detector_workflows.py deleted file mode 100644 index ecac262b508a..000000000000 --- a/src/sentry/workflow_engine/migrations/0112_drop_redundant_error_detector_workflows.py +++ /dev/null @@ -1,87 +0,0 @@ -# Generated by Django 5.2.12 on 2026-04-07 17:56 -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.models import Exists, OuterRef -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.iterators import chunked -from sentry.utils.query import bulk_delete_objects - -logger = logging.getLogger(__name__) - -CHUNK_SIZE = 10000 - - -def delete_redundant_error_detector_workflows( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - """ - Delete DetectorWorkflow rows where: - 1. The detector type is "error" - 2. There exists another DetectorWorkflow with the same workflow_id - connected to an "issue_stream" detector - - Processes error detector IDs in chunks using RangeQuerySetWrapper to avoid - loading millions of IDs into a single query. - """ - Detector = apps.get_model("workflow_engine", "Detector") - DetectorWorkflow = apps.get_model("workflow_engine", "DetectorWorkflow") - - error_detector_ids = Detector.objects.filter(type="error").values_list("id", flat=True) - - for chunk in chunked(error_detector_ids, CHUNK_SIZE): - issue_stream_exists = DetectorWorkflow.objects.filter( - workflow_id=OuterRef("workflow_id"), - detector__type="issue_stream", - ) - - dws_to_delete = ( - DetectorWorkflow.objects.filter( - detector_id__in=chunk, - ) - .filter(Exists(issue_stream_exists)) - .values_list("id", flat=True) - ) - - while bulk_delete_objects( - DetectorWorkflow, - logger=logger, - id__in=dws_to_delete, - ): - pass - - -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 = True - - dependencies = [ - ("workflow_engine", "0111_add_workflowfirehistory_date_added_index"), - ] - - operations = [ - migrations.RunPython( - delete_redundant_error_detector_workflows, - migrations.RunPython.noop, - hints={ - "tables": [ - "workflow_engine_detector", - "workflow_engine_detectorworkflow", - ] - }, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0113_migrate_data_conditions_categories.py b/src/sentry/workflow_engine/migrations/0113_migrate_data_conditions_categories.py deleted file mode 100644 index 8b8e3e45e658..000000000000 --- a/src/sentry/workflow_engine/migrations/0113_migrate_data_conditions_categories.py +++ /dev/null @@ -1,143 +0,0 @@ -# Generated by Django 5.2.12 on 2026-05-01 18:51 - -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - - -def migrate_data_condition_issue_category( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - DataCondition = apps.get_model("workflow_engine", "DataCondition") - DataConditionGroup = apps.get_model("workflow_engine", "DataConditionGroup") - - # Cache the original logic_type per group ID to avoid re-fetching a DCG - dcg_logic_type_cache: dict[int, str] = {} - - for data_condition in RangeQuerySetWrapper(DataCondition.objects.filter(type="issue_category")): - comparison = dict(data_condition.comparison) - - # handle GroupCategory.METRIC_ISSUE (8) -> GroupCategory.METRIC (11) - if comparison.get("value") == 8: - comparison["value"] = 11 - - data_condition.comparison = comparison - data_condition.save() - continue - - # handle GroupCategory.REPLAY (5) -> GroupCategory.FRONTEND (14) - elif comparison.get("value") == 5: - comparison["value"] = 14 - - data_condition.comparison = comparison - data_condition.save() - continue - - # handle GroupCategory.UPTIME (7) -> issue type Uptime Monitor Detected Downtime - elif comparison.get("value") == 7: - data_condition.type = "issue_type" - comparison["value"] = "uptime_domain_failure" - - data_condition.comparison = comparison - data_condition.save() - continue - - # handle GroupCategory.CRON (4) -> issue type Missed or Failed Cron Check-In - elif comparison.get("value") == 4: - data_condition.type = "issue_type" - comparison["value"] = "monitor_check_in_failure" - - data_condition.comparison = comparison - data_condition.save() - continue - - # handle GroupCategory.PERFORMANCE (2) - elif comparison.get("value") == 2: - group_id = data_condition.condition_group_id - - if group_id not in dcg_logic_type_cache: - dcg = DataConditionGroup.objects.filter(id=group_id).first() - if dcg is None: - logger.info( - "No DataConditionGroup found for DataCondition, skipping", - extra={"data_condition_id": data_condition.id}, - ) - continue - dcg_logic_type_cache[group_id] = dcg.logic_type - - logic_type = dcg_logic_type_cache[group_id] - - if logic_type == "all": - comparison["value"] = 1 - comparison["include"] = False # Issue category is NOT errors - data_condition.comparison = comparison - data_condition.save() - continue - else: # logic type is any, any-short, or none (legacy for does not match all) - comparison["value"] = 12 # GroupCategory.DB_QUERY - http_client_comparison: dict[str, object] = {"value": 13} - front_end_comparison: dict[str, object] = {"value": 14} - mobile_comparison: dict[str, object] = {"value": 15} - - include = comparison.get("include") - if include: - http_client_comparison["include"] = include - front_end_comparison["include"] = include - mobile_comparison["include"] = include - - DataCondition.objects.create( - type="issue_category", - condition_result=True, - comparison=http_client_comparison, - condition_group_id=data_condition.condition_group_id, - ) - DataCondition.objects.create( - type="issue_category", - condition_result=True, - comparison=front_end_comparison, - condition_group_id=data_condition.condition_group_id, - ) - DataCondition.objects.create( - type="issue_category", - condition_result=True, - comparison=mobile_comparison, - condition_group_id=data_condition.condition_group_id, - ) - - data_condition.comparison = comparison - data_condition.save() - - -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 = True - - dependencies = [ - ("workflow_engine", "0112_drop_redundant_error_detector_workflows"), - ] - - operations = [ - migrations.RunPython( - code=migrate_data_condition_issue_category, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_data_condition"]}, - ), - ] diff --git a/src/sentry/workflow_engine/migrations/0114_sanitize_dynamic_form_field_choices.py b/src/sentry/workflow_engine/migrations/0114_sanitize_dynamic_form_field_choices.py deleted file mode 100644 index 83227f7c64ec..000000000000 --- a/src/sentry/workflow_engine/migrations/0114_sanitize_dynamic_form_field_choices.py +++ /dev/null @@ -1,130 +0,0 @@ -import logging - -from django.db import migrations -from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from django.db.migrations.state import StateApps - -from sentry.new_migrations.migrations import CheckedMigration -from sentry.utils.query import RangeQuerySetWrapper - -logger = logging.getLogger(__name__) - -TICKET_ACTION_TYPES = ["github", "github_enterprise", "jira", "jira_server", "vsts"] - - -def _extract_choice_label(value: object, label: object) -> tuple[object, bool]: - """ - In the past, the frontend was able to store a serialized React element as a choice label. - This was previously supported, but will now cause the page to crash. This migration will - extract the proper label text from the serialized React element. - - All existing serialized React elements look like the following: - - ``` - { - "key": None, - "ref": None, - "props": { - "children": [ - {...}, - " ", - "This is the actual label text", - ] - } - } - ``` - """ - if isinstance(label, dict) and "props" in label: - props = label.get("props") - children = props.get("children") if isinstance(props, dict) else None - if isinstance(children, list): - text = "".join(c for c in children if isinstance(c, str)).strip() - if text: - return text, True - - return value, False - - -def sanitize_dynamic_form_field_choices( - apps: StateApps, schema_editor: BaseDatabaseSchemaEditor -) -> None: - Action = apps.get_model("workflow_engine", "Action") - - count = 0 - updated = 0 - - for action in RangeQuerySetWrapper(Action.objects.filter(type__in=TICKET_ACTION_TYPES)): - count += 1 - - dynamic_form_fields = (action.data or {}).get("dynamic_form_fields") - if not dynamic_form_fields or not isinstance(dynamic_form_fields, list): - continue - - row_changed = False - - for field_def in dynamic_form_fields: - if not isinstance(field_def, dict): - continue - - choices = field_def.get("choices") - if not choices or not isinstance(choices, list): - continue - - for choice in choices: - if not isinstance(choice, list) or len(choice) < 2: - continue - - new_label, was_changed = _extract_choice_label(choice[0], choice[1]) - if was_changed and new_label: - choice[1] = new_label - row_changed = True - - if row_changed: - action.save(update_fields=["data"]) - updated += 1 - - if count % 1000 == 0: - logger.info( - "sanitize_dynamic_form_field_choices.progress", - extra={ - "count": count, - "updated": updated, - "current_action_id": action.id, - }, - ) - - logger.info( - "sanitize_dynamic_form_field_choices.complete", - extra={ - "count": count, - "updated": updated, - }, - ) - - -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 = True - - dependencies = [ - ("workflow_engine", "0113_migrate_data_conditions_categories"), - ] - - operations = [ - migrations.RunPython( - code=sanitize_dynamic_form_field_choices, - reverse_code=migrations.RunPython.noop, - hints={"tables": ["workflow_engine_action"]}, - ), - ] diff --git a/src/social_auth/migrations/0001_squashed_0002_default_auto_field.py b/src/social_auth/migrations/0001_squashed_0003_social_auth_json_field.py similarity index 89% rename from src/social_auth/migrations/0001_squashed_0002_default_auto_field.py rename to src/social_auth/migrations/0001_squashed_0003_social_auth_json_field.py index 041aefee1b4a..846f67a79688 100644 --- a/src/social_auth/migrations/0001_squashed_0002_default_auto_field.py +++ b/src/social_auth/migrations/0001_squashed_0003_social_auth_json_field.py @@ -1,10 +1,9 @@ -# Generated by Django 5.2.1 on 2025-05-21 16:28 +# Generated by Django 5.2.14 on 2026-06-16 19:05 import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import social_auth.fields from sentry.new_migrations.migrations import CheckedMigration @@ -24,8 +23,8 @@ class Migration(CheckedMigration): is_post_deployment = True replaces = [ - ("social_auth", "0001_initial"), - ("social_auth", "0002_default_auto_field"), + ("social_auth", "0001_squashed_0002_default_auto_field"), + ("social_auth", "0003_social_auth_json_field"), ] initial = True @@ -43,7 +42,7 @@ class Migration(CheckedMigration): ("id", models.AutoField(primary_key=True, serialize=False)), ("provider", models.CharField(max_length=32)), ("uid", models.CharField(max_length=255)), - ("extra_data", social_auth.fields.JSONField(default="{}")), + ("extra_data", models.JSONField(default=dict)), ( "user", models.ForeignKey( diff --git a/src/social_auth/migrations/0003_social_auth_json_field.py b/src/social_auth/migrations/0003_social_auth_json_field.py deleted file mode 100644 index d3d09f020e8f..000000000000 --- a/src/social_auth/migrations/0003_social_auth_json_field.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 5.2.1 on 2025-06-30 17:50 - -from django.db import migrations, models - -from sentry.new_migrations.migrations import CheckedMigration - -mod = __import__("sentry.migrations.0929_no_pickle_authenticator", fromlist=["_trash"]) - - -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 = [ - ("social_auth", "0001_squashed_0002_default_auto_field"), - ] - - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[mod.to_jsonb("social_auth_usersocialauth", "extra_data")], - state_operations=[ - migrations.AlterField( - model_name="usersocialauth", - name="extra_data", - field=models.JSONField(default=dict), - ), - ], - ) - ] diff --git a/tools/migrations/squash.py b/tools/migrations/squash.py index faf1a94da539..566fe950bb7b 100644 --- a/tools/migrations/squash.py +++ b/tools/migrations/squash.py @@ -125,12 +125,13 @@ def _dependencies(app: App, tree: ast.AST) -> Generator[tuple[ast.Tuple, str]]: yield elt, cand -def _target_line(target: str, squashed: dict[str, App]) -> str: - return f' ("{target}", "{squashed[target].squash_name}"),' +def _target_line(target: str, all_apps: dict[str, App]) -> str: + return f' ("{target}", "{all_apps[target].squash_name}"),' @contextlib.contextmanager def _cleared_deps(already_squashed: list[App], squash: dict[str, App]) -> Generator[None]: + all_apps = {app.name: app for app in already_squashed} | squash all_fixups = [] for app in already_squashed: with open(app.squash_fname, encoding="UTF-8") as f: @@ -157,7 +158,7 @@ def _cleared_deps(already_squashed: list[App], squash: dict[str, App]) -> Genera with open(fname, "w", encoding="UTF-8") as f: f.writelines( ( - _target_line(fixups[i], squash) if i in fixups else line + _target_line(fixups[i], all_apps) if i in fixups else line for i, line in enumerate(lines, start=1) ) )