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