diff --git a/docs/docs/tools/review.md b/docs/docs/tools/review.md
index 8d4a5543..4e63bf2d 100644
--- a/docs/docs/tools/review.md
+++ b/docs/docs/tools/review.md
@@ -98,6 +98,11 @@ extra_instructions = "..."
require_security_review |
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. |
+
+
+ require_todo_scan |
+ If set to true, the tool will add a section that lists TODO comments found in the PR code changes. Default is true.
+ |
require_ticket_analysis_review |
diff --git a/pr_agent/algo/utils.py b/pr_agent/algo/utils.py
index 780c7953..ba55f938 100644
--- a/pr_agent/algo/utils.py
+++ b/pr_agent/algo/utils.py
@@ -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"
"
+ if is_value_no(value):
+ markdown_text += f"{emoji} No ToDo sections"
+ else:
+ markdown_text += f"{emoji} ToDo sections
\n\n"
+ if isinstance(value, list):
+ markdown_text += "\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"{file_line}"
+ if content.strip():
+ markdown_text += f"- {file_line}: {content}
\n"
+ else:
+ markdown_text += f"- {file_line}
\n"
+ markdown_text += " \n"
+ markdown_text += f" |
\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""
diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml
index c6437931..e4c279b9 100644
--- a/pr_agent/settings/configuration.toml
+++ b/pr_agent/settings/configuration.toml
@@ -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
diff --git a/pr_agent/settings/pr_reviewer_prompts.toml b/pr_agent/settings/pr_reviewer_prompts.toml
index d4c0a523..87cbbc06 100644
--- a/pr_agent/settings/pr_reviewer_prompts.toml
+++ b/pr_agent/settings/pr_reviewer_prompts.toml
@@ -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 #, //, /*, |