alita-sdk 0.3.193__py3-none-any.whl → 0.3.195__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.
@@ -139,7 +139,7 @@ class AlitaChatModel(BaseChatModel):
139
139
  else:
140
140
  message = _convert_delta_to_message_chunk(chunk, default_chunk_class)
141
141
  finish_reason = None
142
- generation_info = ()
142
+ generation_info = dict()
143
143
  if stop:
144
144
  for stop_word in stop:
145
145
  if stop_word in message.content:
@@ -286,10 +286,7 @@ class BitbucketCloudApi(BitbucketApiAbstract):
286
286
  Returns:
287
287
  List[Dict[str, Any]]: List of commits in the pull request
288
288
  """
289
- commits = self.repository.pullrequests.get(pr_id).get('commits', [])
290
- if not isinstance(commits, list):
291
- commits = list(commits)
292
- return commits
289
+ return self.repository.pullrequests.get(pr_id).get('commits', {}).get('values', [])
293
290
 
294
291
  def get_pull_request(self, pr_id: str) -> Any:
295
292
  """ Get details of a pull request
@@ -322,18 +319,11 @@ class BitbucketCloudApi(BitbucketApiAbstract):
322
319
  """
323
320
  # Build the content dict for Bitbucket Cloud
324
321
  if isinstance(content, str):
325
- content_dict = {"raw": content}
326
- elif isinstance(content, dict):
327
- # Only include allowed keys
328
- content_dict = {k: v for k, v in content.items() if k in ("raw", "markup", "html")}
329
- if not content_dict:
330
- content_dict = {"raw": str(content)}
322
+ content_raw = content
323
+ elif isinstance(content, dict) and "raw" in content:
324
+ content_raw = content.get("raw")
331
325
  else:
332
- content_dict = {"raw": str(content)}
333
-
334
- data = {"content": content_dict}
335
- if inline:
336
- data["inline"] = inline
326
+ content_raw = str(content)
337
327
 
338
- response = self.repository.pullrequests.comments.post(pr_id, data=data)
328
+ response = self.repository.pullrequests.get(pr_id).comment(content_raw)
339
329
  return response['links']['self']['href']
@@ -201,6 +201,8 @@ GetPageAttachmentsInput = create_model(
201
201
  page_id=(str, Field(description="Confluence page ID from which attachments will be retrieved")),
202
202
  max_content_length=(int, Field(default=10000, description="Maximum number of characters to return for attachment content. Content will be truncated if longer. Default is 10000.")),
203
203
  custom_prompt=(Optional[str], Field(default=None, description="Custom prompt to use for LLM-based analysis of attachments (images, pdfs, etc). If not provided, a default prompt will be used.")),
204
+ allowed_extensions=(Optional[List[str]], Field(default=None, description="List of file extensions to include (e.g. ['pdf', 'docx']). If None, all extensions are included.", examples=[["pdf", "docx"]])),
205
+ name_pattern=(Optional[str], Field(default=None, description="Regex pattern to filter attachment names (e.g. '^report_.*\\.pdf$'). If None, all names are included.", examples=["^report_.*\\.pdf$"])),
204
206
  )
205
207
 
206
208
 
@@ -1427,8 +1429,8 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1427
1429
  stacktrace = traceback.format_exc()
1428
1430
  logger.error(f"Error processing page with images: {stacktrace}")
1429
1431
  return f"Error processing page with images: {str(e)}"
1430
-
1431
- def get_page_attachments(self, page_id: str, max_content_length: int = 10000, custom_prompt: str = None):
1432
+
1433
+ def get_page_attachments(self, page_id: str, max_content_length: int = 10000, custom_prompt: str = None, allowed_extensions: Optional[List[str]] = None, name_pattern: Optional[str] = None):
1432
1434
  """
1433
1435
  Retrieve all attachments for a Confluence page, including core metadata (with creator, created, updated), comments,
1434
1436
  file content, and LLM-based analysis for supported types.
@@ -1449,8 +1451,19 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1449
1451
  logger.warning(f"Failed to fetch history for attachment {attachment.get('title', '')}: {str(e)}")
1450
1452
  history_map[attachment['id']] = None
1451
1453
 
1454
+ import re
1452
1455
  results = []
1453
1456
  for attachment in attachments['results']:
1457
+ title = attachment.get('title', '')
1458
+ file_ext = title.lower().split('.')[-1] if '.' in title else ''
1459
+
1460
+ # Filter by allowed_extensions
1461
+ if allowed_extensions and file_ext not in allowed_extensions:
1462
+ continue
1463
+ # Filter by name_pattern
1464
+ if name_pattern and not re.match(name_pattern, title):
1465
+ continue
1466
+
1454
1467
  media_type = attachment.get('metadata', {}).get('mediaType', '')
1455
1468
  # Core metadata extraction with history
1456
1469
  hist = history_map.get(attachment['id']) or {}
@@ -1458,7 +1471,7 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1458
1471
  created_date = hist.get('createdDate', '') if hist else attachment.get('created', '')
1459
1472
  last_updated = hist.get('lastUpdated', {}).get('when', '') if hist else ''
1460
1473
  metadata = {
1461
- 'name': attachment.get('title', ''),
1474
+ 'name': title,
1462
1475
  'size': attachment.get('extensions', {}).get('fileSize', None),
1463
1476
  'creator': created_by,
1464
1477
  'created': created_date,
@@ -1467,6 +1480,7 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1467
1480
  'labels': [label['name'] for label in attachment.get('metadata', {}).get('labels', {}).get('results', [])],
1468
1481
  'download_url': self.base_url.rstrip('/') + attachment['_links']['download'] if attachment.get('_links', {}).get('download') else None
1469
1482
  }
1483
+
1470
1484
  # Fetch comments for the attachment
1471
1485
  comments = []
1472
1486
  try:
@@ -1480,16 +1494,13 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1480
1494
  'body': comment.get('body', {}).get('storage', {}).get('value', '')
1481
1495
  })
1482
1496
  except Exception as e:
1483
- logger.warning(f"Failed to fetch comments for attachment {attachment.get('title', '')}: {str(e)}")
1497
+ logger.warning(f"Failed to fetch comments for attachment {title}: {str(e)}")
1484
1498
 
1485
1499
  content = None
1486
1500
  llm_analysis = None
1487
- title = attachment.get('title', '')
1488
1501
  download_url = self.base_url.rstrip('/') + attachment['_links']['download']
1489
1502
 
1490
1503
  # --- Begin: Raw content for xml, json, markdown, txt ---
1491
- # Check by media type or file extension
1492
- file_ext = title.lower().split('.')[-1] if '.' in title else ''
1493
1504
  is_text_type = (
1494
1505
  media_type in [
1495
1506
  'application/xml', 'text/xml',
@@ -1661,7 +1672,7 @@ class ConfluenceAPIWrapper(BaseVectorStoreToolApiWrapper):
1661
1672
  llm_analysis = self._process_image_with_llm(image_data, title, context_text, custom_prompt)
1662
1673
 
1663
1674
  if llm_analysis and isinstance(llm_analysis, str) and len(llm_analysis) > max_content_length:
1664
- llm_analysis = llm_analysis[:max_content_length] + f"\n...[truncated, showing first {max_content_length} characters]"
1675
+ llm_analysis = llm_analysis[:max_content_length] + f"\n...[truncated, showing first {max_content_length} characters]"
1665
1676
 
1666
1677
  results.append({
1667
1678
  'metadata': metadata,
@@ -44,14 +44,20 @@ class SlackToolkit(BaseToolkit):
44
44
  except SlackApiError as e:
45
45
  logger.error(f"Slack connection failed: {e.response['error']}")
46
46
  return {"success": False, "error": e.response['error']}
47
-
47
+
48
48
  model = create_model(
49
- name,
50
- slack_token=(SecretStr, Field(description="Slack Token like XOXB-*****-*****-*****-*****", json_schema_extra={'secret': True, 'configuration': True})),
51
- channel_id=(str, Field( description="Channel ID", json_schema_extra={'configuration': True})),
52
- selected_tools=(list[str], Field( description="List of tools to enable", default=[],json_schema_extra={'args_schemas': selected_tools})),
53
- __config__={'json_schema_extra': {'metadata': {"label": "Slack", "icon_url": None}}}
54
- )
49
+ name,
50
+ name=(str, Field(description="Toolkit name", json_schema_extra={'toolkit_name': True,
51
+ 'max_toolkit_length': SlackToolkit.toolkit_max_length,
52
+ 'configuration': True,
53
+ 'configuration_title': True})),
54
+ slack_token=(SecretStr, Field(description="Slack Token like XOXB-*****-*****-*****-*****",
55
+ json_schema_extra={'secret': True, 'configuration': True})),
56
+ channel_id=(str, Field(description="Channel ID", json_schema_extra={'configuration': True})),
57
+ selected_tools=(List[Literal[tuple(selected_tools)]],
58
+ Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
59
+ __config__={'json_schema_extra': {'metadata': {"label": "Slack", "icon_url": "slack-icon.svg"}}}
60
+ )
55
61
  model.check_connection = check_connection
56
62
  return model
57
63
 
@@ -1,14 +1,13 @@
1
1
  from typing import List, Literal, Optional
2
2
 
3
- from langchain_community.agent_toolkits.base import BaseToolkit
4
- from langchain_core.tools import BaseTool
3
+ from langchain_core.tools import BaseToolkit, BaseTool
5
4
  from pydantic import create_model, BaseModel, Field, SecretStr
6
5
 
7
6
  from .api_wrapper import ZephyrSquadApiWrapper
8
7
  from ..base.tool import BaseAction
9
8
  from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
10
9
 
11
- name = "zephyr"
10
+ name = "zephyr_squad"
12
11
 
13
12
  def get_tools(tool):
14
13
  return ZephyrSquadToolkit().get_toolkit(
@@ -28,10 +27,10 @@ class ZephyrSquadToolkit(BaseToolkit):
28
27
  selected_tools = {x['name']: x['args_schema'].schema() for x in ZephyrSquadApiWrapper.model_construct().get_available_tools()}
29
28
  ZephyrSquadToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
29
  return create_model(
31
- "zephyr_squad",
30
+ name,
32
31
  account_id=(str, Field(description="AccountID for the user that is going to be authenticating")),
33
- access_key=(str, Field(description="Generated access key")),
34
- secret_key=(SecretStr, Field(description="Generated secret key")),
32
+ access_key=(SecretStr, Field(description="Generated access key", json_schema_extra={'secret': True})),
33
+ secret_key=(SecretStr, Field(description="Generated secret key", json_schema_extra={'secret': True})),
35
34
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
36
35
  __config__={'json_schema_extra': {'metadata': {"label": "Zephyr Squad", "icon_url": "zephyr.svg",
37
36
  "categories": ["test management"],
@@ -55,6 +55,42 @@ class ZephyrSquadApiWrapper(BaseToolApiWrapper):
55
55
  """Retrieve all possible statuses for test steps in Jira."""
56
56
  return self._client.get_all_test_step_statuses()
57
57
 
58
+ def get_bdd_content(self, issue_id):
59
+ """Retrieve BDD (Gherkin) content of an issue (feature or scenario)."""
60
+ return self._client.get_bdd_content(issue_id)
61
+
62
+ def update_bdd_content(self, issue_id, new_content):
63
+ """Replace BDD (Gherkin) content of an issue (feature or scenario)."""
64
+ return self._client.update_bdd_content(issue_id, new_content)
65
+
66
+ def delete_bdd_content(self, issue_id):
67
+ """Remove BDD (Gherkin) content of an issue (feature or scenario)."""
68
+ return self._client.delete_bdd_content(issue_id)
69
+
70
+ def create_new_cycle(self, json):
71
+ """Creates a Cycle from a JSON representation. If no VersionId is passed in the request, it will be defaulted to an unscheduled version"""
72
+ return self._client.create_new_cycle(json)
73
+
74
+ def create_folder(self, json):
75
+ """Creates a Folder from a JSON representation. Folder names within a cycle needs to be unique."""
76
+ return self._client.create_folder(json)
77
+
78
+ def add_test_to_cycle(self, cycle_id, json):
79
+ """Adds Tests(s) to a Cycle."""
80
+ return self._client.add_test_to_cycle(cycle_id, json)
81
+
82
+ def add_test_to_folder(self, folder_id, json):
83
+ """Adds Tests(s) to a Folder."""
84
+ return self._client.add_test_to_folder(folder_id, json)
85
+
86
+ def create_execution(self, json):
87
+ """Creates an execution from a JSON representation."""
88
+ return self._client.create_execution(json)
89
+
90
+ def get_execution(self, execution_id, issue_id, project_id):
91
+ """Retrieves Execution and ExecutionStatus by ExecutionId"""
92
+ return self._client.get_execution(execution_id, issue_id, project_id)
93
+
58
94
  def get_available_tools(self):
59
95
  return [
60
96
  {
@@ -92,14 +128,73 @@ class ZephyrSquadApiWrapper(BaseToolApiWrapper):
92
128
  "description": self.get_all_test_step_statuses.__doc__,
93
129
  "args_schema": create_model("NoInput"),
94
130
  "ref": self.get_all_test_step_statuses,
131
+ },
132
+ {
133
+ "name": "get_bdd_content",
134
+ "description": self.get_bdd_content.__doc__,
135
+ "args_schema": Issue,
136
+ "ref": self.get_bdd_content,
137
+ },
138
+ {
139
+ "name": "update_bdd_content",
140
+ "description": self.update_bdd_content.__doc__,
141
+ "args_schema": UpdateBddContent,
142
+ "ref": self.update_bdd_content,
143
+ },
144
+ {
145
+ "name": "delete_bdd_content",
146
+ "description": self.delete_bdd_content.__doc__,
147
+ "args_schema": Issue,
148
+ "ref": self.delete_bdd_content,
149
+ },
150
+ {
151
+ "name": "create_new_cycle",
152
+ "description": self.create_new_cycle.__doc__,
153
+ "args_schema": CycleJson,
154
+ "ref": self.create_new_cycle,
155
+ },
156
+ {
157
+ "name": "create_folder",
158
+ "description": self.create_folder.__doc__,
159
+ "args_schema": FolderJson,
160
+ "ref": self.create_folder,
161
+ },
162
+ {
163
+ "name": "add_test_to_cycle",
164
+ "description": self.add_test_to_cycle.__doc__,
165
+ "args_schema": TestToCycle,
166
+ "ref": self.add_test_to_cycle,
167
+ },
168
+ {
169
+ "name": "add_test_to_folder",
170
+ "description": self.add_test_to_folder.__doc__,
171
+ "args_schema": TestToFolder,
172
+ "ref": self.add_test_to_folder,
173
+ },
174
+ {
175
+ "name": "create_execution",
176
+ "description": self.create_execution.__doc__,
177
+ "args_schema": ExecutionJson,
178
+ "ref": self.create_execution,
179
+ },
180
+ {
181
+ "name": "get_execution",
182
+ "description": self.get_execution.__doc__,
183
+ "args_schema": GetExecution,
184
+ "ref": self.get_execution,
95
185
  }
96
186
  ]
97
187
 
98
188
 
189
+ Issue = create_model(
190
+ "Issue",
191
+ issue_id=(int, Field(description="Jira ticket id of test case."))
192
+ )
193
+
99
194
  ProjectIssue = create_model(
100
195
  "ProjectIssue",
101
- issue_id=(int, Field(description="Jira ticket id of test case to which the test step belongs.")),
102
- project_id=(int, Field(description="Jira project id to which test case belongs."))
196
+ project_id=(int, Field(description="Jira project id to which test case belongs.")),
197
+ __base__=Issue
103
198
  )
104
199
 
105
200
  ProjectIssueStep = create_model(
@@ -133,3 +228,92 @@ CreateNewTestStep = create_model(
133
228
  "*IMPORTANT*: Use double quotes for all field names and string values."))),
134
229
  __base__=ProjectIssue
135
230
  )
231
+
232
+ UpdateBddContent = create_model(
233
+ "UpdateTestStep",
234
+ new_content=(str, Field(description=(
235
+ "String containing a Gherkin scenario or a feature background.\n"
236
+ "New lines must be encoded as \\n or \\r\\n, and other characters that have special meaning in JSON strings must be escaped accordingly"))),
237
+ __base__=Issue
238
+ )
239
+
240
+ CycleJson = create_model(
241
+ "CycleJson",
242
+ json=(str, Field(description=(
243
+ "JSON body to create a Zephyr test cycle. Fields:\n"
244
+ "- name (string, required): Test cycle name. Example: \"Test Cycle\"\n"
245
+ "- build (string, optional): Build name. Example: \"build 1.0\"\n"
246
+ "- environment (string, optional): Environment name. Example: \"Bug Fix\"\n"
247
+ "- description (string, optional): Cycle description. Example: \"This contains the zephyr tests for a version\"\n"
248
+ "- startDate (long, optional): Start date as a Unix timestamp. Example: 1485278607\n"
249
+ "- endDate (long, optional): End date as a Unix timestamp. Example: 1485302400\n"
250
+ "- projectId (integer, required): Project ID. Example: 10100\n"
251
+ "- versionId (integer, required): Version ID. Example: 10000\n"
252
+ "*IMPORTANT*: Use double quotes for all field names and string values.")))
253
+ )
254
+
255
+ FolderJson = create_model(
256
+ "FolderJson",
257
+ json=(str, Field(description=(
258
+ "JSON body to create a Zephyr folder. Fields:\n"
259
+ "- name (string, required): Folder name. Example: \"Folder 01\"\n"
260
+ "- description (string, optional): Folder description. Example: \"Create New Folder\"\n"
261
+ "- cycleId (string, required): Cycle ID. Example: \"0001513838430954-242ac112-0001\"\n"
262
+ "- projectId (integer, required): Project ID. Example: 10100\n"
263
+ "- versionId (integer, required): Version ID. Example: 10000\n"
264
+ "*IMPORTANT*: Use double quotes for all field names and string values.")))
265
+ )
266
+
267
+ ExecutionJson = create_model(
268
+ "ExecutionJson",
269
+ json=(str, Field(description=(
270
+ "JSON body for Zephyr operation. Fields:\n"
271
+ "- status (object, optional): Status object. Example: {\"id\": 1}\n"
272
+ "- id (string, optional): Unique identifier. Example: \"0001456664462103-5aoee13a3fob-0001\"\n"
273
+ "- projectId (integer, required): Project ID. Example: 10000\n"
274
+ "- issueId (integer, required): Issue ID. Example: 10000\n"
275
+ "- cycleId (string, optional): Cycle ID. Example: \"0001456664262308-5a6ee13a3f6b-0001\"\n"
276
+ "- versionId (integer, required): Version ID. Example: -1\n"
277
+ "- assigneeType (string, optional): \"currentUser\" or \"assignee\". Example: \"assignee\"\n"
278
+ "- assignee (string, optional): Assignee name if assigneeType is \"assignee\". Example: \"jiraUserKey\"\n"
279
+ "*IMPORTANT*: Use double quotes for all field names and string values.")))
280
+ )
281
+
282
+ TestToCycle = create_model(
283
+ "TestToCycle",
284
+ step_id=(str, Field(description="Test step id to operate.")),
285
+ json=(str, Field(description=(
286
+ "JSON body for Zephyr operation. Fields:\n"
287
+ "- issues (array[string], required if method=1): List of Jira issue keys. Example: [\"TEST-1\"]\n"
288
+ "- jql (string, required if method=2): JQL query string. Example: \"project = DEMO AND type = Test AND reporter = admin\"\n"
289
+ "- versionId (integer, required): Version ID. Example: -1\n"
290
+ "- projectId (integer, required): Project ID. Example: 10000\n"
291
+ "- fromVersionId (integer, required if method=3): Source Version ID. Example: -1\n"
292
+ "- fromCycleId (string, required if method=3): Source Cycle ID. Example: \"-0001484006184518-242ac112-0001\"\n"
293
+ "- statuses (string, optional, used when method=3): Statuses. Example: \"-1\"\n"
294
+ "- priorities (string, optional, used when method=3): Priorities (comma-separated). Example: \"1,4\"\n"
295
+ "- labels (string, optional, used when method=3): Labels (comma-separated). Example: \"-High,dock\"\n"
296
+ "- method (string, required): Operation method. Example: \"1\"\n"
297
+ "*IMPORTANT*: Use double quotes for all field names and string values.")))
298
+ )
299
+
300
+ TestToFolder = create_model(
301
+ "TestToFolder",
302
+ step_id=(str, Field(description="folderId of Execution.")),
303
+ json=(str, Field(description=(
304
+ "JSON body to update a Zephyr test step. Fields:\n"
305
+ "- issues (array[string], required): List of Jira issue keys. Example: [\"FSC-2\", \"FSC-3\"]\n"
306
+ "- assigneeType (string, required): Type of assignee. Example: \"currentUser\"\n"
307
+ "- method (integer, required): Method identifier. Example: 1\n"
308
+ "- versionId (integer, required): Version ID. Example: 12829\n"
309
+ "- projectId (integer, required): Project ID. Example: 10930\n"
310
+ "- cycleId (string, required): Cycle ID. Example: \"0001513838430954-242ac112-0001\"\n"
311
+ "*IMPORTANT*: Use double quotes for all field names and string values.")))
312
+ )
313
+
314
+ GetExecution = create_model(
315
+ "GetExecution",
316
+ execution_id=(str, Field(description="executionId of Execution.")),
317
+ issue_id=(int, Field(description="issueId of Execution.")),
318
+ project_id=(int, Field(description="projectId of Execution."))
319
+ )
@@ -1,4 +1,5 @@
1
1
  import hashlib
2
+ import json
2
3
  import time
3
4
 
4
5
  import jwt
@@ -18,44 +19,79 @@ class ZephyrSquadCloud(object):
18
19
  self.base_url = "https://prod-api.zephyr4jiracloud.com/connect"
19
20
 
20
21
  def get_test_step(self, issue_id, step_id, project_id):
21
- canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
22
22
  api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
23
- return self._do_request(method="GET", api_path=api_path, canonical_path=canonical_path)
23
+ return self._do_request(method="GET", api_path=api_path)
24
24
 
25
25
  def update_test_step(self, issue_id, step_id, project_id, json):
26
- canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
27
26
  api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
28
- return self._do_request(method="PUT", api_path=api_path, canonical_path=canonical_path, json=json)
27
+ return self._do_request(method="PUT", api_path=api_path, json=json)
29
28
 
30
29
  def delete_test_step(self, issue_id, step_id, project_id):
31
- canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
32
30
  api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
33
- return self._do_request(method="DELETE", api_path=api_path, canonical_path=canonical_path)
31
+ return self._do_request(method="DELETE", api_path=api_path)
34
32
 
35
33
  def create_new_test_step(self, issue_id, project_id, json):
36
- canonical_path = "/public/rest/api/1.0/teststep/issueId?projectId="
37
34
  api_path = f"/public/rest/api/1.0/teststep/{issue_id}?projectId={project_id}"
38
- return self._do_request(method="POST", api_path=api_path, canonical_path=canonical_path, json=json)
35
+ return self._do_request(method="POST", api_path=api_path, json=json)
39
36
 
40
37
  def get_all_test_steps(self, issue_id, project_id):
41
- canonical_path = "/public/rest/api/2.0/teststep/issueId?projectId="
42
38
  api_path = f"/public/rest/api/2.0/teststep/{issue_id}?projectId={project_id}"
43
- return self._do_request(method='GET', api_path=api_path, canonical_path=canonical_path)
39
+ return self._do_request(method='GET', api_path=api_path)
44
40
 
45
41
  def get_all_test_step_statuses(self):
46
42
  api_path = "/public/rest/api/1.0/teststep/statuses"
47
43
  return self._do_request(method='GET', api_path=api_path)
48
44
 
49
- def _do_request(self, method, api_path, canonical_path=None, json=None):
45
+ def get_bdd_content(self, issue_id):
46
+ api_path = f"/public/rest/api/1.0/integration/bddcontent/{issue_id}"
47
+ return self._do_request(method='GET', api_path=api_path)
48
+
49
+ def update_bdd_content(self, issue_id, new_content: str):
50
+ api_path = f"/public/rest/api/1.0/integration/bddcontent/{issue_id}"
51
+ return self._do_request(method='POST', api_path=api_path, json=json.dumps({"content": new_content}))
52
+
53
+ def delete_bdd_content(self, issue_id):
54
+ api_path = f"/public/rest/api/1.0/integration/bddcontent/{issue_id}"
55
+ return self._do_request(method='DELETE', api_path=api_path, json="[]")
56
+
57
+ def create_new_cycle(self, json):
58
+ api_path = f"public/rest/api/1.0/cycle"
59
+ return self._do_request(method='POST', api_path=api_path, json=json)
60
+
61
+ def create_folder(self, json):
62
+ api_path = f"/public/rest/api/1.0/folder"
63
+ return self._do_request(method='POST', api_path=api_path, json=json)
64
+
65
+ def add_test_to_cycle(self, cycle_id, json):
66
+ api_path = f"/public/rest/api/1.0/executions/add/cycle/{cycle_id}"
67
+ return self._do_request(method='POST', api_path=api_path, json=json)
68
+
69
+ def add_test_to_folder(self, folder_id, json):
70
+ api_path = f"/public/rest/api/1.0/executions/add/folder/{folder_id}"
71
+ return self._do_request(method='POST', api_path=api_path, json=json)
72
+
73
+ def create_execution(self, json):
74
+ api_path = f"/public/rest/api/1.0/execution"
75
+ return self._do_request(method='POST', api_path=api_path, json=json)
76
+
77
+ def get_execution(self, execution_id, issue_id, project_id):
78
+ api_path = f"/public/rest/api/1.0/execution/{execution_id}?issueId={issue_id}&projectId={project_id}"
79
+ return self._do_request(method='GET', api_path=api_path)
80
+
81
+ def _do_request(self, method, api_path, json=None):
50
82
  url = f"{self.base_url}{api_path}"
51
83
  headers = {
52
- "Authorization": f"JWT {self._generate_jwt_token(method, canonical_path or api_path)}",
53
- "zapiAccessKey": self.access_key,
54
- "Content-Type": "application/json"
84
+ "Authorization": f"JWT {self._generate_jwt_token(method, api_path)}",
85
+ "zapiAccessKey": self.access_key
55
86
  }
87
+ if json is not None:
88
+ headers["Content-Type"] = "application/json"
89
+ params = {"method": method, "url": url, "headers": headers}
90
+ if json is not None:
91
+ params["data"] = json
56
92
 
57
93
  try:
58
- resp = requests.request(method=method, url=url, json=json, headers=headers)
94
+ resp = requests.request(**params)
59
95
 
60
96
  if resp.ok:
61
97
  if resp.headers.get("Content-Type", "").startswith("application/json"):
@@ -68,12 +104,16 @@ class ZephyrSquadCloud(object):
68
104
  raise ToolException(f"Error performing request {method}:{api_path}: {e}")
69
105
 
70
106
  def _generate_jwt_token(self, method, path):
71
- canonical_path = f"{method}&{path}&"
107
+ canonical_path = f"{method}&{path}".replace('?', '&')
108
+
109
+ if '&' not in path and '?' not in path:
110
+ canonical_path += '&'
111
+
72
112
  payload_token = {
73
113
  'sub': self.account_id,
74
114
  'qsh': hashlib.sha256(canonical_path.encode('utf-8')).hexdigest(),
75
115
  'iss': self.access_key,
76
- 'exp': int(time.time()) + 3600,
116
+ 'exp': int(time.time()) + 300,
77
117
  'iat': int(time.time())
78
118
  }
79
119
  return jwt.encode(payload_token, self.secret_key, algorithm='HS256').strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.193
3
+ Version: 0.3.195
4
4
  Summary: SDK for building langchain agents using resources from Alita
5
5
  Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedjik@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -63,7 +63,7 @@ alita_sdk/runtime/langchain/tools/bdd_parser/bdd_parser.py,sha256=DiEEOqDef2Xo3x
63
63
  alita_sdk/runtime/langchain/tools/bdd_parser/feature_types.py,sha256=l3AdjSQnNv1CE1NuHi7wts6h6AsCiK-iPu0PnPf3jf0,399
64
64
  alita_sdk/runtime/langchain/tools/bdd_parser/parser.py,sha256=1H1Nd_OH5Wx8A5YV1zUghBxo613yPptZ7fqNo8Eg48M,17289
65
65
  alita_sdk/runtime/llms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
- alita_sdk/runtime/llms/alita.py,sha256=aKvFQgKocwgHm90hngRhkZ6aaHC0-vXKXDWKSdqM6sY,10126
66
+ alita_sdk/runtime/llms/alita.py,sha256=SHKlQ3LVrzISHbDl3BLinvTjPu28EMHuOtvwSYtuQ6c,10130
67
67
  alita_sdk/runtime/llms/preloaded.py,sha256=3AaUbZK3d8fvxAQMjR3ftOoYa0SnkCOL1EvdvDCXIHE,11321
68
68
  alita_sdk/runtime/toolkits/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
69
  alita_sdk/runtime/toolkits/application.py,sha256=akqUuaIL9u7-SsUmS-XgN4qxDEnXFhsK9do4n8inpSo,2432
@@ -120,7 +120,7 @@ alita_sdk/tools/base/tool.py,sha256=-N27AodZS49vdPCgFkU-bFS9bxoPopZBnNrmwInx3d0,
120
120
  alita_sdk/tools/bitbucket/__init__.py,sha256=mPdq25Ib4yP1SV4g1dgK3WD3y-lKyuaNCmcIZTo893w,4355
121
121
  alita_sdk/tools/bitbucket/api_wrapper.py,sha256=iyBaNotbjzhoAOR8WZ9Ue-8vs1J17R5BjnwR2zEbkvM,9721
122
122
  alita_sdk/tools/bitbucket/bitbucket_constants.py,sha256=UsbhQ1iEvrKoxceTFPWTYhaXS1zSxbmjs1TwY0-P4gw,462
123
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py,sha256=KUAt6CB4941nJwvdJqExWedHd8kLWncu3PcAmnS960w,13279
123
+ alita_sdk/tools/bitbucket/cloud_api_wrapper.py,sha256=_ownv-CJ9T15OP4HKCuNbuVQzvoO_8I30-xHqSwRNbc,12920
124
124
  alita_sdk/tools/bitbucket/tools.py,sha256=zKBUq7t9zLa1EvhlVZzyVcZSvwvdcbtz0oslgPFZeeo,15307
125
125
  alita_sdk/tools/browser/__init__.py,sha256=iByi9uMGjd6v44SagIPTm5fu1vWnxIkjn3xsx86uRwI,5249
126
126
  alita_sdk/tools/browser/crawler.py,sha256=jhE35dU94eQLURSM-D50tspOqEMsiGzMDbYNqNSR2mU,2279
@@ -186,7 +186,7 @@ alita_sdk/tools/code/loaders/codesearcher.py,sha256=XoXXZtIQZhvjIwZlnl_4wVGHC-3s
186
186
  alita_sdk/tools/code/sonar/__init__.py,sha256=u8wpgXJ_shToLl3G9-XEtGDor5dhmsnurIImh1-e-U0,3165
187
187
  alita_sdk/tools/code/sonar/api_wrapper.py,sha256=nNqxcWN_6W8c0ckj-Er9HkNuAdgQLoWBXh5UyzNutis,2653
188
188
  alita_sdk/tools/confluence/__init__.py,sha256=1wGSP4CjPbfpdZLsjC1SVftTV7XSvW3QCAMHuh9tIxA,6885
189
- alita_sdk/tools/confluence/api_wrapper.py,sha256=zP8S85oVulhqrom1wlgelN-TSuKtPuYxwwGAlOSn_I0,88776
189
+ alita_sdk/tools/confluence/api_wrapper.py,sha256=WgqiNanj9B5ebmaAWmUT_U_excGUWEguUEFR96K7oYg,89491
190
190
  alita_sdk/tools/confluence/loader.py,sha256=aHqgdIQMqkyRry8feHAhyd-a_ASEyW3JrV6epTRG6-c,9162
191
191
  alita_sdk/tools/confluence/utils.py,sha256=Lxo6dBD0OlvM4o0JuK6qeB_4LV9BptiwJA9e1vqNcDw,435
192
192
  alita_sdk/tools/custom_open_api/__init__.py,sha256=9aT5SPNPWcJC6jMZEM-3rUCXVULj_3-qJLQKmnreKNo,2537
@@ -270,7 +270,7 @@ alita_sdk/tools/sharepoint/__init__.py,sha256=HqKQDFboab1AYh20uJvHxs9HFLJSqVfVTj
270
270
  alita_sdk/tools/sharepoint/api_wrapper.py,sha256=qCHCIH4FRDtgdpIK22ewFhZJeOaTv9hT9BVivslxxlE,7119
271
271
  alita_sdk/tools/sharepoint/authorization_helper.py,sha256=n-nL5dlBoLMK70nHu7P2RYCb8C6c9HMA_gEaw8LxuhE,2007
272
272
  alita_sdk/tools/sharepoint/utils.py,sha256=fZ1YzAu5CTjKSZeslowpOPH974902S8vCp1Wu7L44LM,446
273
- alita_sdk/tools/slack/__init__.py,sha256=Y2sXN1__1923icF8bZbAtKVg3G_EZbCAjnj93yHUwtY,3415
273
+ alita_sdk/tools/slack/__init__.py,sha256=RfOgQqo1ImecVL3LQln2gC9dA9QowJVlAetL15vL5qo,3920
274
274
  alita_sdk/tools/slack/api_wrapper.py,sha256=dkMcS3xozEhoJ-A1ycEn6OqbIftxmVHjyYttTy3D2JI,7343
275
275
  alita_sdk/tools/sql/__init__.py,sha256=9Lh8YHKO8zD5eeolpR4O9swTUsjpXj9LVDn8fM-T5IM,3506
276
276
  alita_sdk/tools/sql/api_wrapper.py,sha256=Rky0_CX9HWDQ2mClHGAgP3LHjYVX4iymPuilZMtaDlQ,3687
@@ -294,11 +294,11 @@ alita_sdk/tools/zephyr_enterprise/api_wrapper.py,sha256=Ir3zHljhbZQJRJJQOBzS_GL5
294
294
  alita_sdk/tools/zephyr_enterprise/zephyr_enterprise.py,sha256=hV9LIrYfJT6oYp-ZfQR0YHflqBFPsUw2Oc55HwK0H48,6809
295
295
  alita_sdk/tools/zephyr_scale/__init__.py,sha256=2NTcdrfkx4GSegqyXhsPLsEpc4FlACuDy85b0fk6cAo,4572
296
296
  alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=UHVQUVqcBc3SZvDfO78HSuBzwAsRw2cCDQa-xMOzndE,68663
297
- alita_sdk/tools/zephyr_squad/__init__.py,sha256=rq4jOb3lRW2GXvAguk4H1KinO5f-zpygzhBJf-E1Ucw,2773
298
- alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=iOMxyE7vOc_LwFB_nBMiSFXkNtvbptA4i-BrTlo7M0A,5854
299
- alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=IYUJoMFOMA70knLhLtAnuGoy3OK80RuqeQZ710oyIxE,3631
300
- alita_sdk-0.3.193.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
301
- alita_sdk-0.3.193.dist-info/METADATA,sha256=_ciaBDZRw_ISqVr3oVPTmZPfE4mkrHSotJeAHvHPiq4,18804
302
- alita_sdk-0.3.193.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
303
- alita_sdk-0.3.193.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
304
- alita_sdk-0.3.193.dist-info/RECORD,,
297
+ alita_sdk/tools/zephyr_squad/__init__.py,sha256=0AI_j27xVO5Gk5HQMFrqPTd4uvuVTpiZUicBrdfEpKg,2796
298
+ alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
299
+ alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
300
+ alita_sdk-0.3.195.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
301
+ alita_sdk-0.3.195.dist-info/METADATA,sha256=XUqYON3Yv7eheVEMka2q1dGZrBlyzZjamd3b8QTot5M,18804
302
+ alita_sdk-0.3.195.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
303
+ alita_sdk-0.3.195.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
304
+ alita_sdk-0.3.195.dist-info/RECORD,,