Skip to content

Commit 136d53c

Browse files
committed
ref: move formatting functions
1 parent e6ffd4c commit 136d53c

File tree

7 files changed

+209
-112
lines changed

7 files changed

+209
-112
lines changed

src/sentry/integrations/github/integration.py

+76
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
CommitContextOrganizationOptionKeys,
3737
CommitContextReferrerIds,
3838
CommitContextReferrers,
39+
PullRequestIssue,
3940
)
4041
from sentry.integrations.source_code_management.repo_trees import RepoTreesIntegration
4142
from sentry.integrations.source_code_management.repository import RepositoryIntegration
@@ -53,6 +54,7 @@
5354
from sentry.shared_integrations.constants import ERR_INTERNAL, ERR_UNAUTHORIZED
5455
from sentry.shared_integrations.exceptions import ApiError, IntegrationError
5556
from sentry.snuba.referrer import Referrer
57+
from sentry.templatetags.sentry_helpers import small_count
5658
from sentry.types.referrer_ids import GITHUB_OPEN_PR_BOT_REFERRER, GITHUB_PR_BOT_REFERRER
5759
from sentry.utils import metrics
5860
from sentry.utils.http import absolute_uri
@@ -389,6 +391,80 @@ def on_create_or_update_comment_error(self, api_error: ApiError, metrics_base: s
389391

390392
return False
391393

394+
def format_open_pr_comment(self, issue_tables: list[str]) -> str:
395+
comment_body_template = """\
396+
## 🔍 Existing Issues For Review
397+
Your pull request is modifying functions with the following pre-existing issues:
398+
399+
{issue_tables}
400+
---
401+
402+
<sub>Did you find this useful? React with a 👍 or 👎</sub>"""
403+
404+
return comment_body_template.format(issue_tables="\n".join(issue_tables))
405+
406+
def format_issue_table(
407+
self,
408+
diff_filename: str,
409+
issues: list[PullRequestIssue],
410+
patch_parsers: dict[str, Any],
411+
toggle: bool,
412+
) -> str:
413+
description_length = 52
414+
415+
issue_table_template = """\
416+
📄 File: **{filename}**
417+
418+
| Function | Unhandled Issue |
419+
| :------- | :----- |
420+
{issue_rows}"""
421+
422+
issue_table_toggle_template = """\
423+
<details>
424+
<summary><b>📄 File: {filename} (Click to Expand)</b></summary>
425+
426+
| Function | Unhandled Issue |
427+
| :------- | :----- |
428+
{issue_rows}
429+
</details>"""
430+
431+
def format_subtitle(title_length: int, subtitle: str) -> str:
432+
# the title length + " " + subtitle should be <= 52
433+
subtitle_length = description_length - title_length - 1
434+
return (
435+
subtitle[: subtitle_length - 3] + "..."
436+
if len(subtitle) > subtitle_length
437+
else subtitle
438+
)
439+
440+
language_parser = patch_parsers.get(diff_filename.split(".")[-1], None)
441+
442+
if not language_parser:
443+
return ""
444+
445+
issue_row_template = language_parser.issue_row_template
446+
447+
issue_rows = "\n".join(
448+
[
449+
issue_row_template.format(
450+
title=issue.title,
451+
subtitle=format_subtitle(len(issue.title), issue.subtitle),
452+
url=self.format_comment_url(
453+
issue.url, referrer=self.commit_context_referrer_ids.open_pr_bot
454+
),
455+
event_count=small_count(issue.event_count),
456+
function_name=issue.function_name,
457+
affected_users=small_count(issue.affected_users),
458+
)
459+
for issue in issues
460+
]
461+
)
462+
463+
if toggle:
464+
return issue_table_toggle_template.format(filename=diff_filename, issue_rows=issue_rows)
465+
466+
return issue_table_template.format(filename=diff_filename, issue_rows=issue_rows)
467+
392468

393469
class GitHubIntegrationProvider(IntegrationProvider):
394470
key = "github"

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

+3-83
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
OPEN_PR_METRICS_BASE,
1616
CommitContextIntegration,
1717
PullRequestFile,
18-
PullRequestIssue,
1918
)
2019
from sentry.integrations.source_code_management.language_parsers import PATCH_PARSERS
2120
from sentry.models.organization import Organization
@@ -26,90 +25,11 @@
2625
from sentry.tasks.base import instrumented_task
2726
from sentry.taskworker.config import TaskworkerConfig
2827
from sentry.taskworker.namespaces import integrations_tasks
29-
from sentry.templatetags.sentry_helpers import small_count
30-
from sentry.types.referrer_ids import GITHUB_OPEN_PR_BOT_REFERRER
3128
from sentry.utils import metrics
3229

3330
logger = logging.getLogger(__name__)
3431

3532

36-
OPEN_PR_COMMENT_BODY_TEMPLATE = """\
37-
## 🔍 Existing Issues For Review
38-
Your pull request is modifying functions with the following pre-existing issues:
39-
40-
{issue_tables}
41-
---
42-
43-
<sub>Did you find this useful? React with a 👍 or 👎</sub>"""
44-
45-
OPEN_PR_ISSUE_TABLE_TEMPLATE = """\
46-
📄 File: **{filename}**
47-
48-
| Function | Unhandled Issue |
49-
| :------- | :----- |
50-
{issue_rows}"""
51-
52-
OPEN_PR_ISSUE_TABLE_TOGGLE_TEMPLATE = """\
53-
<details>
54-
<summary><b>📄 File: {filename} (Click to Expand)</b></summary>
55-
56-
| Function | Unhandled Issue |
57-
| :------- | :----- |
58-
{issue_rows}
59-
</details>"""
60-
61-
OPEN_PR_ISSUE_DESCRIPTION_LENGTH = 52
62-
63-
MAX_RECENT_ISSUES = 5000
64-
65-
66-
def format_comment_url(url, referrer):
67-
return url + "?referrer=" + referrer
68-
69-
70-
def format_open_pr_comment(issue_tables: list[str]) -> str:
71-
return OPEN_PR_COMMENT_BODY_TEMPLATE.format(issue_tables="\n".join(issue_tables))
72-
73-
74-
def format_open_pr_comment_subtitle(title_length, subtitle):
75-
# the title length + " " + subtitle should be <= 52
76-
subtitle_length = OPEN_PR_ISSUE_DESCRIPTION_LENGTH - title_length - 1
77-
return subtitle[: subtitle_length - 3] + "..." if len(subtitle) > subtitle_length else subtitle
78-
79-
80-
# for a single file, create a table
81-
def format_issue_table(
82-
diff_filename: str, issues: list[PullRequestIssue], patch_parsers: dict[str, Any], toggle: bool
83-
) -> str:
84-
language_parser = patch_parsers.get(diff_filename.split(".")[-1], None)
85-
86-
if not language_parser:
87-
return ""
88-
89-
issue_row_template = language_parser.issue_row_template
90-
91-
issue_rows = "\n".join(
92-
[
93-
issue_row_template.format(
94-
title=issue.title,
95-
subtitle=format_open_pr_comment_subtitle(len(issue.title), issue.subtitle),
96-
url=format_comment_url(issue.url, GITHUB_OPEN_PR_BOT_REFERRER),
97-
event_count=small_count(issue.event_count),
98-
function_name=issue.function_name,
99-
affected_users=small_count(issue.affected_users),
100-
)
101-
for issue in issues
102-
]
103-
)
104-
105-
if toggle:
106-
return OPEN_PR_ISSUE_TABLE_TOGGLE_TEMPLATE.format(
107-
filename=diff_filename, issue_rows=issue_rows
108-
)
109-
110-
return OPEN_PR_ISSUE_TABLE_TEMPLATE.format(filename=diff_filename, issue_rows=issue_rows)
111-
112-
11333
# TODO(cathy): Change the client typing to allow for multiple SCM Integrations
11434
def safe_for_comment(
11535
gh_client: GitHubApiClient, repository: Repository, pull_request: PullRequest
@@ -374,19 +294,19 @@ def open_pr_comment_workflow(pr_id: int) -> None:
374294
continue
375295

376296
if first_table:
377-
issue_table = format_issue_table(
297+
issue_table = installation.format_issue_table(
378298
pr_filename, issue_table_content, patch_parsers, toggle=False
379299
)
380300
first_table = False
381301
else:
382302
# toggle all tables but the first one
383-
issue_table = format_issue_table(
303+
issue_table = installation.format_issue_table(
384304
pr_filename, issue_table_content, patch_parsers, toggle=True
385305
)
386306

387307
issue_tables.append(issue_table)
388308

389-
comment_body = format_open_pr_comment(issue_tables)
309+
comment_body = installation.format_open_pr_comment(issue_tables)
390310

391311
# list all issues in the comment
392312
issue_list: list[dict[str, Any]] = list(itertools.chain.from_iterable(top_issues_per_file))

src/sentry/integrations/github_enterprise/integration.py

+13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
CommitContextOrganizationOptionKeys,
3030
CommitContextReferrerIds,
3131
CommitContextReferrers,
32+
PullRequestIssue,
3233
)
3334
from sentry.integrations.source_code_management.repository import RepositoryIntegration
3435
from sentry.models.organization import Organization
@@ -271,6 +272,18 @@ def queue_comment_task(self, pullrequest_id: int, project_id: int) -> None:
271272
def on_create_or_update_comment_error(self, api_error: ApiError, metrics_base: str) -> bool:
272273
raise NotImplementedError
273274

275+
def format_open_pr_comment(self, issue_tables: list[str]) -> str:
276+
raise NotImplementedError
277+
278+
def format_issue_table(
279+
self,
280+
diff_filename: str,
281+
issues: list[PullRequestIssue],
282+
patch_parsers: dict[str, Any],
283+
toggle: bool,
284+
) -> str:
285+
raise NotImplementedError
286+
274287

275288
class InstallationForm(forms.Form):
276289
url = forms.CharField(

src/sentry/integrations/gitlab/integration.py

+13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
CommitContextOrganizationOptionKeys,
2626
CommitContextReferrerIds,
2727
CommitContextReferrers,
28+
PullRequestIssue,
2829
)
2930
from sentry.integrations.source_code_management.repository import RepositoryIntegration
3031
from sentry.models.organization import Organization
@@ -203,6 +204,18 @@ def queue_comment_task(self, pullrequest_id: int, project_id: int) -> None:
203204
def on_create_or_update_comment_error(self, api_error: ApiError, metrics_base: str) -> bool:
204205
raise NotImplementedError
205206

207+
def format_open_pr_comment(self, issue_tables: list[str]) -> str:
208+
raise NotImplementedError
209+
210+
def format_issue_table(
211+
self,
212+
diff_filename: str,
213+
issues: list[PullRequestIssue],
214+
patch_parsers: dict[str, Any],
215+
toggle: bool,
216+
) -> str:
217+
raise NotImplementedError
218+
206219
# Gitlab only functions
207220

208221
def get_group_id(self):

src/sentry/integrations/source_code_management/commit_context.py

+20-19
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from collections.abc import Sequence
66
from dataclasses import dataclass
77
from datetime import UTC, datetime, timedelta, timezone
8-
from typing import Any, TypedDict
8+
from typing import Any
99

1010
import sentry_sdk
1111
from django.db import connection
@@ -157,19 +157,6 @@ class PullRequestFile:
157157
patch: str
158158

159159

160-
class IssueCount(TypedDict):
161-
group_id: int
162-
event_count: int
163-
164-
165-
class IssueCountForFile(TypedDict):
166-
title: str
167-
culprit: str
168-
function_name: str
169-
group_id: int
170-
event_count: int
171-
172-
173160
class CommitContextIntegration(ABC):
174161
"""
175162
Base class for integrations that include commit context features: suspect commits, suspect PR comments
@@ -544,7 +531,9 @@ def get_issue_ids_from_pr(
544531
)
545532
return [issue_id for (issue_id,) in cursor.fetchall()]
546533

547-
def get_top_5_issues_by_count(self, issue_ids: list[int], project: Project) -> list[IssueCount]:
534+
def get_top_5_issues_by_count(
535+
self, issue_ids: list[int], project: Project
536+
) -> list[dict[str, Any]]:
548537
"""Given a list of issue group ids, return a sublist of the top 5 ordered by event count"""
549538
request = SnubaRequest(
550539
dataset=Dataset.Events.value,
@@ -655,9 +644,23 @@ def run_pr_comment_workflow(
655644

656645
# Open PR Comment Workflow
657646

647+
@abstractmethod
648+
def format_open_pr_comment(self, issue_tables: list[str]) -> str:
649+
raise NotImplementedError
650+
651+
@abstractmethod
652+
def format_issue_table(
653+
self,
654+
diff_filename: str,
655+
issues: list[PullRequestIssue],
656+
patch_parsers: dict[str, Any],
657+
toggle: bool,
658+
) -> str:
659+
raise NotImplementedError
660+
658661
def get_top_5_issues_by_count_for_file(
659662
self, projects: list[Project], sentry_filenames: list[str], function_names: list[str]
660-
) -> list[IssueCountForFile]:
663+
) -> list[dict[str, Any]]:
661664
"""
662665
Given a list of projects, filenames reverse-codemapped into filenames in Sentry,
663666
and function names representing the list of functions changed in a PR file, return a
@@ -798,9 +801,7 @@ def get_top_5_issues_by_count_for_file(
798801
)
799802
return []
800803

801-
def get_issue_table_contents(
802-
self, issue_list: list[IssueCountForFile]
803-
) -> list[PullRequestIssue]:
804+
def get_issue_table_contents(self, issue_list: list[dict[str, Any]]) -> list[PullRequestIssue]:
804805
group_id_to_info = {}
805806
for issue in issue_list:
806807
group_id = issue["group_id"]

0 commit comments

Comments
 (0)