python-jira-plus 1.0.3__tar.gz → 1.0.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.
- {python_jira_plus-1.0.3/python_jira_plus.egg-info → python_jira_plus-1.0.5}/PKG-INFO +1 -1
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus/jira_plus.py +67 -56
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5/python_jira_plus.egg-info}/PKG-INFO +1 -1
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/setup.py +1 -1
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/LICENSE +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/MANIFEST.in +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/README.md +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/pyproject.toml +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus/__init__.py +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus/describe_allowed_value.py +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus.egg-info/SOURCES.txt +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus.egg-info/dependency_links.txt +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus.egg-info/requires.txt +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus.egg-info/top_level.txt +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/requirements.txt +0 -0
- {python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/setup.cfg +0 -0
|
@@ -21,33 +21,43 @@ class ServerType(Enum):
|
|
|
21
21
|
|
|
22
22
|
class JiraPlus:
|
|
23
23
|
def __init__(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
self, base_url: Optional[str] = None,
|
|
25
|
+
server_type: ServerType = ServerType.CLOUD,
|
|
26
|
+
urllib3_log_level: int = logging.WARNING,
|
|
27
|
+
jira_username: Optional[str] = None,
|
|
28
|
+
jira_token: Optional[str] = None, # Use API token (not PAT)
|
|
29
|
+
verify_ssl: bool = True,
|
|
30
|
+
sso: bool = False
|
|
27
31
|
) -> None:
|
|
28
32
|
self.logger = logging.getLogger()
|
|
29
33
|
logging.getLogger("urllib3").setLevel(urllib3_log_level)
|
|
30
34
|
|
|
31
|
-
self.jira_username = os.getenv('JIRA_USER_NAME')
|
|
32
|
-
self.jira_token = os.getenv('JIRA_TOKEN')
|
|
33
|
-
|
|
34
|
-
if not base_url:
|
|
35
|
-
self.base_url = os.getenv('JIRA_BASE_URL')
|
|
35
|
+
self.jira_username = jira_username or os.getenv('JIRA_USER_NAME')
|
|
36
|
+
self.jira_token = jira_token or os.getenv('JIRA_TOKEN')
|
|
37
|
+
self.base_url = base_url or os.getenv('JIRA_BASE_URL')
|
|
36
38
|
|
|
37
39
|
self.server_type = server_type
|
|
38
40
|
self.server = f'https://{self.base_url}'
|
|
41
|
+
self.verify_ssl = verify_ssl
|
|
42
|
+
self.sso = sso
|
|
39
43
|
|
|
40
44
|
self.jira_client = self.create_connection()
|
|
41
45
|
self.check_client_connection()
|
|
42
46
|
|
|
43
|
-
@retry(stop_max_attempt_number=3,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
@retry(stop_max_attempt_number=3, wait_fixed=180000) # Retry 3 times with a 3-min (180000) delay between each attempt
|
|
48
|
+
def create_connection(self, timeout=580) -> Optional[JIRA]:
|
|
49
|
+
if self.server_type == ServerType.ON_PREMISE and not self.sso:
|
|
50
|
+
jira_client = JIRA(
|
|
51
|
+
token_auth=self.jira_token,
|
|
52
|
+
options={'server': self.server},
|
|
53
|
+
timeout=timeout
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
jira_client = JIRA(
|
|
57
|
+
basic_auth=(self.jira_username, self.jira_token),
|
|
58
|
+
options={'server': self.server},
|
|
59
|
+
timeout=timeout
|
|
60
|
+
)
|
|
51
61
|
|
|
52
62
|
if jira_client.projects():
|
|
53
63
|
self.logger.info(f"Jira Connection Successful")
|
|
@@ -81,10 +91,10 @@ class JiraPlus:
|
|
|
81
91
|
return False
|
|
82
92
|
|
|
83
93
|
def get_issue_by_key(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
self,
|
|
95
|
+
key: str,
|
|
96
|
+
specific_fields: str | list[str] = '*all',
|
|
97
|
+
json_result: bool = True
|
|
88
98
|
) -> None | Issue | dict[str, Any]:
|
|
89
99
|
try:
|
|
90
100
|
jira_issue = self.jira_client.issue(id=key, fields=specific_fields)
|
|
@@ -99,12 +109,12 @@ class JiraPlus:
|
|
|
99
109
|
return None
|
|
100
110
|
|
|
101
111
|
def get_objects_by_query(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
self,
|
|
113
|
+
query: str,
|
|
114
|
+
max_results: int = 5000,
|
|
115
|
+
specific_fields: Union[str, list[str]] = "*all",
|
|
116
|
+
jira_err_count: int = 3,
|
|
117
|
+
json_result: bool = True,
|
|
108
118
|
) -> Optional[Union[ResultList[Issue], dict]]:
|
|
109
119
|
return self._paginate_query(
|
|
110
120
|
query=query,
|
|
@@ -115,12 +125,12 @@ class JiraPlus:
|
|
|
115
125
|
)
|
|
116
126
|
|
|
117
127
|
def _paginate_query(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
self,
|
|
129
|
+
query: str,
|
|
130
|
+
max_results: int,
|
|
131
|
+
specific_fields: Union[str, list[str]],
|
|
132
|
+
jira_err_limit: int,
|
|
133
|
+
json_result: bool
|
|
124
134
|
) -> Union[ResultList[Issue] | list]:
|
|
125
135
|
start_at = 0
|
|
126
136
|
all_issues = []
|
|
@@ -172,10 +182,10 @@ class JiraPlus:
|
|
|
172
182
|
return meta, issue_meta
|
|
173
183
|
|
|
174
184
|
def get_allowed_values(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
self,
|
|
186
|
+
project_key: str,
|
|
187
|
+
issue_type: str,
|
|
188
|
+
field_id_or_name: str,
|
|
179
189
|
) -> Optional[list]:
|
|
180
190
|
"""
|
|
181
191
|
Returns the allowed values for a specific field in a project + issue type context.
|
|
@@ -209,10 +219,10 @@ class JiraPlus:
|
|
|
209
219
|
return describe_allowed_value(value, allowed_values=allowed_values)
|
|
210
220
|
|
|
211
221
|
def validate_fields(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
222
|
+
self,
|
|
223
|
+
project_key: str,
|
|
224
|
+
issue_type: str,
|
|
225
|
+
fields: Optional[dict] = None
|
|
216
226
|
) -> None:
|
|
217
227
|
meta, issue_meta = self._fetch_metadata(project_key=project_key, issue_type=issue_type)
|
|
218
228
|
field_types = meta['projects'][0]['issuetypes'][0]['fields']
|
|
@@ -246,13 +256,13 @@ class JiraPlus:
|
|
|
246
256
|
return issue_meta['fields'].keys()
|
|
247
257
|
|
|
248
258
|
def create_issue(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
self,
|
|
260
|
+
project_key: str,
|
|
261
|
+
summary: str,
|
|
262
|
+
description: str,
|
|
263
|
+
issue_type: str,
|
|
264
|
+
assignee: Optional[str] = None,
|
|
265
|
+
custom_fields: Optional[dict] = None,
|
|
256
266
|
) -> Optional[Issue]:
|
|
257
267
|
issue_fields = {
|
|
258
268
|
"project": {"key": project_key},
|
|
@@ -261,7 +271,8 @@ class JiraPlus:
|
|
|
261
271
|
"description": description,
|
|
262
272
|
}
|
|
263
273
|
if assignee:
|
|
264
|
-
issue_fields["assignee"] = {"accountId": assignee} if self.server_type == ServerType.CLOUD else {
|
|
274
|
+
issue_fields["assignee"] = {"accountId": assignee} if self.server_type == ServerType.CLOUD else {
|
|
275
|
+
"name": assignee}
|
|
265
276
|
|
|
266
277
|
if custom_fields:
|
|
267
278
|
issue_fields = issue_fields | custom_fields
|
|
@@ -279,9 +290,9 @@ class JiraPlus:
|
|
|
279
290
|
return None
|
|
280
291
|
|
|
281
292
|
def update_issue(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
293
|
+
self,
|
|
294
|
+
issue_key: str,
|
|
295
|
+
fields_to_update: dict
|
|
285
296
|
) -> Optional[Issue]:
|
|
286
297
|
try:
|
|
287
298
|
issue = self.jira_client.issue(issue_key)
|
|
@@ -350,11 +361,11 @@ class JiraPlus:
|
|
|
350
361
|
self.logger.exception(f"Exception - Attachment {file_path} was not uploaded to issue {issue_key}\n{err}")
|
|
351
362
|
|
|
352
363
|
def transition_issue(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
364
|
+
self,
|
|
365
|
+
issue_key: str,
|
|
366
|
+
transition_name: str,
|
|
367
|
+
fields: Optional[dict] = None,
|
|
368
|
+
comment: Optional[str] = None,
|
|
358
369
|
) -> bool:
|
|
359
370
|
try:
|
|
360
371
|
transitions = self.jira_client.transitions(issue_key)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus/describe_allowed_value.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_jira_plus-1.0.3 → python_jira_plus-1.0.5}/python_jira_plus.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|