feat: add TODO comments to PR review output

This commit is contained in:
joosomi
2025-05-24 01:52:52 +09:00
parent 4e80f3999c
commit 788c0c12e6
5 changed files with 73 additions and 1 deletions

View File

@ -98,6 +98,11 @@ extra_instructions = "..."
<tr>
<td><b>require_security_review</b></td>
<td>If set to true, the tool will add a section that checks if the PR contains a possible security or vulnerability issue. Default is true.</td>
</tr>
<tr>
<td><b>require_todo_scan</b></td>
<td>If set to true, the tool will add a section that lists TODO comments found in the PR code changes. Default is true.
</td>
</tr>
<tr>
<td><b>require_ticket_analysis_review</b></td>

View File

@ -131,6 +131,7 @@ def convert_to_markdown_v2(output_data: dict,
"Focused PR": "",
"Relevant ticket": "🎫",
"Security concerns": "🔒",
"Todo sections": "",
"Insights from user's answers": "📝",
"Code feedback": "🤖",
"Estimated effort to review [1-5]": "⏱️",
@ -153,7 +154,7 @@ def convert_to_markdown_v2(output_data: dict,
for key, value in output_data['review'].items():
if value is None or value == '' or value == {} or value == []:
if key.lower() not in ['can_be_split', 'key_issues_to_review']:
if key.lower() not in ['can_be_split', 'key_issues_to_review', 'todo_sections']:
continue
key_nice = key.replace('_', ' ').capitalize()
emoji = emojis.get(key_nice, "")
@ -209,6 +210,50 @@ def convert_to_markdown_v2(output_data: dict,
markdown_text += f"### {emoji} Security concerns\n\n"
value = emphasize_header(value.strip(), only_markdown=True)
markdown_text += f"{value}\n\n"
elif 'todo sections' in key_nice.lower():
if gfm_supported:
markdown_text += f"<tr><td>"
if is_value_no(value):
markdown_text += f"{emoji}&nbsp;<strong>No ToDo sections</strong>"
else:
markdown_text += f"{emoji}&nbsp;<strong>ToDo sections</strong><br><br>\n\n"
if isinstance(value, list):
markdown_text += "<ul>\n"
for todo_item in value:
relevant_file = todo_item.get('relevant_file', '')
line_number = todo_item.get('line_number', '')
content = todo_item.get('content', '')
reference_link = None
if git_provider and relevant_file and line_number:
reference_link = git_provider.get_line_link(relevant_file, line_number, line_number)
file_line = f"{relevant_file} [{line_number}]"
if reference_link:
file_line = f"<a href='{reference_link}'>{file_line}</a>"
if content.strip():
markdown_text += f"<li>{file_line}: {content}</li>\n"
else:
markdown_text += f"<li>{file_line}</li>\n"
markdown_text += "</ul>\n"
markdown_text += f"</td></tr>\n"
else:
if is_value_no(value):
markdown_text += f"### {emoji} No ToDo sections\n\n"
else:
markdown_text += f"### {emoji} ToDo sections\n\n"
if isinstance(value, list):
for todo_item in value:
relevant_file = todo_item.get('relevant_file', '')
line_number = todo_item.get('line_number', '')
content = todo_item.get('content', '')
if git_provider and relevant_file and line_number:
reference_link = git_provider.get_line_link(relevant_file, line_number, line_number)
file_line = f"[{relevant_file} [{line_number}]]({reference_link})"
else:
file_line = f"{relevant_file} [{line_number}]"
if content.strip():
markdown_text += f"- {file_line}: {content}\n"
else:
markdown_text += f"- {file_line}\n"
elif 'can be split' in key_nice.lower():
if gfm_supported:
markdown_text += f"<tr><td>"

View File

@ -77,6 +77,7 @@ require_tests_review=true
require_estimate_effort_to_review=true
require_can_be_split_review=false
require_security_review=true
require_todo_scan=true
require_ticket_analysis_review=true
# general options
persistent_comment=true

View File

@ -72,6 +72,11 @@ class KeyIssuesComponentLink(BaseModel):
start_line: int = Field(description="The start line that corresponds to this issue in the relevant file")
end_line: int = Field(description="The end line that corresponds to this issue in the relevant file")
class TodoSection(BaseModel):
relevant_file: str = Field(description="The file containing the TODO comment")
line_number: int = Field(description="The line number of the TODO comment")
content: str = Field(description="The content of the TODO comment. Only include items that are actual TODO comments inside code comments (e.g., lines starting with #, //, /*, <!--, etc). Remove any leading 'TODO' or similar prefix from the content, but do include lines like '# TODO' even if they result in empty content after prefix removal. Do not include TODOs that are not in comments or not prefixed appropriately.")
{%- if related_tickets %}
class TicketCompliance(BaseModel):
@ -102,6 +107,9 @@ class Review(BaseModel):
{%- if require_security_review %}
security_concerns: str = Field(description="Does this PR code introduce possible vulnerabilities such as exposure of sensitive information (e.g., API keys, secrets, passwords), or security concerns like SQL injection, XSS, CSRF, and others ? Answer 'No' (without explaining why) if there are no possible issues. If there are security concerns or issues, start your answer with a short header, such as: 'Sensitive information exposure: ...', 'SQL injection: ...' etc. Explain your answer. Be specific and give examples if possible")
{%- endif %}
{%- if require_todo_scan %}
todo_sections: List[TodoSection] = Field(description="A list of TODO comments found in the code. Return an empty list if there are no TODO comments.")
{%- endif %}
{%- if require_can_be_split_review %}
can_be_split: List[SubPR] = Field(min_items=0, max_items=3, description="Can this PR, which contains {{ num_pr_files }} changed files in total, be divided into smaller sub-PRs with distinct tasks that can be reviewed and merged independently, regardless of the order ? Make sure that the sub-PRs are indeed independent, with no code dependencies between them, and that each sub-PR represent a meaningful independent task. Output an empty list if the PR code does not need to be split.")
{%- endif %}
@ -148,6 +156,12 @@ review:
- ...
security_concerns: |
No
todo_sections:
- relevant_file: |
src/file1.py
line_number: 13
content: |
...
{%- if require_can_be_split_review %}
can_be_split:
- relevant_files:
@ -266,6 +280,12 @@ review:
- ...
security_concerns: |
No
todo_sections:
- relevant_file: |
...
line_number: ...
content: |
...
{%- if require_can_be_split_review %}
can_be_split:
- relevant_files:

View File

@ -87,6 +87,7 @@ class PRReviewer:
"require_estimate_effort_to_review": get_settings().pr_reviewer.require_estimate_effort_to_review,
'require_can_be_split_review': get_settings().pr_reviewer.require_can_be_split_review,
'require_security_review': get_settings().pr_reviewer.require_security_review,
'require_todo_scan': get_settings().pr_reviewer.require_todo_scan,
'question_str': question_str,
'answer_str': answer_str,
"extra_instructions": get_settings().pr_reviewer.extra_instructions,