alita-sdk 0.3.206__py3-none-any.whl → 0.3.207__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.
- alita_sdk/runtime/clients/client.py +269 -6
- alita_sdk/runtime/langchain/langraph_agent.py +6 -1
- alita_sdk/runtime/langchain/store_manager.py +4 -4
- alita_sdk/runtime/toolkits/tools.py +11 -20
- alita_sdk/runtime/utils/streamlit.py +472 -192
- alita_sdk/runtime/utils/toolkit_runtime.py +147 -0
- alita_sdk/runtime/utils/toolkit_utils.py +157 -0
- alita_sdk/tools/memory/__init__.py +54 -10
- {alita_sdk-0.3.206.dist-info → alita_sdk-0.3.207.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.206.dist-info → alita_sdk-0.3.207.dist-info}/RECORD +13 -20
- alita_sdk/community/analysis/__init__.py +0 -0
- alita_sdk/community/analysis/ado_analyse/__init__.py +0 -103
- alita_sdk/community/analysis/ado_analyse/api_wrapper.py +0 -261
- alita_sdk/community/analysis/github_analyse/__init__.py +0 -98
- alita_sdk/community/analysis/github_analyse/api_wrapper.py +0 -166
- alita_sdk/community/analysis/gitlab_analyse/__init__.py +0 -110
- alita_sdk/community/analysis/gitlab_analyse/api_wrapper.py +0 -172
- alita_sdk/community/analysis/jira_analyse/__init__.py +0 -141
- alita_sdk/community/analysis/jira_analyse/api_wrapper.py +0 -252
- {alita_sdk-0.3.206.dist-info → alita_sdk-0.3.207.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.206.dist-info → alita_sdk-0.3.207.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.206.dist-info → alita_sdk-0.3.207.dist-info}/top_level.txt +0 -0
@@ -1,172 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from typing import Any
|
3
|
-
from pydantic import BaseModel, Field
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
from elitea_analyse.git.main import (
|
7
|
-
get_git_projects_list,
|
8
|
-
get_git_projects_that_in_jira,
|
9
|
-
get_git_commits,
|
10
|
-
get_git_merge_requests,
|
11
|
-
)
|
12
|
-
from elitea_analyse.git.git_search import GitLabV4Search
|
13
|
-
|
14
|
-
|
15
|
-
from alita_sdk.tools.elitea_base import BaseToolApiWrapper
|
16
|
-
from alita_sdk.runtime.utils.save_dataframe import save_dataframe_to_artifact
|
17
|
-
from alita_sdk.runtime.tools.artifact import ArtifactWrapper
|
18
|
-
|
19
|
-
|
20
|
-
logger = logging.getLogger(__name__)
|
21
|
-
|
22
|
-
|
23
|
-
class GitLabProjectsListArgs(BaseModel):
|
24
|
-
date: str = Field(
|
25
|
-
description="Filter projects by last activity date in 'YYYY-MM-DD' format."
|
26
|
-
)
|
27
|
-
|
28
|
-
class GitLabProjectsListInJiraArgs(BaseModel):
|
29
|
-
jira_project_keys: Optional[str] = Field(description="Comma-separated Jira project keys.", default=None)
|
30
|
-
|
31
|
-
class GitLabCommitsArgs(BaseModel):
|
32
|
-
project_ids: Optional[str] = Field(description="GitLab project ID.", default=None)
|
33
|
-
since_date:str = Field(description="Date filter in 'YYYY-MM-DD' format.")
|
34
|
-
|
35
|
-
|
36
|
-
class GitLabAnalyseWrapper(BaseToolApiWrapper):
|
37
|
-
artifacts_wrapper: ArtifactWrapper
|
38
|
-
project_ids: str # Comma-separated list of GitLab project IDs
|
39
|
-
jira_project_keys: str # Comma-separated list of Jira projects' keys
|
40
|
-
gitlab_search: GitLabV4Search # GitLab search client
|
41
|
-
|
42
|
-
class Config:
|
43
|
-
arbitrary_types_allowed = True
|
44
|
-
|
45
|
-
def get_gitlab_projects_list(self, date: str) -> str:
|
46
|
-
"""
|
47
|
-
Get projects list that user has access to in GitLab.
|
48
|
-
|
49
|
-
date: str
|
50
|
-
Filter projects by last activity date.
|
51
|
-
Date in 'YYYY-MM-DD' format.
|
52
|
-
"""
|
53
|
-
|
54
|
-
df_project_list = get_git_projects_list(date, git=self.gitlab_search)
|
55
|
-
|
56
|
-
save_dataframe_to_artifact(
|
57
|
-
self.artifacts_wrapper, df_project_list, "gitlab_projects_info.csv", csv_options={"index": False}
|
58
|
-
)
|
59
|
-
|
60
|
-
return (
|
61
|
-
f"You have access to {len(df_project_list)}. "
|
62
|
-
f"Data has been downloaded to the bucket as 'gitlab_projects_info.csv'"
|
63
|
-
)
|
64
|
-
|
65
|
-
def get_gitlab_projects_that_in_jira(self, jira_project_keys: Optional[str] = None) -> str:
|
66
|
-
"""
|
67
|
-
Find GitLab projects that correspond to Jira projects by matching names.
|
68
|
-
|
69
|
-
jira_project_keys: str
|
70
|
-
Comma-separated Jira project keys.
|
71
|
-
"""
|
72
|
-
jira_project_keys = jira_project_keys or self.jira_project_keys
|
73
|
-
df_projects = get_git_projects_that_in_jira(
|
74
|
-
jira_project_keys, git=self.gitlab_search)
|
75
|
-
|
76
|
-
if df_projects is None or df_projects.empty:
|
77
|
-
return "No GitLab projects found that match the provided Jira project keys."
|
78
|
-
|
79
|
-
save_dataframe_to_artifact(
|
80
|
-
self.artifacts_wrapper, df_projects, "gitlab_projects_that_in_Jira.csv", csv_options={"index": False},
|
81
|
-
)
|
82
|
-
|
83
|
-
return (
|
84
|
-
f"Found {len(df_projects)} GitLab projects that match Jira project names. "
|
85
|
-
f"Data has been downloaded to the bucket as 'gitlab_projects_that_in_Jira.csv'."
|
86
|
-
)
|
87
|
-
|
88
|
-
def get_gitlab_commits(self, since_date: str, project_ids: Optional[str] = None) -> str:
|
89
|
-
"""
|
90
|
-
Get commit data for specified GitLab project.
|
91
|
-
|
92
|
-
project_id: str
|
93
|
-
GitLab project ID.
|
94
|
-
since_date: str
|
95
|
-
Date filter in 'YYYY-MM-DD' format.
|
96
|
-
"""
|
97
|
-
project_ids = project_ids or self.project_ids
|
98
|
-
df_commits = get_git_commits(
|
99
|
-
project_ids, since_date, git_search=self.gitlab_search
|
100
|
-
)
|
101
|
-
|
102
|
-
if df_commits is None or df_commits.empty:
|
103
|
-
return f'There are no commits in the project {project_ids} created after {since_date}'
|
104
|
-
|
105
|
-
save_dataframe_to_artifact(
|
106
|
-
self.artifacts_wrapper, df_commits, f"commits_details_{project_ids}.csv", csv_options={"index": False},
|
107
|
-
)
|
108
|
-
|
109
|
-
return (
|
110
|
-
f"Commits data for project {project_ids} has been saved. "
|
111
|
-
f"Data has been downloaded to the bucket as 'commits_details_{project_ids}.csv'."
|
112
|
-
)
|
113
|
-
|
114
|
-
def get_gitlab_merge_requests(self, since_date: str, project_ids: Optional[str] = None) -> str:
|
115
|
-
"""
|
116
|
-
Get merge requests for specified GitLab project.
|
117
|
-
|
118
|
-
project_ids: str
|
119
|
-
GitLab project ID.
|
120
|
-
since_date: str
|
121
|
-
Date filter in 'YYYY-MM-DD' format.
|
122
|
-
"""
|
123
|
-
project_ids = project_ids or self.project_ids
|
124
|
-
df_mrs = get_git_merge_requests(
|
125
|
-
project_ids, since_date, git_search=self.gitlab_search)
|
126
|
-
|
127
|
-
if df_mrs is None or df_mrs.empty:
|
128
|
-
return f'There are no merge requests in the project {project_ids} created after {since_date}'
|
129
|
-
|
130
|
-
save_dataframe_to_artifact(
|
131
|
-
self.artifacts_wrapper, df_mrs, f"merge_requests_details_{project_ids}.csv", csv_options={"index": False},
|
132
|
-
)
|
133
|
-
|
134
|
-
return (
|
135
|
-
f"Merge requests data for project {project_ids} has been saved. "
|
136
|
-
f"Data has been downloaded to the bucket as 'merge_requests_details_{project_ids}.csv'."
|
137
|
-
)
|
138
|
-
|
139
|
-
|
140
|
-
def get_available_tools(self):
|
141
|
-
return [
|
142
|
-
{
|
143
|
-
"name": "get_gitlab_projects_list",
|
144
|
-
"description": self.get_gitlab_projects_list.__doc__,
|
145
|
-
"args_schema": GitLabProjectsListArgs ,
|
146
|
-
"ref": self.get_gitlab_projects_list
|
147
|
-
},
|
148
|
-
{
|
149
|
-
"name": "get_gitlab_projects_that_in_jira",
|
150
|
-
"description": self.get_gitlab_projects_that_in_jira.__doc__,
|
151
|
-
"args_schema": GitLabProjectsListInJiraArgs,
|
152
|
-
"ref": self.get_gitlab_projects_that_in_jira
|
153
|
-
},
|
154
|
-
{
|
155
|
-
"name": "get_gitlab_commits",
|
156
|
-
"description": self.get_gitlab_commits.__doc__,
|
157
|
-
"args_schema": GitLabCommitsArgs,
|
158
|
-
"ref": self.get_gitlab_commits
|
159
|
-
},
|
160
|
-
{
|
161
|
-
"name": "get_gitlab_merge_requests",
|
162
|
-
"description": self.get_gitlab_merge_requests.__doc__,
|
163
|
-
"args_schema": GitLabCommitsArgs,
|
164
|
-
"ref": self.get_gitlab_merge_requests
|
165
|
-
}
|
166
|
-
]
|
167
|
-
|
168
|
-
def run(self, mode: str, *args: Any, **kwargs: Any):
|
169
|
-
for tool in self.get_available_tools():
|
170
|
-
if tool["name"] == mode:
|
171
|
-
return tool["ref"](*args, **kwargs)
|
172
|
-
raise ValueError(f"Unknown mode: {mode}")
|
@@ -1,141 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from typing import List, Optional, Literal
|
3
|
-
from pydantic import create_model, BaseModel, ConfigDict, Field
|
4
|
-
|
5
|
-
from langchain_core.tools import BaseTool, BaseToolkit
|
6
|
-
|
7
|
-
from elitea_analyse.jira.jira_connect import connect_to_jira
|
8
|
-
from alita_sdk.tools.utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
|
9
|
-
from alita_sdk.tools.base.tool import BaseAction
|
10
|
-
from alita_sdk.runtime.clients.client import AlitaClient
|
11
|
-
from alita_sdk.runtime.tools.artifact import ArtifactWrapper
|
12
|
-
from .api_wrapper import JiraAnalyseWrapper
|
13
|
-
|
14
|
-
from ...utils import check_schema
|
15
|
-
|
16
|
-
name = "Analyse_Jira"
|
17
|
-
|
18
|
-
class AnalyseJira(BaseToolkit):
|
19
|
-
tools: List[BaseTool] = []
|
20
|
-
toolkit_max_length: int = 0
|
21
|
-
|
22
|
-
@staticmethod
|
23
|
-
def toolkit_config_schema() -> type[BaseModel]:
|
24
|
-
selected_tools = {x['name']: x['args_schema'].schema() for x in
|
25
|
-
JiraAnalyseWrapper.model_construct().get_available_tools()}
|
26
|
-
AnalyseJira.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
27
|
-
return create_model(
|
28
|
-
"analyse_jira",
|
29
|
-
jira_base_url=(str, Field(
|
30
|
-
description="Jira URL",
|
31
|
-
json_schema_extra={
|
32
|
-
'toolkit_name': True,
|
33
|
-
'max_toolkit_length': AnalyseJira.toolkit_max_length
|
34
|
-
})
|
35
|
-
),
|
36
|
-
jira_cloud=(bool, Field(description="Hosting Option")),
|
37
|
-
jira_username=(str, Field(description="Jira Username")),
|
38
|
-
jira_api_key=(Optional[str], Field(description="API key", json_schema_extra={'secret': True}, default="")),
|
39
|
-
jira_token=(Optional[str], Field(description="Jira token", json_schema_extra={'secret': True}, default="")),
|
40
|
-
# TODO: Add these fields to the schema as custom fields comma-separated if required
|
41
|
-
project_keys=(Optional[str], Field(description="Jira project keys separated by comma", default=None)),
|
42
|
-
team_field=(Optional[str], Field(description="Jira field used as identifier for team", default="")),
|
43
|
-
environment_field=(Optional[str], Field(description="Jira field used as identifier for environment", default="")),
|
44
|
-
defects_name=(Optional[str], Field(description="Jira defects type", default="")),
|
45
|
-
closed_status=(Optional[str], Field(description="Jira closed status", default="")),
|
46
|
-
jira_verify_ssl=(bool, Field(description="Verify SSL")),
|
47
|
-
jira_custom_fields=(Optional[dict], Field(description="Additional fields, split by comma", default={})),
|
48
|
-
artifact_bucket_path=(Optional[str], Field(description="Artifact Bucket Path", default="")),
|
49
|
-
selected_tools=(List[Literal[tuple(selected_tools)]],
|
50
|
-
Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
51
|
-
__config__=ConfigDict(json_schema_extra={'metadata':
|
52
|
-
{
|
53
|
-
"label": "Analyse_Jira",
|
54
|
-
"icon_url": "jira-icon.svg",
|
55
|
-
"hidden": False,
|
56
|
-
"sections": {
|
57
|
-
"auth": {
|
58
|
-
"required": True,
|
59
|
-
"subsections": [
|
60
|
-
{
|
61
|
-
"name": "Api key",
|
62
|
-
"fields": ["jira_api_key"]
|
63
|
-
},
|
64
|
-
{
|
65
|
-
"name": "Token",
|
66
|
-
"fields": ["jira_token"]
|
67
|
-
}
|
68
|
-
]
|
69
|
-
}
|
70
|
-
}
|
71
|
-
}
|
72
|
-
})
|
73
|
-
)
|
74
|
-
|
75
|
-
@classmethod
|
76
|
-
def get_toolkit(cls, client: "AlitaClient", selected_tools: list[str], **kwargs):
|
77
|
-
if selected_tools is None:
|
78
|
-
selected_tools = []
|
79
|
-
|
80
|
-
bucket_path = kwargs.get('artifact_bucket_path') or 'analyse-jira'
|
81
|
-
artifact_wrapper = ArtifactWrapper(
|
82
|
-
client=client, bucket=bucket_path
|
83
|
-
)
|
84
|
-
check_schema(artifact_wrapper)
|
85
|
-
|
86
|
-
project_keys = kwargs.get('project_keys') or ''
|
87
|
-
|
88
|
-
jira_base_url = kwargs.get('jira_base_url')
|
89
|
-
jira_verify_ssl = kwargs.get('jira_verify_ssl')
|
90
|
-
jira_username = kwargs.get('jira_username')
|
91
|
-
jira_token = kwargs.get('jira_token')
|
92
|
-
jira_api_key = kwargs.get('jira_api_key')
|
93
|
-
|
94
|
-
jira_custom_fields = kwargs.get('jira_custom_fields', {})
|
95
|
-
jira_custom_fields['team'] = kwargs.get('team_field', '')
|
96
|
-
jira_custom_fields['environment'] = kwargs.get('environment_field', '')
|
97
|
-
closed_status = kwargs.get('closed_status', '')
|
98
|
-
defects_name = kwargs.get('defects_name', '')
|
99
|
-
|
100
|
-
jira_credentials = {
|
101
|
-
"username": jira_username,
|
102
|
-
"base_url": jira_base_url,
|
103
|
-
"token": jira_token,
|
104
|
-
"api_key": jira_api_key,
|
105
|
-
"verify_ssl": jira_verify_ssl
|
106
|
-
}
|
107
|
-
|
108
|
-
jira = connect_to_jira(credentials=jira_credentials)
|
109
|
-
if not jira:
|
110
|
-
raise ValueError(
|
111
|
-
"Failed to connect to Jira. Please check your credentials."
|
112
|
-
)
|
113
|
-
|
114
|
-
api_wrapper = JiraAnalyseWrapper(
|
115
|
-
artifacts_wrapper=artifact_wrapper,
|
116
|
-
jira=jira,
|
117
|
-
project_keys=project_keys,
|
118
|
-
closed_status=closed_status,
|
119
|
-
defects_name=defects_name,
|
120
|
-
custom_fields=jira_custom_fields,
|
121
|
-
)
|
122
|
-
|
123
|
-
tools = []
|
124
|
-
available_tools = api_wrapper.get_available_tools()
|
125
|
-
for tool in available_tools:
|
126
|
-
if selected_tools:
|
127
|
-
if tool["name"] not in selected_tools:
|
128
|
-
continue
|
129
|
-
tools.append(
|
130
|
-
BaseAction(
|
131
|
-
api_wrapper=api_wrapper,
|
132
|
-
name=tool["name"],
|
133
|
-
description=tool["description"],
|
134
|
-
args_schema=tool["args_schema"],
|
135
|
-
)
|
136
|
-
)
|
137
|
-
|
138
|
-
return cls(tools=tools)
|
139
|
-
|
140
|
-
def get_tools(self):
|
141
|
-
return self.tools
|
@@ -1,252 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from io import StringIO
|
3
|
-
from typing import Optional, List, Dict, Any
|
4
|
-
from langchain_core.callbacks import dispatch_custom_event
|
5
|
-
from langchain_core.tools import ToolException
|
6
|
-
from pydantic import BaseModel, Field
|
7
|
-
from jira import JIRA
|
8
|
-
import pandas as pd
|
9
|
-
|
10
|
-
|
11
|
-
from elitea_analyse.utils.constants import OUTPUT_MAPPING_FILE, OUTPUT_WORK_ITEMS_FILE
|
12
|
-
from elitea_analyse.jira.jira_projects_overview import jira_projects_overview
|
13
|
-
from elitea_analyse.jira.jira_statuses import get_all_statuses_list
|
14
|
-
from elitea_analyse.jira.jira_issues import JiraIssues
|
15
|
-
|
16
|
-
from alita_sdk.tools.elitea_base import BaseToolApiWrapper
|
17
|
-
from alita_sdk.runtime.tools.artifact import ArtifactWrapper
|
18
|
-
from alita_sdk.runtime.utils.logging import with_streamlit_logs
|
19
|
-
|
20
|
-
logger = logging.getLogger(__name__)
|
21
|
-
|
22
|
-
|
23
|
-
class GetJiraFieldsArgs(BaseModel):
|
24
|
-
project_keys: Optional[str] = Field(
|
25
|
-
description="One or more projects keys separated with comma.",
|
26
|
-
default=''
|
27
|
-
)
|
28
|
-
after_date: str = Field(description="Date after which issues are considered.")
|
29
|
-
|
30
|
-
|
31
|
-
class GetJiraIssuesArgs(BaseModel):
|
32
|
-
project_keys: Optional[str] = Field(
|
33
|
-
description="One or more projects keys separated with comma.", default=''
|
34
|
-
)
|
35
|
-
closed_issues_based_on: int = Field(
|
36
|
-
description=("Define whether issues can be thought as closed based on their status (1) "
|
37
|
-
"or not empty resolved date (2).")
|
38
|
-
)
|
39
|
-
resolved_after: str = Field(description="Resolved after date (i.e. 2023-01-01).")
|
40
|
-
updated_after: str = Field(description="Updated after date (i.e. 2023-01-01).")
|
41
|
-
created_after: str = Field(description="Created after date (i.e. 2023-01-01).")
|
42
|
-
add_filter: Optional[str] = Field(
|
43
|
-
description=("Additional filter for Jira issues in JQL format like "
|
44
|
-
"'customfield_10000 = 'value' AND customfield_10001 = 'value'")
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
class JiraAnalyseWrapper(BaseToolApiWrapper):
|
49
|
-
artifacts_wrapper: ArtifactWrapper
|
50
|
-
jira: JIRA
|
51
|
-
project_keys: str # Jira project keys
|
52
|
-
closed_status: str # Jira ticket closed statuses
|
53
|
-
defects_name: str # Jira ticket defects name
|
54
|
-
custom_fields: dict # Jira ticket custom fields
|
55
|
-
|
56
|
-
class Config:
|
57
|
-
arbitrary_types_allowed = True
|
58
|
-
|
59
|
-
def get_number_off_all_issues(self, after_date: str, project_keys: Optional[str] = None):
|
60
|
-
"""
|
61
|
-
Get projects a user has access to and merge them with issues count.
|
62
|
-
after_date: str
|
63
|
-
date after which issues are considered
|
64
|
-
project_keys: str
|
65
|
-
one or more projects keys separated with comma
|
66
|
-
"""
|
67
|
-
project_keys = project_keys or self.project_keys
|
68
|
-
|
69
|
-
dispatch_custom_event(
|
70
|
-
name="thinking_step",
|
71
|
-
data={
|
72
|
-
"message": f"I am extracting number of all issues with initial parameters:\
|
73
|
-
project keys: {project_keys}, after date: {after_date}",
|
74
|
-
"tool_name": "get_number_off_all_issues",
|
75
|
-
"toolkit": "analyse_jira",
|
76
|
-
},
|
77
|
-
)
|
78
|
-
|
79
|
-
project_df = jira_projects_overview(
|
80
|
-
after_date, project_keys=project_keys, jira=self.jira
|
81
|
-
)
|
82
|
-
|
83
|
-
# Save project_df DataFrame into the bucket
|
84
|
-
self.save_dataframe(
|
85
|
-
project_df,
|
86
|
-
f"projects_overview_{project_keys}.csv",
|
87
|
-
csv_options={"index": False},
|
88
|
-
)
|
89
|
-
return {
|
90
|
-
"projects": project_df["key"].tolist(),
|
91
|
-
"projects_summary": project_df.to_string(),
|
92
|
-
}
|
93
|
-
|
94
|
-
@with_streamlit_logs(tool_name="get_jira_issues")
|
95
|
-
def get_jira_issues(
|
96
|
-
self,
|
97
|
-
closed_issues_based_on: int,
|
98
|
-
resolved_after: str,
|
99
|
-
updated_after: str,
|
100
|
-
created_after: str,
|
101
|
-
add_filter: str = "",
|
102
|
-
project_keys: Optional[str] = None,
|
103
|
-
):
|
104
|
-
"""
|
105
|
-
Extract Jira issues for the specified projects.
|
106
|
-
closed_issues_based_on: int
|
107
|
-
define whether issues can be thought as
|
108
|
-
closed based on their status (1) or not empty resolved date (2)
|
109
|
-
resolved_after: str
|
110
|
-
resolved after date (i.e. 2023-01-01)
|
111
|
-
updated_after: str
|
112
|
-
updated after date (i.e. 2023-01-01)
|
113
|
-
created_after: str
|
114
|
-
created after date (i.e. 2023-01-01)
|
115
|
-
add_filter: str
|
116
|
-
additional filter for Jira issues in JQL format
|
117
|
-
like "customfield_10000 = 'value' AND customfield_10001 = 'value'"
|
118
|
-
project_keys: str
|
119
|
-
one or more projects keys separated with comma
|
120
|
-
"""
|
121
|
-
|
122
|
-
if not (
|
123
|
-
(
|
124
|
-
closed_issues_based_on == 1
|
125
|
-
and self.closed_status in get_all_statuses_list(jira=self.jira)
|
126
|
-
)
|
127
|
-
or closed_issues_based_on == 2
|
128
|
-
):
|
129
|
-
return (
|
130
|
-
f"ERROR: Check input parameters closed_issues_based_on ({closed_issues_based_on}) "
|
131
|
-
f"and closed_status ({self.closed_status}) not in Jira statuses list."
|
132
|
-
)
|
133
|
-
|
134
|
-
project_keys = project_keys or self.project_keys
|
135
|
-
|
136
|
-
dispatch_custom_event(
|
137
|
-
name="thinking_step",
|
138
|
-
data={
|
139
|
-
"message": f"I am extracting Jira issues with initial parameters:\
|
140
|
-
project keys: {project_keys}, closed status: {self.closed_status},\
|
141
|
-
defects name: {self.defects_name}, custom fields: {self.custom_fields}, \
|
142
|
-
closed status based on: {closed_issues_based_on}, resolved after: {resolved_after}, \
|
143
|
-
updated after: {updated_after}, created after: {created_after}, additional filter:{add_filter}",
|
144
|
-
"tool_name": "jira_issues_extraction_start",
|
145
|
-
"toolkit": "analyse_jira",
|
146
|
-
},
|
147
|
-
)
|
148
|
-
|
149
|
-
jira_issues = JiraIssues(
|
150
|
-
self.jira,
|
151
|
-
project_keys,
|
152
|
-
(closed_issues_based_on, self.closed_status),
|
153
|
-
self.defects_name,
|
154
|
-
add_filter="",
|
155
|
-
)
|
156
|
-
|
157
|
-
df_issues, df_map = jira_issues.extract_issues_from_jira_and_transform(
|
158
|
-
self.custom_fields, (resolved_after, updated_after, created_after)
|
159
|
-
)
|
160
|
-
|
161
|
-
dispatch_custom_event(
|
162
|
-
name="thinking_step",
|
163
|
-
data={
|
164
|
-
"message": f"I am saving the extracted Jira issues to the artifact repository. \
|
165
|
-
issues count: {len(df_issues)}, mapping rows: {len(df_map)}, \
|
166
|
-
output file: {OUTPUT_MAPPING_FILE}{jira_issues.projects}.csv",
|
167
|
-
"tool_name": "get_jira_issues",
|
168
|
-
"toolkit": "analyse_jira",
|
169
|
-
},
|
170
|
-
)
|
171
|
-
self.save_dataframe(
|
172
|
-
df_map,
|
173
|
-
f"{OUTPUT_MAPPING_FILE}{jira_issues.projects}.csv",
|
174
|
-
csv_options={"index_label": "id"},
|
175
|
-
)
|
176
|
-
|
177
|
-
if not df_issues.empty:
|
178
|
-
self.save_dataframe(
|
179
|
-
df_issues,
|
180
|
-
f"{OUTPUT_WORK_ITEMS_FILE}{jira_issues.projects}.csv",
|
181
|
-
csv_options={"index_label": "id"},
|
182
|
-
)
|
183
|
-
dispatch_custom_event(
|
184
|
-
name="thinking_step",
|
185
|
-
data={
|
186
|
-
"message": f"Saving Jira issues to the file . \
|
187
|
-
output file: {OUTPUT_WORK_ITEMS_FILE}{jira_issues.projects}.csv,\
|
188
|
-
row count: {len(df_issues)}",
|
189
|
-
"tool_name": "get_jira_issues",
|
190
|
-
"toolkit": "analyse_jira",
|
191
|
-
},
|
192
|
-
)
|
193
|
-
|
194
|
-
return f"{jira_issues.projects} Data has been extracted successfully."
|
195
|
-
|
196
|
-
def get_available_tools(self) -> List[Dict[str, Any]]:
|
197
|
-
"""Get a list of available tools."""
|
198
|
-
return [
|
199
|
-
{
|
200
|
-
"name": "get_number_off_all_issues",
|
201
|
-
"description": self.get_number_off_all_issues.__doc__,
|
202
|
-
"args_schema": GetJiraFieldsArgs,
|
203
|
-
"ref": self.get_number_off_all_issues,
|
204
|
-
},
|
205
|
-
{
|
206
|
-
"name": "get_jira_issues",
|
207
|
-
"description": self.get_jira_issues.__doc__,
|
208
|
-
"args_schema": GetJiraIssuesArgs,
|
209
|
-
"ref": self.get_jira_issues,
|
210
|
-
},
|
211
|
-
]
|
212
|
-
|
213
|
-
def save_dataframe(
|
214
|
-
self,
|
215
|
-
df: pd.DataFrame,
|
216
|
-
target_file: str,
|
217
|
-
csv_options: Optional[Dict[str, Any]] = None,
|
218
|
-
):
|
219
|
-
"""
|
220
|
-
Save a pandas DataFrame as a CSV file in the artifact repository using the ArtifactWrapper.
|
221
|
-
|
222
|
-
Args:
|
223
|
-
df (pd.DataFrame): The DataFrame to save.
|
224
|
-
target_file (str): The target file name in the storage (e.g., "file.csv").
|
225
|
-
csv_options: Dictionary of options to pass to Dataframe.to_csv()
|
226
|
-
|
227
|
-
Raises:
|
228
|
-
ValueError: If the DataFrame is empty or the file name is invalid.
|
229
|
-
Exception: If saving to the artifact repository fails.
|
230
|
-
"""
|
231
|
-
csv_options = csv_options or {}
|
232
|
-
|
233
|
-
# Use StringIO to save the DataFrame as a string
|
234
|
-
try:
|
235
|
-
buffer = StringIO()
|
236
|
-
df.to_csv(buffer, **csv_options)
|
237
|
-
self.artifacts_wrapper.create_file(target_file, buffer.getvalue())
|
238
|
-
logger.info(
|
239
|
-
f"Successfully saved dataframe to {target_file} in bucket {self.artifacts_wrapper.bucket}"
|
240
|
-
)
|
241
|
-
except Exception as e:
|
242
|
-
logger.exception("Failed to save DataFrame to artifact repository")
|
243
|
-
return ToolException(
|
244
|
-
f"Failed to save DataFrame to artifact repository: {str(e)}"
|
245
|
-
)
|
246
|
-
|
247
|
-
def run(self, mode: str, *args: Any, **kwargs: Any):
|
248
|
-
for tool in self.get_available_tools():
|
249
|
-
if tool["name"] == mode:
|
250
|
-
return tool["ref"](*args, **kwargs)
|
251
|
-
|
252
|
-
raise ValueError(f"Unknown mode: {mode}")
|
File without changes
|
File without changes
|
File without changes
|