t-bug-catcher 0.2.0__tar.gz → 0.2.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 (24) hide show
  1. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/setup.cfg +1 -1
  3. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/setup.py +1 -1
  4. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/__init__.py +1 -1
  5. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/bug_catcher.py +3 -0
  6. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/bug_snag.py +27 -23
  7. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/jira.py +98 -48
  8. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  9. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/MANIFEST.in +0 -0
  10. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/README.rst +0 -0
  11. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/pyproject.toml +0 -0
  12. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/requirements.txt +0 -0
  13. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/config.py +0 -0
  14. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/exceptions.py +0 -0
  15. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/utils/__init__.py +0 -0
  16. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/utils/common.py +0 -0
  17. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/utils/logger.py +0 -0
  18. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher/workitems.py +0 -0
  19. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
  20. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  21. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  22. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/requires.txt +0 -0
  23. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.2}/t_bug_catcher.egg-info/top_level.txt +0 -0
  24. {t_bug_catcher-0.2.0 → t_bug_catcher-0.2.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.2.0
3
+ Version: 0.2.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.2.0
2
+ current_version = 0.2.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.2.0",
29
+ version="0.2.2",
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.0'
6
+ __version__ = '0.2.2'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -28,6 +28,7 @@ class Configurator:
28
28
  api_token: str,
29
29
  project_key: str,
30
30
  webhook_url: Optional[str] = None,
31
+ default_assignee: Optional[str] = None,
31
32
  ):
32
33
  """Configures the JiraPoster and BugSnag classes.
33
34
 
@@ -36,6 +37,7 @@ class Configurator:
36
37
  api_token (str): The API token for the Jira account.
37
38
  project_key (str): The key of the Jira project.
38
39
  webhook_url (str, optional): The webhook URL for the Jira project. Defaults to None.
40
+ default_assignee (str, optional): The default assignee for the Jira project. Defaults to None.
39
41
 
40
42
  Returns:
41
43
  None
@@ -45,6 +47,7 @@ class Configurator:
45
47
  api_token=api_token,
46
48
  project_key=project_key,
47
49
  webhook_url=webhook_url,
50
+ default_assignee=default_assignee,
48
51
  )
49
52
 
50
53
  def bugsnag(self, api_key: str):
@@ -28,30 +28,34 @@ class BugSnag:
28
28
  Returns:
29
29
  bool: True if the configuration was successful, False otherwise.
30
30
  """
31
- bugsnag.configure(api_key=api_key, release_stage=CONFIG.ENVIRONMENT, auto_notify=False)
32
- bugsnag.add_metadata_tab(
33
- "Metadata",
34
- {
35
- "run_url": variables.get("processRunUrl", ""),
36
- "run_by": variables.get("userEmail", ""),
37
- },
38
- )
39
- response = requests.request(
40
- "POST",
41
- "https://otlp.bugsnag.com/v1/traces",
42
- headers={
43
- "Content-Type": "application/json",
44
- "Bugsnag-Api-Key": api_key,
45
- "Bugsnag-Payload-Version": "4",
46
- "Bugsnag-Sent-At": f"{datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')}",
47
- "Bugsnag-Span-Sampling": "True",
48
- },
49
- data='{"message": "test"}',
50
- )
51
- if response.status_code not in [200, 201, 202, 204]:
52
- logger.warning(f"Error connecting to Bugsnag: {response.text}")
31
+ try:
32
+ bugsnag.configure(api_key=api_key, release_stage=CONFIG.ENVIRONMENT, auto_notify=False)
33
+ bugsnag.add_metadata_tab(
34
+ "Metadata",
35
+ {
36
+ "run_url": variables.get("processRunUrl", ""),
37
+ "run_by": variables.get("userEmail", ""),
38
+ },
39
+ )
40
+ response = requests.request(
41
+ "POST",
42
+ "https://otlp.bugsnag.com/v1/traces",
43
+ headers={
44
+ "Content-Type": "application/json",
45
+ "Bugsnag-Api-Key": api_key,
46
+ "Bugsnag-Payload-Version": "4",
47
+ "Bugsnag-Sent-At": f"{datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')}",
48
+ "Bugsnag-Span-Sampling": "True",
49
+ },
50
+ data='{"message": "test"}',
51
+ )
52
+ if response.status_code not in [200, 201, 202, 204]:
53
+ logger.warning(f"Error connecting to Bugsnag: {response.text}")
54
+ return False
55
+ return True
56
+ except Exception as ex:
57
+ logger.warning(f"Failed to configure Bugsnag: {ex}")
53
58
  return False
54
- return True
55
59
 
56
60
  def report_error(self, exception: Optional[Exception] = None, metadata: Optional[dict] = None):
57
61
  """Sends an error to BugSnag.
@@ -52,6 +52,7 @@ class Jira:
52
52
  self._project_key = None
53
53
  self._webhook_url = None
54
54
  self._auth = None
55
+ self._default_assignee = None
55
56
 
56
57
  @staticmethod
57
58
  def _is_json_response(response) -> bool:
@@ -88,7 +89,9 @@ class Jira:
88
89
  f"{exc_message}Status Code: {response.status_code}, " f"Headers: {response.headers}"
89
90
  )
90
91
 
91
- def config(self, login, api_token, project_key, webhook_url: Optional[str]) -> bool:
92
+ def config(
93
+ self, login, api_token, project_key, webhook_url: Optional[str] = None, default_assignee: Optional[str] = None
94
+ ) -> bool:
92
95
  """Sets the webhook URL for the Jira project.
93
96
 
94
97
  Args:
@@ -96,22 +99,28 @@ class Jira:
96
99
  api_token (str): The API token for the Jira account.
97
100
  project_key (str): The key of the Jira project.
98
101
  webhook_url (str): The webhook URL for the Jira project.
102
+ default_assignee (str, optional): The default assignee for the Jira project. Defaults to None.
99
103
 
100
104
  Returns:
101
105
  bool: True if the configuration was successful, False otherwise.
102
106
  """
103
- self._project_key = project_key
104
- if not webhook_url:
105
- logger.warning("No JIRA webhook URL provided. All issues will be posted to backlog.")
106
- self._webhook_url = webhook_url
107
- self._auth = self._authenticate(login, api_token)
108
107
  try:
109
- self.get_current_user()
110
- except BadRequestError:
111
- logger.warning("Failed to authenticate to Jira or incorrect project key.")
108
+ self._project_key = project_key
109
+ self._default_assignee = default_assignee
110
+ if not webhook_url:
111
+ logger.warning("No JIRA webhook URL provided. All issues will be posted to backlog.")
112
+ self._webhook_url = webhook_url
113
+ self._auth = self._authenticate(login, api_token)
114
+ try:
115
+ self.get_current_user()
116
+ except BadRequestError:
117
+ logger.warning("Failed to authenticate to Jira or incorrect project key.")
118
+ return False
119
+ self._issue_types = self.__get_issue_types()
120
+ return True
121
+ except Exception as ex:
122
+ logger.warning(f"Failed to configure Jira: {ex}")
112
123
  return False
113
- self._issue_types = self.__get_issue_types()
114
- return True
115
124
 
116
125
  def _authenticate(self, login, api_token) -> HTTPBasicAuth:
117
126
  """Function to authenticate the user with the provided username and API token.
@@ -395,12 +404,8 @@ class Jira:
395
404
  "text": "Run link: ",
396
405
  "marks": [{"type": "strong"}],
397
406
  },
398
- {
399
- "type": "text",
400
- "text": CONFIG.ENVIRONMENT,
401
- "marks": ([] + self.__link_markup()),
402
- },
403
- ],
407
+ ]
408
+ + self.__link_markup(),
404
409
  }
405
410
  ]
406
411
  if CONFIG.ENVIRONMENT != "local"
@@ -520,19 +525,39 @@ class Jira:
520
525
  link_markup = {
521
526
  variables.get("environment"): [
522
527
  {
523
- "type": "link",
524
- "attrs": {"href": variables.get("processRunUrl")},
525
- },
526
- {"type": "underline"},
528
+ "type": "text",
529
+ "text": variables.get("processRunUrl"),
530
+ "marks": [
531
+ {
532
+ "type": "link",
533
+ "attrs": {"href": variables.get("processRunUrl")},
534
+ },
535
+ {"type": "underline"},
536
+ ],
537
+ }
527
538
  ],
528
539
  "robocloud": [
529
540
  {
530
- "type": "link",
531
- "attrs": {"href": CONFIG.RC_RUN_LINK},
532
- },
533
- {"type": "underline"},
541
+ "type": "text",
542
+ "text": "https://cloud.robocorp.com",
543
+ "marks": [
544
+ {
545
+ "type": "link",
546
+ "attrs": {"href": CONFIG.RC_RUN_LINK},
547
+ },
548
+ {"type": "underline"},
549
+ ],
550
+ }
551
+ ],
552
+ "local": [
553
+ {
554
+ "type": "text",
555
+ "text": "local run",
556
+ "marks": [
557
+ {"type": "underline"},
558
+ ],
559
+ }
534
560
  ],
535
- "local": [{"type": "underline"}],
536
561
  }
537
562
  return link_markup[CONFIG.ENVIRONMENT]
538
563
 
@@ -644,28 +669,33 @@ class Jira:
644
669
  if len(error) < CONFIG.LIMITS.MAX_DESCRIPTION_LENGTH
645
670
  else error[: CONFIG.LIMITS.MAX_DESCRIPTION_LENGTH] + "..."
646
671
  )
672
+ date_markup = [
673
+ {
674
+ "type": "text",
675
+ "text": f" at {str(datetime.datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
676
+ },
677
+ {"type": "hardBreak"},
678
+ ]
647
679
 
648
680
  error_markup = [
681
+ {
682
+ "type": "text",
683
+ "text": error,
684
+ "marks": [{"type": "code"}],
685
+ },
686
+ ]
687
+
688
+ comment_markup = [
649
689
  {
650
690
  "type": "paragraph",
651
- "content": [
652
- {"type": "text", "text": "Error occures again in "},
653
- {
654
- "type": "text",
655
- "text": CONFIG.ENVIRONMENT,
656
- "marks": ([] + self.__link_markup()),
657
- },
658
- {
659
- "type": "text",
660
- "text": f" at {str(datetime.datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
661
- },
662
- {"type": "hardBreak"},
663
- {
664
- "type": "text",
665
- "text": error,
666
- "marks": [{"type": "code"}],
667
- },
668
- ],
691
+ "content": (
692
+ [
693
+ {"type": "text", "text": "Error occures again in "},
694
+ ]
695
+ + self.__link_markup()
696
+ + date_markup
697
+ + error_markup
698
+ ),
669
699
  }
670
700
  ]
671
701
 
@@ -702,7 +732,7 @@ class Jira:
702
732
  "type": "doc",
703
733
  "version": 1,
704
734
  "content": []
705
- + (error_markup if error else [])
735
+ + (comment_markup if error else [])
706
736
  + (self.__description_markup(additional_info) if additional_info else [])
707
737
  + (attach_markup if attachments else [])
708
738
  + (self.__metadata_markup(metadata) if metadata else []),
@@ -771,7 +801,13 @@ class Jira:
771
801
  posted_attachments = []
772
802
  else:
773
803
  posted_attachments = (
774
- [self.add_attachment(attachment, issue["id"]) for attachment in attachments] if attachments else []
804
+ [
805
+ self.add_attachment(attachment, issue["id"])
806
+ for attachment in attachments
807
+ if os.path.exists(str(attachment))
808
+ ]
809
+ if attachments
810
+ else []
775
811
  )
776
812
 
777
813
  self.update_comment(
@@ -825,7 +861,8 @@ class Jira:
825
861
  ticket_id = ticket["id"]
826
862
  if attachments:
827
863
  for attachment in attachments:
828
- self.add_attachment(attachment, ticket_id)
864
+ if os.path.exists(str(attachment)):
865
+ self.add_attachment(attachment, ticket_id)
829
866
  if self._webhook_url:
830
867
  self.move_ticket_to_board(ticket_id)
831
868
  return response
@@ -834,7 +871,7 @@ class Jira:
834
871
  self,
835
872
  exception: Optional[Exception] = None,
836
873
  assignee: Optional[str] = None,
837
- attachments: Optional[List] = None,
874
+ attachments: Union[List, str, Path, None] = None,
838
875
  metadata: Optional[dict] = None,
839
876
  additional_info: Optional[str] = None,
840
877
  ) -> dict:
@@ -857,6 +894,9 @@ class Jira:
857
894
  if attachments is None:
858
895
  attachments = []
859
896
 
897
+ if isinstance(attachments, (str, Path)):
898
+ attachments = [str(attachments)]
899
+
860
900
  if not isinstance(attachments, List):
861
901
  logger.warning(f"Incorrect type of attachments: {type(attachments)}")
862
902
  attachments = []
@@ -886,6 +926,7 @@ class Jira:
886
926
  return existing_ticket
887
927
 
888
928
  assignee_id = None
929
+ assignee = assignee if assignee else self._default_assignee
889
930
  if assignee:
890
931
  try:
891
932
  assignee_id = self.__get_assignee(assignee)
@@ -906,6 +947,7 @@ class Jira:
906
947
  description=description,
907
948
  assignee_id=assignee_id,
908
949
  attachments=attachments,
950
+ labels=["bug_catcher"],
909
951
  )
910
952
  return response
911
953
  except Exception as ex:
@@ -939,6 +981,13 @@ class Jira:
939
981
  )
940
982
  return existing_ticket
941
983
 
984
+ assignee_id = None
985
+ if self._default_assignee:
986
+ try:
987
+ assignee_id = self.__get_assignee(self._default_assignee)
988
+ except Exception as ex:
989
+ logger.info(f"Failed to get assignee {self._default_assignee} due to: {ex}")
990
+
942
991
  description = self.__create_description_markup(
943
992
  exc_type=exc_type,
944
993
  exc_value=exc_value,
@@ -949,6 +998,7 @@ class Jira:
949
998
  response = self.__create_new_ticket(
950
999
  summary=summary,
951
1000
  description=description,
1001
+ assignee_id=assignee_id,
952
1002
  labels=["fatal_error"],
953
1003
  )
954
1004
  return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
File without changes
File without changes