t-bug-catcher 0.6.0__tar.gz → 0.6.2__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.
Files changed (26) hide show
  1. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/setup.cfg +1 -1
  3. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/setup.py +1 -1
  4. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/__init__.py +1 -1
  5. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/bug_catcher.py +8 -2
  6. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/config.py +5 -0
  7. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/jira.py +110 -27
  8. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/utils/common.py +14 -0
  9. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  10. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/MANIFEST.in +0 -0
  11. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/README.rst +0 -0
  12. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/pyproject.toml +0 -0
  13. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/requirements.txt +0 -0
  14. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/bug_snag.py +0 -0
  15. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/exceptions.py +0 -0
  16. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/resources/whispers_config.yml +0 -0
  17. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/stack_saver.py +0 -0
  18. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/utils/__init__.py +0 -0
  19. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/utils/logger.py +0 -0
  20. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher/workitems.py +0 -0
  21. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
  22. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  23. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  24. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/requires.txt +0 -0
  25. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/t_bug_catcher.egg-info/top_level.txt +0 -0
  26. {t_bug_catcher-0.6.0 → t_bug_catcher-0.6.2}/tests/test_t_bug_catcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.6.0
2
+ current_version = 0.6.2
3
3
  commit = True
4
4
  tag = False
5
5
 
@@ -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.6.0",
29
+ version="0.6.2",
30
30
  zip_safe=False,
31
31
  install_requires=install_requirements,
32
32
  include_package_data=True,
@@ -3,7 +3,7 @@
3
3
  __author__ = """Thoughtful"""
4
4
  __email__ = "support@thoughtful.ai"
5
5
  # fmt: off
6
- __version__ = '0.6.0'
6
+ __version__ = '0.6.2'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -110,6 +110,8 @@ class BugCatcher:
110
110
  metadata: Optional[dict] = None,
111
111
  attachments: Optional[List] = None,
112
112
  assignee: Optional[str] = None,
113
+ team: Optional[str] = None,
114
+ group_by: Optional[str] = None,
113
115
  ):
114
116
  """Reports an error to the Jira project.
115
117
 
@@ -119,6 +121,8 @@ class BugCatcher:
119
121
  metadata (dict, optional): The metadata to be added to the Jira issue. Defaults to None.
120
122
  attachments (List, optional): The attachments to be added to the Jira issue. Defaults to None.
121
123
  assignee (str, optional): The assignee to be added to the Jira issue. Defaults to None.
124
+ team (str, optional): The team to be assigned to the Jira issue. Defaults to None.
125
+ group_by (str, optional): The group to be assigned to the Jira issue. Defaults to None.
122
126
 
123
127
  Returns:
124
128
  None
@@ -175,10 +179,12 @@ class BugCatcher:
175
179
  self.__jira.report_error(
176
180
  exception=exception,
177
181
  assignee=assignee,
182
+ team=team,
178
183
  attachments=attachments,
179
184
  stack_trace=stack_trace,
180
185
  additional_info=description,
181
186
  metadata=metadata,
187
+ group_by=group_by,
182
188
  )
183
189
 
184
190
  if self.__configurator.is_bugsnag_configured:
@@ -268,7 +274,7 @@ class BugCatcher:
268
274
  Args:
269
275
  exc_type (type): The type of the exception.
270
276
  exc_value (Exception): The value of the exception.
271
- traceback (traceback): The traceback of the exception.
277
+ exc_traceback (traceback): The traceback of the exception.
272
278
 
273
279
  Returns:
274
280
  None
@@ -289,7 +295,7 @@ class BugCatcher:
289
295
  stack_trace = self.__stack_saver.save_stack_trace(exc_value)
290
296
 
291
297
  if self.__configurator.is_jira_configured:
292
- self.__jira.report_unhandled_error(exc_type, exc_value, exc_traceback, stack_trace)
298
+ self.__jira.report_unhandled_error(exc_value, stack_trace)
293
299
  if self.__configurator.is_bugsnag_configured:
294
300
  self.__bug_snag.report_unhandled_error(exc_type, exc_value, exc_traceback)
295
301
  frames = get_frames(exc_value.__traceback__)
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import socket
2
3
 
3
4
  from .workitems import metadata, variables
4
5
 
@@ -16,6 +17,7 @@ class Config:
16
17
  STACK_SCOPE: int = 3
17
18
  STACK_ITEM_LENGTH: int = 100
18
19
  STACK_TEXT_LENGTH: int = 10000
20
+ COMMENT_LIMIT: int = 4950
19
21
 
20
22
  class TICKET_PRIORITIES:
21
23
  """Priorities class for configuring the application."""
@@ -32,6 +34,9 @@ class Config:
32
34
  KEYS_TO_REMOVE = ["credential", "password"]
33
35
  BUILD_INFO_FILE = "commit_info.json"
34
36
 
37
+ HOST = socket.gethostname() if os.name.lower() == "nt" else None
38
+ UNAME = os.getlogin() if os.name.lower() == "nt" else None
39
+
35
40
  RC_RUN_LINK = (
36
41
  f"https://cloud.robocorp.com/organizations/{os.environ.get('RC_ORGANIZATION_ID')}"
37
42
  f"/workspaces/{os.environ.get('RC_WORKSPACE_ID')}/processes"
@@ -7,6 +7,7 @@ import os
7
7
  import re
8
8
  import sys
9
9
  import traceback
10
+ import zlib
10
11
  from datetime import datetime
11
12
  from importlib.metadata import version
12
13
  from pathlib import Path
@@ -21,7 +22,7 @@ from retry import retry
21
22
  from .config import CONFIG
22
23
  from .exceptions import BadRequestError
23
24
  from .utils import logger
24
- from .utils.common import Encoder, get_frames, retrieve_build_info
25
+ from .utils.common import Encoder, get_frames, remove_holotree_id, retrieve_build_info
25
26
  from .workitems import variables
26
27
 
27
28
 
@@ -216,6 +217,7 @@ class Jira:
216
217
  assignee: Optional[str] = None,
217
218
  labels: Optional[list] = None,
218
219
  priority: Optional[str] = None,
220
+ team: Optional[str] = None,
219
221
  ) -> str:
220
222
  """Generates the issue body payload for creating a new issue.
221
223
 
@@ -226,6 +228,7 @@ class Jira:
226
228
  issue_type (str): The type of the issue.
227
229
  labels (list, optional): The labels of the issue. Defaults to None.
228
230
  priority (str, optional): The priority of the issue. Defaults to None.
231
+ team (str, optional): The team to be assigned to the Jira issue. Defaults to None.
229
232
 
230
233
  Returns:
231
234
  The JSON payload for creating a new issue.
@@ -246,6 +249,8 @@ class Jira:
246
249
  fields["fields"]["customfield_10077"] = [CONFIG.ADMIN_CODE]
247
250
  if priority:
248
251
  fields["fields"]["priority"] = {"id": priority}
252
+ if team:
253
+ fields["fields"]["customfield_10001"] = team
249
254
  payload = json.dumps(fields)
250
255
  return payload
251
256
 
@@ -639,6 +644,34 @@ class Jira:
639
644
  else []
640
645
  )
641
646
 
647
+ @staticmethod
648
+ def __host_markup() -> List[dict]:
649
+ """Create the host worker markup.
650
+
651
+ Returns:
652
+ dict: The host worker markup.
653
+ """
654
+ return (
655
+ [
656
+ {
657
+ "type": "paragraph",
658
+ "content": [
659
+ {
660
+ "type": "text",
661
+ "text": "Host: ",
662
+ "marks": [{"type": "strong"}],
663
+ },
664
+ {
665
+ "type": "text",
666
+ "text": f"{CONFIG.HOST} > {CONFIG.UNAME}",
667
+ },
668
+ ],
669
+ }
670
+ ]
671
+ if CONFIG.HOST and CONFIG.UNAME
672
+ else []
673
+ )
674
+
642
675
  @staticmethod
643
676
  def __traceback_markup(exc_traceback_info: str) -> List[dict]:
644
677
  """Create the traceback markup.
@@ -833,6 +866,7 @@ class Jira:
833
866
  + self.__date_markup()
834
867
  + self.__runlink_markup()
835
868
  + self.__environment_markup()
869
+ + self.__host_markup()
836
870
  + self.__branch_info_markup(exc_traceback)
837
871
  + (self.__description_markup(additional_info) if additional_info else [])
838
872
  + self.__traceback_markup(exc_traceback_info)
@@ -1121,9 +1155,10 @@ class Jira:
1121
1155
  else []
1122
1156
  )
1123
1157
 
1124
- if len(issue.get("fields", {}).get("comment", [])) >= 5000:
1158
+ if len(issue.get("fields", {}).get("comment", [])) >= CONFIG.LIMITS.COMMENT_LIMIT:
1125
1159
  logger.warning(
1126
- f"Comments for '{issue.get('key')}' were not posted due to exceeding JIRA comments limit (5000)."
1160
+ f"Comments for '{issue.get('key')}' were not posted due to exceeding JIRA comments limit "
1161
+ f"({CONFIG.LIMITS.COMMENT_LIMIT})."
1127
1162
  )
1128
1163
  return
1129
1164
 
@@ -1146,6 +1181,7 @@ class Jira:
1146
1181
  attachments: Optional[List] = None,
1147
1182
  labels: Optional[list] = None,
1148
1183
  priority: Optional[str] = None,
1184
+ team: Optional[str] = None,
1149
1185
  ) -> requests.Response:
1150
1186
  """Create a new ticket.
1151
1187
 
@@ -1156,6 +1192,7 @@ class Jira:
1156
1192
  attachments (List, optional): The list of attachments. Defaults to None.
1157
1193
  labels (List, optional): The list of labels. Defaults to None.
1158
1194
  priority (str, optional): The priority of the ticket. Defaults to None.
1195
+ team (str, optional): The team to be assigned to the Jira issue. Defaults to None.
1159
1196
 
1160
1197
  Returns:
1161
1198
  The response from creating the ticket.
@@ -1185,6 +1222,7 @@ class Jira:
1185
1222
  "project_key": project_key,
1186
1223
  "labels": labels,
1187
1224
  "priority": priority,
1225
+ "team": team,
1188
1226
  }
1189
1227
 
1190
1228
  issue = self.__generate_issue_body(**issue_body)
@@ -1270,20 +1308,24 @@ class Jira:
1270
1308
  self,
1271
1309
  exception: Optional[Exception] = None,
1272
1310
  assignee: Optional[str] = None,
1311
+ team: Optional[str] = None,
1273
1312
  attachments: Union[List, str, Path, None] = None,
1274
1313
  stack_trace: Optional[str] = None,
1275
1314
  metadata: Optional[dict] = None,
1276
1315
  additional_info: Optional[str] = None,
1316
+ group_by: Optional[str] = None,
1277
1317
  ) -> dict:
1278
1318
  """Create a Jira issue with the given attachments.
1279
1319
 
1280
1320
  Args:
1281
1321
  exception (Exception, optional): The exception to be added to the Jira issue.
1282
1322
  assignee (str, optional): The assignee to be added to the Jira issue.
1323
+ team (str, optional): The team to be assigned to the Jira issue. Defaults to None.
1283
1324
  attachments (List, optional): List of attachments to be added to the Jira issue.
1284
1325
  stack_trace (str, optional): Stack trace to be added to the Jira issue.
1285
1326
  metadata (dict, optional): Metadata to be added to the Jira issue.
1286
1327
  additional_info (str, optional): Additional information to be added to the Jira issue.
1328
+ group_by (str, optional): group_by flag to be added to the Jira issue.
1287
1329
 
1288
1330
  Returns:
1289
1331
  The response from creating the Jira issue.
@@ -1309,13 +1351,31 @@ class Jira:
1309
1351
  logger.warning(f"Only the first {CONFIG.LIMITS.MAX_ATTACHMENTS} attachments were uploaded.")
1310
1352
  attachments = attachments[: CONFIG.LIMITS.MAX_ATTACHMENTS]
1311
1353
 
1312
- summary = self.__create_summary(type(exception), exception, exception.__traceback__)
1313
- error_id = self.__generate_error_id(exc_type=type(exception), exc_traceback=exception.__traceback__)
1354
+ error_id = self.__generate_error_id(exception)
1355
+ group_id = self.generate_group_id(group_by)
1314
1356
 
1357
+ all_issues = self.get_issues()["issues"]
1315
1358
  existing_ticket = self.filter_tickets(
1316
- all_tickets=self.get_issues()["issues"],
1359
+ all_tickets=all_issues,
1317
1360
  error_id=error_id,
1318
1361
  )
1362
+
1363
+ if group_id:
1364
+ existing_tickets = [
1365
+ ticket
1366
+ for ticket in all_issues
1367
+ if ticket["fields"]["description"] and f"{error_id}-" in ticket["fields"]["description"]
1368
+ ]
1369
+ summary = self.__create_summary(
1370
+ type(exception),
1371
+ exception,
1372
+ exception.__traceback__,
1373
+ len(existing_tickets) + 1 if existing_tickets else 1,
1374
+ )
1375
+ error_id = f"{error_id}-{group_id}"
1376
+ else:
1377
+ summary = self.__create_summary(type(exception), exception, exception.__traceback__)
1378
+
1319
1379
  if existing_ticket:
1320
1380
  self.__update_existing_ticket(
1321
1381
  existing_ticket=existing_ticket,
@@ -1357,6 +1417,7 @@ class Jira:
1357
1417
  attachments=attachments,
1358
1418
  labels=["bug_catcher"],
1359
1419
  priority=priority,
1420
+ team=team,
1360
1421
  )
1361
1422
  if stack_trace and os.path.exists(stack_trace):
1362
1423
  os.remove(stack_trace)
@@ -1366,23 +1427,20 @@ class Jira:
1366
1427
  self.report_internal_error(exception=ex, additional_info="Failed to report error.")
1367
1428
  return False
1368
1429
 
1369
- def report_unhandled_error(
1370
- self, exc_type: type, exc_value: Union[Exception, str], exc_traceback: TracebackType, stack_trace: str = None
1371
- ):
1430
+ def report_unhandled_error(self, exception: Exception, stack_trace: str = None):
1372
1431
  """Report an unhandled error to Jira.
1373
1432
 
1374
1433
  Args:
1375
1434
  exc_type (type): The type of the exception.
1376
- exc_value (Exception, str): The value of the exception.
1377
- exc_traceback (TracebackType): The traceback of the exception.
1435
+ exception (Exception, str): The value of the exception.
1378
1436
  stack_trace (str, optional): Stack trace to be added to the Jira issue.
1379
1437
 
1380
1438
  Returns:
1381
1439
  The response from creating the Jira issue.
1382
1440
  """
1383
1441
  try:
1384
- summary = self.__create_summary(exc_type, exc_value, exc_traceback)
1385
- error_id = self.__generate_error_id(exc_type=exc_type, exc_traceback=exc_traceback)
1442
+ summary = self.__create_summary(type(exception), exception, exception.__traceback__)
1443
+ error_id = self.__generate_error_id(exception)
1386
1444
 
1387
1445
  existing_ticket = self.filter_tickets(
1388
1446
  all_tickets=self.get_issues()["issues"],
@@ -1405,9 +1463,9 @@ class Jira:
1405
1463
  logger.info(f"Failed to get assignee {self._default_assignee} due to: {ex}")
1406
1464
 
1407
1465
  description = self.__create_description_markup(
1408
- exc_type=exc_type,
1409
- exc_value=exc_value,
1410
- exc_traceback=exc_traceback,
1466
+ exc_type=type(exception),
1467
+ exc_value=exception,
1468
+ exc_traceback=exception.__traceback__,
1411
1469
  error_id=error_id,
1412
1470
  )
1413
1471
 
@@ -1434,6 +1492,8 @@ class Jira:
1434
1492
 
1435
1493
  Args:
1436
1494
  exception (Exception): The exception to be added to the Jira issue.
1495
+ metadata (dict, optional): The metadata to be added to the Jira issue. Defaults to None.
1496
+ additional_info (str, optional): Additional information to be added to the Jira issue. Defaults to None.
1437
1497
 
1438
1498
  Returns:
1439
1499
  The response from creating the Jira issue.
@@ -1445,7 +1505,7 @@ class Jira:
1445
1505
  attachments = [str(file) for file in Path().cwd().glob("stack_details_*.json")]
1446
1506
 
1447
1507
  summary = self.__create_summary(type(exception), exception, exception.__traceback__)
1448
- error_id = self.__generate_error_id(exc_type=type(exception), exc_traceback=exception.__traceback__)
1508
+ error_id = self.__generate_error_id(exception)
1449
1509
 
1450
1510
  existing_ticket = self.filter_tickets(
1451
1511
  all_tickets=self.get_issues(project_key=CONFIG.BC_BOARD)["issues"],
@@ -1613,30 +1673,47 @@ class Jira:
1613
1673
  for ticket in all_tickets:
1614
1674
  if not ticket["fields"]["description"]:
1615
1675
  continue
1616
- if error_id not in ticket["fields"]["description"]:
1676
+ if f"{error_id}_~" not in ticket["fields"]["description"]:
1617
1677
  continue
1618
1678
  return ticket
1619
1679
 
1620
1680
  else:
1621
1681
  return None
1622
1682
 
1623
- def __generate_error_id(self, exc_type: type, exc_traceback: TracebackType) -> str:
1683
+ def generate_group_id(self, group_by: Optional[str] = None) -> Optional[str]:
1684
+ """Generates a group ID based on the provided group_by string.
1685
+
1686
+ Args:
1687
+ group_by (str): The string to use for generating the group ID.
1688
+
1689
+ Returns:
1690
+ str or None: The generated group ID if group_by is not None, otherwise None.
1691
+ """
1692
+ if not group_by:
1693
+ return None
1694
+ crc_hash = zlib.crc32(group_by.encode())
1695
+ return format(crc_hash, "x")
1696
+
1697
+ def __generate_error_id(self, exception: Exception) -> str:
1624
1698
  """Generates an error string ID using the exception, function name, and error string.
1625
1699
 
1626
1700
  Args:
1627
- exc_type (type): The type of the exception.
1628
- exc_traceback (TracebackType): The traceback of the exception.
1701
+ exception (Exception):
1629
1702
 
1630
1703
  Returns:
1631
- str: The generated error string ID.
1704
+ str: The generated error string ID and the group ID.
1632
1705
 
1633
1706
  """
1634
- frames = get_frames(exc_traceback)
1707
+ frames = get_frames(exception.__traceback__)
1635
1708
  exception_chain = "-".join([f"{frame.name}" for frame in frames])
1636
1709
  rel_path = os.path.relpath(frames[-1].filename, os.getcwd())
1637
1710
  path = Path(os.path.splitext(rel_path)[0]).as_posix()
1638
- error_id = f"{path}-{exception_chain}-{frames[-1].line}-" f"{exc_type.__module__}-{exc_type.__name__}"
1639
- return hashlib.md5(error_id.encode()).hexdigest()
1711
+ path = remove_holotree_id(path)
1712
+ error_id = (
1713
+ f"{path}-{exception_chain}-{frames[-1].line}-" f"{type(exception).__module__}-{type(exception).__name__}"
1714
+ )
1715
+ hashed_id = hashlib.md5(error_id.encode()).hexdigest()
1716
+ return hashed_id
1640
1717
 
1641
1718
  @staticmethod
1642
1719
  def __generate_warning_id(inspected_frame) -> tuple:
@@ -1689,7 +1766,9 @@ class Jira:
1689
1766
  return str(message)
1690
1767
  return re.sub(r"\'(.+)\'", "'...'", message)
1691
1768
 
1692
- def __create_summary(self, exc_type: type, exc_value: Union[Exception, str], exc_traceback: TracebackType) -> str:
1769
+ def __create_summary(
1770
+ self, exc_type: type, exc_value: Union[Exception, str], exc_traceback: TracebackType, idx: Optional[int] = None
1771
+ ) -> str:
1693
1772
  """Create the summary of the ticket.
1694
1773
 
1695
1774
  Args:
@@ -1702,7 +1781,11 @@ class Jira:
1702
1781
  """
1703
1782
  frames = get_frames(exc_traceback)
1704
1783
  file_name, line_no, _, _ = frames[-1]
1705
- summary = f"[{exc_type.__name__}:{os.path.basename(file_name)}:{line_no}]"
1784
+
1785
+ if idx:
1786
+ summary = f"[{exc_type.__name__}:{os.path.basename(file_name)}:{line_no}({idx})]"
1787
+ else:
1788
+ summary = f"[{exc_type.__name__}:{os.path.basename(file_name)}:{line_no}]"
1706
1789
  if self._project_key == CONFIG.SUPPORT_BOARD and CONFIG.ADMIN_CODE:
1707
1790
  summary = CONFIG.ADMIN_CODE + " - " + summary
1708
1791
  if CONFIG.LIMITS.SUMMARY_LENGTH <= len(summary):
@@ -1,6 +1,7 @@
1
1
  import copy
2
2
  import json
3
3
  import os
4
+ import re
4
5
  import traceback
5
6
  import urllib
6
7
  from datetime import date, datetime
@@ -101,6 +102,19 @@ def strip_path(path: str):
101
102
  return path.replace(os.getcwd(), "").strip(os.sep)
102
103
 
103
104
 
105
+ def remove_holotree_id(path: str) -> str:
106
+ """A function to remove the value after 'holotree' from the path.
107
+
108
+ Args:
109
+ path (str): The path from which to remove the value after 'holotree'.
110
+
111
+ Returns:
112
+ str: The modified path.
113
+ """
114
+ pattern = r"(holotree\/)[^\/]+\/"
115
+ return re.sub(pattern, r"\1", path)
116
+
117
+
104
118
  def retrieve_build_info():
105
119
  """Logs build information."""
106
120
  if not os.path.exists(CONFIG.BUILD_INFO_FILE):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
File without changes
File without changes