python-jira-plus 1.0.6__tar.gz → 1.0.8__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.6/python_jira_plus.egg-info → python_jira_plus-1.0.8}/PKG-INFO +1 -1
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus/describe_allowed_value.py +5 -1
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus/jira_plus.py +38 -10
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8/python_jira_plus.egg-info}/PKG-INFO +1 -1
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/setup.py +1 -1
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/LICENSE +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/MANIFEST.in +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/README.md +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/pyproject.toml +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus/__init__.py +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus.egg-info/SOURCES.txt +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus.egg-info/dependency_links.txt +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus.egg-info/requires.txt +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus.egg-info/top_level.txt +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/requirements.txt +0 -0
- {python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/setup.cfg +0 -0
{python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus/describe_allowed_value.py
RENAMED
|
@@ -25,7 +25,11 @@ def _(value: str, allowed_values: list = None):
|
|
|
25
25
|
|
|
26
26
|
@describe_allowed_value.register
|
|
27
27
|
def _(value: list, allowed_values: list = None):
|
|
28
|
-
|
|
28
|
+
if all(isinstance(v, (str, int, float)) for v in value):
|
|
29
|
+
return any(v in allowed_values for v in value)
|
|
30
|
+
if all(isinstance(v, dict) for v in value):
|
|
31
|
+
return any([list(v.values())[0] in allowed_values for v in value])
|
|
32
|
+
return False
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
@describe_allowed_value.register
|
|
@@ -51,7 +51,8 @@ class JiraPlus:
|
|
|
51
51
|
self.jira_client = self.create_connection()
|
|
52
52
|
self.check_client_connection()
|
|
53
53
|
|
|
54
|
-
@retry(stop_max_attempt_number=3,
|
|
54
|
+
@retry(stop_max_attempt_number=3,
|
|
55
|
+
wait_fixed=180000) # Retry 3 times with a 3-min (180000) delay between each attempt
|
|
55
56
|
def create_connection(self, timeout=580) -> Optional[JIRA]:
|
|
56
57
|
if self.server_type == ServerType.ON_PREMISE and not self.sso:
|
|
57
58
|
jira_client = JIRA(
|
|
@@ -197,13 +198,16 @@ class JiraPlus:
|
|
|
197
198
|
"""
|
|
198
199
|
Returns the allowed values for a specific field in a project + issue type context.
|
|
199
200
|
"""
|
|
200
|
-
|
|
201
|
+
fields_metadata = self.get_project_fields_metadata(
|
|
202
|
+
project_key=project_key,
|
|
203
|
+
issue_type=issue_type
|
|
204
|
+
)
|
|
201
205
|
|
|
202
206
|
# Try to find by ID or fallback to case-insensitive name
|
|
203
|
-
field =
|
|
207
|
+
field = fields_metadata.get(field_id_or_name)
|
|
204
208
|
if not field:
|
|
205
209
|
# Try matching by name (case-insensitive)
|
|
206
|
-
for fid, fmeta in
|
|
210
|
+
for fid, fmeta in fields_metadata.items():
|
|
207
211
|
if fmeta['name'].lower() == field_id_or_name.lower():
|
|
208
212
|
field = fmeta
|
|
209
213
|
break
|
|
@@ -225,28 +229,53 @@ class JiraPlus:
|
|
|
225
229
|
allowed_values = allowed_names | allowed_keys
|
|
226
230
|
return describe_allowed_value(value, allowed_values=allowed_values)
|
|
227
231
|
|
|
232
|
+
def get_server_version(self):
|
|
233
|
+
return tuple(self.jira_client.server_info()['versionNumbers'])
|
|
234
|
+
|
|
235
|
+
def check_server_createmeta_compatibility(self) -> bool:
|
|
236
|
+
server_version = self.get_server_version()
|
|
237
|
+
if self.server_type == ServerType.ON_PREMISE and ''.join(str(x) for x in server_version) > '9.0.0':
|
|
238
|
+
self.logger.warning(
|
|
239
|
+
f"JIRA server version {server_version} is below the minimum required version (9.0.0). "
|
|
240
|
+
"Some features may not work as expected."
|
|
241
|
+
)
|
|
242
|
+
return False
|
|
243
|
+
return True
|
|
244
|
+
|
|
245
|
+
def get_project_fields_metadata(self, project_key: str, issue_type: str) -> dict:
|
|
246
|
+
if self.check_server_createmeta_compatibility():
|
|
247
|
+
meta, issue_meta = self._fetch_metadata(project_key=project_key, issue_type=issue_type)
|
|
248
|
+
return issue_meta['fields']
|
|
249
|
+
else:
|
|
250
|
+
_project_issue_types = self.jira_client.project_issue_types(project_key)
|
|
251
|
+
_issue_types = {t.name: t for t in _project_issue_types}
|
|
252
|
+
field_list = self.jira_client.project_issue_fields(project_key, _issue_types[issue_type].id)
|
|
253
|
+
return {f.fieldId: f.raw for f in field_list}
|
|
254
|
+
|
|
228
255
|
def validate_fields(
|
|
229
256
|
self,
|
|
230
257
|
project_key: str,
|
|
231
258
|
issue_type: str,
|
|
232
259
|
fields: Optional[dict] = None
|
|
233
260
|
) -> None:
|
|
234
|
-
|
|
235
|
-
|
|
261
|
+
fields_metadata = self.get_project_fields_metadata(
|
|
262
|
+
project_key=project_key,
|
|
263
|
+
issue_type=issue_type
|
|
264
|
+
)
|
|
236
265
|
for custom_field, value in fields.items():
|
|
237
|
-
if custom_field not in
|
|
266
|
+
if custom_field not in fields_metadata:
|
|
238
267
|
raise ValueError(
|
|
239
268
|
f'Invalid field(s) for project "{project_key}", issue type "{issue_type}": "{custom_field}"'
|
|
240
269
|
)
|
|
241
270
|
|
|
242
|
-
if allowed_value :=
|
|
271
|
+
if allowed_value := fields_metadata[custom_field].get('allowedValues'):
|
|
243
272
|
if not self._is_value_allowed(value=value, allowed_values=allowed_value):
|
|
244
273
|
raise ValueError(
|
|
245
274
|
f"Invalid value '{value}' for field '{custom_field}' in project '{project_key}' with issue type '{issue_type}'."
|
|
246
275
|
f"The allowed values are: {json.dumps(allowed_value, indent=4, sort_keys=True)}"
|
|
247
276
|
)
|
|
248
277
|
|
|
249
|
-
field_type =
|
|
278
|
+
field_type = fields_metadata[custom_field]['schema']['type']
|
|
250
279
|
if field_type == 'string' and not isinstance(value, str):
|
|
251
280
|
raise ValueError(f"Field '{custom_field}' must be a string")
|
|
252
281
|
elif field_type == 'number' and not isinstance(value, (int, float)):
|
|
@@ -260,7 +289,6 @@ class JiraPlus:
|
|
|
260
289
|
elif field_type == 'issuetype' and not isinstance(value, dict):
|
|
261
290
|
raise ValueError(f"Field '{custom_field}' must be an issue type")
|
|
262
291
|
# Add more field type checks as needed
|
|
263
|
-
return issue_meta['fields'].keys()
|
|
264
292
|
|
|
265
293
|
def create_issue(
|
|
266
294
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_jira_plus-1.0.6 → python_jira_plus-1.0.8}/python_jira_plus.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|