t-bug-catcher 0.2.6__tar.gz → 0.3.1__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 (24) hide show
  1. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/setup.cfg +1 -1
  3. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/setup.py +1 -1
  4. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/__init__.py +1 -1
  5. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/config.py +9 -1
  6. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/jira.py +102 -19
  7. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/workitems.py +2 -0
  8. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  9. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/MANIFEST.in +0 -0
  10. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/README.rst +0 -0
  11. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/pyproject.toml +0 -0
  12. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/requirements.txt +0 -0
  13. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/bug_catcher.py +0 -0
  14. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/bug_snag.py +0 -0
  15. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/exceptions.py +0 -0
  16. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/utils/__init__.py +0 -0
  17. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/utils/common.py +0 -0
  18. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher/utils/logger.py +0 -0
  19. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
  20. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  21. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  22. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/requires.txt +0 -0
  23. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/t_bug_catcher.egg-info/top_level.txt +0 -0
  24. {t_bug_catcher-0.2.6 → t_bug_catcher-0.3.1}/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.2.6
3
+ Version: 0.3.1
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.2.6
2
+ current_version = 0.3.1
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.2.6",
29
+ version="0.3.1",
30
30
  zip_safe=False,
31
31
  install_requires=install_requirements,
32
32
  )
@@ -3,7 +3,7 @@
3
3
  __author__ = """Thoughtful"""
4
4
  __email__ = "support@thoughtful.ai"
5
5
  # fmt: off
6
- __version__ = '0.2.6'
6
+ __version__ = '0.3.1'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -1,6 +1,6 @@
1
1
  import os
2
2
 
3
- from .workitems import variables
3
+ from .workitems import metadata, variables
4
4
 
5
5
 
6
6
  class Config:
@@ -12,6 +12,9 @@ class Config:
12
12
  MAX_ATTACHMENTS: int = 5
13
13
  MAX_ISSUE_ATTACHMENTS: int = 100
14
14
  MAX_DESCRIPTION_LENGTH: int = 250
15
+ SUMMARY_LENGTH: int = 120
16
+
17
+ SUPPORT_BOARD = "AB"
15
18
 
16
19
  RC_RUN_LINK = (
17
20
  f"https://cloud.robocorp.com/organizations/{os.environ.get('RC_ORGANIZATION_ID')}"
@@ -25,5 +28,10 @@ class Config:
25
28
  else variables.get("environment", "local")
26
29
  )
27
30
 
31
+ STAGE = metadata.get("process", dict()).get("implementationStage", "")
32
+ ADMIN_CODE = metadata.get("process", dict()).get("adminCode", "")
33
+ WORKER_NAME = metadata.get("process", dict()).get("name", "")
34
+ EMPOWER_URL = metadata.get("process", dict()).get("processRunUrl") or variables.get("processRunUrl")
35
+
28
36
 
29
37
  CONFIG = Config()
@@ -7,6 +7,7 @@ import os
7
7
  import re
8
8
  import sys
9
9
  import traceback
10
+ from importlib.metadata import version
10
11
  from pathlib import Path
11
12
  from types import TracebackType
12
13
  from typing import List, Optional, Union
@@ -89,7 +90,12 @@ class Jira:
89
90
  )
90
91
 
91
92
  def config(
92
- self, login, api_token, project_key, webhook_url: Optional[str] = None, default_assignee: Optional[str] = None
93
+ self,
94
+ login: str,
95
+ api_token: str,
96
+ project_key: str,
97
+ webhook_url: Optional[str] = None,
98
+ default_assignee: Optional[str] = None,
93
99
  ) -> bool:
94
100
  """Sets the webhook URL for the Jira project.
95
101
 
@@ -104,7 +110,7 @@ class Jira:
104
110
  bool: True if the configuration was successful, False otherwise.
105
111
  """
106
112
  try:
107
- self._project_key = project_key
113
+ self._project_key = project_key if CONFIG.STAGE not in ["hypercare", "support"] else CONFIG.SUPPORT_BOARD
108
114
  self._default_assignee = default_assignee
109
115
  if not webhook_url:
110
116
  logger.warning("No JIRA webhook URL provided. All issues will be posted to backlog.")
@@ -227,6 +233,8 @@ class Jira:
227
233
  }
228
234
  if labels:
229
235
  fields["fields"]["labels"] = labels
236
+ if self._project_key == CONFIG.SUPPORT_BOARD and CONFIG.ADMIN_CODE:
237
+ fields["fields"]["customfield_10077"] = [CONFIG.ADMIN_CODE]
230
238
  payload = json.dumps(fields)
231
239
  return payload
232
240
 
@@ -435,6 +443,34 @@ class Jira:
435
443
  }
436
444
  ]
437
445
 
446
+ @staticmethod
447
+ def __bot_name_markup() -> List[dict]:
448
+ """Create the ai worker markup.
449
+
450
+ Returns:
451
+ dict: The ai worker markup.
452
+ """
453
+ return (
454
+ [
455
+ {
456
+ "type": "paragraph",
457
+ "content": [
458
+ {
459
+ "type": "text",
460
+ "text": "Process name: ",
461
+ "marks": [{"type": "strong"}],
462
+ },
463
+ {
464
+ "type": "text",
465
+ "text": f"{CONFIG.ADMIN_CODE} - {CONFIG.WORKER_NAME}",
466
+ },
467
+ ],
468
+ }
469
+ ]
470
+ if CONFIG.ADMIN_CODE and CONFIG.WORKER_NAME
471
+ else []
472
+ )
473
+
438
474
  @staticmethod
439
475
  def __traceback_markup(exc_traceback_info: str) -> List[dict]:
440
476
  """Create the traceback markup.
@@ -515,6 +551,14 @@ class Jira:
515
551
  {"type": "subsup", "attrs": {"type": "sub"}},
516
552
  ],
517
553
  },
554
+ {
555
+ "type": "text",
556
+ "text": f" (v{version('t_bug_catcher')})",
557
+ "marks": [
558
+ {"type": "em"},
559
+ {"type": "subsup", "attrs": {"type": "sub"}},
560
+ ],
561
+ },
518
562
  ],
519
563
  },
520
564
  ]
@@ -525,15 +569,34 @@ class Jira:
525
569
  variables.get("environment"): [
526
570
  {
527
571
  "type": "text",
528
- "text": variables.get("processRunUrl"),
572
+ "text": CONFIG.EMPOWER_URL,
529
573
  "marks": [
530
574
  {
531
575
  "type": "link",
532
- "attrs": {"href": variables.get("processRunUrl")},
576
+ "attrs": {"href": CONFIG.EMPOWER_URL},
533
577
  },
534
578
  {"type": "underline"},
535
579
  ],
536
- }
580
+ },
581
+ {
582
+ "type": "text",
583
+ "text": " [Robocloud ",
584
+ },
585
+ {
586
+ "type": "text",
587
+ "text": "link",
588
+ "marks": [
589
+ {
590
+ "type": "link",
591
+ "attrs": {"href": CONFIG.RC_RUN_LINK},
592
+ },
593
+ {"type": "underline"},
594
+ ],
595
+ },
596
+ {
597
+ "type": "text",
598
+ "text": "]",
599
+ },
537
600
  ],
538
601
  "robocloud": [
539
602
  {
@@ -594,6 +657,7 @@ class Jira:
594
657
  "type": "doc",
595
658
  "content": []
596
659
  + (self.__error_string_markup(error_string, exc_info) if error_string else [])
660
+ + self.__bot_name_markup()
597
661
  + self.__date_markup()
598
662
  + self.__runlink_markup()
599
663
  + self.__environment_markup()
@@ -839,11 +903,20 @@ class Jira:
839
903
  Returns:
840
904
  The response from creating the ticket.
841
905
  """
842
- issue_type = (
843
- self._issue_types.get("bug")
844
- or self._issue_types.get("task")
845
- or self._issue_types.get("support", self._issue_types["epic"])
846
- )
906
+ if CONFIG.STAGE.lower() == "hypercare":
907
+ issue_type = self._issue_types.get("hypercare") or self._issue_types.get("epic")
908
+ elif CONFIG.STAGE.lower() == "support":
909
+ issue_type = self._issue_types.get("support") or self._issue_types.get("epic")
910
+ elif CONFIG.STAGE.lower() == "delivery" and self._project_key == CONFIG.SUPPORT_BOARD:
911
+ issue_type = self._issue_types.get("development") or self._issue_types.get("epic")
912
+ else:
913
+ issue_type = (
914
+ self._issue_types.get("bug")
915
+ or self._issue_types.get("task")
916
+ or self._issue_types.get("support")
917
+ or self._issue_types.get("epic")
918
+ )
919
+
847
920
  issue = self.__generate_issue_body(
848
921
  summary=summary[:255].split("\n")[0],
849
922
  description=description,
@@ -877,7 +950,7 @@ class Jira:
877
950
  for attachment in attachments:
878
951
  if os.path.exists(str(attachment)):
879
952
  self.add_attachment(attachment, ticket_id)
880
- if self._webhook_url:
953
+ if self._webhook_url and self._project_key != CONFIG.SUPPORT_BOARD:
881
954
  self.move_ticket_to_board(ticket_id)
882
955
  return response
883
956
 
@@ -1188,7 +1261,7 @@ class Jira:
1188
1261
  return response[0]["accountId"]
1189
1262
 
1190
1263
  @staticmethod
1191
- def remove_locators_from_exception(exception: Union[Exception, str]) -> str:
1264
+ def sanitize_summary(exception: Union[Exception, str]) -> str:
1192
1265
  """Remove locators from the exception.
1193
1266
 
1194
1267
  Args:
@@ -1197,9 +1270,11 @@ class Jira:
1197
1270
  Returns:
1198
1271
  str: The cleaned exception string.
1199
1272
  """
1273
+ message = re.sub("<([a-z]+)(?![^>]*\/>)[^>]*>", r"<\1>", str(exception))
1274
+ message = re.sub(">([^<]+)<\/", ">...</", message)
1200
1275
  if "selenium" not in exception.__class__.__name__.lower() and not isinstance(exception, AssertionError):
1201
- return str(exception)
1202
- return re.sub(r"\'(.+)\'", "'...'", str(exception))
1276
+ return str(message)
1277
+ return re.sub(r"\'(.+)\'", "'...'", message)
1203
1278
 
1204
1279
  def __create_summary(self, exc_type: type, exc_value: Union[Exception, str], exc_traceback: TracebackType) -> str:
1205
1280
  """Create the summary of the ticket.
@@ -1214,8 +1289,16 @@ class Jira:
1214
1289
  """
1215
1290
  frames = get_frames(exc_traceback)
1216
1291
  file_name, line_no, _, _ = frames[-1]
1217
- summary = (
1218
- f"[{exc_type.__name__}:{os.path.basename(file_name)}:{line_no}] "
1219
- f"{self.remove_locators_from_exception(exc_value)}"
1220
- )
1221
- return summary
1292
+ summary = f"[{exc_type.__name__}:{os.path.basename(file_name)}:{line_no}]"
1293
+ if self._project_key == CONFIG.SUPPORT_BOARD and CONFIG.ADMIN_CODE:
1294
+ summary = CONFIG.ADMIN_CODE + " - " + summary
1295
+ if CONFIG.LIMITS.SUMMARY_LENGTH <= len(summary):
1296
+ return summary
1297
+ else:
1298
+ message = self.sanitize_summary(exc_value)
1299
+ message = (
1300
+ message
1301
+ if len(message) <= CONFIG.LIMITS.SUMMARY_LENGTH - len(summary)
1302
+ else message[: CONFIG.LIMITS.SUMMARY_LENGTH - len(summary)] + "..."
1303
+ )
1304
+ return summary + " " + message
@@ -7,6 +7,8 @@ try:
7
7
  work_items.get_input_work_item()
8
8
  work_item = work_items.get_work_item_variables()
9
9
  variables = work_item.get("variables", dict())
10
+ metadata = work_item.get("metadata", dict())
10
11
  except (ImportError, KeyError):
11
12
  logger.warning("Workitems unavailable. Variables will be empty.")
12
13
  variables = {}
14
+ metadata = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.2.6
3
+ Version: 0.3.1
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
File without changes
File without changes