t-bug-catcher 0.2.1__tar.gz → 0.2.3__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 (25) hide show
  1. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/setup.cfg +1 -1
  3. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/setup.py +1 -1
  4. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/__init__.py +1 -1
  5. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/bug_catcher.py +1 -1
  6. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/jira.py +71 -41
  7. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  8. t_bug_catcher-0.2.3/tests/test_t_bug_catcher.py +72 -0
  9. t_bug_catcher-0.2.1/tests/test_t_bug_catcher.py +0 -10
  10. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/MANIFEST.in +0 -0
  11. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/README.rst +0 -0
  12. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/pyproject.toml +0 -0
  13. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/requirements.txt +0 -0
  14. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/bug_snag.py +0 -0
  15. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/config.py +0 -0
  16. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/exceptions.py +0 -0
  17. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/utils/__init__.py +0 -0
  18. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/utils/common.py +0 -0
  19. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/utils/logger.py +0 -0
  20. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher/workitems.py +0 -0
  21. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
  22. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  23. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  24. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/requires.txt +0 -0
  25. {t_bug_catcher-0.2.1 → t_bug_catcher-0.2.3}/t_bug_catcher.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.2.1
3
+ Version: 0.2.3
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.1
2
+ current_version = 0.2.3
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.1",
29
+ version="0.2.3",
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.1'
6
+ __version__ = '0.2.3'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -98,7 +98,7 @@ class BugCatcher:
98
98
  def report_error(
99
99
  self,
100
100
  exception: Optional[Exception] = None,
101
- description: Optional[str] = "",
101
+ description: Optional[str] = None,
102
102
  metadata: Optional[dict] = None,
103
103
  attachments: Optional[List] = None,
104
104
  assignee: Optional[str] = None,
@@ -33,7 +33,6 @@ def retry_if_bad_request(func):
33
33
  return func(*args, **kwargs)
34
34
  except BadRequestError as ex:
35
35
  nonlocal attempt
36
- print(f"Bad request Attempt {attempt}...", "WARN")
37
36
  attempt = attempt + 1 if attempt < tries else 1
38
37
  raise ex
39
38
 
@@ -404,12 +403,8 @@ class Jira:
404
403
  "text": "Run link: ",
405
404
  "marks": [{"type": "strong"}],
406
405
  },
407
- {
408
- "type": "text",
409
- "text": CONFIG.ENVIRONMENT,
410
- "marks": ([] + self.__link_markup()),
411
- },
412
- ],
406
+ ]
407
+ + self.__link_markup(),
413
408
  }
414
409
  ]
415
410
  if CONFIG.ENVIRONMENT != "local"
@@ -529,19 +524,39 @@ class Jira:
529
524
  link_markup = {
530
525
  variables.get("environment"): [
531
526
  {
532
- "type": "link",
533
- "attrs": {"href": variables.get("processRunUrl")},
534
- },
535
- {"type": "underline"},
527
+ "type": "text",
528
+ "text": variables.get("processRunUrl"),
529
+ "marks": [
530
+ {
531
+ "type": "link",
532
+ "attrs": {"href": variables.get("processRunUrl")},
533
+ },
534
+ {"type": "underline"},
535
+ ],
536
+ }
536
537
  ],
537
538
  "robocloud": [
538
539
  {
539
- "type": "link",
540
- "attrs": {"href": CONFIG.RC_RUN_LINK},
541
- },
542
- {"type": "underline"},
540
+ "type": "text",
541
+ "text": "https://cloud.robocorp.com",
542
+ "marks": [
543
+ {
544
+ "type": "link",
545
+ "attrs": {"href": CONFIG.RC_RUN_LINK},
546
+ },
547
+ {"type": "underline"},
548
+ ],
549
+ }
550
+ ],
551
+ "local": [
552
+ {
553
+ "type": "text",
554
+ "text": "local run",
555
+ "marks": [
556
+ {"type": "underline"},
557
+ ],
558
+ }
543
559
  ],
544
- "local": [{"type": "underline"}],
545
560
  }
546
561
  return link_markup[CONFIG.ENVIRONMENT]
547
562
 
@@ -653,28 +668,33 @@ class Jira:
653
668
  if len(error) < CONFIG.LIMITS.MAX_DESCRIPTION_LENGTH
654
669
  else error[: CONFIG.LIMITS.MAX_DESCRIPTION_LENGTH] + "..."
655
670
  )
671
+ date_markup = [
672
+ {
673
+ "type": "text",
674
+ "text": f" at {str(datetime.datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
675
+ },
676
+ {"type": "hardBreak"},
677
+ ]
656
678
 
657
679
  error_markup = [
680
+ {
681
+ "type": "text",
682
+ "text": error,
683
+ "marks": [{"type": "code"}],
684
+ },
685
+ ]
686
+
687
+ comment_markup = [
658
688
  {
659
689
  "type": "paragraph",
660
- "content": [
661
- {"type": "text", "text": "Error occures again in "},
662
- {
663
- "type": "text",
664
- "text": CONFIG.ENVIRONMENT,
665
- "marks": ([] + self.__link_markup()),
666
- },
667
- {
668
- "type": "text",
669
- "text": f" at {str(datetime.datetime.now().strftime('%B %d, %Y %I:%M:%S %p'))}",
670
- },
671
- {"type": "hardBreak"},
672
- {
673
- "type": "text",
674
- "text": error,
675
- "marks": [{"type": "code"}],
676
- },
677
- ],
690
+ "content": (
691
+ [
692
+ {"type": "text", "text": "Error occures again in "},
693
+ ]
694
+ + self.__link_markup()
695
+ + date_markup
696
+ + error_markup
697
+ ),
678
698
  }
679
699
  ]
680
700
 
@@ -711,7 +731,7 @@ class Jira:
711
731
  "type": "doc",
712
732
  "version": 1,
713
733
  "content": []
714
- + (error_markup if error else [])
734
+ + (comment_markup if error else [])
715
735
  + (self.__description_markup(additional_info) if additional_info else [])
716
736
  + (attach_markup if attachments else [])
717
737
  + (self.__metadata_markup(metadata) if metadata else []),
@@ -759,10 +779,10 @@ class Jira:
759
779
  """
760
780
  issue_status = self.check_issue_status(existing_ticket["id"])
761
781
  self._transition_types = self.__get_transtion_types(issue_id=existing_ticket["id"])
762
- if issue_status.lower() != "to do":
782
+ if issue_status.lower() not in ["to do", "open"]:
763
783
  self.issue_transition(
764
784
  ticket_id=existing_ticket["id"],
765
- transition_id=self._transition_types["to do"],
785
+ transition_id=self._transition_types.get("to do", "open"),
766
786
  )
767
787
  self.update_comment(
768
788
  ticket_id=existing_ticket["id"],
@@ -780,7 +800,13 @@ class Jira:
780
800
  posted_attachments = []
781
801
  else:
782
802
  posted_attachments = (
783
- [self.add_attachment(attachment, issue["id"]) for attachment in attachments] if attachments else []
803
+ [
804
+ self.add_attachment(attachment, issue["id"])
805
+ for attachment in attachments
806
+ if os.path.exists(str(attachment))
807
+ ]
808
+ if attachments
809
+ else []
784
810
  )
785
811
 
786
812
  self.update_comment(
@@ -817,7 +843,7 @@ class Jira:
817
843
  summary=summary[:255].split("\n")[0],
818
844
  description=description,
819
845
  assignee=assignee_id,
820
- issue_type=self._issue_types.get("bug", self._issue_types["task"]),
846
+ issue_type=self._issue_types.get("bug") or self._issue_types.get("task", "support"),
821
847
  labels=labels,
822
848
  )
823
849
  response = self.post_ticket(issue=issue)
@@ -834,7 +860,8 @@ class Jira:
834
860
  ticket_id = ticket["id"]
835
861
  if attachments:
836
862
  for attachment in attachments:
837
- self.add_attachment(attachment, ticket_id)
863
+ if os.path.exists(str(attachment)):
864
+ self.add_attachment(attachment, ticket_id)
838
865
  if self._webhook_url:
839
866
  self.move_ticket_to_board(ticket_id)
840
867
  return response
@@ -843,7 +870,7 @@ class Jira:
843
870
  self,
844
871
  exception: Optional[Exception] = None,
845
872
  assignee: Optional[str] = None,
846
- attachments: Optional[List] = None,
873
+ attachments: Union[List, str, Path, None] = None,
847
874
  metadata: Optional[dict] = None,
848
875
  additional_info: Optional[str] = None,
849
876
  ) -> dict:
@@ -866,6 +893,9 @@ class Jira:
866
893
  if attachments is None:
867
894
  attachments = []
868
895
 
896
+ if isinstance(attachments, (str, Path)):
897
+ attachments = [str(attachments)]
898
+
869
899
  if not isinstance(attachments, List):
870
900
  logger.warning(f"Incorrect type of attachments: {type(attachments)}")
871
901
  attachments = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -0,0 +1,72 @@
1
+ import os
2
+ import unittest
3
+ from unittest.mock import PropertyMock, patch
4
+
5
+ from t_bug_catcher.bug_catcher import BugCatcher
6
+ from t_bug_catcher.config import CONFIG
7
+ from t_bug_catcher.utils import logger
8
+
9
+
10
+ class TestBugCatcher(unittest.TestCase):
11
+ """TestBugCatcher class."""
12
+
13
+ def setUp(self):
14
+ """Set up."""
15
+ self.bug_catcher = BugCatcher()
16
+
17
+ def test_report_error_with_local_environment(self):
18
+ """Test report_error function."""
19
+ with patch.object(logger, "warning") as mock_warning:
20
+ self.bug_catcher.report_error()
21
+ mock_warning.assert_called_once_with("Reporting an error is not supported in local environment.")
22
+
23
+ @patch.object(CONFIG, "ENVIRONMENT", "robocloud")
24
+ def test_report_error_with_no_configurations(self):
25
+ """Test report_error function."""
26
+ with patch.object(logger, "warning") as mock_warning:
27
+ self.bug_catcher.report_error()
28
+ mock_warning.assert_called_once_with(
29
+ "Jira and BugSnag are not configured. Please configure them before reporting an error."
30
+ )
31
+
32
+ def test_jira_configure(self):
33
+ """Test jira_configure function."""
34
+ self.bug_catcher.configure.jira(
35
+ login=os.getenv("JIRA_LOGIN"),
36
+ api_token=os.getenv("JIRA_API_TOKEN"),
37
+ project_key=os.getenv("JIRA_PROJECT_KEY"),
38
+ )
39
+ assert self.bug_catcher.configure.is_jira_configured
40
+
41
+ def test_bugsnag_configure(self):
42
+ """Test bugsnag_configure function."""
43
+ self.bug_catcher.configure.bugsnag(api_key=os.getenv("BUGSNAG_API_KEY"))
44
+ assert self.bug_catcher.configure.is_bugsnag_configured
45
+
46
+ def test_attach_file(self):
47
+ """Test attach_file function."""
48
+ ex = Exception("some error")
49
+ self.bug_catcher.attach_file_to_exception(exception=ex, attachment="test.txt")
50
+ assert hasattr(ex, "custom_attachments")
51
+
52
+ @patch.object(CONFIG, "ENVIRONMENT", "robocloud")
53
+ def test_report_error(self):
54
+ """Test report_error function."""
55
+ with patch.object(
56
+ self.bug_catcher, "_BugCatcher__configurator", new_callable=PropertyMock
57
+ ) as mock_configurator:
58
+ patch.object(mock_configurator, "is_jira_configured", return_value=True)
59
+ patch.object(mock_configurator, "is_bugsnag_configured", return_value=True)
60
+ try:
61
+ raise Exception("Test exception")
62
+ except Exception as ex:
63
+ with patch.object(logger, "warning") as mock_warning:
64
+ self.bug_catcher.report_error(exception=ex)
65
+ actual_call = mock_warning.call_args
66
+ warning_message = actual_call[0][0]
67
+ self.assertTrue(warning_message.startswith("Failed to create Jira issue due to"))
68
+ self.assertEqual(mock_warning.call_count, 1)
69
+
70
+
71
+ if __name__ == "__main__":
72
+ unittest.main()
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env python
2
- """Tests for `t_bug_catcher` package."""
3
-
4
-
5
- class TestTBugCatcher:
6
- """Smoke tests of the package."""
7
-
8
- def test_example(self):
9
- """Smoke test."""
10
- assert True
File without changes
File without changes