mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-12-11 18:35:18 +00:00
Compare commits
5 commits
1f68deae9d
...
58d99ab564
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58d99ab564 | ||
|
|
bf5da9a9fb | ||
|
|
725a26ba88 | ||
|
|
1a4df62f89 | ||
|
|
6561d0478e |
4 changed files with 107 additions and 5 deletions
|
|
@ -56,7 +56,7 @@ A `PR Code Verified` label indicates the PR code meets ticket requirements, but
|
||||||
|
|
||||||
-
|
-
|
||||||
|
|
||||||
By default, the tool will automatically validate if the PR complies with the referenced ticket.
|
By default, the `review` tool will automatically validate if the PR complies with the referenced ticket.
|
||||||
If you want to disable this feedback, add the following line to your configuration file:
|
If you want to disable this feedback, add the following line to your configuration file:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|
@ -75,6 +75,33 @@ A `PR Code Verified` label indicates the PR code meets ticket requirements, but
|
||||||
|
|
||||||
the `review` tool will also validate that the PR code doesn't contain any additional content that is not related to the ticket. If it does, the PR will be labeled at best as `PR Code Verified`, and the `review` tool will provide a comment with the additional unrelated content found in the PR code.
|
the `review` tool will also validate that the PR code doesn't contain any additional content that is not related to the ticket. If it does, the PR will be labeled at best as `PR Code Verified`, and the `review` tool will provide a comment with the additional unrelated content found in the PR code.
|
||||||
|
|
||||||
|
### Compliance tool
|
||||||
|
|
||||||
|
The `compliance` tool also uses ticket context to validate that PR changes fulfill the requirements specified in linked tickets.
|
||||||
|
|
||||||
|
#### Configuration options
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
By default, the `compliance` tool will automatically validate if the PR complies with the referenced ticket.
|
||||||
|
If you want to disable ticket compliance checking in the compliance tool, add the following line to your configuration file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[pr_compliance]
|
||||||
|
require_ticket_analysis_review=false
|
||||||
|
```
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
If you set:
|
||||||
|
```toml
|
||||||
|
[pr_compliance]
|
||||||
|
check_pr_additional_content=true
|
||||||
|
```
|
||||||
|
(default: `false`)
|
||||||
|
|
||||||
|
the `compliance` tool will also validate that the PR code doesn't contain any additional content that is not related to the ticket.
|
||||||
|
|
||||||
## GitHub/Gitlab Issues Integration
|
## GitHub/Gitlab Issues Integration
|
||||||
|
|
||||||
Qodo Merge will automatically recognize GitHub/Gitlab issues mentioned in the PR description and fetch the issue content.
|
Qodo Merge will automatically recognize GitHub/Gitlab issues mentioned in the PR description and fetch the issue content.
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,10 @@ enable_global_pr_compliance = true
|
||||||
???+ example "Ticket compliance options"
|
???+ example "Ticket compliance options"
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><b>require_ticket_analysis_review</b></td>
|
||||||
|
<td>If set to true, the tool will fetch and analyze ticket context for compliance validation. Default is true.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>enable_ticket_labels</b></td>
|
<td><b>enable_ticket_labels</b></td>
|
||||||
<td>If set to true, the tool will add ticket compliance labels to the PR. Default is false.</td>
|
<td>If set to true, the tool will add ticket compliance labels to the PR. Default is false.</td>
|
||||||
|
|
|
||||||
|
|
@ -868,6 +868,44 @@ def try_fix_yaml(response_text: str,
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 5.5 fallback - try to normalize diff-style removal markers ('-') within list items
|
||||||
|
response_text_lines_copy = response_text_lines.copy()
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
for i, line in enumerate(response_text_lines_copy):
|
||||||
|
if line.startswith('+'):
|
||||||
|
response_text_lines_copy[i] = ' ' + line[1:]
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
# normalize lines starting with '-'. Distinguish real YAML list items from diff deletions.
|
||||||
|
for i, line in enumerate(response_text_lines_copy):
|
||||||
|
if not line.startswith('-'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
remainder = line[1:]
|
||||||
|
if line.startswith('- '):
|
||||||
|
second_char = remainder[1] if len(remainder) > 1 else ''
|
||||||
|
if second_char and second_char not in (' ', '\t', '+', '-'):
|
||||||
|
continue # real list item → keep as-is
|
||||||
|
|
||||||
|
# treat it as a diff "removed" marker inside block content
|
||||||
|
cleaned = remainder
|
||||||
|
while cleaned and cleaned[0] in ('+', '-'):
|
||||||
|
cleaned = cleaned[1:]
|
||||||
|
if cleaned and cleaned[0] not in (' ', '\t'):
|
||||||
|
cleaned = ' ' + cleaned
|
||||||
|
if cleaned != line:
|
||||||
|
response_text_lines_copy[i] = cleaned
|
||||||
|
modified = True
|
||||||
|
if modified:
|
||||||
|
try:
|
||||||
|
data = yaml.safe_load('\n'.join(response_text_lines_copy))
|
||||||
|
get_logger().info("Successfully parsed AI prediction after normalizing diff removal markers")
|
||||||
|
return data
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# sixth fallback - replace tabs with spaces
|
# sixth fallback - replace tabs with spaces
|
||||||
if '\t' in response_text:
|
if '\t' in response_text:
|
||||||
response_text_copy = copy.deepcopy(response_text)
|
response_text_copy = copy.deepcopy(response_text)
|
||||||
|
|
|
||||||
|
|
@ -244,3 +244,36 @@ int sub(int a, int b) {
|
||||||
'''
|
'''
|
||||||
expected_output = {'code_suggestions': [{'relevant_file': 'a.c\n', 'existing_code': ' int sum(int a, int b) {\n return a + b;\n }\n\n int sub(int a, int b) {\n return a - b;\n }\n'}]}
|
expected_output = {'code_suggestions': [{'relevant_file': 'a.c\n', 'existing_code': ' int sum(int a, int b) {\n return a + b;\n }\n\n int sub(int a, int b) {\n return a - b;\n }\n'}]}
|
||||||
assert try_fix_yaml(review_text, first_key='code_suggestions', last_key='existing_code') == expected_output
|
assert try_fix_yaml(review_text, first_key='code_suggestions', last_key='existing_code') == expected_output
|
||||||
|
|
||||||
|
def test_diff_markers_removed_within_list_item(self):
|
||||||
|
"""
|
||||||
|
Ensures diff-style '-' markers nested inside list items are normalised so the YAML parses
|
||||||
|
into the expected structure.
|
||||||
|
"""
|
||||||
|
review_text = '''\
|
||||||
|
code_suggestions:
|
||||||
|
- relevant_file: |
|
||||||
|
example.rb
|
||||||
|
existing_code: |
|
||||||
|
+ puts 'hello'
|
||||||
|
+ puts 'world'
|
||||||
|
- relevant_file: |
|
||||||
|
- example.py
|
||||||
|
- existing_code: |
|
||||||
|
-+ print('hello')
|
||||||
|
-+ print('world')
|
||||||
|
'''
|
||||||
|
expected_output = {
|
||||||
|
'code_suggestions': [
|
||||||
|
{
|
||||||
|
'relevant_file': 'example.rb\n',
|
||||||
|
'existing_code': "puts 'hello'\nputs 'world'\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'relevant_file': 'example.py\n',
|
||||||
|
'existing_code': "print('hello')\nprint('world')\n"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert try_fix_yaml(review_text, first_key='code_suggestions', last_key='existing_code') == expected_output
|
||||||
Loading…
Reference in a new issue