Просмотр исходного кода

fix(projects): Backfill `has_release` flag for `Project` rows (#34209)

Relies on https://github.com/getsentry/sentry/pull/34205

Once we've deployed 34205 we can run this backfill to correct old bad data.
Dan Fuller 2 лет назад
Родитель
Сommit
1f2e52553c

+ 1 - 1
migrations_lockfile.txt

@@ -6,5 +6,5 @@ To resolve this, rebase against latest master and regenerate your migration. Thi
 will then be regenerated, and you should be able to merge without conflicts.
 
 nodestore: 0002_nodestore_no_dictfield
-sentry: 0289_dashboardwidgetquery_convert_orderby_to_field
+sentry: 0290_fix_project_has_releases
 social_auth: 0001_initial

+ 52 - 0
src/sentry/migrations/0290_fix_project_has_releases.py

@@ -0,0 +1,52 @@
+# Generated by Django 2.2.24 on 2022-05-03 22:33
+
+from django.db import migrations
+
+from sentry.new_migrations.migrations import CheckedMigration
+from sentry.utils.query import RangeQuerySetWrapperWithProgressBar
+
+
+def backfill_project_has_release(apps, schema_editor):
+    # We have some projects that don't have the `has_release` flag correctly set. We want to go
+    # through all projects and if they don't have `has_release` set, check whether they're
+    # associated with any release and set the flag.
+    Project = apps.get_model("sentry", "Project")
+    ReleaseProject = apps.get_model("sentry", "ReleaseProject")
+    for project in RangeQuerySetWrapperWithProgressBar(Project.objects.all()):
+        if (
+            not project.flags.has_releases
+            and ReleaseProject.objects.filter(project=project).exists()
+        ):
+            project.flags.has_releases = True
+            project.save(update_fields=["flags"])
+
+
+class Migration(CheckedMigration):
+    # This flag is used to mark that a migration shouldn't be automatically run in production. For
+    # the most part, this should only be used for operations where it's safe to run the migration
+    # after your code has deployed. So this should not be used for most operations that alter the
+    # schema of a table.
+    # Here are some things that make sense to mark as dangerous:
+    # - Large data migrations. Typically we want these to be run manually by ops so that they can
+    #   be monitored and not block the deploy for a long period of time while they run.
+    # - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
+    #   have ops run this and not block the deploy. Note that while adding an index is a schema
+    #   change, it's completely safe to run the operation after the code has deployed.
+    is_dangerous = True
+
+    # This flag is used to decide whether to run this migration in a transaction or not. Generally
+    # we don't want to run in a transaction here, since for long running operations like data
+    # back-fills this results in us locking an increasing number of rows until we finally commit.
+    atomic = False
+
+    dependencies = [
+        ("sentry", "0289_dashboardwidgetquery_convert_orderby_to_field"),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            backfill_project_has_release,
+            migrations.RunPython.noop,
+            hints={"tables": ["sentry_release", "sentry_project", "sentry_releaseproject"]},
+        ),
+    ]

+ 21 - 0
tests/sentry/migrations/test_0290_fix_project_has_releases.py

@@ -0,0 +1,21 @@
+from sentry.models import ReleaseProject
+from sentry.testutils.cases import TestMigrations
+
+
+class BackfillProjectHasReleaseTest(TestMigrations):
+    migrate_from = "0289_dashboardwidgetquery_convert_orderby_to_field"
+    migrate_to = "0290_fix_project_has_releases"
+
+    def setup_before_migration(self, apps):
+        self.project.flags.has_releases = False
+        self.project.save(update_fields=["flags"])
+        ReleaseProject.objects.get_or_create(project=self.project, release=self.release)
+        self.no_release_project = self.create_project()
+
+    def test(self):
+        for project, should_have_releases in [
+            (self.project, True),
+            (self.no_release_project, False),
+        ]:
+            project.refresh_from_db()
+            assert project.flags.has_releases == should_have_releases