diff --git a/apps/utils/pr_agent/settings/pr_code_suggestions_prompts.toml b/apps/utils/pr_agent/settings/pr_code_suggestions_prompts.toml index a1574ec..8dfb163 100644 --- a/apps/utils/pr_agent/settings/pr_code_suggestions_prompts.toml +++ b/apps/utils/pr_agent/settings/pr_code_suggestions_prompts.toml @@ -4,6 +4,7 @@ system="""你是 PR-Reviewer, 一个专注于 Pull Request (PR) 代码分析和 你的任务是检查所提供的代码 diff, 重点关注新增代码 (行以 '+' 为前缀), 并提供简洁且可操作的建议以修复可能的 bug 和问题, 同时提升代码质量和性能. {%- else %} 你的任务是检查所提供的代码 diff, 重点关注新增代码 (行以 '+' 为前缀), 并提供简洁且可操作的建议以修复关键 bug 和问题. +从代码的角度生成测试可读的信息,使得在后续的测试中能够针对变更的内容进行功能的测试. {%- endif %} PR 代码差异将采用以下结构化格式: @@ -73,6 +74,7 @@ __new hunk__ 额外用户提供的指令(应优先处理): ====== +从代码的角度生成测试可读的信息,使得在后续的测试中能够针对变更的内容进行功能的测试. {{ extra_instructions }} 回答必须使用简体中文,并且必须使用英文标点符号! ====== @@ -85,6 +87,7 @@ class CodeSuggestion(BaseModel): relevant_file: str = Field(description="相关文件的完整路径") language: str = Field(description="相关文件使用的编程语言") suggestion_content: str = Field(description="一个可操作的建议,用于增强、改进或修复PR中引入的新代码. 不要在这里呈现实际的代码片段, 只需要建议. 简明扼要") + test_content: str = Field(description="请用面向测试人员、非技术化的语言,描述本次变更对功能、流程、接口、页面等的影响,指出需要重点验证的功能点、场景或风险。不要出现任何代码术语或实现细节,让测试能直接据此设计用例或关注点。") existing_code: str = Field(description="一个简短的代码片段, 来自PR更改后的 '__new hunk__' 部分, 该建议旨在增强或修复. 仅包括完整的代码行. 如果需要, 使用省略号 (...) 来保持简洁. 此片段应代表目标改进的特定PR代码.") improved_code: str = Field(description="一个改进的代码片段, 在实施建议后替换 'existing_code' 片段.") one_sentence_summary: str = Field(description="对建议的改进进行简明扼要的单句概述 (最多6个词). 关注 'what'. 保持通用性, 避免方法或变量名称,回答尽量使用简体中文,并且必须使用英文标点符号.") @@ -109,6 +112,8 @@ code_suggestions: python suggestion_content: | ... + test_content: | + ... existing_code: | ... improved_code: | @@ -148,6 +153,8 @@ code_suggestions: python suggestion_content: | ... + test_content: | + ... existing_code: | ... improved_code: | diff --git a/apps/utils/pr_agent/tools/pr_code_suggestions.py b/apps/utils/pr_agent/tools/pr_code_suggestions.py index 9fce273..a5c1bb1 100644 --- a/apps/utils/pr_agent/tools/pr_code_suggestions.py +++ b/apps/utils/pr_agent/tools/pr_code_suggestions.py @@ -690,10 +690,10 @@ class PRCodeSuggestions: one_sentence_summary_list = [] for i, suggestion in enumerate(data['code_suggestions']): try: - needed_keys = ['one_sentence_summary', 'label', 'relevant_file'] + needed_keys = ['one_sentence_summary', 'label', 'relevant_file', 'test_content'] is_valid_keys = True for key in needed_keys: - if key not in suggestion: + if key not in suggestion or not suggestion[key]: is_valid_keys = False get_logger().debug( f"Skipping suggestion {i + 1}, because it does not contain '{key}':\n'{suggestion}" @@ -776,17 +776,23 @@ class PRCodeSuggestions: relevant_file, relevant_lines_start, new_code_snippet ) + # 增加 test_content 到 suggestion body + test_content = d.get('test_content', '').strip() + test_content_str = f"\n\n**测试建议:** {test_content}" if test_content else "" + if d.get('score'): body = ( f"**Suggestion:** {content} [{label}, importance: {d.get('score')}]\n```suggestion\n" + new_code_snippet + "\n```" + + test_content_str ) else: body = ( f"**Suggestion:** {content} [{label}]\n```suggestion\n" + new_code_snippet + "\n```" + + test_content_str ) code_suggestions.append( { @@ -999,7 +1005,7 @@ class PRCodeSuggestions: header = f"建议" delta = 66 header += "  " * delta - pr_body += f"""类别{header}影响""" + pr_body += f"""类别{header}测试建议影响""" pr_body += """""" suggestions_labels = dict() # add all suggestions related to each label @@ -1013,14 +1019,14 @@ class PRCodeSuggestions: suggestions_labels = dict( sorted( suggestions_labels.items(), - key=lambda x: max([s['score'] for s in x[1]]), + key=lambda x: max([s.get('score', 0) for s in x[1]]), reverse=True, ) ) # sort the suggestions inside each label group by score for label, suggestions in suggestions_labels.items(): suggestions_labels[label] = sorted( - suggestions, key=lambda x: x['score'], reverse=True + suggestions, key=lambda x: x.get('score', 0), reverse=True ) counter_suggestions = 0 @@ -1068,9 +1074,9 @@ class PRCodeSuggestions: pr_body += f"""\n\n""" else: pr_body += f"""\n\n""" - suggestion_summary = ( - suggestion['one_sentence_summary'].strip().rstrip('.') - ) + # 新增测试建议表格列 + test_content = suggestion.get('test_content', '').strip() + suggestion_summary = suggestion.get('one_sentence_summary', '').strip().rstrip('.') if "'<" in suggestion_summary and ">'" in suggestion_summary: # escape the '<' and '>' characters, otherwise they are interpreted as html tags get_logger().info( @@ -1085,6 +1091,8 @@ class PRCodeSuggestions: pr_body += f""" **{suggestion_content}** +**测试建议:** {suggestion.get('test_content', '').strip()} + [{relevant_file} {range_str}]({code_snippet_link}) {example_code.rstrip()} @@ -1096,12 +1104,15 @@ class PRCodeSuggestions: pr_body += f"" + # 新增测试建议表格列 + pr_body += f"{test_content}" + # # add another column for 'score' score_int = int(suggestion.get('score', 0)) score_str = f"{score_int}" if get_settings().pr_code_suggestions.new_score_mechanism: score_str = self.get_score_str(score_int) - pr_body += f"{score_str}\n\n" + pr_body += f"{score_str}\n\n" pr_body += f"" counter_suggestions += 1 @@ -1109,6 +1120,19 @@ class PRCodeSuggestions: # pr_body += "" # pr_body += """""" pr_body += """""" + + # 额外输出测试建议列表 + test_suggestions = [ + s.get('test_content', '').strip() + for label in suggestions_labels.values() + for s in label + if s.get('test_content', '').strip() + ] + if test_suggestions: + pr_body += "\n\n【测试建议汇总】
\n" + for idx, test_content in enumerate(test_suggestions, 1): + pr_body += f"{idx}. {test_content}
\n" + return pr_body except Exception as e: get_logger().info(