Skip to content

Commit b2fd4a6

Browse files
authored
feat(open-pr-comments): get sentry projects and filenames (#59952)
1 parent 2849351 commit b2fd4a6

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

src/sentry/tasks/integrations/github/open_pr_comment.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
from __future__ import annotations
22

33
import logging
4-
from typing import List
4+
from typing import List, Set, Tuple
5+
6+
from django.db.models import Value
7+
from django.db.models.functions import StrIndex
58

69
from sentry.integrations.github.client import GitHubAppsClient
10+
from sentry.models.integrations.repository_project_path_config import RepositoryProjectPathConfig
11+
from sentry.models.project import Project
712
from sentry.models.pullrequest import PullRequest
813
from sentry.models.repository import Repository
914
from sentry.shared_integrations.exceptions.base import ApiError
@@ -44,7 +49,7 @@ def safe_for_comment(
4449
OPEN_PR_METRIC_BASE.format(key="api_error"),
4550
tags={"type": GithubAPIErrorType.UNKNOWN.value, "code": e.code},
4651
)
47-
logger.exception("github.open_pr_comment.unknown_api_error")
52+
logger.exception("github.open_pr_comment.unknown_api_error", extra={"error": str(e)})
4853
return False
4954

5055
safe_to_comment = True
@@ -74,3 +79,26 @@ def get_pr_filenames(
7479
# new files will not have sentry issues associated with them
7580
pr_filenames: List[str] = [file["filename"] for file in pr_files if file["status"] != "added"]
7681
return pr_filenames
82+
83+
84+
def get_projects_and_filenames_from_source_file(
85+
org_id: int,
86+
pr_filename: str,
87+
) -> Tuple[Set[Project], Set[str]]:
88+
# fetch the code mappings in which the source_root is a substring at the start of pr_filename
89+
code_mappings = (
90+
RepositoryProjectPathConfig.objects.filter(organization_id=org_id)
91+
.annotate(substring_match=StrIndex(Value(pr_filename), "source_root"))
92+
.filter(substring_match=1)
93+
)
94+
95+
project_list: Set[Project] = set()
96+
sentry_filenames = set()
97+
98+
if len(code_mappings):
99+
for code_mapping in code_mappings:
100+
project_list.add(code_mapping.project)
101+
sentry_filenames.add(
102+
pr_filename.replace(code_mapping.source_root, code_mapping.stack_root)
103+
)
104+
return project_list, sentry_filenames

tests/sentry/tasks/integrations/github/test_open_pr_comment.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
import responses
44

5-
from sentry.tasks.integrations.github.open_pr_comment import get_pr_filenames, safe_for_comment
5+
from sentry.tasks.integrations.github.open_pr_comment import (
6+
get_pr_filenames,
7+
get_projects_and_filenames_from_source_file,
8+
safe_for_comment,
9+
)
610
from sentry.testutils.silo import region_silo_test
711
from sentry.testutils.skips import requires_snuba
812
from tests.sentry.tasks.integrations.github.test_pr_comment import GithubCommentTestCase
@@ -144,7 +148,7 @@ def setUp(self):
144148
self.gh_client = installation.get_client()
145149

146150
@responses.activate
147-
def test_simple(self):
151+
def test_get_pr_filenames(self):
148152
responses.add(
149153
responses.GET,
150154
self.gh_path.format(pull_number=self.pr.key),
@@ -157,3 +161,58 @@ def test_simple(self):
157161
)
158162

159163
assert set(get_pr_filenames(self.gh_client, self.gh_repo, self.pr)) == {"bar.py", "baz.py"}
164+
165+
def test_get_projects_and_filenames_from_source_file(self):
166+
projects = [self.create_project() for _ in range(4)]
167+
168+
source_stack_pairs = [
169+
("", "./"),
170+
("src/sentry", "sentry/"),
171+
("src/", ""),
172+
("src/sentry/", "sentry/"),
173+
]
174+
for i, pair in enumerate(source_stack_pairs):
175+
source_root, stack_root = pair
176+
self.create_code_mapping(
177+
project=projects[i],
178+
repo=self.gh_repo,
179+
source_root=source_root,
180+
stack_root=stack_root,
181+
default_branch="master",
182+
)
183+
184+
# matching code mapping from a different org
185+
other_org_code_mapping = self.create_code_mapping(
186+
project=self.another_org_project,
187+
repo=self.another_org_repo,
188+
source_root="",
189+
stack_root="./",
190+
)
191+
other_org_code_mapping.organization_id = self.another_organization.id
192+
other_org_code_mapping.save()
193+
194+
source_stack_nonmatches = [
195+
("/src/sentry", "sentry"),
196+
("tests/", "tests/"),
197+
("app/", "static/app"),
198+
]
199+
for source_root, stack_root in source_stack_nonmatches:
200+
self.create_code_mapping(
201+
project=self.create_project(),
202+
repo=self.gh_repo,
203+
source_root=source_root,
204+
stack_root=stack_root,
205+
default_branch="master",
206+
)
207+
208+
filename = "src/sentry/tasks/integrations/github/open_pr_comment.py"
209+
correct_filenames = [
210+
filename.replace(source_root, stack_root)
211+
for source_root, stack_root in source_stack_pairs
212+
]
213+
214+
project_list, sentry_filenames = get_projects_and_filenames_from_source_file(
215+
self.organization.id, filename
216+
)
217+
assert project_list == set(projects)
218+
assert sentry_filenames == set(correct_filenames)

0 commit comments

Comments
 (0)