Skip to content

Commit 3da2161

Browse files
author
Matthieu Honel
committed
Merge branch 'release/2.7.4'
2 parents 7c7aa55 + 8d73b35 commit 3da2161

8 files changed

Lines changed: 138 additions & 6 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ Since data is pulled from YWH platform to your server, only regular outbound web
5252
- v2.7:
5353
- added synchronization of "fix verification" logs when "Upload status updates" is checked
5454
- fixed an issue with jira when scope contains special markdown characters
55+
- fixed an issue when "Download bug trackers comments" feedback option is activated
56+
and bug tracker attachments do not meet platform attachments requirements (unacceptable mime-type, maximum allowed size exceeded)
5557
- v2.6:
5658
- added work around bug trackers maximum size allowed for the text of the issues/comments (content put in Markdown file attachment when necessary)
5759
- v2.5:

docs/user-guide/User-Guide.pdf

-3 Bytes
Binary file not shown.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "ywh2bt"
3-
version = "2.7.3"
3+
version = "2.7.4"
44
description = "ywh2bt - YesWeHack to Bug Tracker"
55
readme = "README.md"
66
authors = ["m.honel <m.honel@yeswehack.com>"]

ywh2bt/core/api/yeswehack.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
YesWeHackConfiguration,
3535
)
3636
from ywh2bt.core.exceptions import CoreException
37+
from ywh2bt.version import __VERSION__
3738

3839

3940
class YesWeHackApiClientError(CoreException):
@@ -83,6 +84,9 @@ def _build_raw_client(
8384
pat=configuration.pat,
8485
verify=configuration.verify,
8586
lazy=True,
87+
headers={
88+
'User-Agent': f'ywh2bt/{__VERSION__}',
89+
},
8690
)
8791
except (YesWeHackRawAPiError, requests.RequestException) as e:
8892
raise YesWeHackApiClientError('Unable to initialize YesWeHack API client') from e

ywh2bt/core/synchronizer/synchronizer.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
)
3535
from ywh2bt.core.api.tracker import (
3636
SendLogsResult,
37+
TrackerAttachment,
3738
TrackerClient,
3839
TrackerClientError,
3940
TrackerIssue,
@@ -76,6 +77,7 @@
7677
SynchronizerStartFetchReportsEvent,
7778
SynchronizerStartSendReportEvent,
7879
)
80+
from ywh2bt.size import sizeof_fmt_si
7981

8082

8183
class Synchronizer:
@@ -624,6 +626,7 @@ def _download_comment(
624626
tracker_issue: TrackerIssue,
625627
tracker_comment: TrackerIssueComment,
626628
) -> None:
629+
failed_attachments = {}
627630
attachments = {}
628631
for attachment_key, attachment in tracker_comment.attachments.items():
629632
try:
@@ -633,10 +636,9 @@ def _download_comment(
633636
file_content=attachment.content,
634637
file_type=attachment.mime_type,
635638
)
636-
except YesWeHackApiClientError as upload_attachment_error:
637-
raise SynchronizerError(
638-
f'Unable to upload attachment {attachment.filename} for report #{self._report.report_id}',
639-
) from upload_attachment_error
639+
except YesWeHackApiClientError:
640+
failed_attachments[attachment_key] = attachment
641+
continue
640642
attachments[attachment_key] = uploaded_attachment
641643
try:
642644
self._yeswehack_client.post_report_tracker_message(
@@ -647,6 +649,7 @@ def _download_comment(
647649
comment=self._message_formatter.format_download_comment(
648650
comment=tracker_comment,
649651
attachments=attachments,
652+
failed_attachments=failed_attachments,
650653
),
651654
attachments=[uploaded_attachment.name for attachment_key, uploaded_attachment in attachments.items()],
652655
)
@@ -783,13 +786,15 @@ def format_download_comment(
783786
self,
784787
comment: TrackerIssueComment,
785788
attachments: Dict[str, Attachment],
789+
failed_attachments: Dict[str, TrackerAttachment],
786790
) -> str:
787791
"""
788792
Format a downloaded comment.
789793
790794
Args:
791795
comment: a comment
792796
attachments: a dict of attachments
797+
failed_attachments: a dict of tracker attachments that failed to be uploaded
793798
"""
794799

795800
@abstractmethod
@@ -835,6 +840,15 @@ class SynchronizerMessageFormatter(AbstractSynchronizerMessageFormatter):
835840
+ '\n\n'
836841
+ '${comment}',
837842
)
843+
_failed_attachments_template: Template = Template(
844+
'**YWH2BT note:**'
845+
+ '\n*There was an issue while uploading the following attachments from the bugtracker*:'
846+
+ '\n\n'
847+
+ '${attachments}',
848+
)
849+
_failed_attachment_template: Template = Template(
850+
'- ${filename} (size=${size}, mime=${mimetype})',
851+
)
838852
_status_update_comment_template: Template = Template(
839853
'${comment}',
840854
)
@@ -909,25 +923,42 @@ def format_download_comment(
909923
self,
910924
comment: TrackerIssueComment,
911925
attachments: Dict[str, Attachment],
926+
failed_attachments: Dict[str, TrackerAttachment],
912927
) -> str:
913928
"""
914929
Format a downloaded comment.
915930
916931
Args:
917932
comment: a comment
918933
attachments: a dict of attachments
934+
failed_attachments: a dict of tracker attachments that failed to be uploaded
919935
920936
Returns:
921937
a formatted comment
922938
"""
923-
return self._download_comment_template.substitute(
939+
formatted_comment = self._download_comment_template.substitute(
924940
date=comment.created_at,
925941
author=comment.author,
926942
comment=markdown_to_ywh(
927943
message=comment.body,
928944
attachments=attachments,
929945
),
930946
)
947+
if failed_attachments:
948+
formatted_attachments = []
949+
for _attachment_key, failed_attachment in failed_attachments.items():
950+
formatted_attachments.append(
951+
self._failed_attachment_template.substitute(
952+
filename=failed_attachment.filename,
953+
mimetype=failed_attachment.mime_type,
954+
size=sizeof_fmt_si(len(failed_attachment.content), precision=2),
955+
),
956+
)
957+
formatted_failed_attachments = self._failed_attachments_template.substitute(
958+
attachments='\n'.join(formatted_attachments),
959+
)
960+
formatted_comment = f'{formatted_comment}\n\n{formatted_failed_attachments}'
961+
return formatted_comment
931962

932963
def format_status_update_comment(
933964
self,

ywh2bt/size.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from typing import (
2+
List,
3+
Union,
4+
)
5+
6+
7+
def _sizeof_fmt(
8+
num: Union[int, float],
9+
base: int,
10+
units: List[str],
11+
max_unit: str,
12+
precision: int = 1,
13+
suffix: str = 'B'
14+
) -> str:
15+
for unit in units:
16+
if abs(num) < base:
17+
return f'{num:.{precision}f}{unit}{suffix}'
18+
num /= base
19+
return f'{num:.{precision}f}{max_unit}{suffix}'
20+
21+
22+
def sizeof_fmt_iec(num: Union[int, float], precision: int = 1, suffix: str = 'B') -> str:
23+
return _sizeof_fmt(
24+
num,
25+
base=1024,
26+
units=['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi'],
27+
max_unit='Yi',
28+
precision=precision,
29+
suffix=suffix,
30+
)
31+
32+
33+
def sizeof_fmt_si(num: Union[int, float], precision: int = 1, suffix: str = 'B') -> str:
34+
return _sizeof_fmt(
35+
num,
36+
base=1000,
37+
units=['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z'],
38+
max_unit='Y',
39+
precision=precision,
40+
suffix=suffix,
41+
)

ywh2bt/tests/core/synchronizer/test_synchronizer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
)
3737
from ywh2bt.core.api.tracker import (
3838
SendLogsResult,
39+
TrackerAttachment,
3940
TrackerClient,
4041
TrackerIssue,
4142
TrackerIssueComment,
@@ -669,6 +670,7 @@ def format_download_comment(
669670
self,
670671
comment: TrackerIssueComment,
671672
attachments: Dict[str, Attachment],
673+
failed_attachments: Dict[str, TrackerAttachment],
672674
) -> str:
673675
return self.download_comment_format.format(
674676
author=comment.author,

ywh2bt/tests/test_size.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import unittest
2+
from typing import Union
3+
4+
from ywh2bt.size import sizeof_fmt_si, sizeof_fmt_iec
5+
6+
7+
class TestCli(unittest.TestCase):
8+
def _test_sizeof_fmt_si(self, expected: str, num: Union[int, float], precision: int) -> None:
9+
with self.subTest(f'sizeof_fmt_si({num}, precision={precision})'):
10+
self.assertEqual(expected, sizeof_fmt_si(num, precision=precision))
11+
12+
def _test_sizeof_fmt_iec(self, expected: str, num: Union[int, float], precision: int) -> None:
13+
with self.subTest(f'sizeof_fmt_iec({num}, precision={precision})'):
14+
self.assertEqual(expected, sizeof_fmt_iec(num, precision=precision))
15+
16+
def test_sizeof_fmt(self) -> None:
17+
values = {
18+
999: {
19+
0: ['999B', '999B'],
20+
1: ['999.0B', '999.0B'],
21+
2: ['999.00B', '999.00B'],
22+
},
23+
1000: {
24+
0: ['1kB', '1000B'],
25+
1: ['1.0kB', '1000.0B'],
26+
2: ['1.00kB', '1000.00B'],
27+
},
28+
1024: {
29+
0: ['1kB', '1KiB'],
30+
1: ['1.0kB', '1.0KiB'],
31+
2: ['1.02kB', '1.00KiB'],
32+
},
33+
2000000: {
34+
0: ['2MB', '2MiB'],
35+
1: ['2.0MB', '1.9MiB'],
36+
2: ['2.00MB', '1.91MiB'],
37+
},
38+
123456897101112: {
39+
0: ['123TB', '112TiB'],
40+
1: ['123.5TB', '112.3TiB'],
41+
2: ['123.46TB', '112.28TiB'],
42+
},
43+
9999999999999999999999999: {
44+
0: ['10YB', '8YiB'],
45+
1: ['10.0YB', '8.3YiB'],
46+
2: ['10.00YB', '8.27YiB'],
47+
},
48+
}
49+
for num, precisions in values.items():
50+
for precision, expected_values in precisions.items():
51+
self._test_sizeof_fmt_si(expected_values[0], num=num, precision=precision)
52+
self._test_sizeof_fmt_iec(expected_values[1], num=num, precision=precision)

0 commit comments

Comments
 (0)