altimate-datapilot-cli 0.0.19__py3-none-any.whl → 0.0.21__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.
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/METADATA +14 -5
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/RECORD +14 -10
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/WHEEL +1 -1
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/entry_points.txt +0 -1
- datapilot/__init__.py +1 -1
- datapilot/cli/decorators.py +82 -0
- datapilot/cli/main.py +4 -0
- datapilot/core/knowledge/__init__.py +0 -0
- datapilot/core/knowledge/cli.py +48 -0
- datapilot/core/knowledge/server.py +84 -0
- datapilot/core/platforms/dbt/cli/cli.py +32 -21
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info/licenses}/AUTHORS.rst +0 -0
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info/licenses}/LICENSE +0 -0
- {altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/top_level.txt +0 -0
{altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: altimate-datapilot-cli
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.21
|
4
4
|
Summary: Assistant for Data Teams
|
5
5
|
Home-page: https://github.com/AltimateAI/datapilot-cli
|
6
6
|
Author: Altimate Inc
|
@@ -9,7 +9,6 @@ License: MIT
|
|
9
9
|
Project-URL: Documentation, https://datapilot.readthedocs.io/
|
10
10
|
Project-URL: Changelog, https://datapilot.readthedocs.io/en/latest/changelog.html
|
11
11
|
Project-URL: Issue Tracker, https://github.com/AltimateAI/datapilot-cli/issues
|
12
|
-
Platform: UNKNOWN
|
13
12
|
Classifier: Development Status :: 5 - Production/Stable
|
14
13
|
Classifier: Intended Audience :: Developers
|
15
14
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -38,6 +37,18 @@ Requires-Dist: requests>=2.31
|
|
38
37
|
Requires-Dist: sqlglot~=25.30.0
|
39
38
|
Requires-Dist: mcp~=1.9.0
|
40
39
|
Requires-Dist: pyperclip~=1.8.2
|
40
|
+
Requires-Dist: python-dotenv~=1.0.0
|
41
|
+
Dynamic: author
|
42
|
+
Dynamic: author-email
|
43
|
+
Dynamic: classifier
|
44
|
+
Dynamic: description
|
45
|
+
Dynamic: home-page
|
46
|
+
Dynamic: license
|
47
|
+
Dynamic: license-file
|
48
|
+
Dynamic: project-url
|
49
|
+
Dynamic: requires-dist
|
50
|
+
Dynamic: requires-python
|
51
|
+
Dynamic: summary
|
41
52
|
|
42
53
|
========
|
43
54
|
Overview
|
@@ -100,5 +111,3 @@ Changelog
|
|
100
111
|
------------------
|
101
112
|
|
102
113
|
* First release on PyPI.
|
103
|
-
|
104
|
-
|
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
altimate_datapilot_cli-0.0.21.dist-info/licenses/AUTHORS.rst,sha256=S4H4zw_v3GVyz5_55jF5Gf_YNG3s5Y0VgbQaEov9PFk,50
|
2
|
+
altimate_datapilot_cli-0.0.21.dist-info/licenses/LICENSE,sha256=Mf7VqpsmU2QR5_s2Cb_ZeeMB2Q9KW7YXJENZPFZRK1k,1100
|
3
|
+
datapilot/__init__.py,sha256=PsqtE_T084MVsMv47JyTQ3DK2CRZJ3Kd9Q_vnw02oZk,23
|
2
4
|
datapilot/__main__.py,sha256=I9USmeNnK-cAHb6LZfydJC0LeNSE8enieeY55wpR6uw,380
|
3
5
|
datapilot/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
datapilot/cli/
|
6
|
+
datapilot/cli/decorators.py,sha256=TYO_q-AMsq-86T3i9zI0fVLAhfwu87qAHmvZAJgt3xQ,2842
|
7
|
+
datapilot/cli/main.py,sha256=pf3Thf5zX3s4SmgB8fYVn00WnQKYJ1ARqSjJ3q-M4xo,444
|
5
8
|
datapilot/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
9
|
datapilot/clients/altimate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
10
|
datapilot/clients/altimate/client.py,sha256=00TRe_ck8UgbhFMAnrLBmug3fAWxAggNl2do5Um_4oU,4083
|
@@ -21,6 +24,9 @@ datapilot/core/insights/sql/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
21
24
|
datapilot/core/insights/sql/base/insight.py,sha256=k8UUn0qrN-QG6NCunPl7Hd6L6kd1X1eUAeGEsyl8v0o,250
|
22
25
|
datapilot/core/insights/sql/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
26
|
datapilot/core/insights/sql/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
+
datapilot/core/knowledge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
|
+
datapilot/core/knowledge/cli.py,sha256=f9cmHTJW1Ts5slUgk7TqM2zqhjmEx5axRcnZPQgbO5s,1524
|
29
|
+
datapilot/core/knowledge/server.py,sha256=hO6WyMUKBkukx_7JSBDvLztoFIKqEezNl4flQdtmNwQ,3191
|
24
30
|
datapilot/core/mcp_utils/__init__.py,sha256=39zN2cGQCsEjRFeExv2bX4MoqVv4H14o_SYp_QG2jHU,18
|
25
31
|
datapilot/core/mcp_utils/mcp.py,sha256=e-FbHmpEr673hxVBFHv996qnHCuqKqiCrMMy_g5tMjg,6027
|
26
32
|
datapilot/core/platforms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -32,7 +38,7 @@ datapilot/core/platforms/dbt/factory.py,sha256=YIQtb-FQQAJsifJ3KiLjjk0WIKTHtEPTN
|
|
32
38
|
datapilot/core/platforms/dbt/formatting.py,sha256=bpfa7XmVghTq4WnGDGYC6DruwOwH8YmjFHghoo5cPD8,1638
|
33
39
|
datapilot/core/platforms/dbt/utils.py,sha256=ozFHprR6LTLXQdrGyaRoyIBTua4P1NkP8T7LGgN-9c0,18577
|
34
40
|
datapilot/core/platforms/dbt/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
-
datapilot/core/platforms/dbt/cli/cli.py,sha256=
|
41
|
+
datapilot/core/platforms/dbt/cli/cli.py,sha256=JAEH3PSXKK8qhKxPd4pAFf_LB-FSqVVXOD9iG1Kuv20,7098
|
36
42
|
datapilot/core/platforms/dbt/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
43
|
datapilot/core/platforms/dbt/hooks/executor_hook.py,sha256=gSM50vAO7C-f1rdnHogWbqc87aCXPXysZepjp5L2qzw,2966
|
38
44
|
datapilot/core/platforms/dbt/insights/__init__.py,sha256=hk7BAzCTDkY8WNV6L0v-CPn9mrsDyJJusoQxNxGyzAY,7634
|
@@ -141,10 +147,8 @@ datapilot/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
141
147
|
datapilot/utils/utils.py,sha256=MY8q6ZBJ0hkrTuH7gWMxAlEAQGrajXFMabEhtGtT7sc,11524
|
142
148
|
datapilot/utils/formatting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
143
149
|
datapilot/utils/formatting/utils.py,sha256=rAVmIYuldvw9VvCSwG2kMTEgiT7cEconp_F1sAWVyCo,1377
|
144
|
-
altimate_datapilot_cli-0.0.
|
145
|
-
altimate_datapilot_cli-0.0.
|
146
|
-
altimate_datapilot_cli-0.0.
|
147
|
-
altimate_datapilot_cli-0.0.
|
148
|
-
altimate_datapilot_cli-0.0.
|
149
|
-
altimate_datapilot_cli-0.0.19.dist-info/top_level.txt,sha256=gAOFOdwB00vcxv74y4M1J-nQtPvEatU8-mYViEBcToo,10
|
150
|
-
altimate_datapilot_cli-0.0.19.dist-info/RECORD,,
|
150
|
+
altimate_datapilot_cli-0.0.21.dist-info/METADATA,sha256=tWGs7r6Ovf6fCsGbs7sUw01fNFFfGVqD3Hi1_obKeng,2677
|
151
|
+
altimate_datapilot_cli-0.0.21.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
152
|
+
altimate_datapilot_cli-0.0.21.dist-info/entry_points.txt,sha256=5fKdw1Xm1RPJ6EZkBWvjNgLP6z3OU6iUvgDARe29pN8,140
|
153
|
+
altimate_datapilot_cli-0.0.21.dist-info/top_level.txt,sha256=gAOFOdwB00vcxv74y4M1J-nQtPvEatU8-mYViEBcToo,10
|
154
|
+
altimate_datapilot_cli-0.0.21.dist-info/RECORD,,
|
datapilot/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.21"
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
from functools import wraps
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import Dict
|
7
|
+
from typing import Optional
|
8
|
+
|
9
|
+
import click
|
10
|
+
from dotenv import load_dotenv
|
11
|
+
|
12
|
+
|
13
|
+
def load_config_from_file() -> Optional[Dict]:
|
14
|
+
"""Load configuration from ~/.altimate/altimate.json if it exists."""
|
15
|
+
config_path = Path.home() / ".altimate" / "altimate.json"
|
16
|
+
|
17
|
+
if not config_path.exists():
|
18
|
+
return None
|
19
|
+
|
20
|
+
try:
|
21
|
+
with config_path.open() as f:
|
22
|
+
config = json.load(f)
|
23
|
+
return config
|
24
|
+
except (OSError, json.JSONDecodeError) as e:
|
25
|
+
click.echo(f"Warning: Failed to load config from {config_path}: {e}", err=True)
|
26
|
+
return None
|
27
|
+
|
28
|
+
|
29
|
+
def substitute_env_vars(value):
|
30
|
+
"""Replace ${env:ENV_VARIABLE} patterns with actual environment variable values."""
|
31
|
+
if not isinstance(value, str):
|
32
|
+
return value
|
33
|
+
|
34
|
+
# Pattern to match ${env:VARIABLE_NAME}
|
35
|
+
pattern = r"\$\{env:([^}]+)\}"
|
36
|
+
|
37
|
+
def replacer(match):
|
38
|
+
env_var = match.group(1)
|
39
|
+
return os.environ.get(env_var, match.group(0))
|
40
|
+
|
41
|
+
return re.sub(pattern, replacer, value)
|
42
|
+
|
43
|
+
|
44
|
+
def process_config(config):
|
45
|
+
"""Process configuration dictionary to substitute environment variables."""
|
46
|
+
processed = {}
|
47
|
+
for key, value in config.items():
|
48
|
+
processed[key] = substitute_env_vars(value)
|
49
|
+
return processed
|
50
|
+
|
51
|
+
|
52
|
+
def auth_options(f):
|
53
|
+
"""Decorator to add authentication options to commands."""
|
54
|
+
|
55
|
+
@click.option("--token", required=False, help="Your API token for authentication.", hide_input=True)
|
56
|
+
@click.option("--instance-name", required=False, help="Your tenant ID.")
|
57
|
+
@click.option("--backend-url", required=False, help="Altimate's Backend URL", default="https://api.myaltimate.com")
|
58
|
+
@wraps(f)
|
59
|
+
def wrapper(token, instance_name, backend_url, *args, **kwargs):
|
60
|
+
# Load .env file from current directory if it exists
|
61
|
+
load_dotenv()
|
62
|
+
|
63
|
+
final_token = token
|
64
|
+
final_instance_name = instance_name
|
65
|
+
final_backend_url = backend_url
|
66
|
+
|
67
|
+
if final_token is None and final_instance_name is None:
|
68
|
+
# Try to Load configuration from file if no CLI arguments are provided
|
69
|
+
file_config = load_config_from_file()
|
70
|
+
if file_config is not None:
|
71
|
+
# File config is provided
|
72
|
+
file_config = process_config(file_config)
|
73
|
+
if "altimateApiKey" in file_config:
|
74
|
+
final_token = file_config["altimateApiKey"]
|
75
|
+
if "altimateInstanceName" in file_config:
|
76
|
+
final_instance_name = file_config["altimateInstanceName"]
|
77
|
+
if "altimateUrl" in file_config:
|
78
|
+
final_backend_url = file_config["altimateUrl"] or final_backend_url
|
79
|
+
|
80
|
+
return f(final_token, final_instance_name, final_backend_url, *args, **kwargs)
|
81
|
+
|
82
|
+
return wrapper
|
datapilot/cli/main.py
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
import click
|
2
2
|
|
3
|
+
from datapilot import __version__
|
4
|
+
from datapilot.core.knowledge.cli import cli as knowledge
|
3
5
|
from datapilot.core.mcp_utils.mcp import mcp
|
4
6
|
from datapilot.core.platforms.dbt.cli.cli import dbt
|
5
7
|
|
6
8
|
|
7
9
|
@click.group()
|
10
|
+
@click.version_option(version=__version__, prog_name="datapilot")
|
8
11
|
def datapilot():
|
9
12
|
"""Altimate CLI for DBT project management."""
|
10
13
|
|
11
14
|
|
12
15
|
datapilot.add_command(dbt)
|
13
16
|
datapilot.add_command(mcp)
|
17
|
+
datapilot.add_command(knowledge)
|
File without changes
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from http.server import HTTPServer
|
2
|
+
|
3
|
+
import click
|
4
|
+
|
5
|
+
from datapilot.cli.decorators import auth_options
|
6
|
+
from datapilot.clients.altimate.utils import validate_credentials
|
7
|
+
|
8
|
+
from .server import KnowledgeBaseHandler
|
9
|
+
|
10
|
+
|
11
|
+
@click.group(name="knowledge")
|
12
|
+
def cli():
|
13
|
+
"""knowledge specific commands."""
|
14
|
+
|
15
|
+
|
16
|
+
@cli.command()
|
17
|
+
@auth_options
|
18
|
+
@click.option("--port", default=4000, help="Port to run the server on")
|
19
|
+
def serve(token, instance_name, backend_url, port):
|
20
|
+
"""Serve knowledge bases via HTTP server."""
|
21
|
+
if not token or not instance_name:
|
22
|
+
click.echo(
|
23
|
+
"Error: API token and instance name are required. Use --token and --instance-name options or set them in config.", err=True
|
24
|
+
)
|
25
|
+
raise click.Abort
|
26
|
+
|
27
|
+
if not validate_credentials(token, backend_url, instance_name):
|
28
|
+
click.echo("Error: Invalid credentials.", err=True)
|
29
|
+
raise click.Abort
|
30
|
+
|
31
|
+
# Set context data for the handler
|
32
|
+
KnowledgeBaseHandler.token = token
|
33
|
+
KnowledgeBaseHandler.instance_name = instance_name
|
34
|
+
KnowledgeBaseHandler.backend_url = backend_url
|
35
|
+
|
36
|
+
server_address = ("", port)
|
37
|
+
httpd = HTTPServer(server_address, KnowledgeBaseHandler)
|
38
|
+
|
39
|
+
click.echo(f"Starting knowledge base server on port {port}...")
|
40
|
+
click.echo(f"Backend URL: {backend_url}")
|
41
|
+
click.echo(f"Instance: {instance_name}")
|
42
|
+
click.echo(f"Server running at http://localhost:{port}")
|
43
|
+
|
44
|
+
try:
|
45
|
+
httpd.serve_forever()
|
46
|
+
except KeyboardInterrupt:
|
47
|
+
click.echo("\nShutting down server...")
|
48
|
+
httpd.shutdown()
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import json
|
2
|
+
import re
|
3
|
+
from http.server import BaseHTTPRequestHandler
|
4
|
+
from urllib.error import HTTPError
|
5
|
+
from urllib.error import URLError
|
6
|
+
from urllib.parse import urlparse
|
7
|
+
from urllib.request import Request
|
8
|
+
from urllib.request import urlopen
|
9
|
+
|
10
|
+
import click
|
11
|
+
|
12
|
+
|
13
|
+
class KnowledgeBaseHandler(BaseHTTPRequestHandler):
|
14
|
+
"""HTTP request handler for serving knowledge bases and health checks."""
|
15
|
+
|
16
|
+
token: str = ""
|
17
|
+
instance_name: str = ""
|
18
|
+
backend_url: str = ""
|
19
|
+
|
20
|
+
def do_GET(self):
|
21
|
+
"""Handle GET requests."""
|
22
|
+
path = urlparse(self.path).path
|
23
|
+
|
24
|
+
# Match /knowledge_bases/{uuid} pattern
|
25
|
+
match = re.match(r"^/kb/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$", path)
|
26
|
+
|
27
|
+
if match:
|
28
|
+
public_id = match.group(1)
|
29
|
+
self.handle_knowledge_base(public_id)
|
30
|
+
elif path == "/health":
|
31
|
+
self.handle_health()
|
32
|
+
else:
|
33
|
+
self.send_error(404, "Not Found")
|
34
|
+
|
35
|
+
def handle_knowledge_base(self, public_id):
|
36
|
+
"""Fetch and return knowledge base data."""
|
37
|
+
url = f"{self.backend_url}/knowledge_bases/private/{public_id}"
|
38
|
+
|
39
|
+
# Validate URL scheme for security
|
40
|
+
parsed_url = urlparse(url)
|
41
|
+
if parsed_url.scheme not in ("http", "https"):
|
42
|
+
self.send_response(400)
|
43
|
+
self.send_header("Content-Type", "application/json")
|
44
|
+
self.end_headers()
|
45
|
+
error_msg = json.dumps({"error": "Invalid URL scheme. Only HTTP and HTTPS are allowed."})
|
46
|
+
self.wfile.write(error_msg.encode("utf-8"))
|
47
|
+
return
|
48
|
+
|
49
|
+
headers = {"Authorization": f"Bearer {self.token}", "X-Tenant": self.instance_name, "Content-Type": "application/json"}
|
50
|
+
|
51
|
+
req = Request(url, headers=headers) # noqa: S310
|
52
|
+
|
53
|
+
try:
|
54
|
+
# URL scheme validated above - only HTTP/HTTPS allowed
|
55
|
+
with urlopen(req, timeout=30) as response: # noqa: S310
|
56
|
+
data = response.read()
|
57
|
+
self.send_response(200)
|
58
|
+
self.send_header("Content-Type", "application/json")
|
59
|
+
self.end_headers()
|
60
|
+
self.wfile.write(data)
|
61
|
+
except HTTPError as e:
|
62
|
+
error_body = e.read()
|
63
|
+
error_data = error_body.decode("utf-8") if error_body else '{"error": "HTTP Error"}'
|
64
|
+
self.send_response(e.code)
|
65
|
+
self.send_header("Content-Type", "application/json")
|
66
|
+
self.end_headers()
|
67
|
+
self.wfile.write(error_data.encode("utf-8"))
|
68
|
+
except URLError as e:
|
69
|
+
self.send_response(500)
|
70
|
+
self.send_header("Content-Type", "application/json")
|
71
|
+
self.end_headers()
|
72
|
+
error_msg = json.dumps({"error": str(e)})
|
73
|
+
self.wfile.write(error_msg.encode("utf-8"))
|
74
|
+
|
75
|
+
def handle_health(self):
|
76
|
+
"""Handle health check endpoint."""
|
77
|
+
self.send_response(200)
|
78
|
+
self.send_header("Content-Type", "application/json")
|
79
|
+
self.end_headers()
|
80
|
+
self.wfile.write(json.dumps({"status": "ok"}).encode("utf-8"))
|
81
|
+
|
82
|
+
def log_message(self, format, *args):
|
83
|
+
"""Override to use click.echo for logging."""
|
84
|
+
click.echo(f"{self.address_string()} - {format % args}")
|
@@ -2,6 +2,7 @@ import logging
|
|
2
2
|
|
3
3
|
import click
|
4
4
|
|
5
|
+
from datapilot.cli.decorators import auth_options
|
5
6
|
from datapilot.clients.altimate.utils import check_token_and_instance
|
6
7
|
from datapilot.clients.altimate.utils import get_all_dbt_configs
|
7
8
|
from datapilot.clients.altimate.utils import onboard_file
|
@@ -29,8 +30,7 @@ def dbt():
|
|
29
30
|
|
30
31
|
|
31
32
|
@dbt.command("project-health")
|
32
|
-
@
|
33
|
-
@click.option("--instance-name", required=False, help="Your tenant ID.")
|
33
|
+
@auth_options
|
34
34
|
@click.option(
|
35
35
|
"--manifest-path",
|
36
36
|
required=True,
|
@@ -57,21 +57,21 @@ def dbt():
|
|
57
57
|
default=None,
|
58
58
|
help="Selective model testing. Specify one or more models to run tests on.",
|
59
59
|
)
|
60
|
-
@click.option("--backend-url", required=False, help="Altimate's Backend URL", default="https://api.myaltimate.com")
|
61
60
|
def project_health(
|
62
61
|
token,
|
63
62
|
instance_name,
|
63
|
+
backend_url,
|
64
64
|
manifest_path,
|
65
65
|
catalog_path,
|
66
66
|
config_path=None,
|
67
67
|
config_name=None,
|
68
68
|
select=None,
|
69
|
-
backend_url="https://api.myaltimate.com",
|
70
69
|
):
|
71
70
|
"""
|
72
71
|
Validate the DBT project's configuration and structure.
|
73
72
|
:param manifest_path: Path to the DBT manifest file.
|
74
73
|
"""
|
74
|
+
|
75
75
|
config = None
|
76
76
|
if config_path:
|
77
77
|
config = load_config(config_path)
|
@@ -131,25 +131,41 @@ def project_health(
|
|
131
131
|
|
132
132
|
|
133
133
|
@dbt.command("onboard")
|
134
|
-
@
|
135
|
-
@click.option(
|
136
|
-
|
134
|
+
@auth_options
|
135
|
+
@click.option(
|
136
|
+
"--dbt_core_integration_id",
|
137
|
+
"--dbt_integration_id",
|
138
|
+
"dbt_integration_id", # This is the parameter name that will be passed to the function
|
139
|
+
prompt="DBT Integration ID",
|
140
|
+
help="DBT Core Integration ID or DBT Integration ID",
|
141
|
+
)
|
137
142
|
@click.option(
|
138
|
-
"--dbt_core_integration_environment",
|
143
|
+
"--dbt_core_integration_environment",
|
144
|
+
"--dbt_integration_environment",
|
145
|
+
"dbt_integration_environment", # This is the parameter name that will be passed to the function
|
146
|
+
default="PROD",
|
147
|
+
prompt="DBT Integration Environment",
|
148
|
+
help="DBT Core Integration Environment or DBT Integration Environment",
|
139
149
|
)
|
140
150
|
@click.option("--manifest-path", required=True, prompt="Manifest Path", help="Path to the manifest file.")
|
141
151
|
@click.option("--catalog-path", required=False, prompt=False, help="Path to the catalog file.")
|
142
|
-
@click.option("--backend-url", required=False, help="Altimate's Backend URL", default="https://api.myaltimate.com")
|
143
152
|
def onboard(
|
144
153
|
token,
|
145
154
|
instance_name,
|
146
|
-
|
147
|
-
|
155
|
+
backend_url,
|
156
|
+
dbt_integration_id,
|
157
|
+
dbt_integration_environment,
|
148
158
|
manifest_path,
|
149
159
|
catalog_path,
|
150
|
-
backend_url="https://api.myaltimate.com",
|
151
160
|
):
|
152
161
|
"""Onboard a manifest file to DBT."""
|
162
|
+
|
163
|
+
# For onboard command, token and instance_name are required
|
164
|
+
if not token:
|
165
|
+
token = click.prompt("API Token")
|
166
|
+
if not instance_name:
|
167
|
+
instance_name = click.prompt("Instance Name")
|
168
|
+
|
153
169
|
check_token_and_instance(token, instance_name)
|
154
170
|
|
155
171
|
if not validate_credentials(token, backend_url, instance_name):
|
@@ -160,16 +176,13 @@ def onboard(
|
|
160
176
|
click.echo("Error: You don't have permission to perform this action.")
|
161
177
|
return
|
162
178
|
|
163
|
-
# This will throw error if manifest file is incorrect
|
164
179
|
try:
|
165
180
|
load_manifest(manifest_path)
|
166
181
|
except Exception as e:
|
167
182
|
click.echo(f"Error: {e}")
|
168
183
|
return
|
169
184
|
|
170
|
-
response = onboard_file(
|
171
|
-
token, instance_name, dbt_core_integration_id, dbt_core_integration_environment, "manifest", manifest_path, backend_url
|
172
|
-
)
|
185
|
+
response = onboard_file(token, instance_name, dbt_integration_id, dbt_integration_environment, "manifest", manifest_path, backend_url)
|
173
186
|
if response["ok"]:
|
174
187
|
click.echo("Manifest onboarded successfully!")
|
175
188
|
else:
|
@@ -178,21 +191,19 @@ def onboard(
|
|
178
191
|
if not catalog_path:
|
179
192
|
return
|
180
193
|
|
181
|
-
response = onboard_file(
|
182
|
-
token, instance_name, dbt_core_integration_id, dbt_core_integration_environment, "catalog", catalog_path, backend_url
|
183
|
-
)
|
194
|
+
response = onboard_file(token, instance_name, dbt_integration_id, dbt_integration_environment, "catalog", catalog_path, backend_url)
|
184
195
|
if response["ok"]:
|
185
196
|
click.echo("Catalog onboarded successfully!")
|
186
197
|
else:
|
187
198
|
click.echo(f"{response['message']}")
|
188
199
|
|
189
|
-
response = start_dbt_ingestion(token, instance_name,
|
200
|
+
response = start_dbt_ingestion(token, instance_name, dbt_integration_id, dbt_integration_environment, backend_url)
|
190
201
|
if response["ok"]:
|
191
202
|
url = map_url_to_instance(backend_url, instance_name)
|
192
203
|
if not url:
|
193
204
|
click.echo("Manifest and catalog ingestion has started.")
|
194
205
|
else:
|
195
|
-
url = f"{url}/settings/integrations/{
|
206
|
+
url = f"{url}/settings/integrations/{dbt_integration_id}/{dbt_integration_environment}"
|
196
207
|
click.echo(f"Manifest and catalog ingestion has started. You can check the status at {url}")
|
197
208
|
else:
|
198
209
|
click.echo(f"{response['message']}")
|
File without changes
|
{altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info/licenses}/LICENSE
RENAMED
File without changes
|
{altimate_datapilot_cli-0.0.19.dist-info → altimate_datapilot_cli-0.0.21.dist-info}/top_level.txt
RENAMED
File without changes
|