brynq-sdk-jira 1.1.1__tar.gz → 1.1.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq_sdk_jira
3
- Version: 1.1.1
3
+ Version: 1.1.5
4
4
  Summary: JIRA wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -0,0 +1,2 @@
1
+ from brynq_sdk_jira.brynq_sdk.brynq_sdk_jira.jira import Jira
2
+ from brynq_sdk_jira.brynq_sdk.brynq_sdk_jira.tempo import Tempo
@@ -0,0 +1,114 @@
1
+ import json
2
+ from typing import Union, List
3
+ import pandas as pd
4
+ import requests
5
+ from brynq_sdk_brynq import BrynQ
6
+
7
+ class Jira(BrynQ):
8
+ def __init__(self, label: Union[str, List], debug=False):
9
+ super().__init__()
10
+ credentials = self.get_system_credential(system='jira', label=label)
11
+ self.base_url = credentials['base_url']
12
+ self.headers = {
13
+ "Authorization": f"Basic {credentials['access_token']}",
14
+ "Content-Type": "application/json"
15
+ }
16
+ self.debug = debug
17
+
18
+ def get_issues(self, jql_filter: str = None, jira_filter_id: int = None, get_extra_fields: list = None, expand_fields: list = None) -> pd.DataFrame:
19
+ """
20
+ This method retrieves issues from Jira.
21
+ :param jql_filter: optional filter in jql format
22
+ :param jira_filter_id: optional filter id of predefined filter in jira
23
+ :param get_extra_fields: an optional list of extra fields to retrieve
24
+ :param expand_fields: an optional list of fields to expand
25
+ :return: dataframe with issues
26
+ """
27
+ total_response = []
28
+ got_all_results = False
29
+ no_of_loops = 0
30
+ while not got_all_results:
31
+ query = {
32
+ 'startAt': f'{100 * no_of_loops}',
33
+ 'maxResults': '100',
34
+ 'fields': ["summary", "issuetype", "timetracking", "timespent", "description", "assignee", "project"],
35
+ 'fieldsByKeys': 'false'
36
+ }
37
+ if self.debug:
38
+ print(query)
39
+ if jql_filter is not None:
40
+ query['jql'] = jql_filter
41
+ if get_extra_fields is not None:
42
+ query['fields'] += get_extra_fields
43
+ if expand_fields is not None:
44
+ query['expand'] = expand_fields
45
+ if jira_filter_id is not None:
46
+ url = f"{self.base_url}rest/api/3/search/jira/filter/{jira_filter_id}"
47
+ else:
48
+ url = f"{self.base_url}rest/api/3/search"
49
+ response = requests.post(url=url, headers=self.headers, data=json.dumps(query))
50
+ if response.status_code == 200:
51
+ response_json = response.json()
52
+ no_of_loops += 1
53
+ got_all_results = False if len(response_json['issues']) == 100 else True
54
+ total_response += response_json['issues']
55
+ else:
56
+ raise ConnectionError(f"Error getting issues from Jira with message: {response.status_code, response.text}")
57
+
58
+ if self.debug:
59
+ print(f"Received {len(total_response)} issues from Jira")
60
+
61
+ df = pd.json_normalize(total_response)
62
+
63
+ return df
64
+
65
+ def get_projects(self) -> pd.DataFrame:
66
+ """
67
+ This method retrieves projects from Jira.
68
+ :return: a dataframe with projects
69
+ """
70
+ total_response = []
71
+ got_all_results = False
72
+ no_of_loops = 0
73
+
74
+ while not got_all_results:
75
+ query = {
76
+ 'startAt': f'{50 * no_of_loops}',
77
+ 'maxResults': '50',
78
+ 'expand': 'description'
79
+ }
80
+ if self.debug:
81
+ print(query)
82
+ response = requests.get(f"{self.base_url}rest/api/3/project/search", headers=self.headers, params=query)
83
+ if response.status_code == 200:
84
+ response_json = response.json()
85
+ response.raise_for_status()
86
+ no_of_loops += 1
87
+ got_all_results = False if len(response_json['values']) == 50 else True
88
+ total_response += response_json['values']
89
+ else:
90
+ raise ConnectionError(f"Error getting projects from Jira with message: {response.status_code, response.text}")
91
+
92
+ if self.debug:
93
+ print(f"Received {len(total_response)} projects from Jira")
94
+
95
+ df = pd.json_normalize(total_response)
96
+
97
+ return df
98
+
99
+ def get_versions(self, project_key: str) -> pd.DataFrame:
100
+ """
101
+ This method retrieves versions for a given project from Jira.
102
+ :param project_key: The key of the project for which versions are to be retrieved.
103
+ :return: A dataframe with the versions.
104
+ """
105
+ url = f"{self.base_url}rest/api/latest/project/{project_key}/versions"
106
+ response = requests.get(url=url, headers=self.headers)
107
+ if response.status_code == 200:
108
+ response_json = response.json()
109
+ df = pd.json_normalize(response_json)
110
+ if self.debug:
111
+ print(f"Received {len(df)} versions for project {project_key}")
112
+ return df
113
+ else:
114
+ raise ConnectionError(f"Error getting versions from Jira with message: {response.status_code, response.text}")
@@ -0,0 +1,50 @@
1
+ import json
2
+ import requests
3
+ from typing import Union, List
4
+ from brynq_sdk_brynq import BrynQ
5
+
6
+ class Tempo(BrynQ):
7
+ def __init__(self, label: Union[str, List], debug=False):
8
+ super().__init__()
9
+ self.debug = debug
10
+ credentials = self.get_system_credential(system='tempo-timesheets', label=label)
11
+ self.headers = {
12
+ "Authorization": f"Bearer {credentials['api_token']}",
13
+ "Content-Type": "application/json"
14
+ }
15
+ if self.debug:
16
+ print(self.headers)
17
+
18
+ def get_tempo_hours(self, from_date: str = None, to_date: str = None, updated_from: str = None) -> json:
19
+ """
20
+ This function gets hours from Tempo for max 8 backs week
21
+ :param from_date:
22
+ :param to_date:
23
+ :return: json response with results
24
+ """
25
+ total_response = []
26
+ got_all_results = False
27
+ no_of_loops = 0
28
+ parameters = {}
29
+ if from_date is not None:
30
+ parameters.update({"from": from_date})
31
+ if to_date is not None:
32
+ parameters.update({"to": to_date})
33
+ if updated_from is not None:
34
+ parameters.update({"updatedFrom": updated_from})
35
+
36
+ while not got_all_results:
37
+ loop_parameters = parameters | {"limit": 1000, "offset": 1000 * no_of_loops}
38
+ response = requests.get('https://api.tempo.io/4/worklogs', headers=self.headers, params=loop_parameters)
39
+ if response.status_code == 200:
40
+ response_json = response.json()
41
+ no_of_loops += 1
42
+ got_all_results = False if int(response_json['metadata']['count']) == 1000 else True
43
+ total_response += response_json['results']
44
+ else:
45
+ raise ConnectionError(f"Error getting worklogs from Tempo: {response.status_code, response.text}")
46
+
47
+ if self.debug:
48
+ print(f"Received {len(total_response)} lines from Tempo")
49
+
50
+ return total_response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq-sdk-jira
3
- Version: 1.1.1
3
+ Version: 1.1.5
4
4
  Summary: JIRA wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -1,4 +1,7 @@
1
1
  setup.py
2
+ brynq_sdk/brynq_sdk_jira/__init__.py
3
+ brynq_sdk/brynq_sdk_jira/jira.py
4
+ brynq_sdk/brynq_sdk_jira/tempo.py
2
5
  brynq_sdk_jira.egg-info/PKG-INFO
3
6
  brynq_sdk_jira.egg-info/SOURCES.txt
4
7
  brynq_sdk_jira.egg-info/dependency_links.txt
@@ -1,3 +1,3 @@
1
- brynq-sdk-brynq>=2
1
+ brynq-sdk-brynq<3,>=2
2
2
  pandas<3,>=1
3
3
  requests<=3,>=2
@@ -2,7 +2,7 @@ from setuptools import setup, find_namespace_packages
2
2
 
3
3
  setup(
4
4
  name='brynq_sdk_jira',
5
- version='1.1.1',
5
+ version='1.1.5',
6
6
  description='JIRA wrapper from BrynQ',
7
7
  long_description='JIRA wrapper from BrynQ',
8
8
  author='BrynQ',
@@ -10,7 +10,7 @@ setup(
10
10
  packages=find_namespace_packages(include=['brynq_sdk*']),
11
11
  license='BrynQ License',
12
12
  install_requires=[
13
- 'brynq-sdk-brynq>=2',
13
+ 'brynq-sdk-brynq>=2,<3',
14
14
  'pandas>=1,<3',
15
15
  'requests>=2,<=3'
16
16
  ],
File without changes