From 4d0b053c5825d71d31f0a6d5159657c611defc05 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:08:23 -0400 Subject: [PATCH 1/2] ref(dashboards): Remove DashboardTombstone model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the DashboardTombstone model class and all code references. The model tracked which pre-built dashboards were deleted for an org, but no production code references it anymore. The database table is left in place — a follow-up migration will move it to pending deletion, and a final migration will drop it. Refs DAIN-1567 Co-Authored-By: Claude Opus 4.6 --- src/sentry/models/dashboard.py | 22 ------------------- src/sentry/testutils/helpers/backups.py | 2 -- .../test_success.pysnap | 2 +- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/sentry/models/dashboard.py b/src/sentry/models/dashboard.py index baa5d09c9e6c..bb235f947346 100644 --- a/src/sentry/models/dashboard.py +++ b/src/sentry/models/dashboard.py @@ -16,7 +16,6 @@ from sentry.db.models.fields.bounded import BoundedBigIntegerField, BoundedPositiveIntegerField from sentry.db.models.fields.hybrid_cloud_foreign_key import HybridCloudForeignKey from sentry.db.models.fields.jsonfield import JSONField -from sentry.db.models.fields.slug import SentrySlugField from sentry.db.models.manager.base import BaseManager from sentry.models.organization import Organization @@ -381,27 +380,6 @@ def get_filters(self) -> dict[str, Any]: } -@cell_silo_model -class DashboardTombstone(Model): - """ - A tombstone to indicate that a pre-built dashboard - has been replaced or deleted for an organization. - """ - - __relocation_scope__ = RelocationScope.Organization - - slug = SentrySlugField(max_length=255, db_index=False) - organization = FlexibleForeignKey("sentry.Organization") - date_added = models.DateTimeField(default=timezone.now) - - class Meta: - app_label = "sentry" - db_table = "sentry_dashboardtombstone" - unique_together = (("organization", "slug"),) - - __repr__ = sane_repr("organization", "slug") - - @cell_silo_model class DashboardRevision(DefaultFieldsModel): __relocation_scope__ = RelocationScope.Organization diff --git a/src/sentry/testutils/helpers/backups.py b/src/sentry/testutils/helpers/backups.py index 741a2e8adb63..197fbf642b7e 100644 --- a/src/sentry/testutils/helpers/backups.py +++ b/src/sentry/testutils/helpers/backups.py @@ -68,7 +68,6 @@ DashboardFavoriteUser, DashboardLastVisited, DashboardRevision, - DashboardTombstone, ) from sentry.models.dashboard_permissions import DashboardPermissions from sentry.models.dashboard_widget import ( @@ -607,7 +606,6 @@ def create_exhaustive_organization( title=dashboard.title, snapshot_schema_version=1, ) - DashboardTombstone.objects.create(organization=org, slug=f"test-tombstone-in-{slug}") # *Search RecentSearch.objects.create( diff --git a/tests/sentry/tasks/snapshots/PreprocessingTransferTest/test_success.pysnap b/tests/sentry/tasks/snapshots/PreprocessingTransferTest/test_success.pysnap index bb542cfeee47..b18d503da3be 100644 --- a/tests/sentry/tasks/snapshots/PreprocessingTransferTest/test_success.pysnap +++ b/tests/sentry/tasks/snapshots/PreprocessingTransferTest/test_success.pysnap @@ -96,7 +96,7 @@ steps: - -U - postgres - -c - - TRUNCATE sentry_controloption,sentry_integration,sentry_option,sentry_organization,sentry_organizationintegration,sentry_organizationoptions,sentry_projecttemplate,sentry_projecttemplateoption,sentry_relay,sentry_relayusage,sentry_repository,sentry_team,auth_user,sentry_userip,sentry_userpermission,sentry_userrole,sentry_userrole_users,workflow_engine_dataconditiongroup,workflow_engine_datasource,workflow_engine_datacondition,sentry_savedsearch,sentry_recentsearch,sentry_project,sentry_orgauthtoken,sentry_organizationmember,sentry_organizationaccessrequest,sentry_monitor,sentry_groupsearchview,sentry_environment,sentry_email,sentry_datasecrecywaiver,sentry_dashboardtombstone,sentry_dashboard,sentry_projectcounter,sentry_authprovider,sentry_authidentity,auth_authenticator,sentry_apikey,sentry_apiapplication,workflow_engine_workflow,workflow_engine_detector,workflow_engine_datasourcedetector,sentry_useroption,sentry_useremail,sentry_snubaquery,sentry_sentryapp,sentry_rule,sentry_querysubscription,sentry_projectteam,sentry_projectredirect,sentry_projectownership,sentry_projectoptions,sentry_projectkey,sentry_projectintegration,sentry_projectbookmark,sentry_organizationmember_teams,sentry_notificationaction,sentry_neglectedrule,sentry_environmentproject,sentry_dashboardwidget,sentry_dashboardpermissions,sentry_dashboardfavoriteuser,sentry_apitoken,sentry_apigrant,sentry_apiauthorization,sentry_alertrule,workflow_engine_workflowdataconditiongroup,workflow_engine_detectorworkflow,workflow_engine_alertruleworkflow,workflow_engine_alertruledetector,sentry_snubaqueryeventtype,sentry_sentryappinstallation,sentry_sentryappcomponent,sentry_rulesnooze,sentry_ruleactivity,sentry_notificationactionproject,sentry_dashboardwidgetquery,sentry_dashboardpermissionsteam,sentry_alertruletrigger,sentry_alertruleprojects,sentry_alertruleactivity,sentry_alertruleactivationcondition,workflow_engine_alertruletriggerdatacondition,sentry_servicehook,sentry_incident,sentry_dashboardwidgetqueryondemand,sentry_alertruletriggeraction,sentry_timeseriessnapshot,sentry_pendingincidentsnapshot,sentry_incidenttrigger,sentry_incidentsnapshot,sentry_incidentactivity + - TRUNCATE sentry_controloption,sentry_integration,sentry_option,sentry_organization,sentry_organizationintegration,sentry_organizationoptions,sentry_projecttemplate,sentry_projecttemplateoption,sentry_relay,sentry_relayusage,sentry_repository,sentry_team,auth_user,sentry_userip,sentry_userpermission,sentry_userrole,sentry_userrole_users,workflow_engine_dataconditiongroup,workflow_engine_datasource,workflow_engine_datacondition,sentry_savedsearch,sentry_recentsearch,sentry_project,sentry_orgauthtoken,sentry_organizationmember,sentry_organizationaccessrequest,sentry_monitor,sentry_groupsearchview,sentry_environment,sentry_email,sentry_datasecrecywaiver,sentry_dashboard,sentry_projectcounter,sentry_authprovider,sentry_authidentity,auth_authenticator,sentry_apikey,sentry_apiapplication,workflow_engine_workflow,workflow_engine_detector,workflow_engine_datasourcedetector,sentry_useroption,sentry_useremail,sentry_snubaquery,sentry_sentryapp,sentry_rule,sentry_querysubscription,sentry_projectteam,sentry_projectredirect,sentry_projectownership,sentry_projectoptions,sentry_projectkey,sentry_projectintegration,sentry_projectbookmark,sentry_organizationmember_teams,sentry_notificationaction,sentry_neglectedrule,sentry_environmentproject,sentry_dashboardwidget,sentry_dashboardpermissions,sentry_dashboardfavoriteuser,sentry_apitoken,sentry_apigrant,sentry_apiauthorization,sentry_alertrule,workflow_engine_workflowdataconditiongroup,workflow_engine_detectorworkflow,workflow_engine_alertruleworkflow,workflow_engine_alertruledetector,sentry_snubaqueryeventtype,sentry_sentryappinstallation,sentry_sentryappcomponent,sentry_rulesnooze,sentry_ruleactivity,sentry_notificationactionproject,sentry_dashboardwidgetquery,sentry_dashboardpermissionsteam,sentry_alertruletrigger,sentry_alertruleprojects,sentry_alertruleactivity,sentry_alertruleactivationcondition,workflow_engine_alertruletriggerdatacondition,sentry_servicehook,sentry_incident,sentry_dashboardwidgetqueryondemand,sentry_alertruletriggeraction,sentry_timeseriessnapshot,sentry_pendingincidentsnapshot,sentry_incidenttrigger,sentry_incidentsnapshot,sentry_incidentactivity RESTART IDENTITY CASCADE; id: clear-database name: gcr.io/cloud-builders/docker From 30040266ed1357756bcd0e9ac8474119b949e6b3 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Wed, 29 Apr 2026 10:30:09 -0400 Subject: [PATCH 2/2] ref(dashboards): Add MOVE_TO_PENDING migration for DashboardTombstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI requires the migration to ship alongside the model removal. Drop the FK constraint and move to pending deletion state — the table stays in PostgreSQL for rolling deploy safety. Refs DAIN-1567 Co-Authored-By: Claude Opus 4.6 --- migrations_lockfile.txt | 2 +- .../1074_remove_dashboardtombstone.py | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/sentry/migrations/1074_remove_dashboardtombstone.py diff --git a/migrations_lockfile.txt b/migrations_lockfile.txt index a1d4896034b1..8d6ba33376cb 100644 --- a/migrations_lockfile.txt +++ b/migrations_lockfile.txt @@ -31,7 +31,7 @@ replays: 0007_organizationmember_replay_access seer: 0008_add_seer_run_models -sentry: 1073_add_org_ci_scope +sentry: 1074_remove_dashboardtombstone social_auth: 0003_social_auth_json_field diff --git a/src/sentry/migrations/1074_remove_dashboardtombstone.py b/src/sentry/migrations/1074_remove_dashboardtombstone.py new file mode 100644 index 000000000000..3633aa7f59f7 --- /dev/null +++ b/src/sentry/migrations/1074_remove_dashboardtombstone.py @@ -0,0 +1,31 @@ +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, + ), + ]