qase-python-commons 3.5.2__py3-none-any.whl → 3.5.3__py3-none-any.whl

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.

Potentially problematic release.


This version of qase-python-commons might be problematic. Click here for more details.

@@ -3,7 +3,7 @@ from typing import Union
3
3
 
4
4
  import certifi
5
5
  from qase.api_client_v1 import ApiClient, ProjectsApi, Project, EnvironmentsApi, RunsApi, AttachmentsApi, \
6
- AttachmentGet, RunCreate
6
+ AttachmentGet, RunCreate, ConfigurationsApi, ConfigurationCreate, ConfigurationGroupCreate
7
7
  from qase.api_client_v1.configuration import Configuration
8
8
  from .. import Logger
9
9
  from .base_api_client import BaseApiClient
@@ -11,6 +11,7 @@ from ..exceptions.reporter import ReporterException
11
11
  from ..models import Attachment
12
12
  from ..models.config.framework import Video, Trace
13
13
  from ..models.config.qaseconfig import QaseConfig
14
+ from ..models.config.testops import ConfigurationValue
14
15
 
15
16
 
16
17
  class ApiV1Client(BaseApiClient):
@@ -66,6 +67,73 @@ class ApiV1Client(BaseApiClient):
66
67
  self.logger.log("Exception when calling EnvironmentsApi->get_environments: %s\n" % e, "error")
67
68
  raise ReporterException(e)
68
69
 
70
+ def get_configurations(self, project_code: str):
71
+ """Get all configurations for the project"""
72
+ try:
73
+ self.logger.log_debug(f"Getting configurations for project {project_code}")
74
+ api_instance = ConfigurationsApi(self.client)
75
+ response = api_instance.get_configurations(code=project_code)
76
+ if hasattr(response, 'result') and hasattr(response.result, 'entities'):
77
+ return response.result.entities
78
+ return []
79
+ except Exception as e:
80
+ self.logger.log(f"Exception when calling ConfigurationsApi->get_configurations: {e}", "error")
81
+ return []
82
+
83
+ def find_or_create_configuration(self, project_code: str, config_value: ConfigurationValue) -> Union[int, None]:
84
+ """Find existing configuration or create new one if createIfNotExists is True"""
85
+ try:
86
+ configurations = self.get_configurations(project_code)
87
+
88
+ # Search for existing configuration
89
+ for group in configurations:
90
+ if hasattr(group, 'configurations'):
91
+ for config in group.configurations:
92
+ # API returns configurations with 'title' field, not 'name' and 'value'
93
+ # We need to match group.title with config_value.name and config.title with config_value.value
94
+ config_title = config.title if hasattr(config, 'title') else 'No title'
95
+ group_title = group.title if hasattr(group, 'title') else 'No title'
96
+
97
+ if (group_title == config_value.name and config_title == config_value.value):
98
+ return config.id
99
+
100
+ # Configuration not found
101
+ if not self.config.testops.configurations.create_if_not_exists:
102
+ return None
103
+
104
+ # Create new configuration
105
+ # First, try to find existing group or create new one
106
+ group_id = None
107
+ for group in configurations:
108
+ if hasattr(group, 'title') and group.title == config_value.name:
109
+ group_id = group.id
110
+ break
111
+
112
+ if group_id is None:
113
+ # Create new group
114
+ group_create = ConfigurationGroupCreate(title=config_value.name)
115
+ group_response = ConfigurationsApi(self.client).create_configuration_group(
116
+ code=project_code,
117
+ configuration_group_create=group_create
118
+ )
119
+ group_id = group_response.result.id
120
+
121
+ # Create configuration in the group
122
+ config_create = ConfigurationCreate(
123
+ title=config_value.value,
124
+ group_id=group_id
125
+ )
126
+ config_response = ConfigurationsApi(self.client).create_configuration(
127
+ code=project_code,
128
+ configuration_create=config_create
129
+ )
130
+ config_id = config_response.result.id
131
+ return config_id
132
+
133
+ except Exception as e:
134
+ self.logger.log(f"Error at finding/creating configuration {config_value.name}={config_value.value}: {e}", "error")
135
+ return None
136
+
69
137
  def complete_run(self, project_code: str, run_id: int) -> None:
70
138
  api_runs = RunsApi(self.client)
71
139
  self.logger.log_debug(f"Completing run {run_id}")
@@ -94,6 +162,15 @@ class ApiV1Client(BaseApiClient):
94
162
 
95
163
  def create_test_run(self, project_code: str, title: str, description: str, plan_id=None,
96
164
  environment_id=None) -> str:
165
+ # Process configurations
166
+ configuration_ids = []
167
+
168
+ if self.config.testops.configurations and self.config.testops.configurations.values:
169
+ for config_value in self.config.testops.configurations.values:
170
+ config_id = self.find_or_create_configuration(project_code, config_value)
171
+ if config_id:
172
+ configuration_ids.append(config_id)
173
+
97
174
  kwargs = dict(
98
175
  title=title,
99
176
  description=description,
@@ -103,7 +180,11 @@ class ApiV1Client(BaseApiClient):
103
180
  start_time=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"),
104
181
  tags=self.config.testops.run.tags
105
182
  )
106
- self.logger.log_debug(f"Creating test run with parameters: {kwargs}")
183
+
184
+ # Add configurations if any found
185
+ if configuration_ids:
186
+ kwargs['configurations'] = configuration_ids
187
+
107
188
  try:
108
189
  result = RunsApi(self.client).create_run(
109
190
  code=project_code,
qase/commons/config.py CHANGED
@@ -128,6 +128,20 @@ class ConfigManager:
128
128
  self.config.testops.batch.set_size(
129
129
  batch.get("size"))
130
130
 
131
+ if testops.get("configurations"):
132
+ configurations = testops.get("configurations")
133
+
134
+ if configurations.get("values"):
135
+ values = configurations.get("values")
136
+ for value in values:
137
+ if value.get("name") and value.get("value"):
138
+ self.config.testops.configurations.add_value(
139
+ value.get("name"), value.get("value"))
140
+
141
+ if configurations.get("createIfNotExists") is not None:
142
+ self.config.testops.configurations.set_create_if_not_exists(
143
+ configurations.get("createIfNotExists"))
144
+
131
145
  if config.get("report"):
132
146
  report = config.get("report")
133
147
 
@@ -235,6 +249,19 @@ class ConfigManager:
235
249
  if key == 'QASE_TESTOPS_BATCH_SIZE':
236
250
  self.config.testops.batch.set_size(value)
237
251
 
252
+ if key == 'QASE_TESTOPS_CONFIGURATIONS_VALUES':
253
+ # Parse configurations from environment variable
254
+ # Format: "group1=value1,group2=value2"
255
+ if value:
256
+ config_pairs = value.split(',')
257
+ for pair in config_pairs:
258
+ if '=' in pair:
259
+ name, config_value = pair.split('=', 1)
260
+ self.config.testops.configurations.add_value(name.strip(), config_value.strip())
261
+
262
+ if key == 'QASE_TESTOPS_CONFIGURATIONS_CREATE_IF_NOT_EXISTS':
263
+ self.config.testops.configurations.set_create_if_not_exists(value)
264
+
238
265
  if key == 'QASE_REPORT_DRIVER':
239
266
  self.config.report.set_driver(value)
240
267
 
@@ -4,6 +4,40 @@ from .plan import PlanConfig
4
4
  from .run import RunConfig
5
5
  from ..basemodel import BaseModel
6
6
  from ... import QaseUtils
7
+ from typing import List
8
+
9
+
10
+ class ConfigurationValue(BaseModel):
11
+ name: str = None
12
+ value: str = None
13
+
14
+ def __init__(self, name: str = None, value: str = None):
15
+ self.name = name
16
+ self.value = value
17
+
18
+ def set_name(self, name: str):
19
+ self.name = name
20
+
21
+ def set_value(self, value: str):
22
+ self.value = value
23
+
24
+
25
+ class ConfigurationsConfig(BaseModel):
26
+ values: List[ConfigurationValue] = None
27
+ create_if_not_exists: bool = None
28
+
29
+ def __init__(self):
30
+ self.values = []
31
+ self.create_if_not_exists = False
32
+
33
+ def set_values(self, values: List[ConfigurationValue]):
34
+ self.values = values
35
+
36
+ def set_create_if_not_exists(self, create_if_not_exists):
37
+ self.create_if_not_exists = QaseUtils.parse_bool(create_if_not_exists)
38
+
39
+ def add_value(self, name: str, value: str):
40
+ self.values.append(ConfigurationValue(name=name, value=value))
7
41
 
8
42
 
9
43
  class TestopsConfig(BaseModel):
@@ -13,12 +47,14 @@ class TestopsConfig(BaseModel):
13
47
  run: RunConfig = None
14
48
  plan: PlanConfig = None
15
49
  batch: BatchConfig = None
50
+ configurations: ConfigurationsConfig = None
16
51
 
17
52
  def __init__(self):
18
53
  self.api = ApiConfig()
19
54
  self.run = RunConfig()
20
55
  self.batch = BatchConfig()
21
56
  self.plan = PlanConfig()
57
+ self.configurations = ConfigurationsConfig()
22
58
  self.defect = False
23
59
 
24
60
  def set_project(self, project: str):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qase-python-commons
3
- Version: 3.5.2
3
+ Version: 3.5.3
4
4
  Summary: A library for Qase TestOps and Qase Report
5
5
  Author-email: Qase Team <support@qase.io>
6
6
  Project-URL: Homepage, https://github.com/qase-tms/qase-python/tree/main/qase-python-commons
@@ -22,8 +22,8 @@ Requires-Python: >=3.7
22
22
  Description-Content-Type: text/markdown
23
23
  Requires-Dist: certifi>=2024.2.2
24
24
  Requires-Dist: attrs>=23.2.0
25
- Requires-Dist: qase-api-client~=1.2.0
26
- Requires-Dist: qase-api-v2-client~=1.2.0
25
+ Requires-Dist: qase-api-client~=1.2.3
26
+ Requires-Dist: qase-api-v2-client~=1.2.2
27
27
  Requires-Dist: more_itertools
28
28
  Provides-Extra: testing
29
29
  Requires-Dist: pytest; extra == "testing"
@@ -1,9 +1,9 @@
1
1
  qase/commons/__init__.py,sha256=3HI65PJES4Q6YvtkSuRPh6tZboTETJo8wbdHlNYaePU,323
2
- qase/commons/config.py,sha256=tRxuaRaTrng5q0fiknlmNSK8I0Rd9Oj_4yPcdKSG1j8,10117
2
+ qase/commons/config.py,sha256=-JSKACvKPsUSFwU6Eilq7cgFJlY-6V7AdmJJnUTmYOM,11666
3
3
  qase/commons/loader.py,sha256=-MMY4HgSI6q1xq3NaJoq_w4liM73qdFKjYLVCT1E7Pc,1064
4
4
  qase/commons/logger.py,sha256=KEQr8G0eFZxlI3LJIaaNWOKD8o3NhKsZD06swXFn3FI,1313
5
5
  qase/commons/utils.py,sha256=utPRoYyThLs2tgD1lmjkwJ9KZuE7ZjliUiZkJJWFca0,3330
6
- qase/commons/client/api_v1_client.py,sha256=8neslPdfbtICTtVZZ6Dqd7VFudVz0kdG30CgeP0PVwk,6215
6
+ qase/commons/client/api_v1_client.py,sha256=cxECfjM68KrjRVNr6nsTY4uOc_bBlo5qQJ10C5roEyk,10130
7
7
  qase/commons/client/api_v2_client.py,sha256=GsIrXJcBw6GtzvJjbjMYa0tvUIxEEe4pALRN2LBMKPM,9043
8
8
  qase/commons/client/base_api_client.py,sha256=qiK93rXXeLOmp6e3cgsLA4lmrV_rCL1BIi_xUeqFrDE,2613
9
9
  qase/commons/exceptions/reporter.py,sha256=dP-Mwcq8HKBOjgu3YqhyULDmDGU09BmT6Fh9HjICaUc,45
@@ -23,7 +23,7 @@ qase/commons/models/config/plan.py,sha256=JbAY7qfGXYreXOLa32OLxw6z0paeCCf87-2b1m
23
23
  qase/commons/models/config/qaseconfig.py,sha256=ho_22bcouoJb1f68EGffeBs_ovK3DVyfbFrYXwQFrWs,1918
24
24
  qase/commons/models/config/report.py,sha256=g3Z2B3Tewaasjc1TMj2mkXxz0Zc1C39sHeTXH0MRM2Y,497
25
25
  qase/commons/models/config/run.py,sha256=UeZ_1khhKSLbER3pzAl__5iKfDMErvUsXikelc31iKo,682
26
- qase/commons/models/config/testops.py,sha256=_GT0Px04y2JqhmXdRbqC6vvSm4yRIU74L9Sr6eiYVLU,708
26
+ qase/commons/models/config/testops.py,sha256=jofietKpOISLeTM-vHmn5Jboqj-D1WFoydQZCloZMPE,1722
27
27
  qase/commons/profilers/__init__.py,sha256=GhKT5hRbHbhAC4GhdyChA8XoAsGQOnIb8S2Z4-fdS7Q,222
28
28
  qase/commons/profilers/db.py,sha256=Am1tvvLgJq4_A8JsuSeBGf47BD2lnSX-5KiMjSgr-Ko,391
29
29
  qase/commons/profilers/network.py,sha256=zKNBnTQG4BMg8dn8O--tQzQLpu-qs5ADhHEnqIas0gM,4950
@@ -35,7 +35,7 @@ qase/commons/reporters/testops.py,sha256=pYSLjSSvDeN3K1DN_7pFHataZHQEjU3ul-8x8-9
35
35
  qase/commons/util/__init__.py,sha256=0sRRfrMOIPCHpk9tXM94Pj10qrk18B61qEcbLpRjw_I,74
36
36
  qase/commons/util/host_data.py,sha256=n8o5PDs8kELCZZ5GR7Jug6LsgZHWJudU7iRmZHRdrlw,5264
37
37
  qase/commons/validators/base.py,sha256=wwSn-4YiuXtfGMGnSKgo9Vm5hAKevVmmfd2Ro6Q7MYQ,173
38
- qase_python_commons-3.5.2.dist-info/METADATA,sha256=mo-mgFlC9juQ_JrN-p2WXPEHegIGu75_i8dVF8bJTnw,1857
39
- qase_python_commons-3.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
- qase_python_commons-3.5.2.dist-info/top_level.txt,sha256=Mn5aFk7H7Uia4s1NRDsvebu8vCrFy9nOuRIBfkIY5kQ,5
41
- qase_python_commons-3.5.2.dist-info/RECORD,,
38
+ qase_python_commons-3.5.3.dist-info/METADATA,sha256=PSg3wNbBOow7ahZ4hg4satURnYpfANL_Os3wKSmHd1Q,1857
39
+ qase_python_commons-3.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
+ qase_python_commons-3.5.3.dist-info/top_level.txt,sha256=Mn5aFk7H7Uia4s1NRDsvebu8vCrFy9nOuRIBfkIY5kQ,5
41
+ qase_python_commons-3.5.3.dist-info/RECORD,,