Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 5 additions & 31 deletions src/sentry/api/helpers/group_index/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
from sentry.models.grouphistory import record_group_history_from_activity_type
from sentry.models.groupinbox import GroupInboxRemoveAction, remove_group_from_inbox
from sentry.models.grouplink import GroupLink
from sentry.models.grouprelease import GroupRelease
from sentry.models.groupresolution import GroupResolution
from sentry.models.groupseen import GroupSeen
from sentry.models.groupshare import GroupShare
Expand Down Expand Up @@ -136,24 +135,7 @@ def get_current_release_version_of_group(group: Group, follows_semver: bool = Fa
"""
current_release_version = None
if follows_semver:
if not features.has(
"organizations:releases-resolve-next-release-semver-fix", group.project.organization
):
try:
# This sets current_release_version to the latest semver version associated with a group
associated_release_id = GroupRelease.objects.filter(
project_id=group.project.id, group_id=group.id
).values_list("release_id")
current_release_version = (
get_semver_releases(group.project)
.filter(id__in=associated_release_id)
.values_list("version", flat=True)[:1]
.get()
)
except Release.DoesNotExist:
pass
else:
current_release_version = greatest_semver_release(group.project).version
current_release_version = greatest_semver_release(group.project).version

else:
# This sets current_release_version to the most recent release associated with a group
Expand Down Expand Up @@ -839,18 +821,10 @@ def prepare_response(


def get_release_to_resolve_by(project: Project) -> Release | None:
# XXX: Remove block once released
follows_semver = False
if features.has("organizations:releases-resolve-next-release-semver-fix", project.organization):
follows_semver = follows_semver_versioning_scheme(
org_id=project.organization_id, project_id=project.id
)

if follows_semver:
release = greatest_semver_release(project)
else:
release = most_recent_release(project)
return release
follows_semver = follows_semver_versioning_scheme(
org_id=project.organization_id, project_id=project.id
)
return greatest_semver_release(project) if follows_semver else most_recent_release(project)


def most_recent_release(project: Project) -> Release | None:
Expand Down
2 changes: 0 additions & 2 deletions src/sentry/features/temporary.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,6 @@ def register_temporary_features(manager: FeatureManager):
manager.add("organizations:relay-cardinality-limiter", OrganizationFeature, FeatureHandlerStrategy.INTERNAL, api_expose=False)
# Enable the release details performance section
manager.add("organizations:release-comparison-performance", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Fixes the next release resolution for semver releases
manager.add("organizations:releases-resolve-next-release-semver-fix", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# enable new release set_commits functionality
manager.add("organizations:set-commits-updated", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
# Enable new release UI
Expand Down
70 changes: 2 additions & 68 deletions tests/sentry/issues/endpoints/test_group_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,53 +355,6 @@ def test_resolved_in_next_release_non_semver(self):
assert group_resolution.status == GroupResolution.Status.pending
assert group_resolution.release.version == most_recent_version.version

# XXX: Remove this test once the feature flag is removed
def test_resolved_in_next_release_semver_no_flag_and_first_release(self):
self.login_as(user=self.user)
project = self.create_project_with_releases()
first_release = Release.get_or_create(version="com.foo.bar@1.0+0", project=project)
Release.get_or_create(version="com.foo.bar@2.0+0", project=project)
wrong_release = Release.get_or_create(version="com.foo.bar@1.0+1", project=project)
# Using store_event() instead of create_group() produces GroupRelease objects
# which is considered during the update_groups() call
event = self.store_event(data={"release": first_release.version}, project_id=project.id)
group = event.group
assert group is not None
assert group.status == GroupStatus.UNRESOLVED
assert group.substatus == GroupSubStatus.NEW
assert group.first_release == first_release
assert GroupResolution.objects.all().count() == 0

url = f"/api/0/issues/{group.id}/"
data = {"status": "resolvedInNextRelease"}
response = self.client.put(url, data=data)
assert response.status_code == 200, response.content == {}

# Refetch from DB to ensure the latest state is fetched
group = Group.objects.get(id=group.id, project=project.id)
assert group.status == GroupStatus.RESOLVED

group_resolution = GroupResolution.objects.filter(group=group).first()
assert group_resolution is not None
assert group_resolution.group == group
# For semver projects, we consider resolution based on an expression rather than a specific release,
# thus, it is considered resolved in the release that has the highest semver
assert group_resolution.type == GroupResolution.Type.in_release
assert group_resolution.status == GroupResolution.Status.resolved
assert group_resolution.release.version == wrong_release.version
assert response.data["statusDetails"]["inRelease"] == wrong_release.version

# Let's test that it does not regress to the first release
event = self.store_event(data={"release": first_release.version}, project_id=project.id)
group = Group.objects.get(id=group.id, project=project.id)
assert group.status == GroupStatus.RESOLVED

# Let's test that it does regress - this is fixed with the feature flag
event = self.store_event(data={"release": wrong_release.version}, project_id=project.id)
group = Group.objects.get(id=group.id, project=project.id)
assert group.status == GroupStatus.UNRESOLVED
assert group.substatus == GroupSubStatus.REGRESSED

def create_project_with_releases(self) -> Project:
project = self.create_project()
project.flags.has_releases = True
Expand Down Expand Up @@ -482,12 +435,10 @@ def resolved_in_next_release_helper(self, with_first_release: bool = True) -> No
assert group.status == GroupStatus.UNRESOLVED
assert group.substatus == GroupSubStatus.REGRESSED

@with_feature("organizations:releases-resolve-next-release-semver-fix")
def test_resolved_in_next_release_semver_with_flag_no_first_release(self):
def test_resolved_in_next_release_semver_no_first_release(self):
self.resolved_in_next_release_helper(with_first_release=False)

@with_feature("organizations:releases-resolve-next-release-semver-fix")
def test_resolved_in_next_release_semver_with_flag_and_first_release(self):
def test_resolved_in_next_release_semver_and_first_release(self):
self.resolved_in_next_release_helper(with_first_release=True)

def test_resolved_in_next_release_no_release(self):
Expand All @@ -499,23 +450,6 @@ def test_resolved_in_next_release_no_release(self):
response = self.client.put(url, data={"status": "resolvedInNextRelease"})
assert response.status_code == 200, response.content

group = Group.objects.get(id=group.id, project=group.project.id)
assert group.status == GroupStatus.RESOLVED

# no GroupResolution because there is no release
assert not GroupResolution.objects.filter(group=group).exists()
assert response.data["statusDetails"] == {}

@with_feature("organizations:releases-resolve-next-release-semver-fix")
def test_resolved_in_next_release_with_flag_no_release(self):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was to prevent normal releases from regressing with the new fix.

This is the test it duplicated:

def test_resolved_in_next_release_no_release(self):
self.login_as(user=self.user)
project = self.create_project()
project.flags.has_releases = True
project.save()
event = self.store_event(data={}, project_id=project.id)
group = event.group
assert group is not None
url = f"/api/0/organizations/{group.organization.slug}/issues/{group.id}/"
response = self.client.put(url, data={"status": "resolvedInNextRelease"})
assert response.status_code == 200, response.content
# Refetch from DB to ensure the latest state is fetched
group = Group.objects.get(id=group.id, project=group.project.id)
assert group.status == GroupStatus.RESOLVED
# no GroupResolution because there is no release
assert not GroupResolution.objects.filter(group=group).exists()
assert response.data["statusDetails"] == {}

self.login_as(user=self.user)
project = self.create_project_with_releases()
group = self.create_group_with_no_release(project)

url = f"/api/0/organizations/{group.organization.slug}/issues/{group.id}/"
response = self.client.put(url, data={"status": "resolvedInNextRelease"})
assert response.status_code == 200, response.content

# Refetch from DB to ensure the latest state is fetched
group = Group.objects.get(id=group.id, project=group.project.id)
assert group.status == GroupStatus.RESOLVED
Expand Down
21 changes: 11 additions & 10 deletions tests/sentry/issues/endpoints/test_organization_group_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -4348,23 +4348,23 @@ def test_in_semver_projects_group_resolution_stores_current_release_version(self
GroupResolution.current_release_version is set to the latest release associated with a
Group, when the project follows semantic versioning scheme
"""
release_1 = self.create_release(version="fake_package@21.1.0")
release_2 = self.create_release(version="fake_package@21.1.1")
release_3 = self.create_release(version="fake_package@21.1.2")
release_21_1_0 = self.create_release(version="fake_package@21.1.0")
release_21_1_1 = self.create_release(version="fake_package@21.1.1")
release_21_1_2 = self.create_release(version="fake_package@21.1.2")

self.store_event(
data={
"timestamp": iso_format(before_now(seconds=10)),
"fingerprint": ["group-1"],
"release": release_2.version,
"release": release_21_1_1.version,
},
project_id=self.project.id,
)
group = self.store_event(
data={
"timestamp": iso_format(before_now(seconds=12)),
"fingerprint": ["group-1"],
"release": release_1.version,
"release": release_21_1_0.version,
},
project_id=self.project.id,
).group
Expand All @@ -4381,20 +4381,21 @@ def test_in_semver_projects_group_resolution_stores_current_release_version(self
# a group
grp_resolution = GroupResolution.objects.get(group=group)

assert grp_resolution.current_release_version == release_2.version
assert grp_resolution.current_release_version == release_21_1_2.version

# "resolvedInNextRelease" with semver releases is considered as "resolvedInRelease"
assert grp_resolution.type == GroupResolution.Type.in_release
assert grp_resolution.status == GroupResolution.Status.resolved

# Add release that is between 2 and 3 to ensure that any release after release 2 should
# not have a resolution
release_4 = self.create_release(version="fake_package@21.1.1+1")
release_21_1_1_plus_1 = self.create_release(version="fake_package@21.1.1+1")
release_21_1_3 = self.create_release(version="fake_package@21.1.3")

for release in [release_1, release_2]:
for release in [release_21_1_0, release_21_1_1, release_21_1_1_plus_1, release_21_1_2]:
assert GroupResolution.has_resolution(group=group, release=release)

for release in [release_3, release_4]:
for release in [release_21_1_3]:
assert not GroupResolution.has_resolution(group=group, release=release)

# Ensure that Activity has `current_release_version` set on `Resolved in next release`
Expand All @@ -4404,7 +4405,7 @@ def test_in_semver_projects_group_resolution_stores_current_release_version(self
ident=grp_resolution.id,
)

assert activity.data["current_release_version"] == release_2.version
assert activity.data["current_release_version"] == release_21_1_2.version

def test_in_non_semver_projects_group_resolution_stores_current_release_version(self) -> None:
"""
Expand Down
Loading