Skip to content

Commit 96da026

Browse files
scttcperclaude
andauthored
fix(teams): Deduplicate project features list (#112326)
When a project belongs to multiple teams, the team serializer was building the projects list from the ProjectTeam join table without deduplicating. This meant `get_features_for_projects()` iterated the same project N times (once per team it belongs to), appending features to the same list each time. The features array in the response ended up with N copies of every feature. Deduplicates the project list before passing it to `serialize()`. You can see duplicates in the production endpoint https://us.sentry.io/api/0/organizations/sentry/teams/ --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6af5951 commit 96da026

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

src/sentry/api/serializers/models/team.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ def get_attrs(
249249

250250
if self._expand("projects"):
251251
project_teams = ProjectTeam.objects.get_for_teams_with_org_cache(item_list)
252-
projects = [pt.project for pt in project_teams]
252+
253+
# A project can be on multiple teams, dedupe before serializing
254+
projects = list({pt.project_id: pt.project for pt in project_teams}.values())
253255

254256
projects_by_id = {
255257
project.id: data

tests/sentry/api/serializers/test_team.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,20 @@ def test_simple(self) -> None:
277277
"externalTeams": [],
278278
}
279279

280+
def test_project_on_multiple_teams_no_duplicate_features(self) -> None:
281+
"""A project belonging to multiple teams should not have its features list duplicated."""
282+
user = self.create_user(username="foo")
283+
organization = self.create_organization()
284+
team1 = self.create_team(organization=organization)
285+
team2 = self.create_team(organization=organization)
286+
self.create_project(teams=[team1, team2], organization=organization)
287+
288+
result = serialize([team1, team2], user, TeamWithProjectsSerializer())
289+
features = result[0]["projects"][0]["features"]
290+
291+
assert len(features) > 0
292+
assert features == list(dict.fromkeys(features))
293+
280294

281295
class TeamSCIMSerializerTest(TestCase):
282296
def test_simple_with_members(self) -> None:

0 commit comments

Comments
 (0)