From 41e17be7e88019c6ab4851f3f5536593cc01798a Mon Sep 17 00:00:00 2001 From: Alex Zaslavsky Date: Fri, 11 Aug 2023 12:56:48 -0700 Subject: [PATCH] ref(backup): Remove ManyToMany dependencies (#54480) The `sorted_dependencies` function has, since time immemorial, tried to track all `ManyToManyField` dependencies without a `through` model set, since there is otherwise no way to deduce the dependency relationship for the shadow junction tables Django creates under the hood. Except... we actually don't have any `ManyToManyField` definitions without an explicit `through` argument. Maybe we did when this code was written, but today we no longer do. The removed bits of code were thus never really executed, since they were checking for a state of affairs that wasn't really a problem in our actual code base. They were also buggy: the comment said they were checking for `through`-ness, but there was no code to this effect, resulting in double dependencies. This change removes the check altogether, and adds an invariant test to ensure that all `ManyToManyField`s defined in the future carry a `through` argument. Issue: getsentry/team-ospo#171 --- .../backup/model_dependencies/detailed.json | 763 ++++++++---------- fixtures/backup/model_dependencies/flat.json | 37 +- .../backup/model_dependencies/sorted.json | 136 ++-- src/sentry/backup/dependencies.py | 37 +- tests/sentry/backup/test_coverage.py | 14 +- tests/sentry/backup/test_invariants.py | 38 + 6 files changed, 483 insertions(+), 542 deletions(-) create mode 100644 tests/sentry/backup/test_invariants.py diff --git a/fixtures/backup/model_dependencies/detailed.json b/fixtures/backup/model_dependencies/detailed.json index 7b388a7abf8e9b..2684931e016419 100644 --- a/fixtures/backup/model_dependencies/detailed.json +++ b/fixtures/backup/model_dependencies/detailed.json @@ -1,21 +1,20 @@ { "nodestore.Node": { + "foreign_keys": {}, "model": "nodestore.Node", - "relations": {}, "silos": [ "REGION" ] }, "replays.ReplayRecordingSegment": { + "foreign_keys": {}, "model": "replays.ReplayRecordingSegment", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Activity": { - "model": "sentry.Activity", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -25,24 +24,20 @@ "model": "sentry.Project" } }, + "model": "sentry.Activity", "silos": [ "REGION" ] }, "sentry.Actor": { + "foreign_keys": {}, "model": "sentry.Actor", - "relations": {}, "silos": [ "REGION" ] }, "sentry.AlertRule": { - "model": "sentry.AlertRule", - "relations": { - "excluded_projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" - }, + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -56,13 +51,13 @@ "model": "sentry.SnubaQuery" } }, + "model": "sentry.AlertRule", "silos": [ "REGION" ] }, "sentry.AlertRuleActivity": { - "model": "sentry.AlertRuleActivity", - "relations": { + "foreign_keys": { "alert_rule": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRule" @@ -72,13 +67,13 @@ "model": "sentry.AlertRule" } }, + "model": "sentry.AlertRuleActivity", "silos": [ "REGION" ] }, "sentry.AlertRuleExcludedProjects": { - "model": "sentry.AlertRuleExcludedProjects", - "relations": { + "foreign_keys": { "alert_rule": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRule" @@ -88,41 +83,37 @@ "model": "sentry.Project" } }, + "model": "sentry.AlertRuleExcludedProjects", "silos": [ "REGION" ] }, "sentry.AlertRuleTrigger": { - "model": "sentry.AlertRuleTrigger", - "relations": { + "foreign_keys": { "alert_rule": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRule" - }, - "triggered_incidents": { - "kind": "ManyToManyField", - "model": "sentry.Incident" } }, + "model": "sentry.AlertRuleTrigger", "silos": [ "REGION" ] }, "sentry.AlertRuleTriggerAction": { - "model": "sentry.AlertRuleTriggerAction", - "relations": { + "foreign_keys": { "alert_rule_trigger": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRuleTrigger" } }, + "model": "sentry.AlertRuleTriggerAction", "silos": [ "REGION" ] }, "sentry.AlertRuleTriggerExclusion": { - "model": "sentry.AlertRuleTriggerExclusion", - "relations": { + "foreign_keys": { "alert_rule_trigger": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRuleTrigger" @@ -132,25 +123,25 @@ "model": "sentry.QuerySubscription" } }, + "model": "sentry.AlertRuleTriggerExclusion", "silos": [ "REGION" ] }, "sentry.ApiApplication": { - "model": "sentry.ApiApplication", - "relations": { + "foreign_keys": { "owner": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.ApiApplication", "silos": [ "CONTROL" ] }, "sentry.ApiAuthorization": { - "model": "sentry.ApiAuthorization", - "relations": { + "foreign_keys": { "application": { "kind": "FlexibleForeignKey", "model": "sentry.ApiApplication" @@ -160,13 +151,13 @@ "model": "sentry.User" } }, + "model": "sentry.ApiAuthorization", "silos": [ "CONTROL" ] }, "sentry.ApiGrant": { - "model": "sentry.ApiGrant", - "relations": { + "foreign_keys": { "application": { "kind": "FlexibleForeignKey", "model": "sentry.ApiApplication" @@ -176,20 +167,20 @@ "model": "sentry.User" } }, + "model": "sentry.ApiGrant", "silos": [ "CONTROL" ] }, "sentry.ApiKey": { + "foreign_keys": {}, "model": "sentry.ApiKey", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.ApiToken": { - "model": "sentry.ApiToken", - "relations": { + "foreign_keys": { "application": { "kind": "FlexibleForeignKey", "model": "sentry.ApiApplication" @@ -199,73 +190,73 @@ "model": "sentry.User" } }, + "model": "sentry.ApiToken", "silos": [ "CONTROL" ] }, "sentry.AppConnectBuild": { - "model": "sentry.AppConnectBuild", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.AppConnectBuild", "silos": [ "REGION" ] }, "sentry.ArtifactBundle": { - "model": "sentry.ArtifactBundle", - "relations": { + "foreign_keys": { "file": { "kind": "FlexibleForeignKey", "model": "sentry.File" } }, + "model": "sentry.ArtifactBundle", "silos": [ "REGION" ] }, "sentry.ArtifactBundleFlatFileIndex": { - "model": "sentry.ArtifactBundleFlatFileIndex", - "relations": { + "foreign_keys": { "flat_file_index": { "kind": "FlexibleForeignKey", "model": "sentry.File" } }, + "model": "sentry.ArtifactBundleFlatFileIndex", "silos": [ "REGION" ] }, "sentry.ArtifactBundleIndex": { - "model": "sentry.ArtifactBundleIndex", - "relations": { + "foreign_keys": { "artifact_bundle": { "kind": "FlexibleForeignKey", "model": "sentry.ArtifactBundle" } }, + "model": "sentry.ArtifactBundleIndex", "silos": [ "REGION" ] }, "sentry.AssistantActivity": { - "model": "sentry.AssistantActivity", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.AssistantActivity", "silos": [ "CONTROL" ] }, "sentry.AuditLogEntry": { - "model": "sentry.AuditLogEntry", - "relations": { + "foreign_keys": { "actor": { "kind": "FlexibleForeignKey", "model": "sentry.User" @@ -279,13 +270,13 @@ "model": "sentry.User" } }, + "model": "sentry.AuditLogEntry", "silos": [ "CONTROL" ] }, "sentry.AuthIdentity": { - "model": "sentry.AuthIdentity", - "relations": { + "foreign_keys": { "auth_provider": { "kind": "FlexibleForeignKey", "model": "sentry.AuthProvider" @@ -295,46 +286,46 @@ "model": "sentry.User" } }, + "model": "sentry.AuthIdentity", "silos": [ "CONTROL" ] }, "sentry.AuthProvider": { + "foreign_keys": {}, "model": "sentry.AuthProvider", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.AuthProviderDefaultTeams": { + "foreign_keys": {}, "model": "sentry.AuthProviderDefaultTeams", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.Authenticator": { - "model": "sentry.Authenticator", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.Authenticator", "silos": [ "CONTROL" ] }, "sentry.Broadcast": { + "foreign_keys": {}, "model": "sentry.Broadcast", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.BroadcastSeen": { - "model": "sentry.BroadcastSeen", - "relations": { + "foreign_keys": { "broadcast": { "kind": "FlexibleForeignKey", "model": "sentry.Broadcast" @@ -344,63 +335,58 @@ "model": "sentry.User" } }, + "model": "sentry.BroadcastSeen", "silos": [ "CONTROL" ] }, "sentry.Commit": { - "model": "sentry.Commit", - "relations": { + "foreign_keys": { "author": { "kind": "FlexibleForeignKey", "model": "sentry.CommitAuthor" } }, + "model": "sentry.Commit", "silos": [ "REGION" ] }, "sentry.CommitAuthor": { + "foreign_keys": {}, "model": "sentry.CommitAuthor", - "relations": {}, "silos": [ "REGION" ] }, "sentry.CommitFileChange": { - "model": "sentry.CommitFileChange", - "relations": { + "foreign_keys": { "commit": { "kind": "FlexibleForeignKey", "model": "sentry.Commit" } }, + "model": "sentry.CommitFileChange", "silos": [ "REGION" ] }, "sentry.ControlFile": { + "foreign_keys": {}, "model": "sentry.ControlFile", - "relations": { - "blobs": { - "kind": "ManyToManyField", - "model": "sentry.ControlFileBlob" - } - }, "silos": [ "CONTROL" ] }, "sentry.ControlFileBlob": { + "foreign_keys": {}, "model": "sentry.ControlFileBlob", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.ControlFileBlobIndex": { - "model": "sentry.ControlFileBlobIndex", - "relations": { + "foreign_keys": { "blob": { "kind": "FlexibleForeignKey", "model": "sentry.ControlFileBlob" @@ -410,74 +396,70 @@ "model": "sentry.ControlFile" } }, + "model": "sentry.ControlFileBlobIndex", "silos": [ "CONTROL" ] }, "sentry.ControlFileBlobOwner": { - "model": "sentry.ControlFileBlobOwner", - "relations": { + "foreign_keys": { "blob": { "kind": "FlexibleForeignKey", "model": "sentry.ControlFileBlob" } }, + "model": "sentry.ControlFileBlobOwner", "silos": [ "CONTROL" ] }, "sentry.ControlOption": { + "foreign_keys": {}, "model": "sentry.ControlOption", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.ControlOutbox": { + "foreign_keys": {}, "model": "sentry.ControlOutbox", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.ControlTombstone": { + "foreign_keys": {}, "model": "sentry.ControlTombstone", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.Counter": { - "model": "sentry.Counter", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.Counter", "silos": [ "REGION" ] }, "sentry.Dashboard": { - "model": "sentry.Dashboard", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" } }, + "model": "sentry.Dashboard", "silos": [ "REGION" ] }, "sentry.DashboardProject": { - "model": "sentry.DashboardProject", - "relations": { + "foreign_keys": { "dashboard": { "kind": "FlexibleForeignKey", "model": "sentry.Dashboard" @@ -487,110 +469,106 @@ "model": "sentry.Project" } }, + "model": "sentry.DashboardProject", "silos": [ "REGION" ] }, "sentry.DashboardTombstone": { - "model": "sentry.DashboardTombstone", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.DashboardTombstone", "silos": [ "REGION" ] }, "sentry.DashboardWidget": { - "model": "sentry.DashboardWidget", - "relations": { + "foreign_keys": { "dashboard": { "kind": "FlexibleForeignKey", "model": "sentry.Dashboard" } }, + "model": "sentry.DashboardWidget", "silos": [ "REGION" ] }, "sentry.DashboardWidgetQuery": { - "model": "sentry.DashboardWidgetQuery", - "relations": { + "foreign_keys": { "widget": { "kind": "FlexibleForeignKey", "model": "sentry.DashboardWidget" } }, + "model": "sentry.DashboardWidgetQuery", "silos": [ "REGION" ] }, "sentry.DebugIdArtifactBundle": { - "model": "sentry.DebugIdArtifactBundle", - "relations": { + "foreign_keys": { "artifact_bundle": { "kind": "FlexibleForeignKey", "model": "sentry.ArtifactBundle" } }, + "model": "sentry.DebugIdArtifactBundle", "silos": [ "REGION" ] }, "sentry.DeletedOrganization": { + "foreign_keys": {}, "model": "sentry.DeletedOrganization", - "relations": {}, "silos": [ "REGION" ] }, "sentry.DeletedProject": { + "foreign_keys": {}, "model": "sentry.DeletedProject", - "relations": {}, "silos": [ "REGION" ] }, "sentry.DeletedTeam": { + "foreign_keys": {}, "model": "sentry.DeletedTeam", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Deploy": { - "model": "sentry.Deploy", - "relations": { + "foreign_keys": { "release": { "kind": "FlexibleForeignKey", "model": "sentry.Release" } }, + "model": "sentry.Deploy", "silos": [ "REGION" ] }, "sentry.DiscoverSavedQuery": { - "model": "sentry.DiscoverSavedQuery", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" } }, + "model": "sentry.DiscoverSavedQuery", "silos": [ "REGION" ] }, "sentry.DiscoverSavedQueryProject": { - "model": "sentry.DiscoverSavedQueryProject", - "relations": { + "foreign_keys": { "discover_saved_query": { "kind": "FlexibleForeignKey", "model": "sentry.DiscoverSavedQuery" @@ -600,63 +578,58 @@ "model": "sentry.Project" } }, + "model": "sentry.DiscoverSavedQueryProject", "silos": [ "REGION" ] }, "sentry.Distribution": { - "model": "sentry.Distribution", - "relations": { + "foreign_keys": { "release": { "kind": "FlexibleForeignKey", "model": "sentry.Release" } }, + "model": "sentry.Distribution", "silos": [ "REGION" ] }, "sentry.DocIntegration": { + "foreign_keys": {}, "model": "sentry.DocIntegration", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.DocIntegrationAvatar": { - "model": "sentry.DocIntegrationAvatar", - "relations": { + "foreign_keys": { "doc_integration": { "kind": "FlexibleForeignKey", "model": "sentry.DocIntegration" } }, + "model": "sentry.DocIntegrationAvatar", "silos": [ "CONTROL" ] }, "sentry.Email": { + "foreign_keys": {}, "model": "sentry.Email", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.Environment": { + "foreign_keys": {}, "model": "sentry.Environment", - "relations": { - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" - } - }, "silos": [ "REGION" ] }, "sentry.EnvironmentProject": { - "model": "sentry.EnvironmentProject", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" @@ -666,20 +639,20 @@ "model": "sentry.Project" } }, + "model": "sentry.EnvironmentProject", "silos": [ "REGION" ] }, "sentry.EventAttachment": { + "foreign_keys": {}, "model": "sentry.EventAttachment", - "relations": {}, "silos": [ "REGION" ] }, "sentry.EventProcessingIssue": { - "model": "sentry.EventProcessingIssue", - "relations": { + "foreign_keys": { "processing_issue": { "kind": "FlexibleForeignKey", "model": "sentry.ProcessingIssue" @@ -689,44 +662,44 @@ "model": "sentry.RawEvent" } }, + "model": "sentry.EventProcessingIssue", "silos": [ "REGION" ] }, "sentry.EventUser": { + "foreign_keys": {}, "model": "sentry.EventUser", - "relations": {}, "silos": [ "REGION" ] }, "sentry.ExportedData": { - "model": "sentry.ExportedData", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.ExportedData", "silos": [ "REGION" ] }, "sentry.ExportedDataBlob": { - "model": "sentry.ExportedDataBlob", - "relations": { + "foreign_keys": { "data_export": { "kind": "FlexibleForeignKey", "model": "sentry.ExportedData" } }, + "model": "sentry.ExportedDataBlob", "silos": [ "REGION" ] }, "sentry.ExternalActor": { - "model": "sentry.ExternalActor", - "relations": { + "foreign_keys": { "actor": { "kind": "FlexibleForeignKey", "model": "sentry.Actor" @@ -736,60 +709,56 @@ "model": "sentry.Organization" } }, + "model": "sentry.ExternalActor", "silos": [ "REGION" ] }, "sentry.ExternalIssue": { - "model": "sentry.ExternalIssue", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.ExternalIssue", "silos": [ "REGION" ] }, "sentry.FeatureAdoption": { - "model": "sentry.FeatureAdoption", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.FeatureAdoption", "silos": [ "REGION" ] }, "sentry.File": { - "model": "sentry.File", - "relations": { + "foreign_keys": { "blob": { "kind": "FlexibleForeignKey", "model": "sentry.FileBlob" - }, - "blobs": { - "kind": "ManyToManyField", - "model": "sentry.FileBlob" } }, + "model": "sentry.File", "silos": [ "REGION" ] }, "sentry.FileBlob": { + "foreign_keys": {}, "model": "sentry.FileBlob", - "relations": {}, "silos": [ "REGION" ] }, "sentry.FileBlobIndex": { - "model": "sentry.FileBlobIndex", - "relations": { + "foreign_keys": { "blob": { "kind": "FlexibleForeignKey", "model": "sentry.FileBlob" @@ -799,25 +768,25 @@ "model": "sentry.File" } }, + "model": "sentry.FileBlobIndex", "silos": [ "REGION" ] }, "sentry.FileBlobOwner": { - "model": "sentry.FileBlobOwner", - "relations": { + "foreign_keys": { "blob": { "kind": "FlexibleForeignKey", "model": "sentry.FileBlob" } }, + "model": "sentry.FileBlobOwner", "silos": [ "REGION" ] }, "sentry.FlatFileIndexState": { - "model": "sentry.FlatFileIndexState", - "relations": { + "foreign_keys": { "artifact_bundle": { "kind": "FlexibleForeignKey", "model": "sentry.ArtifactBundle" @@ -827,13 +796,13 @@ "model": "sentry.ArtifactBundleFlatFileIndex" } }, + "model": "sentry.FlatFileIndexState", "silos": [ "REGION" ] }, "sentry.Group": { - "model": "sentry.Group", - "relations": { + "foreign_keys": { "first_release": { "kind": "FlexibleForeignKey", "model": "sentry.Release" @@ -843,13 +812,13 @@ "model": "sentry.Project" } }, + "model": "sentry.Group", "silos": [ "REGION" ] }, "sentry.GroupAssignee": { - "model": "sentry.GroupAssignee", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -863,13 +832,13 @@ "model": "sentry.Team" } }, + "model": "sentry.GroupAssignee", "silos": [ "REGION" ] }, "sentry.GroupBookmark": { - "model": "sentry.GroupBookmark", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -879,20 +848,20 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupBookmark", "silos": [ "REGION" ] }, "sentry.GroupCommitResolution": { + "foreign_keys": {}, "model": "sentry.GroupCommitResolution", - "relations": {}, "silos": [ "REGION" ] }, "sentry.GroupEmailThread": { - "model": "sentry.GroupEmailThread", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -902,13 +871,13 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupEmailThread", "silos": [ "REGION" ] }, "sentry.GroupEnvironment": { - "model": "sentry.GroupEnvironment", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" @@ -922,13 +891,13 @@ "model": "sentry.Group" } }, + "model": "sentry.GroupEnvironment", "silos": [ "REGION" ] }, "sentry.GroupHash": { - "model": "sentry.GroupHash", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -938,13 +907,13 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupHash", "silos": [ "REGION" ] }, "sentry.GroupHistory": { - "model": "sentry.GroupHistory", - "relations": { + "foreign_keys": { "actor": { "kind": "FlexibleForeignKey", "model": "sentry.Actor" @@ -966,13 +935,13 @@ "model": "sentry.Release" } }, + "model": "sentry.GroupHistory", "silos": [ "REGION" ] }, "sentry.GroupInbox": { - "model": "sentry.GroupInbox", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -986,13 +955,13 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupInbox", "silos": [ "REGION" ] }, "sentry.GroupLink": { - "model": "sentry.GroupLink", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1002,25 +971,25 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupLink", "silos": [ "REGION" ] }, "sentry.GroupMeta": { - "model": "sentry.GroupMeta", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" } }, + "model": "sentry.GroupMeta", "silos": [ "REGION" ] }, "sentry.GroupOwner": { - "model": "sentry.GroupOwner", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1038,27 +1007,27 @@ "model": "sentry.Team" } }, + "model": "sentry.GroupOwner", "silos": [ "REGION" ] }, "sentry.GroupRedirect": { + "foreign_keys": {}, "model": "sentry.GroupRedirect", - "relations": {}, "silos": [ "REGION" ] }, "sentry.GroupRelease": { + "foreign_keys": {}, "model": "sentry.GroupRelease", - "relations": {}, "silos": [ "REGION" ] }, "sentry.GroupResolution": { - "model": "sentry.GroupResolution", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1068,13 +1037,13 @@ "model": "sentry.Release" } }, + "model": "sentry.GroupResolution", "silos": [ "REGION" ] }, "sentry.GroupRuleStatus": { - "model": "sentry.GroupRuleStatus", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1088,13 +1057,13 @@ "model": "sentry.Rule" } }, + "model": "sentry.GroupRuleStatus", "silos": [ "REGION" ] }, "sentry.GroupSeen": { - "model": "sentry.GroupSeen", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1104,13 +1073,13 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupSeen", "silos": [ "REGION" ] }, "sentry.GroupShare": { - "model": "sentry.GroupShare", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1120,25 +1089,25 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupShare", "silos": [ "REGION" ] }, "sentry.GroupSnooze": { - "model": "sentry.GroupSnooze", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" } }, + "model": "sentry.GroupSnooze", "silos": [ "REGION" ] }, "sentry.GroupSubscription": { - "model": "sentry.GroupSubscription", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1148,25 +1117,25 @@ "model": "sentry.Project" } }, + "model": "sentry.GroupSubscription", "silos": [ "REGION" ] }, "sentry.GroupTombstone": { - "model": "sentry.GroupTombstone", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.GroupTombstone", "silos": [ "REGION" ] }, "sentry.Identity": { - "model": "sentry.Identity", - "relations": { + "foreign_keys": { "idp": { "kind": "FlexibleForeignKey", "model": "sentry.IdentityProvider" @@ -1176,20 +1145,20 @@ "model": "sentry.User" } }, + "model": "sentry.Identity", "silos": [ "CONTROL" ] }, "sentry.IdentityProvider": { + "foreign_keys": {}, "model": "sentry.IdentityProvider", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.Incident": { - "model": "sentry.Incident", - "relations": { + "foreign_keys": { "alert_rule": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRule" @@ -1197,31 +1166,27 @@ "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" } }, + "model": "sentry.Incident", "silos": [ "REGION" ] }, "sentry.IncidentActivity": { - "model": "sentry.IncidentActivity", - "relations": { + "foreign_keys": { "incident": { "kind": "FlexibleForeignKey", "model": "sentry.Incident" } }, + "model": "sentry.IncidentActivity", "silos": [ "REGION" ] }, "sentry.IncidentProject": { - "model": "sentry.IncidentProject", - "relations": { + "foreign_keys": { "incident": { "kind": "FlexibleForeignKey", "model": "sentry.Incident" @@ -1231,25 +1196,25 @@ "model": "sentry.Project" } }, + "model": "sentry.IncidentProject", "silos": [ "REGION" ] }, "sentry.IncidentSeen": { - "model": "sentry.IncidentSeen", - "relations": { + "foreign_keys": { "incident": { "kind": "FlexibleForeignKey", "model": "sentry.Incident" } }, + "model": "sentry.IncidentSeen", "silos": [ "REGION" ] }, "sentry.IncidentSnapshot": { - "model": "sentry.IncidentSnapshot", - "relations": { + "foreign_keys": { "event_stats_snapshot": { "kind": "FlexibleForeignKey", "model": "sentry.TimeSeriesSnapshot" @@ -1259,25 +1224,25 @@ "model": "sentry.Incident" } }, + "model": "sentry.IncidentSnapshot", "silos": [ "REGION" ] }, "sentry.IncidentSubscription": { - "model": "sentry.IncidentSubscription", - "relations": { + "foreign_keys": { "incident": { "kind": "FlexibleForeignKey", "model": "sentry.Incident" } }, + "model": "sentry.IncidentSubscription", "silos": [ "REGION" ] }, "sentry.IncidentTrigger": { - "model": "sentry.IncidentTrigger", - "relations": { + "foreign_keys": { "alert_rule_trigger": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRuleTrigger" @@ -1287,79 +1252,79 @@ "model": "sentry.Incident" } }, + "model": "sentry.IncidentTrigger", "silos": [ "REGION" ] }, "sentry.Integration": { + "foreign_keys": {}, "model": "sentry.Integration", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.IntegrationExternalProject": { + "foreign_keys": {}, "model": "sentry.IntegrationExternalProject", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.IntegrationFeature": { + "foreign_keys": {}, "model": "sentry.IntegrationFeature", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.LatestAppConnectBuildsCheck": { - "model": "sentry.LatestAppConnectBuildsCheck", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.LatestAppConnectBuildsCheck", "silos": [ "REGION" ] }, "sentry.LatestRepoReleaseEnvironment": { + "foreign_keys": {}, "model": "sentry.LatestRepoReleaseEnvironment", - "relations": {}, "silos": [ "REGION" ] }, "sentry.LostPasswordHash": { - "model": "sentry.LostPasswordHash", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.LostPasswordHash", "silos": [ "CONTROL" ] }, "sentry.MetricsKeyIndexer": { + "foreign_keys": {}, "model": "sentry.MetricsKeyIndexer", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Monitor": { + "foreign_keys": {}, "model": "sentry.Monitor", - "relations": {}, "silos": [ "REGION" ] }, "sentry.MonitorCheckIn": { - "model": "sentry.MonitorCheckIn", - "relations": { + "foreign_keys": { "location": { "kind": "FlexibleForeignKey", "model": "sentry.MonitorLocation" @@ -1373,13 +1338,13 @@ "model": "sentry.MonitorEnvironment" } }, + "model": "sentry.MonitorCheckIn", "silos": [ "REGION" ] }, "sentry.MonitorEnvironment": { - "model": "sentry.MonitorEnvironment", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" @@ -1389,36 +1354,32 @@ "model": "sentry.Monitor" } }, + "model": "sentry.MonitorEnvironment", "silos": [ "REGION" ] }, "sentry.MonitorLocation": { + "foreign_keys": {}, "model": "sentry.MonitorLocation", - "relations": {}, "silos": [ "REGION" ] }, "sentry.NotificationAction": { - "model": "sentry.NotificationAction", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" } }, + "model": "sentry.NotificationAction", "silos": [ "REGION" ] }, "sentry.NotificationActionProject": { - "model": "sentry.NotificationActionProject", - "relations": { + "foreign_keys": { "action": { "kind": "FlexibleForeignKey", "model": "sentry.NotificationAction" @@ -1428,51 +1389,51 @@ "model": "sentry.Project" } }, + "model": "sentry.NotificationActionProject", "silos": [ "REGION" ] }, "sentry.NotificationSetting": { - "model": "sentry.NotificationSetting", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.NotificationSetting", "silos": [ "CONTROL" ] }, "sentry.Option": { + "foreign_keys": {}, "model": "sentry.Option", - "relations": {}, "silos": [ "REGION" ] }, "sentry.OrgAuthToken": { - "model": "sentry.OrgAuthToken", - "relations": { + "foreign_keys": { "created_by": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.OrgAuthToken", "silos": [ "CONTROL" ] }, "sentry.Organization": { + "foreign_keys": {}, "model": "sentry.Organization", - "relations": {}, "silos": [ "REGION" ] }, "sentry.OrganizationAccessRequest": { - "model": "sentry.OrganizationAccessRequest", - "relations": { + "foreign_keys": { "member": { "kind": "FlexibleForeignKey", "model": "sentry.OrganizationMember" @@ -1482,60 +1443,56 @@ "model": "sentry.Team" } }, + "model": "sentry.OrganizationAccessRequest", "silos": [ "REGION" ] }, "sentry.OrganizationAvatar": { - "model": "sentry.OrganizationAvatar", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.OrganizationAvatar", "silos": [ "REGION" ] }, "sentry.OrganizationIntegration": { - "model": "sentry.OrganizationIntegration", - "relations": { + "foreign_keys": { "integration": { "kind": "FlexibleForeignKey", "model": "sentry.Integration" } }, + "model": "sentry.OrganizationIntegration", "silos": [ "CONTROL" ] }, "sentry.OrganizationMapping": { + "foreign_keys": {}, "model": "sentry.OrganizationMapping", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.OrganizationMember": { - "model": "sentry.OrganizationMember", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "teams": { - "kind": "ManyToManyField", - "model": "sentry.Team" } }, + "model": "sentry.OrganizationMember", "silos": [ "REGION" ] }, "sentry.OrganizationMemberMapping": { - "model": "sentry.OrganizationMemberMapping", - "relations": { + "foreign_keys": { "inviter": { "kind": "FlexibleForeignKey", "model": "sentry.User" @@ -1545,13 +1502,13 @@ "model": "sentry.User" } }, + "model": "sentry.OrganizationMemberMapping", "silos": [ "CONTROL" ] }, "sentry.OrganizationMemberTeam": { - "model": "sentry.OrganizationMemberTeam", - "relations": { + "foreign_keys": { "organizationmember": { "kind": "FlexibleForeignKey", "model": "sentry.OrganizationMember" @@ -1561,13 +1518,13 @@ "model": "sentry.Team" } }, + "model": "sentry.OrganizationMemberTeam", "silos": [ "REGION" ] }, "sentry.OrganizationOnboardingTask": { - "model": "sentry.OrganizationOnboardingTask", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -1577,56 +1534,56 @@ "model": "sentry.Project" } }, + "model": "sentry.OrganizationOnboardingTask", "silos": [ "REGION" ] }, "sentry.OrganizationOption": { - "model": "sentry.OrganizationOption", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.OrganizationOption", "silos": [ "REGION" ] }, "sentry.PagerDutyService": { - "model": "sentry.PagerDutyService", - "relations": { + "foreign_keys": { "organization_integration": { "kind": "FlexibleForeignKey", "model": "sentry.OrganizationIntegration" } }, + "model": "sentry.PagerDutyService", "silos": [ "CONTROL" ] }, "sentry.PendingIncidentSnapshot": { - "model": "sentry.PendingIncidentSnapshot", - "relations": { + "foreign_keys": { "incident": { "kind": "OneToOneCascadeDeletes", "model": "sentry.Incident" } }, + "model": "sentry.PendingIncidentSnapshot", "silos": [ "REGION" ] }, "sentry.PerfStringIndexer": { + "foreign_keys": {}, "model": "sentry.PerfStringIndexer", - "relations": {}, "silos": [ "REGION" ] }, "sentry.PlatformExternalIssue": { - "model": "sentry.PlatformExternalIssue", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -1636,89 +1593,85 @@ "model": "sentry.Project" } }, + "model": "sentry.PlatformExternalIssue", "silos": [ "REGION" ] }, "sentry.ProcessingIssue": { - "model": "sentry.ProcessingIssue", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProcessingIssue", "silos": [ "REGION" ] }, "sentry.ProguardArtifactRelease": { - "model": "sentry.ProguardArtifactRelease", - "relations": { + "foreign_keys": { "project_debug_file": { "kind": "FlexibleForeignKey", "model": "sentry.ProjectDebugFile" } }, + "model": "sentry.ProguardArtifactRelease", "silos": [ "REGION" ] }, "sentry.Project": { - "model": "sentry.Project", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "teams": { - "kind": "ManyToManyField", - "model": "sentry.Team" } }, + "model": "sentry.Project", "silos": [ "REGION" ] }, "sentry.ProjectArtifactBundle": { - "model": "sentry.ProjectArtifactBundle", - "relations": { + "foreign_keys": { "artifact_bundle": { "kind": "FlexibleForeignKey", "model": "sentry.ArtifactBundle" } }, + "model": "sentry.ProjectArtifactBundle", "silos": [ "REGION" ] }, "sentry.ProjectAvatar": { - "model": "sentry.ProjectAvatar", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectAvatar", "silos": [ "REGION" ] }, "sentry.ProjectBookmark": { - "model": "sentry.ProjectBookmark", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectBookmark", "silos": [ "REGION" ] }, "sentry.ProjectCodeOwners": { - "model": "sentry.ProjectCodeOwners", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" @@ -1728,80 +1681,80 @@ "model": "sentry.RepositoryProjectPathConfig" } }, + "model": "sentry.ProjectCodeOwners", "silos": [ "REGION" ] }, "sentry.ProjectDebugFile": { - "model": "sentry.ProjectDebugFile", - "relations": { + "foreign_keys": { "file": { "kind": "FlexibleForeignKey", "model": "sentry.File" } }, + "model": "sentry.ProjectDebugFile", "silos": [ "REGION" ] }, "sentry.ProjectIntegration": { - "model": "sentry.ProjectIntegration", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectIntegration", "silos": [ "REGION" ] }, "sentry.ProjectKey": { - "model": "sentry.ProjectKey", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectKey", "silos": [ "REGION" ] }, "sentry.ProjectOption": { - "model": "sentry.ProjectOption", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectOption", "silos": [ "REGION" ] }, "sentry.ProjectOwnership": { - "model": "sentry.ProjectOwnership", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ProjectOwnership", "silos": [ "REGION" ] }, "sentry.ProjectPlatform": { + "foreign_keys": {}, "model": "sentry.ProjectPlatform", - "relations": {}, "silos": [ "REGION" ] }, "sentry.ProjectRedirect": { - "model": "sentry.ProjectRedirect", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -1811,13 +1764,13 @@ "model": "sentry.Project" } }, + "model": "sentry.ProjectRedirect", "silos": [ "REGION" ] }, "sentry.ProjectTeam": { - "model": "sentry.ProjectTeam", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" @@ -1827,13 +1780,13 @@ "model": "sentry.Team" } }, + "model": "sentry.ProjectTeam", "silos": [ "REGION" ] }, "sentry.ProjectTransactionThreshold": { - "model": "sentry.ProjectTransactionThreshold", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -1843,13 +1796,13 @@ "model": "sentry.Project" } }, + "model": "sentry.ProjectTransactionThreshold", "silos": [ "REGION" ] }, "sentry.ProjectTransactionThresholdOverride": { - "model": "sentry.ProjectTransactionThresholdOverride", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -1859,44 +1812,44 @@ "model": "sentry.Project" } }, + "model": "sentry.ProjectTransactionThresholdOverride", "silos": [ "REGION" ] }, "sentry.PromptsActivity": { + "foreign_keys": {}, "model": "sentry.PromptsActivity", - "relations": {}, "silos": [ "REGION" ] }, "sentry.PullRequest": { - "model": "sentry.PullRequest", - "relations": { + "foreign_keys": { "author": { "kind": "FlexibleForeignKey", "model": "sentry.CommitAuthor" } }, + "model": "sentry.PullRequest", "silos": [ "REGION" ] }, "sentry.PullRequestComment": { - "model": "sentry.PullRequestComment", - "relations": { + "foreign_keys": { "pull_request": { "kind": "FlexibleForeignKey", "model": "sentry.PullRequest" } }, + "model": "sentry.PullRequestComment", "silos": [ "REGION" ] }, "sentry.PullRequestCommit": { - "model": "sentry.PullRequestCommit", - "relations": { + "foreign_keys": { "commit": { "kind": "FlexibleForeignKey", "model": "sentry.Commit" @@ -1906,13 +1859,13 @@ "model": "sentry.PullRequest" } }, + "model": "sentry.PullRequestCommit", "silos": [ "REGION" ] }, "sentry.QuerySubscription": { - "model": "sentry.QuerySubscription", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" @@ -1922,112 +1875,108 @@ "model": "sentry.SnubaQuery" } }, + "model": "sentry.QuerySubscription", "silos": [ "REGION" ] }, "sentry.RawEvent": { - "model": "sentry.RawEvent", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.RawEvent", "silos": [ "REGION" ] }, "sentry.RecentSearch": { - "model": "sentry.RecentSearch", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.RecentSearch", "silos": [ "REGION" ] }, "sentry.RegionOutbox": { + "foreign_keys": {}, "model": "sentry.RegionOutbox", - "relations": {}, "silos": [ "REGION" ] }, "sentry.RegionScheduledDeletion": { + "foreign_keys": {}, "model": "sentry.RegionScheduledDeletion", - "relations": {}, "silos": [ "REGION" ] }, "sentry.RegionTombstone": { + "foreign_keys": {}, "model": "sentry.RegionTombstone", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Relay": { + "foreign_keys": {}, "model": "sentry.Relay", - "relations": {}, "silos": [ "REGION" ] }, "sentry.RelayUsage": { + "foreign_keys": {}, "model": "sentry.RelayUsage", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Release": { - "model": "sentry.Release", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" - }, - "projects": { - "kind": "ManyToManyField", - "model": "sentry.Project" } }, + "model": "sentry.Release", "silos": [ "REGION" ] }, "sentry.ReleaseActivity": { - "model": "sentry.ReleaseActivity", - "relations": { + "foreign_keys": { "release": { "kind": "FlexibleForeignKey", "model": "sentry.Release" } }, + "model": "sentry.ReleaseActivity", "silos": [ "REGION" ] }, "sentry.ReleaseArtifactBundle": { - "model": "sentry.ReleaseArtifactBundle", - "relations": { + "foreign_keys": { "artifact_bundle": { "kind": "FlexibleForeignKey", "model": "sentry.ArtifactBundle" } }, + "model": "sentry.ReleaseArtifactBundle", "silos": [ "REGION" ] }, "sentry.ReleaseCommit": { - "model": "sentry.ReleaseCommit", - "relations": { + "foreign_keys": { "commit": { "kind": "FlexibleForeignKey", "model": "sentry.Commit" @@ -2037,13 +1986,13 @@ "model": "sentry.Release" } }, + "model": "sentry.ReleaseCommit", "silos": [ "REGION" ] }, "sentry.ReleaseEnvironment": { - "model": "sentry.ReleaseEnvironment", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" @@ -2057,25 +2006,25 @@ "model": "sentry.Release" } }, + "model": "sentry.ReleaseEnvironment", "silos": [ "REGION" ] }, "sentry.ReleaseFile": { - "model": "sentry.ReleaseFile", - "relations": { + "foreign_keys": { "file": { "kind": "FlexibleForeignKey", "model": "sentry.File" } }, + "model": "sentry.ReleaseFile", "silos": [ "REGION" ] }, "sentry.ReleaseHeadCommit": { - "model": "sentry.ReleaseHeadCommit", - "relations": { + "foreign_keys": { "commit": { "kind": "FlexibleForeignKey", "model": "sentry.Commit" @@ -2085,13 +2034,13 @@ "model": "sentry.Release" } }, + "model": "sentry.ReleaseHeadCommit", "silos": [ "REGION" ] }, "sentry.ReleaseProject": { - "model": "sentry.ReleaseProject", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" @@ -2101,13 +2050,13 @@ "model": "sentry.Release" } }, + "model": "sentry.ReleaseProject", "silos": [ "REGION" ] }, "sentry.ReleaseProjectEnvironment": { - "model": "sentry.ReleaseProjectEnvironment", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" @@ -2121,20 +2070,20 @@ "model": "sentry.Release" } }, + "model": "sentry.ReleaseProjectEnvironment", "silos": [ "REGION" ] }, "sentry.Repository": { + "foreign_keys": {}, "model": "sentry.Repository", - "relations": {}, "silos": [ "REGION" ] }, "sentry.RepositoryProjectPathConfig": { - "model": "sentry.RepositoryProjectPathConfig", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" @@ -2144,25 +2093,25 @@ "model": "sentry.Repository" } }, + "model": "sentry.RepositoryProjectPathConfig", "silos": [ "REGION" ] }, "sentry.ReprocessingReport": { - "model": "sentry.ReprocessingReport", - "relations": { + "foreign_keys": { "project": { "kind": "FlexibleForeignKey", "model": "sentry.Project" } }, + "model": "sentry.ReprocessingReport", "silos": [ "REGION" ] }, "sentry.Rule": { - "model": "sentry.Rule", - "relations": { + "foreign_keys": { "owner": { "kind": "FlexibleForeignKey", "model": "sentry.Actor" @@ -2172,25 +2121,25 @@ "model": "sentry.Project" } }, + "model": "sentry.Rule", "silos": [ "REGION" ] }, "sentry.RuleActivity": { - "model": "sentry.RuleActivity", - "relations": { + "foreign_keys": { "rule": { "kind": "FlexibleForeignKey", "model": "sentry.Rule" } }, + "model": "sentry.RuleActivity", "silos": [ "REGION" ] }, "sentry.RuleFireHistory": { - "model": "sentry.RuleFireHistory", - "relations": { + "foreign_keys": { "group": { "kind": "FlexibleForeignKey", "model": "sentry.Group" @@ -2204,13 +2153,13 @@ "model": "sentry.Rule" } }, + "model": "sentry.RuleFireHistory", "silos": [ "REGION" ] }, "sentry.RuleSnooze": { - "model": "sentry.RuleSnooze", - "relations": { + "foreign_keys": { "alert_rule": { "kind": "FlexibleForeignKey", "model": "sentry.AlertRule" @@ -2220,32 +2169,32 @@ "model": "sentry.Rule" } }, + "model": "sentry.RuleSnooze", "silos": [ "REGION" ] }, "sentry.SavedSearch": { - "model": "sentry.SavedSearch", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.SavedSearch", "silos": [ "REGION" ] }, "sentry.ScheduledDeletion": { + "foreign_keys": {}, "model": "sentry.ScheduledDeletion", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.SentryApp": { - "model": "sentry.SentryApp", - "relations": { + "foreign_keys": { "application": { "kind": "DefaultOneToOneField", "model": "sentry.ApiApplication" @@ -2259,37 +2208,37 @@ "model": "sentry.User" } }, + "model": "sentry.SentryApp", "silos": [ "CONTROL" ] }, "sentry.SentryAppAvatar": { - "model": "sentry.SentryAppAvatar", - "relations": { + "foreign_keys": { "sentry_app": { "kind": "FlexibleForeignKey", "model": "sentry.SentryApp" } }, + "model": "sentry.SentryAppAvatar", "silos": [ "CONTROL" ] }, "sentry.SentryAppComponent": { - "model": "sentry.SentryAppComponent", - "relations": { + "foreign_keys": { "sentry_app": { "kind": "FlexibleForeignKey", "model": "sentry.SentryApp" } }, + "model": "sentry.SentryAppComponent", "silos": [ "CONTROL" ] }, "sentry.SentryAppInstallation": { - "model": "sentry.SentryAppInstallation", - "relations": { + "foreign_keys": { "api_grant": { "kind": "DefaultOneToOneField", "model": "sentry.ApiGrant" @@ -2303,25 +2252,25 @@ "model": "sentry.SentryApp" } }, + "model": "sentry.SentryAppInstallation", "silos": [ "CONTROL" ] }, "sentry.SentryAppInstallationForProvider": { - "model": "sentry.SentryAppInstallationForProvider", - "relations": { + "foreign_keys": { "sentry_app_installation": { "kind": "FlexibleForeignKey", "model": "sentry.SentryAppInstallation" } }, + "model": "sentry.SentryAppInstallationForProvider", "silos": [ "CONTROL" ] }, "sentry.SentryAppInstallationToken": { - "model": "sentry.SentryAppInstallationToken", - "relations": { + "foreign_keys": { "api_token": { "kind": "FlexibleForeignKey", "model": "sentry.ApiToken" @@ -2331,75 +2280,75 @@ "model": "sentry.SentryAppInstallation" } }, + "model": "sentry.SentryAppInstallationToken", "silos": [ "CONTROL" ] }, "sentry.SentryFunction": { - "model": "sentry.SentryFunction", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" } }, + "model": "sentry.SentryFunction", "silos": [ "REGION" ] }, "sentry.ServiceHook": { + "foreign_keys": {}, "model": "sentry.ServiceHook", - "relations": {}, "silos": [ "REGION" ] }, "sentry.ServiceHookProject": { - "model": "sentry.ServiceHookProject", - "relations": { + "foreign_keys": { "service_hook": { "kind": "FlexibleForeignKey", "model": "sentry.ServiceHook" } }, + "model": "sentry.ServiceHookProject", "silos": [ "REGION" ] }, "sentry.SnubaQuery": { - "model": "sentry.SnubaQuery", - "relations": { + "foreign_keys": { "environment": { "kind": "FlexibleForeignKey", "model": "sentry.Environment" } }, + "model": "sentry.SnubaQuery", "silos": [ "REGION" ] }, "sentry.SnubaQueryEventType": { - "model": "sentry.SnubaQueryEventType", - "relations": { + "foreign_keys": { "snuba_query": { "kind": "FlexibleForeignKey", "model": "sentry.SnubaQuery" } }, + "model": "sentry.SnubaQueryEventType", "silos": [ "REGION" ] }, "sentry.StringIndexer": { + "foreign_keys": {}, "model": "sentry.StringIndexer", - "relations": {}, "silos": [ "REGION" ] }, "sentry.Team": { - "model": "sentry.Team", - "relations": { + "foreign_keys": { "actor": { "kind": "FlexibleForeignKey", "model": "sentry.Actor" @@ -2409,25 +2358,25 @@ "model": "sentry.Organization" } }, + "model": "sentry.Team", "silos": [ "REGION" ] }, "sentry.TeamAvatar": { - "model": "sentry.TeamAvatar", - "relations": { + "foreign_keys": { "team": { "kind": "FlexibleForeignKey", "model": "sentry.Team" } }, + "model": "sentry.TeamAvatar", "silos": [ "REGION" ] }, "sentry.TeamKeyTransaction": { - "model": "sentry.TeamKeyTransaction", - "relations": { + "foreign_keys": { "organization": { "kind": "FlexibleForeignKey", "model": "sentry.Organization" @@ -2437,106 +2386,101 @@ "model": "sentry.ProjectTeam" } }, + "model": "sentry.TeamKeyTransaction", "silos": [ "REGION" ] }, "sentry.TimeSeriesSnapshot": { + "foreign_keys": {}, "model": "sentry.TimeSeriesSnapshot", - "relations": {}, "silos": [ "REGION" ] }, "sentry.User": { + "foreign_keys": {}, "model": "sentry.User", - "relations": {}, "silos": [ "CONTROL" ] }, "sentry.UserAvatar": { - "model": "sentry.UserAvatar", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.UserAvatar", "silos": [ "CONTROL" ] }, "sentry.UserEmail": { - "model": "sentry.UserEmail", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.UserEmail", "silos": [ "CONTROL" ] }, "sentry.UserIP": { - "model": "sentry.UserIP", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.UserIP", "silos": [ "CONTROL" ] }, "sentry.UserOption": { - "model": "sentry.UserOption", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.UserOption", "silos": [ "CONTROL" ] }, "sentry.UserPermission": { - "model": "sentry.UserPermission", - "relations": { + "foreign_keys": { "user": { "kind": "FlexibleForeignKey", "model": "sentry.User" } }, + "model": "sentry.UserPermission", "silos": [ "CONTROL" ] }, "sentry.UserReport": { + "foreign_keys": {}, "model": "sentry.UserReport", - "relations": {}, "silos": [ "REGION" ] }, "sentry.UserRole": { + "foreign_keys": {}, "model": "sentry.UserRole", - "relations": { - "users": { - "kind": "ManyToManyField", - "model": "sentry.User" - } - }, "silos": [ "CONTROL" ] }, "sentry.UserRoleUser": { - "model": "sentry.UserRoleUser", - "relations": { + "foreign_keys": { "role": { "kind": "FlexibleForeignKey", "model": "sentry.UserRole" @@ -2546,32 +2490,33 @@ "model": "sentry.User" } }, + "model": "sentry.UserRoleUser", "silos": [ "CONTROL" ] }, "sessions.Session": { + "foreign_keys": {}, "model": "sessions.Session", - "relations": {}, "silos": [ "MONOLITH" ] }, "sites.Site": { + "foreign_keys": {}, "model": "sites.Site", - "relations": {}, "silos": [ "MONOLITH" ] }, "social_auth.UserSocialAuth": { - "model": "social_auth.UserSocialAuth", - "relations": { + "foreign_keys": { "user": { "kind": "DefaultForeignKey", "model": "sentry.User" } }, + "model": "social_auth.UserSocialAuth", "silos": [ "CONTROL" ] diff --git a/fixtures/backup/model_dependencies/flat.json b/fixtures/backup/model_dependencies/flat.json index 5d7e1418203d87..b7164d6a1c022c 100644 --- a/fixtures/backup/model_dependencies/flat.json +++ b/fixtures/backup/model_dependencies/flat.json @@ -9,7 +9,6 @@ "sentry.AlertRule": [ "sentry.Actor", "sentry.Organization", - "sentry.Project", "sentry.SnubaQuery" ], "sentry.AlertRuleActivity": [ @@ -20,8 +19,7 @@ "sentry.Project" ], "sentry.AlertRuleTrigger": [ - "sentry.AlertRule", - "sentry.Incident" + "sentry.AlertRule" ], "sentry.AlertRuleTriggerAction": [ "sentry.AlertRuleTrigger" @@ -86,9 +84,7 @@ "sentry.CommitFileChange": [ "sentry.Commit" ], - "sentry.ControlFile": [ - "sentry.ControlFileBlob" - ], + "sentry.ControlFile": [], "sentry.ControlFileBlob": [], "sentry.ControlFileBlobIndex": [ "sentry.ControlFile", @@ -104,8 +100,7 @@ "sentry.Project" ], "sentry.Dashboard": [ - "sentry.Organization", - "sentry.Project" + "sentry.Organization" ], "sentry.DashboardProject": [ "sentry.Dashboard", @@ -130,8 +125,7 @@ "sentry.Release" ], "sentry.DiscoverSavedQuery": [ - "sentry.Organization", - "sentry.Project" + "sentry.Organization" ], "sentry.DiscoverSavedQueryProject": [ "sentry.DiscoverSavedQuery", @@ -145,9 +139,7 @@ "sentry.DocIntegration" ], "sentry.Email": [], - "sentry.Environment": [ - "sentry.Project" - ], + "sentry.Environment": [], "sentry.EnvironmentProject": [ "sentry.Environment", "sentry.Project" @@ -277,8 +269,7 @@ "sentry.IdentityProvider": [], "sentry.Incident": [ "sentry.AlertRule", - "sentry.Organization", - "sentry.Project" + "sentry.Organization" ], "sentry.IncidentActivity": [ "sentry.Incident" @@ -324,8 +315,7 @@ ], "sentry.MonitorLocation": [], "sentry.NotificationAction": [ - "sentry.Organization", - "sentry.Project" + "sentry.Organization" ], "sentry.NotificationActionProject": [ "sentry.NotificationAction", @@ -351,8 +341,7 @@ ], "sentry.OrganizationMapping": [], "sentry.OrganizationMember": [ - "sentry.Organization", - "sentry.Team" + "sentry.Organization" ], "sentry.OrganizationMemberMapping": [ "sentry.User" @@ -386,8 +375,7 @@ "sentry.ProjectDebugFile" ], "sentry.Project": [ - "sentry.Organization", - "sentry.Team" + "sentry.Organization" ], "sentry.ProjectArtifactBundle": [ "sentry.ArtifactBundle" @@ -461,8 +449,7 @@ "sentry.Relay": [], "sentry.RelayUsage": [], "sentry.Release": [ - "sentry.Organization", - "sentry.Project" + "sentry.Organization" ], "sentry.ReleaseActivity": [ "sentry.Release" @@ -588,9 +575,7 @@ "sentry.User" ], "sentry.UserReport": [], - "sentry.UserRole": [ - "sentry.User" - ], + "sentry.UserRole": [], "sentry.UserRoleUser": [ "sentry.User", "sentry.UserRole" diff --git a/fixtures/backup/model_dependencies/sorted.json b/fixtures/backup/model_dependencies/sorted.json index cfae1388296aca..ba1f837055756a 100644 --- a/fixtures/backup/model_dependencies/sorted.json +++ b/fixtures/backup/model_dependencies/sorted.json @@ -21,12 +21,14 @@ "sentry.DeletedProject", "sentry.DeletedTeam", "sentry.Email", + "sentry.Environment", "sentry.EventAttachment", "sentry.EventUser", "sentry.GroupCommitResolution", "sentry.GroupRedirect", "sentry.GroupRelease", "sentry.Organization", + "sentry.Release", "sentry.IdentityProvider", "sentry.DocIntegration", "sentry.ExternalActor", @@ -40,15 +42,29 @@ "sentry.OrganizationMapping", "sentry.OrganizationMemberMapping", "sentry.OrgAuthToken", + "sentry.SnubaQuery", + "sentry.SnubaQueryEventType", + "sentry.Project", + "sentry.ProjectBookmark", + "sentry.ProjectKey", + "sentry.ProjectOwnership", "sentry.ProjectPlatform", + "sentry.ProjectRedirect", "sentry.PromptsActivity", "sentry.PullRequest", "sentry.PullRequestComment", + "sentry.RawEvent", "sentry.RecentSearch", "sentry.RelayUsage", "sentry.Relay", + "sentry.ReleaseActivity", + "sentry.ReleaseEnvironment", "sentry.ReleaseFile", + "sentry.ReleaseProjectEnvironment", "sentry.Repository", + "sentry.ReprocessingReport", + "sentry.Rule", + "sentry.RuleActivity", "sentry.SavedSearch", "sentry.ScheduledDeletion", "sentry.RegionScheduledDeletion", @@ -56,15 +72,24 @@ "sentry.ServiceHook", "sentry.RegionTombstone", "sentry.ControlTombstone", + "sentry.ProjectTransactionThresholdOverride", + "sentry.ProjectTransactionThreshold", "sentry.UserEmail", "sentry.UserIP", "sentry.UserPermission", "sentry.UserReport", "sentry.UserRole", "sentry.UserRoleUser", + "sentry.NotificationAction", "sentry.TimeSeriesSnapshot", + "sentry.AlertRule", + "sentry.AlertRuleTrigger", + "sentry.AlertRuleTriggerAction", + "sentry.AlertRuleActivity", + "sentry.DiscoverSavedQuery", "sentry.Monitor", "sentry.MonitorLocation", + "sentry.MonitorEnvironment", "sentry.MetricsKeyIndexer", "sentry.StringIndexer", "sentry.PerfStringIndexer", @@ -73,17 +98,44 @@ "nodestore.Node", "replays.ReplayRecordingSegment", "social_auth.UserSocialAuth", + "sentry.MonitorCheckIn", + "sentry.DiscoverSavedQueryProject", + "sentry.AlertRuleExcludedProjects", + "sentry.Incident", + "sentry.IncidentSeen", + "sentry.IncidentProject", + "sentry.NotificationActionProject", "sentry.ServiceHookProject", + "sentry.RuleSnooze", + "sentry.QuerySubscription", + "sentry.ProcessingIssue", + "sentry.OrganizationOnboardingTask", "sentry.LostPasswordHash", + "sentry.LatestAppConnectBuildsCheck", + "sentry.RepositoryProjectPathConfig", + "sentry.ProjectIntegration", "sentry.OrganizationIntegration", "sentry.Identity", + "sentry.GroupTombstone", + "sentry.ReleaseProject", + "sentry.OrganizationMember", "sentry.Team", + "sentry.OrganizationMemberTeam", + "sentry.Group", + "sentry.GroupHistory", "sentry.FeatureAdoption", + "sentry.EnvironmentProject", + "sentry.Distribution", + "sentry.Deploy", "sentry.DashboardTombstone", + "sentry.Dashboard", + "sentry.DashboardProject", + "sentry.Counter", "sentry.Commit", "sentry.BroadcastSeen", "sentry.UserAvatar", "sentry.TeamAvatar", + "sentry.ProjectAvatar", "sentry.OrganizationAvatar", "sentry.DocIntegrationAvatar", "sentry.FileBlobIndex", @@ -96,9 +148,12 @@ "sentry.AssistantActivity", "sentry.ArtifactBundleFlatFileIndex", "sentry.ArtifactBundle", + "sentry.AppConnectBuild", "sentry.ApiApplication", "sentry.UserOption", + "sentry.ProjectOption", "sentry.OrganizationOption", + "sentry.Activity", "sentry.ApiAuthorization", "sentry.ApiGrant", "sentry.ApiToken", @@ -108,54 +163,6 @@ "sentry.DebugIdArtifactBundle", "sentry.ProjectArtifactBundle", "sentry.CommitFileChange", - "sentry.OrganizationMember", - "sentry.SentryApp", - "sentry.PagerDutyService", - "sentry.SentryAppComponent", - "sentry.SentryAppInstallation", - "sentry.SentryAppInstallationForProvider", - "sentry.SentryAppInstallationToken", - "sentry.OrganizationAccessRequest", - "sentry.Project", - "sentry.ProjectBookmark", - "sentry.ProjectKey", - "sentry.ProjectOwnership", - "sentry.ProjectRedirect", - "sentry.PullRequestCommit", - "sentry.RawEvent", - "sentry.ReprocessingReport", - "sentry.Rule", - "sentry.RuleActivity", - "sentry.ProjectTransactionThresholdOverride", - "sentry.ProjectTransactionThreshold", - "sentry.NotificationAction", - "sentry.DiscoverSavedQuery", - "sentry.DiscoverSavedQueryProject", - "sentry.NotificationActionProject", - "sentry.ProjectTeam", - "sentry.ProcessingIssue", - "sentry.OrganizationOnboardingTask", - "sentry.LatestAppConnectBuildsCheck", - "sentry.RepositoryProjectPathConfig", - "sentry.ProjectIntegration", - "sentry.GroupTombstone", - "sentry.Release", - "sentry.ReleaseProject", - "sentry.OrganizationMemberTeam", - "sentry.Group", - "sentry.GroupHistory", - "sentry.Environment", - "sentry.EnvironmentProject", - "sentry.Distribution", - "sentry.Deploy", - "sentry.Dashboard", - "sentry.DashboardProject", - "sentry.Counter", - "sentry.SentryAppAvatar", - "sentry.ProjectAvatar", - "sentry.AppConnectBuild", - "sentry.ProjectOption", - "sentry.Activity", "sentry.DashboardWidget", "sentry.GroupOwner", "sentry.GroupAssignee", @@ -172,35 +179,28 @@ "sentry.GroupShare", "sentry.GroupSnooze", "sentry.GroupSubscription", + "sentry.SentryApp", + "sentry.PagerDutyService", + "sentry.SentryAppComponent", + "sentry.SentryAppInstallation", + "sentry.SentryAppInstallationForProvider", + "sentry.SentryAppInstallationToken", + "sentry.OrganizationAccessRequest", "sentry.PlatformExternalIssue", "sentry.EventProcessingIssue", - "sentry.SnubaQuery", - "sentry.SnubaQueryEventType", - "sentry.QuerySubscription", + "sentry.ProjectTeam", "sentry.ProjectCodeOwners", - "sentry.ReleaseActivity", + "sentry.PullRequestCommit", "sentry.ReleaseCommit", - "sentry.ReleaseEnvironment", "sentry.ReleaseHeadCommit", - "sentry.ReleaseProjectEnvironment", "sentry.RuleFireHistory", - "sentry.AlertRule", - "sentry.AlertRuleActivity", - "sentry.TeamKeyTransaction", - "sentry.MonitorEnvironment", - "sentry.MonitorCheckIn", - "sentry.AlertRuleExcludedProjects", - "sentry.Incident", - "sentry.IncidentSeen", - "sentry.IncidentProject", - "sentry.RuleSnooze", - "sentry.DashboardWidgetQuery", "sentry.PendingIncidentSnapshot", "sentry.IncidentSnapshot", "sentry.IncidentActivity", "sentry.IncidentSubscription", - "sentry.AlertRuleTrigger", + "sentry.IncidentTrigger", "sentry.AlertRuleTriggerExclusion", - "sentry.AlertRuleTriggerAction", - "sentry.IncidentTrigger" + "sentry.TeamKeyTransaction", + "sentry.DashboardWidgetQuery", + "sentry.SentryAppAvatar" ] \ No newline at end of file diff --git a/src/sentry/backup/dependencies.py b/src/sentry/backup/dependencies.py index 77b4c31267a465..7421f4af8bb5fc 100644 --- a/src/sentry/backup/dependencies.py +++ b/src/sentry/backup/dependencies.py @@ -4,7 +4,7 @@ from typing import NamedTuple from django.db import models -from django.db.models.fields.related import ForeignKey, ManyToManyField, OneToOneField +from django.db.models.fields.related import ForeignKey, OneToOneField from sentry.backup.helpers import EXCLUDED_APPS from sentry.silo import SiloMode @@ -24,9 +24,6 @@ class ForeignFieldKind(Enum): # Uses our `OneToOneCascadeDeletes` wrapper. OneToOneCascadeDeletes = auto() - # A naked usage of Django's `ManyToManyField`. - ManyToManyField = auto() - # A naked usage of Django's `ForeignKey`. DefaultForeignKey = auto() @@ -45,13 +42,13 @@ class ModelRelations(NamedTuple): """What other models does this model depend on, and how?""" model: models.base.ModelBase - relations: dict[str, ForeignField] + foreign_keys: dict[str, ForeignField] silos: list[SiloMode] def flatten(self) -> set[models.base.ModelBase]: """Returns a flat list of all related models, omitting the kind of relation they have.""" - return {ff.model for ff in self.relations.values()} + return {ff.model for ff in self.foreign_keys.values()} def normalize_model_name(model): @@ -95,7 +92,7 @@ def dependencies() -> dict[str, ModelRelations]: model_iterator = app_config.get_models() for model in model_iterator: - relations: dict[str, ForeignField] = dict() + foreign_keys: dict[str, ForeignField] = dict() # Now add a dependency for any FK relation with a model that defines a natural key. for field in model._meta.fields: @@ -108,34 +105,22 @@ def dependencies() -> dict[str, ModelRelations]: continue if isinstance(field, FlexibleForeignKey): - relations[field.name] = ForeignField( + foreign_keys[field.name] = ForeignField( model=rel_model, kind=ForeignFieldKind.FlexibleForeignKey, ) elif isinstance(field, HybridCloudForeignKey): - relations[field.name] = ForeignField( + foreign_keys[field.name] = ForeignField( model=rel_model, kind=ForeignFieldKind.HybridCloudForeignKey, ) elif isinstance(field, ForeignKey): - relations[field.name] = ForeignField( + foreign_keys[field.name] = ForeignField( model=rel_model, kind=ForeignFieldKind.DefaultForeignKey, ) - # Also add a dependency for any simple M2M relation. - many_to_many_fields = [ - field for field in model._meta.get_fields() if isinstance(field, ManyToManyField) - ] - for field in many_to_many_fields: - rel_model = getattr(field.remote_field, "model", None) - if rel_model is not None and rel_model != model: - relations[field.name] = ForeignField( - model=rel_model, - kind=ForeignFieldKind.ManyToManyField, - ) - - # Finally, get all simple O2O relations as well. + # Get all simple O2O relations as well. one_to_one_fields = [ field for field in model._meta.get_fields() if isinstance(field, OneToOneField) ] @@ -143,12 +128,12 @@ def dependencies() -> dict[str, ModelRelations]: rel_model = getattr(field.remote_field, "model", None) if rel_model is not None and rel_model != model: if isinstance(field, OneToOneCascadeDeletes): - relations[field.name] = ForeignField( + foreign_keys[field.name] = ForeignField( model=rel_model, kind=ForeignFieldKind.OneToOneCascadeDeletes, ) elif isinstance(field, OneToOneField): - relations[field.name] = ForeignField( + foreign_keys[field.name] = ForeignField( model=rel_model, kind=ForeignFieldKind.DefaultOneToOneField, ) @@ -157,7 +142,7 @@ def dependencies() -> dict[str, ModelRelations]: model_dependencies_list[normalize_model_name(model)] = ModelRelations( model=model, - relations=relations, + foreign_keys=foreign_keys, silos=list( getattr(model._meta, "silo_limit", ModelSiloLimit(SiloMode.MONOLITH)).modes ), diff --git a/tests/sentry/backup/test_coverage.py b/tests/sentry/backup/test_coverage.py index 6c1a7af584ed66..f209c593b7e8b1 100644 --- a/tests/sentry/backup/test_coverage.py +++ b/tests/sentry/backup/test_coverage.py @@ -1,6 +1,6 @@ from __future__ import annotations -from sentry.backup.helpers import get_exportable_final_derivations_of, get_final_derivations_of +from sentry.backup.helpers import get_exportable_final_derivations_of from sentry.db.models import BaseModel from tests.sentry.backup.test_models import UNIT_TESTED_MODELS from tests.sentry.backup.test_releases import RELEASE_TESTED_MODELS @@ -8,18 +8,6 @@ ALL_EXPORTABLE_MODELS = {c.__name__ for c in get_exportable_final_derivations_of(BaseModel)} -# Note: this gets checked at runtime, but better to avoid possible runtime errors and catch it early -# in CI. -def test_all_final_derivations_of_django_model_set_included_in_export(): - missing = set( - filter( - lambda c: not hasattr(c, "__include_in_export__"), - get_final_derivations_of(BaseModel), - ) - ) - assert not missing - - def test_exportable_final_derivations_of_django_model_are_unit_tested(): untested = ALL_EXPORTABLE_MODELS - UNIT_TESTED_MODELS assert not untested diff --git a/tests/sentry/backup/test_invariants.py b/tests/sentry/backup/test_invariants.py new file mode 100644 index 00000000000000..36b612d8af873c --- /dev/null +++ b/tests/sentry/backup/test_invariants.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from django.db.models.fields.related import ManyToManyField + +from sentry.backup.helpers import get_exportable_final_derivations_of, get_final_derivations_of +from sentry.db.models import BaseModel + + +# Note: this gets checked at runtime, but better to avoid possible runtime errors and catch it early +# in CI. +def test_all_final_derivations_of_django_model_set_included_in_export(): + missing = set( + filter( + lambda c: not hasattr(c, "__include_in_export__"), + get_final_derivations_of(BaseModel), + ) + ) + assert not missing + + +def test_all_many_to_many_fields_explicitly_set_through_attribute(): + # Make sure we are visiting the field definitions correctly. + visited = 0 + + for model in get_exportable_final_derivations_of(BaseModel): + many_to_many_fields = [ + field for field in model._meta.get_fields() if isinstance(field, ManyToManyField) + ] + for field in many_to_many_fields: + if field.remote_field.through is not None and field.remote_field.through._meta: + if field.remote_field.through._meta.auto_created: + raise AssertionError( + f"""{model!r} model has a `ManyToManyField` field, "{field.name}", that does not set an explicit `through=...` junction model.""" + ) + else: + visited += 1 + + assert visited > 0