MindsDB 25.4.4.0__py3-none-any.whl → 25.5.3.0__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 MindsDB might be problematic. Click here for more details.
- mindsdb/__about__.py +1 -1
- mindsdb/__main__.py +107 -125
- mindsdb/api/executor/command_executor.py +14 -3
- mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +8 -0
- mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +2 -1
- mindsdb/api/executor/datahub/datanodes/system_tables.py +10 -13
- mindsdb/api/executor/planner/query_plan.py +1 -0
- mindsdb/api/executor/planner/query_planner.py +9 -1
- mindsdb/api/executor/sql_query/sql_query.py +24 -8
- mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +21 -3
- mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +3 -1
- mindsdb/api/http/initialize.py +20 -3
- mindsdb/api/http/namespaces/analysis.py +14 -1
- mindsdb/api/http/namespaces/config.py +19 -11
- mindsdb/api/http/namespaces/tree.py +1 -1
- mindsdb/api/http/start.py +7 -2
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +4 -8
- mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -4
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +2 -2
- mindsdb/integrations/handlers/bigquery_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/chromadb_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/gmail_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/google_analytics_handler/requirements.txt +2 -1
- mindsdb/integrations/handlers/google_books_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_calendar_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/google_content_shopping_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_fit_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/google_search_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/jira_handler/jira_handler.archived.py +75 -0
- mindsdb/integrations/handlers/jira_handler/jira_handler.py +113 -38
- mindsdb/integrations/handlers/jira_handler/jira_tables.py +229 -0
- mindsdb/integrations/handlers/jira_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/lightfm_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -2
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
- mindsdb/integrations/handlers/lindorm_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/ms_one_drive_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/ms_teams_handler/requirements.txt +3 -1
- mindsdb/integrations/handlers/openai_handler/helpers.py +3 -5
- mindsdb/integrations/handlers/openai_handler/openai_handler.py +25 -12
- mindsdb/integrations/handlers/snowflake_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/togetherai_handler/__about__.py +9 -0
- mindsdb/integrations/handlers/togetherai_handler/__init__.py +20 -0
- mindsdb/integrations/handlers/togetherai_handler/creation_args.py +14 -0
- mindsdb/integrations/handlers/togetherai_handler/icon.svg +15 -0
- mindsdb/integrations/handlers/togetherai_handler/model_using_args.py +5 -0
- mindsdb/integrations/handlers/togetherai_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/togetherai_handler/settings.py +33 -0
- mindsdb/integrations/handlers/togetherai_handler/togetherai_handler.py +234 -0
- mindsdb/integrations/handlers/vertex_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/youtube_handler/requirements.txt +1 -0
- mindsdb/integrations/utilities/files/file_reader.py +5 -2
- mindsdb/integrations/utilities/handler_utils.py +4 -0
- mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +360 -0
- mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +6 -346
- mindsdb/interfaces/agents/constants.py +14 -2
- mindsdb/interfaces/agents/langchain_agent.py +2 -4
- mindsdb/interfaces/database/projects.py +1 -7
- mindsdb/interfaces/functions/controller.py +14 -16
- mindsdb/interfaces/functions/to_markdown.py +9 -124
- mindsdb/interfaces/knowledge_base/controller.py +109 -92
- mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +28 -5
- mindsdb/interfaces/knowledge_base/utils.py +10 -15
- mindsdb/interfaces/model/model_controller.py +0 -2
- mindsdb/interfaces/query_context/context_controller.py +55 -15
- mindsdb/interfaces/query_context/query_task.py +19 -0
- mindsdb/interfaces/skills/sql_agent.py +33 -11
- mindsdb/interfaces/storage/db.py +2 -2
- mindsdb/interfaces/tasks/task_monitor.py +5 -1
- mindsdb/interfaces/tasks/task_thread.py +6 -0
- mindsdb/migrations/migrate.py +0 -2
- mindsdb/migrations/versions/2025-04-22_53502b6d63bf_query_database.py +27 -0
- mindsdb/utilities/config.py +15 -3
- mindsdb/utilities/context.py +2 -1
- mindsdb/utilities/functions.py +0 -36
- mindsdb/utilities/langfuse.py +19 -10
- mindsdb/utilities/otel/__init__.py +9 -193
- mindsdb/utilities/otel/metric_handlers/__init__.py +5 -1
- mindsdb/utilities/otel/prepare.py +198 -0
- mindsdb/utilities/sql.py +83 -0
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/METADATA +662 -592
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/RECORD +85 -69
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/WHEEL +1 -1
- mindsdb/api/mysql/mysql_proxy/classes/sql_statement_parser.py +0 -151
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/top_level.txt +0 -0
|
@@ -27,33 +27,41 @@ class GetConfig(Resource):
|
|
|
27
27
|
@api_endpoint_metrics('GET', '/config')
|
|
28
28
|
def get(self):
|
|
29
29
|
config = Config()
|
|
30
|
-
|
|
30
|
+
resp = {
|
|
31
31
|
'auth': {
|
|
32
32
|
'http_auth_enabled': config['auth']['http_auth_enabled']
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
for key in ['default_llm', 'default_embedding_model']:
|
|
36
|
+
value = config.get(key)
|
|
37
|
+
if value is not None:
|
|
38
|
+
resp[key] = value
|
|
39
|
+
return resp
|
|
35
40
|
|
|
36
41
|
@ns_conf.doc('put_config')
|
|
37
42
|
@api_endpoint_metrics('PUT', '/config')
|
|
38
43
|
def put(self):
|
|
39
44
|
data = request.json
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
allowed_arguments = {'auth', 'default_llm', 'default_embedding_model'}
|
|
47
|
+
unknown_arguments = list(set(data.keys()) - allowed_arguments)
|
|
48
|
+
if len(unknown_arguments) > 0:
|
|
43
49
|
return http_error(
|
|
44
50
|
HTTPStatus.BAD_REQUEST, 'Wrong arguments',
|
|
45
|
-
f'Unknown argumens: {
|
|
51
|
+
f'Unknown argumens: {unknown_arguments}'
|
|
46
52
|
)
|
|
47
53
|
|
|
54
|
+
nested_keys_to_validate = {'auth'}
|
|
48
55
|
for key in data.keys():
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if len(unknown_argumens) > 0:
|
|
53
|
-
return http_error(
|
|
54
|
-
HTTPStatus.BAD_REQUEST, 'Wrong arguments',
|
|
55
|
-
f'Unknown argumens: {unknown_argumens}'
|
|
56
|
+
if key in nested_keys_to_validate:
|
|
57
|
+
unknown_arguments = list(
|
|
58
|
+
set(data[key].keys()) - set(Config()[key].keys())
|
|
56
59
|
)
|
|
60
|
+
if len(unknown_arguments) > 0:
|
|
61
|
+
return http_error(
|
|
62
|
+
HTTPStatus.BAD_REQUEST, 'Wrong arguments',
|
|
63
|
+
f'Unknown argumens: {unknown_arguments}'
|
|
64
|
+
)
|
|
57
65
|
|
|
58
66
|
Config().update(data)
|
|
59
67
|
|
|
@@ -94,7 +94,7 @@ class GetLeaf(Resource):
|
|
|
94
94
|
} for key, val in schemas.items()]
|
|
95
95
|
elif db['type'] == 'system':
|
|
96
96
|
system_db = ca.database_controller.get_system_db(db_name)
|
|
97
|
-
tables = system_db.
|
|
97
|
+
tables = system_db.get_tree_tables()
|
|
98
98
|
tables = [{
|
|
99
99
|
'name': table.name,
|
|
100
100
|
'class': table.kind,
|
mindsdb/api/http/start.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
gc.disable()
|
|
3
|
+
|
|
1
4
|
from flask import Flask
|
|
2
5
|
from waitress import serve
|
|
3
6
|
|
|
@@ -8,6 +11,8 @@ from mindsdb.utilities.config import config
|
|
|
8
11
|
from mindsdb.utilities.functions import init_lexer_parsers
|
|
9
12
|
from mindsdb.integrations.libs.ml_exec_base import process_cache
|
|
10
13
|
|
|
14
|
+
gc.enable()
|
|
15
|
+
|
|
11
16
|
logger = log.getLogger(__name__)
|
|
12
17
|
|
|
13
18
|
|
|
@@ -26,7 +31,7 @@ def start(verbose, no_studio, app: Flask = None):
|
|
|
26
31
|
process_cache.init()
|
|
27
32
|
|
|
28
33
|
if server_type == "waitress":
|
|
29
|
-
logger.debug("Serving HTTP app with waitress
|
|
34
|
+
logger.debug("Serving HTTP app with waitress...")
|
|
30
35
|
serve(
|
|
31
36
|
app,
|
|
32
37
|
host='*' if host in ('', '0.0.0.0') else host,
|
|
@@ -34,7 +39,7 @@ def start(verbose, no_studio, app: Flask = None):
|
|
|
34
39
|
**server_config
|
|
35
40
|
)
|
|
36
41
|
elif server_type == "flask":
|
|
37
|
-
logger.debug("Serving HTTP app with flask
|
|
42
|
+
logger.debug("Serving HTTP app with flask...")
|
|
38
43
|
# that will 'disable access' log in console
|
|
39
44
|
|
|
40
45
|
app.run(debug=False, port=port, host=host, **server_config)
|
|
@@ -32,13 +32,11 @@ from mindsdb.api.mysql.mysql_proxy.data_types.mysql_datum import Datum
|
|
|
32
32
|
|
|
33
33
|
import mindsdb.utilities.hooks as hooks
|
|
34
34
|
import mindsdb.utilities.profiler as profiler
|
|
35
|
+
from mindsdb.utilities.sql import clear_sql
|
|
35
36
|
from mindsdb.api.mysql.mysql_proxy.classes.client_capabilities import ClentCapabilities
|
|
36
37
|
from mindsdb.api.mysql.mysql_proxy.classes.server_capabilities import (
|
|
37
38
|
server_capabilities,
|
|
38
39
|
)
|
|
39
|
-
from mindsdb.api.mysql.mysql_proxy.classes.sql_statement_parser import (
|
|
40
|
-
SqlStatementParser,
|
|
41
|
-
)
|
|
42
40
|
from mindsdb.api.executor.controllers import SessionController
|
|
43
41
|
from mindsdb.api.mysql.mysql_proxy.data_types.mysql_packet import Packet
|
|
44
42
|
from mindsdb.api.mysql.mysql_proxy.data_types.mysql_packets import (
|
|
@@ -85,7 +83,7 @@ from mindsdb.api.mysql.mysql_proxy.utilities.lightwood_dtype import dtype
|
|
|
85
83
|
from mindsdb.utilities import log
|
|
86
84
|
from mindsdb.utilities.config import config
|
|
87
85
|
from mindsdb.utilities.context import context as ctx
|
|
88
|
-
from mindsdb.utilities.otel
|
|
86
|
+
from mindsdb.utilities.otel import increment_otel_query_request_counter
|
|
89
87
|
from mindsdb.utilities.wizards import make_ssl_cert
|
|
90
88
|
|
|
91
89
|
logger = log.getLogger(__name__)
|
|
@@ -560,9 +558,7 @@ class MysqlProxy(SocketServer.BaseRequestHandler):
|
|
|
560
558
|
)
|
|
561
559
|
|
|
562
560
|
# Increment the counter and include metadata in attributes
|
|
563
|
-
|
|
564
|
-
query_request_counter = get_query_request_counter()
|
|
565
|
-
query_request_counter.add(1, metadata)
|
|
561
|
+
increment_otel_query_request_counter(ctx.get_metadata(query=sql))
|
|
566
562
|
|
|
567
563
|
return resp
|
|
568
564
|
|
|
@@ -741,7 +737,7 @@ class MysqlProxy(SocketServer.BaseRequestHandler):
|
|
|
741
737
|
try:
|
|
742
738
|
if p.type.value == COMMANDS.COM_QUERY:
|
|
743
739
|
sql = self.decode_utf(p.sql.value)
|
|
744
|
-
sql =
|
|
740
|
+
sql = clear_sql(sql)
|
|
745
741
|
logger.debug(f'Incoming query: {sql}')
|
|
746
742
|
profiler.set_meta(
|
|
747
743
|
query=sql, api="mysql", environment=config.get("environment")
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import BinaryIO, Sequence, Dict, Type
|
|
2
2
|
|
|
3
|
-
from mindsdb.api.mysql.mysql_proxy.classes.sql_statement_parser import SqlStatementParser
|
|
4
3
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_fields import PostgresField
|
|
5
4
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message import PostgresMessage
|
|
6
5
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message_identifiers import \
|
|
@@ -8,6 +7,7 @@ from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message_ident
|
|
|
8
7
|
|
|
9
8
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_packets import PostgresPacketReader
|
|
10
9
|
from mindsdb.api.postgres.postgres_proxy.utilities import strip_null_byte
|
|
10
|
+
from mindsdb.utilities.sql import clear_sql
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
# All docstrings for Messages are taken from
|
|
@@ -507,7 +507,7 @@ class Query(PostgresMessage):
|
|
|
507
507
|
raise Exception(f'SQL contains non {encoding} values: {self.sql}')
|
|
508
508
|
# Remove null bytes from end of sql statement. This is important.
|
|
509
509
|
sql = strip_null_byte(sql)
|
|
510
|
-
sql =
|
|
510
|
+
sql = clear_sql(sql)
|
|
511
511
|
return sql
|
|
512
512
|
|
|
513
513
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
google-api-python-client
|
|
2
|
-
google-auth
|
|
2
|
+
google-auth
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
google-api-python-client
|
|
2
|
-
google-auth
|
|
2
|
+
google-auth
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
google-api-python-client
|
|
2
|
-
google-auth
|
|
2
|
+
google-auth
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from mindsdb.integrations.libs.api_handler import APIHandler
|
|
2
|
+
from mindsdb.integrations.libs.response import (
|
|
3
|
+
HandlerStatusResponse as StatusResponse,
|
|
4
|
+
)
|
|
5
|
+
from mindsdb.utilities import log
|
|
6
|
+
from mindsdb.integrations.libs.api_handler_generator import APIResourceGenerator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = log.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class JiraHandler(APIHandler):
|
|
13
|
+
|
|
14
|
+
def __init__(self, name=None, **kwargs):
|
|
15
|
+
"""
|
|
16
|
+
Initialize the handler.
|
|
17
|
+
Args:
|
|
18
|
+
name (str): name of particular handler instance
|
|
19
|
+
connection_data (dict): parameters for connecting to the database
|
|
20
|
+
**kwargs: arbitrary keyword arguments.
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(name)
|
|
23
|
+
self.connection_data = kwargs.get("connection_data", {})
|
|
24
|
+
|
|
25
|
+
self.connection = None
|
|
26
|
+
self.is_connected = False
|
|
27
|
+
|
|
28
|
+
# todo store parsed data in files
|
|
29
|
+
|
|
30
|
+
self.api_resource_generator = APIResourceGenerator(
|
|
31
|
+
"https://developer.atlassian.com/cloud/jira/platform/swagger-v3.v3.json",
|
|
32
|
+
self.connection_data,
|
|
33
|
+
url_base='/rest/api/3/',
|
|
34
|
+
options={
|
|
35
|
+
'offset_param': ['startAt', 'offset'],
|
|
36
|
+
'total_column': ['totalEntryCount', 'total'],
|
|
37
|
+
'check_connection_table': 'myself'
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
resource_tables = self.api_resource_generator.generate_api_resources(self)
|
|
42
|
+
|
|
43
|
+
for table_name, resource in resource_tables.items():
|
|
44
|
+
self._register_table(table_name, resource)
|
|
45
|
+
|
|
46
|
+
def __del__(self):
|
|
47
|
+
if self.is_connected is True:
|
|
48
|
+
self.disconnect()
|
|
49
|
+
|
|
50
|
+
def connect(self):
|
|
51
|
+
"""
|
|
52
|
+
Set up the connection required by the handler.
|
|
53
|
+
Returns:
|
|
54
|
+
HandlerStatusResponse
|
|
55
|
+
"""
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
def check_connection(self) -> StatusResponse:
|
|
59
|
+
"""
|
|
60
|
+
Check connection to the handler.
|
|
61
|
+
Returns:
|
|
62
|
+
HandlerStatusResponse
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
response = StatusResponse(False)
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
self.api_resource_generator.check_connection()
|
|
69
|
+
response.success = True
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Error connecting to Jira API: {e}!")
|
|
72
|
+
response.error_message = e
|
|
73
|
+
|
|
74
|
+
self.is_connected = response.success
|
|
75
|
+
return response
|
|
@@ -1,75 +1,150 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from atlassian import Jira
|
|
4
|
+
from requests.exceptions import HTTPError
|
|
5
|
+
|
|
6
|
+
from mindsdb.integrations.handlers.jira_handler.jira_tables import JiraProjectsTable, JiraIssuesTable, JiraUsersTable, JiraGroupsTable
|
|
1
7
|
from mindsdb.integrations.libs.api_handler import APIHandler
|
|
2
8
|
from mindsdb.integrations.libs.response import (
|
|
9
|
+
HandlerResponse as Response,
|
|
3
10
|
HandlerStatusResponse as StatusResponse,
|
|
11
|
+
RESPONSE_TYPE,
|
|
4
12
|
)
|
|
5
13
|
from mindsdb.utilities import log
|
|
6
|
-
from mindsdb.integrations.libs.api_handler_generator import APIResourceGenerator
|
|
7
14
|
|
|
8
15
|
|
|
9
16
|
logger = log.getLogger(__name__)
|
|
10
17
|
|
|
11
18
|
|
|
12
19
|
class JiraHandler(APIHandler):
|
|
20
|
+
"""
|
|
21
|
+
This handler handles the connection and execution of SQL statements on Jira.
|
|
22
|
+
"""
|
|
13
23
|
|
|
14
|
-
def __init__(self, name
|
|
24
|
+
def __init__(self, name: str, connection_data: Dict, **kwargs: Any) -> None:
|
|
15
25
|
"""
|
|
16
|
-
|
|
26
|
+
Initializes the handler.
|
|
27
|
+
|
|
17
28
|
Args:
|
|
18
|
-
name (
|
|
19
|
-
connection_data (
|
|
20
|
-
|
|
29
|
+
name (Text): The name of the handler instance.
|
|
30
|
+
connection_data (Dict): The connection data required to connect to the Jira API.
|
|
31
|
+
kwargs: Arbitrary keyword arguments.
|
|
21
32
|
"""
|
|
22
33
|
super().__init__(name)
|
|
23
|
-
self.connection_data =
|
|
34
|
+
self.connection_data = connection_data
|
|
35
|
+
self.kwargs = kwargs
|
|
24
36
|
|
|
25
37
|
self.connection = None
|
|
26
38
|
self.is_connected = False
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
self._register_table("projects", JiraProjectsTable(self))
|
|
41
|
+
self._register_table("issues", JiraIssuesTable(self))
|
|
42
|
+
self._register_table("groups", JiraGroupsTable(self))
|
|
43
|
+
self._register_table("users", JiraUsersTable(self))
|
|
29
44
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
url_base='/rest/api/3/',
|
|
34
|
-
options={
|
|
35
|
-
'offset_param': ['startAt', 'offset'],
|
|
36
|
-
'total_column': ['totalEntryCount', 'total'],
|
|
37
|
-
'check_connection_table': 'myself'
|
|
38
|
-
}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
resource_tables = self.api_resource_generator.generate_api_resources(self)
|
|
42
|
-
|
|
43
|
-
for table_name, resource in resource_tables.items():
|
|
44
|
-
self._register_table(table_name, resource)
|
|
45
|
+
def connect(self) -> Jira:
|
|
46
|
+
"""
|
|
47
|
+
Establishes a connection to the Jira API.
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
Raises:
|
|
50
|
+
ValueError: If the required connection parameters are not provided.
|
|
51
|
+
AuthenticationError: If an authentication error occurs while connecting to the Salesforce API.
|
|
49
52
|
|
|
50
|
-
def connect(self):
|
|
51
|
-
"""
|
|
52
|
-
Set up the connection required by the handler.
|
|
53
53
|
Returns:
|
|
54
|
-
|
|
54
|
+
atlassian.jira.Jira: A connection object to the Jira API.
|
|
55
55
|
"""
|
|
56
|
-
|
|
56
|
+
if self.is_connected is True:
|
|
57
|
+
return self.connection
|
|
58
|
+
|
|
59
|
+
is_cloud = self.connection_data.get("cloud", True)
|
|
60
|
+
|
|
61
|
+
if is_cloud:
|
|
62
|
+
# Jira Cloud supports API token authentication.
|
|
63
|
+
if not all(key in self.connection_data for key in ['username', 'api_token', 'url']):
|
|
64
|
+
raise ValueError("Required parameters (username, api_token, url) must be provided.")
|
|
65
|
+
|
|
66
|
+
config = {
|
|
67
|
+
"username": self.connection_data['username'],
|
|
68
|
+
"password": self.connection_data['api_token'],
|
|
69
|
+
"url": self.connection_data['url'],
|
|
70
|
+
}
|
|
71
|
+
else:
|
|
72
|
+
# Jira Server supports personal access token authentication or open access.
|
|
73
|
+
if 'url' not in self.connection_data:
|
|
74
|
+
raise ValueError("Required parameter 'url' must be provided.")
|
|
75
|
+
|
|
76
|
+
config = {
|
|
77
|
+
"url": self.connection_data['url'],
|
|
78
|
+
"cloud": False
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if 'personal_access_token' in self.connection_data:
|
|
82
|
+
config['session'] = ({"Authorization": f"Bearer {self.connection_data['personal_access_token']}"})
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
self.connection = Jira(**config)
|
|
86
|
+
self.is_connected = True
|
|
87
|
+
return self.connection
|
|
88
|
+
except Exception as unknown_error:
|
|
89
|
+
logger.error(f"Unknown error connecting to Jira, {unknown_error}!")
|
|
90
|
+
raise
|
|
57
91
|
|
|
58
92
|
def check_connection(self) -> StatusResponse:
|
|
59
93
|
"""
|
|
60
|
-
|
|
94
|
+
Checks the status of the connection to the Salesforce API.
|
|
95
|
+
|
|
61
96
|
Returns:
|
|
62
|
-
|
|
97
|
+
StatusResponse: An object containing the success status and an error message if an error occurs.
|
|
63
98
|
"""
|
|
64
|
-
|
|
65
99
|
response = StatusResponse(False)
|
|
66
100
|
|
|
67
101
|
try:
|
|
68
|
-
self.
|
|
102
|
+
connection = self.connect()
|
|
103
|
+
connection.myself()
|
|
69
104
|
response.success = True
|
|
70
|
-
except
|
|
71
|
-
logger.error(f
|
|
72
|
-
response.error_message =
|
|
105
|
+
except (HTTPError, ValueError) as known_error:
|
|
106
|
+
logger.error(f'Connection check to Jira failed, {known_error}!')
|
|
107
|
+
response.error_message = str(known_error)
|
|
108
|
+
except Exception as unknown_error:
|
|
109
|
+
logger.error(f'Connection check to Jira failed due to an unknown error, {unknown_error}!')
|
|
110
|
+
response.error_message = str(unknown_error)
|
|
73
111
|
|
|
74
112
|
self.is_connected = response.success
|
|
113
|
+
|
|
75
114
|
return response
|
|
115
|
+
|
|
116
|
+
def native_query(self, query: str) -> Response:
|
|
117
|
+
"""
|
|
118
|
+
Executes a native JQL query on Jira and returns the result.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
query (Text): The JQL query to be executed.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Response: A response object containing the result of the query or an error message.
|
|
125
|
+
"""
|
|
126
|
+
connection = self.connect()
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
results = connection.jql(query)
|
|
130
|
+
df = JiraIssuesTable(self).normalize(results['issues'])
|
|
131
|
+
response = Response(
|
|
132
|
+
RESPONSE_TYPE.TABLE,
|
|
133
|
+
df
|
|
134
|
+
)
|
|
135
|
+
except HTTPError as http_error:
|
|
136
|
+
logger.error(f'Error running query: {query} on Jira, {http_error}!')
|
|
137
|
+
response = Response(
|
|
138
|
+
RESPONSE_TYPE.ERROR,
|
|
139
|
+
error_code=0,
|
|
140
|
+
error_message=str(http_error)
|
|
141
|
+
)
|
|
142
|
+
except Exception as unknown_error:
|
|
143
|
+
logger.error(f'Error running query: {query} on Jira, {unknown_error}!')
|
|
144
|
+
response = Response(
|
|
145
|
+
RESPONSE_TYPE.ERROR,
|
|
146
|
+
error_code=0,
|
|
147
|
+
error_message=str(unknown_error)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return response
|