t-bug-catcher 0.4.9__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/PKG-INFO +1 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/setup.cfg +1 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/setup.py +1 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/__init__.py +1 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/config.py +1 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/jira.py +112 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/utils/common.py +18 -3
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/PKG-INFO +1 -1
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/MANIFEST.in +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/README.rst +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/pyproject.toml +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/requirements.txt +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/bug_catcher.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/bug_snag.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/exceptions.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/resources/whispers_config.yml +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/stack_saver.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/utils/__init__.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/utils/logger.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/validation.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher/workitems.py +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/not-zip-safe +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/requires.txt +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/t_bug_catcher.egg-info/top_level.txt +0 -0
- {t_bug_catcher-0.4.9 → t_bug_catcher-0.5.0}/tests/test_t_bug_catcher.py +0 -0
|
@@ -26,7 +26,7 @@ setup(
|
|
|
26
26
|
packages=find_packages(include=["t_bug_catcher", "t_bug_catcher.*"]),
|
|
27
27
|
test_suite="tests",
|
|
28
28
|
url="https://www.thoughtful.ai/",
|
|
29
|
-
version="0.
|
|
29
|
+
version="0.5.0",
|
|
30
30
|
zip_safe=False,
|
|
31
31
|
install_requires=install_requirements,
|
|
32
32
|
include_package_data=True,
|
|
@@ -20,7 +20,7 @@ from retry import retry
|
|
|
20
20
|
from .config import CONFIG
|
|
21
21
|
from .exceptions import BadRequestError
|
|
22
22
|
from .utils import logger
|
|
23
|
-
from .utils.common import Encoder, get_frames
|
|
23
|
+
from .utils.common import Encoder, get_frames, retrieve_build_info
|
|
24
24
|
from .workitems import variables
|
|
25
25
|
|
|
26
26
|
|
|
@@ -54,6 +54,7 @@ class Jira:
|
|
|
54
54
|
self._webhook_url = None
|
|
55
55
|
self._auth = None
|
|
56
56
|
self._default_assignee = None
|
|
57
|
+
self._build_info: Optional[dict] = None
|
|
57
58
|
|
|
58
59
|
@staticmethod
|
|
59
60
|
def _is_json_response(response) -> bool:
|
|
@@ -113,6 +114,7 @@ class Jira:
|
|
|
113
114
|
try:
|
|
114
115
|
self._project_key = project_key if CONFIG.STAGE not in ["hypercare", "support"] else CONFIG.SUPPORT_BOARD
|
|
115
116
|
self._default_assignee = default_assignee
|
|
117
|
+
self._build_info = retrieve_build_info()
|
|
116
118
|
if not webhook_url:
|
|
117
119
|
logger.warning("No JIRA webhook URL provided. All issues will be posted to backlog.")
|
|
118
120
|
self._webhook_url = webhook_url
|
|
@@ -460,6 +462,114 @@ class Jira:
|
|
|
460
462
|
else []
|
|
461
463
|
)
|
|
462
464
|
|
|
465
|
+
def __branch_info_markup(self, exc_traceback: TracebackType) -> List[dict]:
|
|
466
|
+
"""Create the branch info markup.
|
|
467
|
+
|
|
468
|
+
Returns:
|
|
469
|
+
dict: The branch markup.
|
|
470
|
+
"""
|
|
471
|
+
if not self._build_info:
|
|
472
|
+
return []
|
|
473
|
+
frames = get_frames(exc_traceback)
|
|
474
|
+
file_name, line_no, _, _ = frames[-1]
|
|
475
|
+
path = Path.relative_to(Path(file_name), Path.cwd())
|
|
476
|
+
code_line = (
|
|
477
|
+
f"{self._build_info['repository_url']}/src/{self._build_info['last_commit']}"
|
|
478
|
+
f"/{path.as_posix()}?at={self._build_info['branch']}#lines-{line_no}"
|
|
479
|
+
)
|
|
480
|
+
input_datetime = datetime.strptime(self._build_info["commit_datetime"], "%Y-%m-%d %H:%M:%S").strftime(
|
|
481
|
+
"%d %B %Y %I:%M:%S %p"
|
|
482
|
+
)
|
|
483
|
+
return [
|
|
484
|
+
{
|
|
485
|
+
"type": "paragraph",
|
|
486
|
+
"content": [
|
|
487
|
+
{
|
|
488
|
+
"type": "text",
|
|
489
|
+
"text": "Bitbucket: ",
|
|
490
|
+
"marks": [{"type": "strong"}],
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"type": "text",
|
|
494
|
+
"text": self._build_info["repository_name"],
|
|
495
|
+
"marks": [
|
|
496
|
+
{
|
|
497
|
+
"type": "link",
|
|
498
|
+
"attrs": {"href": self._build_info["repository_url"]},
|
|
499
|
+
}
|
|
500
|
+
],
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"type": "text",
|
|
504
|
+
"text": " @ ",
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"type": "text",
|
|
508
|
+
"text": self._build_info["branch"],
|
|
509
|
+
"marks": [
|
|
510
|
+
{
|
|
511
|
+
"type": "link",
|
|
512
|
+
"attrs": {"href": self._build_info["branch_url"]},
|
|
513
|
+
}
|
|
514
|
+
],
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
"type": "text",
|
|
518
|
+
"text": " > ",
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"type": "text",
|
|
522
|
+
"text": f"{str(path.as_posix())}:{line_no}",
|
|
523
|
+
"marks": [
|
|
524
|
+
{
|
|
525
|
+
"type": "link",
|
|
526
|
+
"attrs": {"href": code_line},
|
|
527
|
+
}
|
|
528
|
+
],
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"type": "paragraph",
|
|
534
|
+
"content": [
|
|
535
|
+
{
|
|
536
|
+
"type": "text",
|
|
537
|
+
"text": "Last commit: ",
|
|
538
|
+
"marks": [{"type": "strong"}],
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
"type": "text",
|
|
542
|
+
"text": self._build_info["last_commit"][:7],
|
|
543
|
+
"marks": [
|
|
544
|
+
{
|
|
545
|
+
"type": "link",
|
|
546
|
+
"attrs": {"href": self._build_info["commit_url"]},
|
|
547
|
+
}
|
|
548
|
+
],
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
"type": "text",
|
|
552
|
+
"text": " by ",
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"type": "text",
|
|
556
|
+
"text": self._build_info["author_username"],
|
|
557
|
+
"marks": [
|
|
558
|
+
{
|
|
559
|
+
"type": "link",
|
|
560
|
+
"attrs": {"href": self._build_info["author_email"]},
|
|
561
|
+
}
|
|
562
|
+
],
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
"type": "text",
|
|
566
|
+
"text": " on ",
|
|
567
|
+
},
|
|
568
|
+
{"type": "text", "text": input_datetime, "marks": [{"type": "code"}]},
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
]
|
|
572
|
+
|
|
463
573
|
@staticmethod
|
|
464
574
|
def __environment_markup() -> List[dict]:
|
|
465
575
|
"""Create the environment markup.
|
|
@@ -706,6 +816,7 @@ class Jira:
|
|
|
706
816
|
+ self.__date_markup()
|
|
707
817
|
+ self.__runlink_markup()
|
|
708
818
|
+ self.__environment_markup()
|
|
819
|
+
+ self.__branch_info_markup(exc_traceback)
|
|
709
820
|
+ (self.__description_markup(additional_info) if additional_info else [])
|
|
710
821
|
+ self.__traceback_markup(exc_traceback_info)
|
|
711
822
|
+ (self.__metadata_markup(metadata) if metadata else [])
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import copy
|
|
2
|
+
import json
|
|
2
3
|
import os
|
|
3
4
|
import traceback
|
|
5
|
+
import urllib
|
|
4
6
|
from datetime import date, datetime
|
|
5
|
-
from json import JSONEncoder
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from types import TracebackType
|
|
8
9
|
from typing import List
|
|
@@ -10,7 +11,7 @@ from typing import List
|
|
|
10
11
|
from ..config import CONFIG
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
class Encoder(JSONEncoder):
|
|
14
|
+
class Encoder(json.JSONEncoder):
|
|
14
15
|
"""This class is used to encode the Episode object to json."""
|
|
15
16
|
|
|
16
17
|
def default(self, o):
|
|
@@ -24,7 +25,7 @@ class Encoder(JSONEncoder):
|
|
|
24
25
|
"""
|
|
25
26
|
try:
|
|
26
27
|
object_copy = copy.deepcopy(o)
|
|
27
|
-
except TypeError:
|
|
28
|
+
except (TypeError, AttributeError):
|
|
28
29
|
return str(o)
|
|
29
30
|
try:
|
|
30
31
|
if hasattr(object_copy, "__dict__"):
|
|
@@ -87,3 +88,17 @@ def strip_path(path: str):
|
|
|
87
88
|
str: The stripped path.
|
|
88
89
|
"""
|
|
89
90
|
return path.replace(os.getcwd(), "").strip(os.sep)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def retrieve_build_info():
|
|
94
|
+
"""Logs build information."""
|
|
95
|
+
if not os.path.exists(CONFIG.BUILD_INFO_FILE):
|
|
96
|
+
return
|
|
97
|
+
with open(CONFIG.BUILD_INFO_FILE, "r") as json_file:
|
|
98
|
+
commit_info = json.load(json_file)
|
|
99
|
+
repository_url = commit_info["repository_url"]
|
|
100
|
+
current_branch = commit_info["branch"]
|
|
101
|
+
encoded_branch = urllib.parse.quote(current_branch)
|
|
102
|
+
commit_info["branch_url"] = f"{repository_url}/src/{commit_info['last_commit']}/?at={encoded_branch}"
|
|
103
|
+
commit_info["commit_url"] = f"{repository_url}/commits/{commit_info['last_commit']}/"
|
|
104
|
+
return commit_info
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|