diff --git a/.pr_agent.toml b/.pr_agent.toml new file mode 100644 index 00000000..6937b547 --- /dev/null +++ b/.pr_agent.toml @@ -0,0 +1,2 @@ +[pr_reviewer] +enable_review_labels_effort = true \ No newline at end of file diff --git a/docs/REVIEW.md b/docs/REVIEW.md index 82eef6c3..533ac466 100644 --- a/docs/REVIEW.md +++ b/docs/REVIEW.md @@ -29,6 +29,9 @@ Under the section 'pr_reviewer', the [configuration file](./../pr_agent/settings - `remove_previous_review_comment`: if set to true, the tool will remove the previous review comment before adding a new one. Default is false. - `persistent_comment`: if set to true, the review comment will be persistent, meaning that every new review request will edit the previous one. Default is true. - `extra_instructions`: Optional extra instructions to the tool. For example: "focus on the changes in the file X. Ignore change in ...". +#### review labels +- `enable_review_labels_security`: if set to true, the tool will publish a 'possible security issue' label if it detects a security issue. Default is true. +- `enable_review_labels_effort`: if set to true, the tool will publish a 'Review effort [1-5]: x' label. Default is false. - To enable `custom labels`, apply the configuration changes described [here](./GENERATE_CUSTOM_LABELS.md#configuration-changes) #### Incremental Mode For an incremental review, which only considers changes since the last PR-Agent review, this can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again, the following command can be used: diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index dd863ebb..da69ad8e 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -16,11 +16,13 @@ secret_provider="google_cloud_storage" cli_mode=false [pr_reviewer] # /review # +# enable/disable features require_focused_review=false require_score_review=false require_tests_review=true require_security_review=true require_estimate_effort_to_review=true +# general options num_code_suggestions=4 inline_code_comments = false ask_and_reflect=false @@ -28,6 +30,9 @@ automatic_review=true remove_previous_review_comment=false persistent_comment=true extra_instructions = "" +# review labels +enable_review_labels_security=true +enable_review_labels_effort=false # specific configurations for incremental review (/review -i) require_all_thresholds_for_incremental_review=false minimal_commits_for_incremental_review=0 diff --git a/pr_agent/settings/pr_reviewer_prompts.toml b/pr_agent/settings/pr_reviewer_prompts.toml index 103d5e14..b75c296a 100644 --- a/pr_agent/settings/pr_reviewer_prompts.toml +++ b/pr_agent/settings/pr_reviewer_prompts.toml @@ -93,7 +93,7 @@ PR Analysis: description: >- Estimate, on a scale of 1-5 (inclusive), the time and effort required to review this PR by an experienced and knowledgeable developer. 1 means short and easy review , 5 means long and hard review. Take into account the size, complexity, quality, and the needed changes of the PR code diff. - Explain your answer shortly (1-2 sentences). + Explain your answer shortly (1-2 sentences). Use the format: '1, because ...' {%- endif %} PR Feedback: General suggestions: @@ -130,7 +130,8 @@ PR Feedback: Security concerns: type: string description: >- - yes\\no question: 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 ? If answered 'yes', explain your answer briefly. + 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' if there are no possible issues. + Answer 'Yes, because ...' if there are security concerns or issues. Explain your answer shortly. {%- endif %} ``` diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py index 7a839ce0..525bc128 100644 --- a/pr_agent/tools/pr_reviewer.py +++ b/pr_agent/tools/pr_reviewer.py @@ -10,7 +10,7 @@ from yaml import SafeLoader from pr_agent.algo.ai_handler import AiHandler from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models from pr_agent.algo.token_handler import TokenHandler -from pr_agent.algo.utils import convert_to_markdown, load_yaml, try_fix_yaml, set_custom_labels +from pr_agent.algo.utils import convert_to_markdown, load_yaml, try_fix_yaml, set_custom_labels, get_user_labels from pr_agent.config_loader import get_settings from pr_agent.git_providers import get_git_provider from pr_agent.git_providers.git_provider import IncrementalPR, get_main_pr_language @@ -255,6 +255,9 @@ class PRReviewer: else: markdown_text += actions_help_text + # Add custom labels from the review prediction (effort, security) + self.set_review_labels(data) + # Log markdown response if verbosity level is high if get_settings().config.verbosity_level >= 2: get_logger().info(f"Markdown response:\n{markdown_text}") @@ -375,3 +378,28 @@ class PRReviewer: ) return False return True + + def set_review_labels(self, data): + if (get_settings().pr_reviewer.enable_review_labels_security or + get_settings().pr_reviewer.enable_review_labels_effort): + try: + review_labels = [] + if get_settings().pr_reviewer.enable_review_labels_effort: + estimated_effort = data['PR Analysis']['Estimated effort to review [1-5]'] + estimated_effort_number = int(estimated_effort.split(',')[0]) + if 1 <= estimated_effort_number <= 5: # 1, because ... + review_labels.append(f'Review effort [1-5]: {estimated_effort_number}') + if get_settings().pr_reviewer.enable_review_labels_security: + security_concerns = data['PR Analysis']['Security concerns'] # yes, because ... + security_concerns_bool = 'yes' in security_concerns.lower() or 'true' in security_concerns.lower() + if security_concerns_bool: + review_labels.append('Possible security concern') + + if review_labels: + current_labels = self.git_provider.get_labels() + current_labels_filtered = [label for label in current_labels if + not label.lower().startswith('review effort [1-5]:') and not label.lower().startswith( + 'possible security concern')] + self.git_provider.publish_labels(review_labels + current_labels_filtered) + except Exception as e: + get_logger().error(f"Failed to set review labels, error: {e}")