Browse Source

fix(semver): Set semver cols on pre_save (#28946)

Creates a pre_save signal that parses release
version into semver on creation
Ahmed Etefy 3 years ago
parent
commit
3cc2e18152
2 changed files with 50 additions and 10 deletions
  1. 13 10
      src/sentry/models/release.py
  2. 37 0
      tests/sentry/models/test_release.py

+ 13 - 10
src/sentry/models/release.py

@@ -8,6 +8,7 @@ from typing import List, Mapping, Optional, Sequence, Union
 import sentry_sdk
 from django.db import IntegrityError, models, router
 from django.db.models import Case, F, Func, Q, Subquery, Sum, Value, When
+from django.db.models.signals import pre_save
 from django.utils import timezone
 from django.utils.functional import cached_property
 from django.utils.translation import ugettext_lazy as _
@@ -268,7 +269,7 @@ class ReleaseQuerySet(models.QuerySet):
         return self.order_by("-date_added", "-id")
 
     @staticmethod
-    def _massage_semver_cols_into_release_object_data(kwargs):
+    def massage_semver_cols_into_release_object_data(kwargs):
         """
         Helper function that takes kwargs as an argument and massages into it the release semver
         columns (if possible)
@@ -324,15 +325,6 @@ class ReleaseQuerySet(models.QuerySet):
                 pass
         return build_number
 
-    def create(self, *args, **kwargs):
-        """
-        Override create method to parse semver release if it follows semver format, and updates the
-        release object that is about to be created with semver columns i.e. major, minor, patch,
-        revision, prerelease, build_code, build_number and package
-        """
-        self._massage_semver_cols_into_release_object_data(kwargs)
-        return super().create(*args, **kwargs)
-
 
 class ReleaseModelManager(BaseManager):
     def get_queryset(self):
@@ -1159,3 +1151,14 @@ def follows_semver_versioning_scheme(org_id, project_id, release_version=None):
     if release_version:
         follows_semver = follows_semver and Release.is_semver_version(release_version)
     return follows_semver
+
+
+def parse_semver_pre_save(instance, **kwargs):
+    if instance.id:
+        return
+    ReleaseQuerySet.massage_semver_cols_into_release_object_data(instance.__dict__)
+
+
+pre_save.connect(
+    parse_semver_pre_save, sender="sentry.Release", dispatch_uid="parse_semver_pre_save"
+)

+ 37 - 0
tests/sentry/models/test_release.py

@@ -847,6 +847,43 @@ class SemverReleaseParseTestCase(TestCase):
         assert release.build_number is None
         assert release.package == "org.example.FooApp"
 
+    def test_parse_release_into_semver_cols_on_pre_save(self):
+        """
+        Test that ensures that calling save on a new Release instance parses version into semver
+        columns
+        """
+        version = "org.example.FooApp@1.0rc1+-2020"
+        release = Release(organization=self.org, version=version)
+        release.save()
+        assert release.major == 1
+        assert release.minor == 0
+        assert release.patch == 0
+        assert release.revision == 0
+        assert release.prerelease == "rc1"
+        assert release.build_code == "-2020"
+        assert release.build_number is None
+        assert release.package == "org.example.FooApp"
+
+    def test_does_not_parse_release_into_semver_cols_on_pre_save_for_existing_release(self):
+        """
+        Test that ensures that calling save on an existing Release instance does not re-parse
+        version into semver columns
+        """
+        version = "org.example.FooApp@1.0rc1+-2020"
+        release = Release(organization=self.org, version=version)
+        release.save()
+        assert release.major == 1
+        assert release.minor == 0
+        assert release.patch == 0
+        assert release.revision == 0
+        assert release.prerelease == "rc1"
+        assert release.build_code == "-2020"
+        assert release.build_number is None
+        assert release.package == "org.example.FooApp"
+        release.version = "org.example.FooApp@1.0rc1+-1999"
+        release.save()
+        assert release.build_code == "-2020"
+
 
 class ReleaseFilterBySemverTest(TestCase):
     def test_invalid_query(self):