Skip to content

Commit

Permalink
fix: improve PR patch decoding and clean up Bitbucket provider code
Browse files Browse the repository at this point in the history
- Add fallback encodings for PR patch decoding to handle non-UTF-8 encodings.
- Update logging messages for better clarity.
- Remove unnecessary blank lines and fix minor formatting issues.
- Ensure full files are retrieved in `get_diff_files` method.
  • Loading branch information
mrT23 committed Sep 1, 2024
1 parent 5ac41dd commit 2c496b9
Showing 1 changed file with 34 additions and 17 deletions.
51 changes: 34 additions & 17 deletions pr_agent/git_providers/bitbucket_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def publish_file_comments(self, file_comments: list) -> bool:

def is_supported(self, capability: str) -> bool:
if capability in ['get_issue_comments', 'publish_inline_comments', 'get_labels', 'gfm_markdown',
'publish_file_comments']:
'publish_file_comments']:
return False
return True

Expand All @@ -142,7 +142,6 @@ def get_files(self):
self.git_files = [_gef_filename(diff) for diff in self.pr.diffstat()]
return self.git_files


def get_diff_files(self) -> list[FilePatchInfo]:
if self.diff_files:
return self.diff_files
Expand All @@ -164,8 +163,25 @@ def get_diff_files(self) -> list[FilePatchInfo]:
pass

# get the pr patches
pr_patch = self.pr.diff()
diff_split = ["diff --git" + x for x in pr_patch.split("diff --git") if x.strip()]
try:
pr_patches = self.pr.diff()
except Exception as e:
# Try different encodings if UTF-8 fails
get_logger().warning(f"Failed to decode PR patch with utf-8, error: {e}")
encodings_to_try = ['iso-8859-1', 'latin-1', 'ascii', 'utf-16']
pr_patches = None
for encoding in encodings_to_try:
try:
pr_patches = self.pr.diff(encoding=encoding)
get_logger().info(f"Successfully decoded PR patch with encoding {encoding}")
break
except UnicodeDecodeError:
continue

if pr_patches is None:
raise ValueError(f"Failed to decode PR patch with encodings {encodings_to_try}")

diff_split = ["diff --git" + x for x in pr_patches.split("diff --git") if x.strip()]
# filter all elements of 'diff_split' that are of indices in 'diffs_original' that are not in 'diffs'
if len(diff_split) > len(diffs) and len(diffs_original) == len(diff_split):
diff_split = [diff_split[i] for i in range(len(diff_split)) if diffs_original[i] in diffs]
Expand Down Expand Up @@ -196,12 +212,13 @@ def get_diff_files(self) -> list[FilePatchInfo]:
diff_split[i] = ""
get_logger().info(f"Disregarding empty diff for file {_gef_filename(diffs[i])}")
else:
get_logger().error(f"Error - failed to get diff for file {_gef_filename(diffs[i])}")
get_logger().warning(f"Bitbucket failed to get diff for file {_gef_filename(diffs[i])}")
diff_split[i] = ""

invalid_files_names = []
diff_files = []
counter_valid = 0
# get full files
for index, diff in enumerate(diffs):
file_path = _gef_filename(diff)
if not is_valid_file(file_path):
Expand Down Expand Up @@ -316,11 +333,13 @@ def remove_comment(self, comment):
get_logger().exception(f"Failed to remove comment, error: {e}")

# function to create_inline_comment
def create_inline_comment(self, body: str, relevant_file: str, relevant_line_in_file: str, absolute_position: int = None):
def create_inline_comment(self, body: str, relevant_file: str, relevant_line_in_file: str,
absolute_position: int = None):
body = self.limit_output_characters(body, self.max_comment_length)
position, absolute_position = find_line_number_of_relevant_line_in_file(self.get_diff_files(),
relevant_file.strip('`'),
relevant_line_in_file, absolute_position)
relevant_file.strip('`'),
relevant_line_in_file,
absolute_position)
if position == -1:
if get_settings().config.verbosity_level >= 2:
get_logger().info(f"Could not find position for {relevant_file} {relevant_line_in_file}")
Expand All @@ -330,10 +349,9 @@ def create_inline_comment(self, body: str, relevant_file: str, relevant_line_in_
path = relevant_file.strip()
return dict(body=body, path=path, position=absolute_position) if subject_type == "LINE" else {}


def publish_inline_comment(self, comment: str, from_line: int, file: str, original_suggestion=None):
comment = self.limit_output_characters(comment, self.max_comment_length)
payload = json.dumps( {
payload = json.dumps({
"content": {
"raw": comment,
},
Expand Down Expand Up @@ -378,10 +396,10 @@ def publish_inline_comments(self, comments: list[dict]):
for comment in comments:
if 'position' in comment:
self.publish_inline_comment(comment['body'], comment['position'], comment['path'])
elif 'start_line' in comment: # multi-line comment
elif 'start_line' in comment: # multi-line comment
# note that bitbucket does not seem to support range - only a comment on a single line - https://community.developer.atlassian.com/t/api-post-endpoint-for-inline-pull-request-comments/60452
self.publish_inline_comment(comment['body'], comment['start_line'], comment['path'])
elif 'line' in comment: # single-line comment
elif 'line' in comment: # single-line comment
self.publish_inline_comment(comment['body'], comment['line'], comment['path'])
else:
get_logger().error(f"Could not publish inline comment {comment}")
Expand Down Expand Up @@ -465,20 +483,19 @@ def get_pr_file_content(self, file_path: str, branch: str) -> str:
except Exception:
return ""


def create_or_update_pr_file(self, file_path: str, branch: str, contents="", message="") -> None:
url = (f"https://api.bitbucket.org/2.0/repositories/{self.workspace_slug}/{self.repo_slug}/src/")
if not message:
if contents:
message = f"Update {file_path}"
else:
message = f"Create {file_path}"
files={file_path: contents}
data={
files = {file_path: contents}
data = {
"message": message,
"branch": branch
}
headers = {'Authorization':self.headers['Authorization']} if 'Authorization' in self.headers else {}
headers = {'Authorization': self.headers['Authorization']} if 'Authorization' in self.headers else {}
try:
requests.request("POST", url, headers=headers, data=data, files=files)
except Exception:
Expand All @@ -503,7 +520,7 @@ def publish_description(self, pr_title: str, description: str):
"description": description,
"title": pr_title

})
})

response = requests.request("PUT", self.bitbucket_pull_request_api_url, headers=self.headers, data=payload)
try:
Expand Down

0 comments on commit 2c496b9

Please sign in to comment.