tinybird 0.0.1.dev132__tar.gz → 0.0.1.dev134__tar.gz
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 tinybird might be problematic. Click here for more details.
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/feedback_manager.py +0 -3
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/config.py +3 -3
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/build.py +10 -14
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/common.py +27 -4
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/create.py +6 -14
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datasource.py +0 -7
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/deployment.py +44 -31
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/exceptions.py +51 -1
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/feedback_manager.py +0 -4
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/local.py +10 -4
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/local_common.py +5 -2
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/login.py +72 -67
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/mock.py +7 -10
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/telemetry.py +1 -2
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/test.py +98 -93
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/datasource.py +0 -7
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/setup.cfg +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/client.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/datafile.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/prompts.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/cli.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/client.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/cli.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/config.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/connection.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/common.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/playground.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/infra.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/logout.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/open.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/project.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/secret.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/shell.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/tag.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/watch.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/workspace.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/SOURCES.txt +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev132 → tinybird-0.0.1.dev134}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -910,9 +910,6 @@ Ready? """
|
|
|
910
910
|
success_delete_rows_datasource = success_message(
|
|
911
911
|
"** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
|
|
912
912
|
)
|
|
913
|
-
success_delete_rows_datasource_no_rows = success_message(
|
|
914
|
-
"** Data Source '{datasource}' no rows to delete matching condition \"{delete_condition}\""
|
|
915
|
-
)
|
|
916
913
|
success_dry_run_delete_rows_datasource = success_message(
|
|
917
914
|
"** [DRY RUN] Data Source '{datasource}' rows '{rows}' matching condition \"{delete_condition}\" to be deleted"
|
|
918
915
|
)
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev134'
|
|
8
|
+
__revision__ = '921269a'
|
|
@@ -42,7 +42,7 @@ CLOUD_HOSTS = {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
def get_config(
|
|
46
46
|
host: str, token: Optional[str], semver: Optional[str] = None, config_file: Optional[str] = None
|
|
47
47
|
) -> Dict[str, Any]:
|
|
48
48
|
if host:
|
|
@@ -50,8 +50,8 @@ async def get_config(
|
|
|
50
50
|
|
|
51
51
|
config = {}
|
|
52
52
|
try:
|
|
53
|
-
|
|
54
|
-
res =
|
|
53
|
+
with open(config_file or Path(getcwd()) / ".tinyb") as file:
|
|
54
|
+
res = file.read()
|
|
55
55
|
config = json.loads(res)
|
|
56
56
|
except OSError:
|
|
57
57
|
pass
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
-
import sys
|
|
5
4
|
import threading
|
|
6
5
|
import time
|
|
7
6
|
from copy import deepcopy
|
|
@@ -16,7 +15,7 @@ import requests
|
|
|
16
15
|
import tinybird.context as context
|
|
17
16
|
from tinybird.tb.client import TinyB
|
|
18
17
|
from tinybird.tb.modules.cli import cli
|
|
19
|
-
from tinybird.tb.modules.common import push_data
|
|
18
|
+
from tinybird.tb.modules.common import push_data, sys_exit
|
|
20
19
|
from tinybird.tb.modules.config import CLIConfig
|
|
21
20
|
from tinybird.tb.modules.datafile.build import folder_build
|
|
22
21
|
from tinybird.tb.modules.datafile.exceptions import ParseException
|
|
@@ -99,12 +98,10 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
99
98
|
except Exception as e:
|
|
100
99
|
logging.debug(e, exc_info=True)
|
|
101
100
|
click.echo(FeedbackManager.error(message="Couldn't parse response from server"))
|
|
102
|
-
|
|
101
|
+
sys_exit("build_error", str(e))
|
|
103
102
|
|
|
104
103
|
logging.debug(json.dumps(result, indent=2))
|
|
105
104
|
|
|
106
|
-
output_pre_formatted = False
|
|
107
|
-
|
|
108
105
|
build_result = result.get("result")
|
|
109
106
|
if build_result == "success":
|
|
110
107
|
build = result.get("build")
|
|
@@ -174,8 +171,7 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
174
171
|
build_errors = result.get("errors")
|
|
175
172
|
full_error_msg = ""
|
|
176
173
|
for build_error in build_errors:
|
|
177
|
-
|
|
178
|
-
filename_bit = FeedbackManager.build_result_error_title(message=f"{build_error.get('filename', '')}")
|
|
174
|
+
filename_bit = build_error.get("filename", "")
|
|
179
175
|
error_bit = build_error.get("error") or build_error.get("message") or ""
|
|
180
176
|
error_msg = ((filename_bit + "\n") if filename_bit else "") + error_bit
|
|
181
177
|
full_error_msg += error_msg + "\n\n"
|
|
@@ -187,11 +183,9 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
187
183
|
finally:
|
|
188
184
|
for fd in fds:
|
|
189
185
|
fd.close()
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
click.echo(error)
|
|
194
|
-
raise click.ClickException("") # Needed so the caller shows the right message
|
|
186
|
+
|
|
187
|
+
if error:
|
|
188
|
+
raise click.ClickException(error)
|
|
195
189
|
|
|
196
190
|
|
|
197
191
|
def append_fixture(
|
|
@@ -270,6 +264,7 @@ def process(
|
|
|
270
264
|
) -> None:
|
|
271
265
|
time_start = time.time()
|
|
272
266
|
build_failed = False
|
|
267
|
+
build_error: Optional[str] = None
|
|
273
268
|
if file_changed and (file_changed.endswith(FixtureExtension.NDJSON) or file_changed.endswith(FixtureExtension.CSV)):
|
|
274
269
|
rebuild_fixture(project, tb_client, file_changed)
|
|
275
270
|
elif file_changed and file_changed.endswith(".sql"):
|
|
@@ -278,7 +273,8 @@ def process(
|
|
|
278
273
|
try:
|
|
279
274
|
build_project(project, tb_client, file_changed, silent)
|
|
280
275
|
except click.ClickException as e:
|
|
281
|
-
click.echo(FeedbackManager.
|
|
276
|
+
click.echo(FeedbackManager.info(message=str(e)))
|
|
277
|
+
build_error = str(e)
|
|
282
278
|
build_failed = True
|
|
283
279
|
try:
|
|
284
280
|
if file_changed and not build_failed:
|
|
@@ -294,7 +290,7 @@ def process(
|
|
|
294
290
|
if build_failed:
|
|
295
291
|
click.echo(FeedbackManager.error(message=f"✗ {rebuild_str} failed"))
|
|
296
292
|
if not watch:
|
|
297
|
-
|
|
293
|
+
sys_exit("build_error", build_error or "Unknown error")
|
|
298
294
|
else:
|
|
299
295
|
if not silent:
|
|
300
296
|
click.echo(FeedbackManager.success(message=f"\n✓ {rebuild_str} completed in {elapsed_time:.1f}s"))
|
|
@@ -250,6 +250,7 @@ line experience. To opt-out, set TB_CLI_TELEMETRY_OPTOUT to '1' or 'true'."""
|
|
|
250
250
|
|
|
251
251
|
def __call__(self, *args, **kwargs) -> None:
|
|
252
252
|
error_msg: Optional[str] = None
|
|
253
|
+
silent_error_msg: Optional[str] = None
|
|
253
254
|
error_event: str = "error"
|
|
254
255
|
|
|
255
256
|
exit_code: int = 0
|
|
@@ -265,14 +266,19 @@ line experience. To opt-out, set TB_CLI_TELEMETRY_OPTOUT to '1' or 'true'."""
|
|
|
265
266
|
error_event = "auth_error"
|
|
266
267
|
exit_code = 1
|
|
267
268
|
except SystemExit as ex:
|
|
268
|
-
|
|
269
|
+
if isinstance(ex.code, str):
|
|
270
|
+
exit_code = 1
|
|
271
|
+
error_event, silent_error_msg = get_error_event(ex.code)
|
|
272
|
+
else:
|
|
273
|
+
exit_code = ex.code or 0
|
|
269
274
|
except Exception as ex:
|
|
270
275
|
error_msg = str(ex)
|
|
271
276
|
exit_code = 1
|
|
272
277
|
|
|
273
|
-
if error_msg:
|
|
274
|
-
|
|
275
|
-
|
|
278
|
+
if error_msg or silent_error_msg:
|
|
279
|
+
if error_msg:
|
|
280
|
+
click.echo(error_msg)
|
|
281
|
+
add_telemetry_event(error_event, error=error_msg or silent_error_msg)
|
|
276
282
|
flush_telemetry(wait=True)
|
|
277
283
|
|
|
278
284
|
sys.exit(exit_code)
|
|
@@ -2232,3 +2238,20 @@ async def ask_for_organization(
|
|
|
2232
2238
|
else:
|
|
2233
2239
|
return None, None
|
|
2234
2240
|
return organization_id, organization_name
|
|
2241
|
+
|
|
2242
|
+
|
|
2243
|
+
event_error_separator = "__error__"
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
def sys_exit(event: str, msg: str) -> None:
|
|
2247
|
+
sys.exit(f"{event}{event_error_separator}{msg}")
|
|
2248
|
+
|
|
2249
|
+
|
|
2250
|
+
def get_error_event(error: str) -> Tuple[str, str]:
|
|
2251
|
+
try:
|
|
2252
|
+
error_event = error.split(event_error_separator)[0]
|
|
2253
|
+
silent_error_msg = error.split(event_error_separator)[1]
|
|
2254
|
+
except Exception:
|
|
2255
|
+
error_event = "error"
|
|
2256
|
+
silent_error_msg = "Unknown error"
|
|
2257
|
+
return error_event, silent_error_msg
|
|
@@ -12,7 +12,7 @@ from tinybird.tb.modules.cli import cli
|
|
|
12
12
|
from tinybird.tb.modules.common import _generate_datafile, coro, generate_datafile
|
|
13
13
|
from tinybird.tb.modules.config import CLIConfig
|
|
14
14
|
from tinybird.tb.modules.datafile.fixture import persist_fixture
|
|
15
|
-
from tinybird.tb.modules.exceptions import
|
|
15
|
+
from tinybird.tb.modules.exceptions import CLICreateException
|
|
16
16
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
17
17
|
from tinybird.tb.modules.llm import LLM
|
|
18
18
|
from tinybird.tb.modules.llm_utils import extract_xml, parse_xml
|
|
@@ -70,17 +70,9 @@ async def create(
|
|
|
70
70
|
user_token: Optional[str] = None
|
|
71
71
|
created_something = False
|
|
72
72
|
if prompt:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
raise CLIException("No user token found")
|
|
77
|
-
except Exception as e:
|
|
78
|
-
click.echo(
|
|
79
|
-
FeedbackManager.error(
|
|
80
|
-
message=f"This action requires authentication. Run 'tb login' first. Error: {e}"
|
|
81
|
-
)
|
|
82
|
-
)
|
|
83
|
-
return
|
|
73
|
+
user_token = ctx_config.get("user_token")
|
|
74
|
+
if not user_token:
|
|
75
|
+
raise Exception("This action requires authentication. Run 'tb login' first.")
|
|
84
76
|
|
|
85
77
|
if not validate_project_structure(folder):
|
|
86
78
|
click.echo(FeedbackManager.highlight(message="\n» Creating new project structure..."))
|
|
@@ -164,7 +156,7 @@ async def create(
|
|
|
164
156
|
if not created_something:
|
|
165
157
|
click.echo(FeedbackManager.warning(message="△ No resources created\n"))
|
|
166
158
|
except Exception as e:
|
|
167
|
-
|
|
159
|
+
raise CLICreateException(FeedbackManager.error(message=str(e)))
|
|
168
160
|
|
|
169
161
|
|
|
170
162
|
PROJECT_PATHS = ("datasources", "endpoints", "materializations", "copies", "pipes", "fixtures", "tests", "connections")
|
|
@@ -328,7 +320,7 @@ def init_git(folder: str):
|
|
|
328
320
|
|
|
329
321
|
click.echo(FeedbackManager.info_file_created(file=".gitignore"))
|
|
330
322
|
except Exception as e:
|
|
331
|
-
raise
|
|
323
|
+
raise Exception(f"Error initializing Git: {e}")
|
|
332
324
|
|
|
333
325
|
|
|
334
326
|
def generate_pipe_file(name: str, content: str, folder: str) -> Path:
|
|
@@ -322,13 +322,6 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
322
322
|
)
|
|
323
323
|
)
|
|
324
324
|
return
|
|
325
|
-
if res is None: # 204,205
|
|
326
|
-
click.echo(
|
|
327
|
-
FeedbackManager.success_delete_rows_datasource_no_rows(
|
|
328
|
-
datasource=datasource_name, delete_condition=sql_condition
|
|
329
|
-
)
|
|
330
|
-
)
|
|
331
|
-
return
|
|
332
325
|
job_id = res["job_id"]
|
|
333
326
|
job_url = res["job_url"]
|
|
334
327
|
click.echo(FeedbackManager.info_datasource_delete_rows_job_url(url=job_url))
|
|
@@ -10,7 +10,11 @@ import click
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
12
|
from tinybird.tb.modules.cli import cli
|
|
13
|
-
from tinybird.tb.modules.common import
|
|
13
|
+
from tinybird.tb.modules.common import (
|
|
14
|
+
echo_safe_humanfriendly_tables_format_smart_table,
|
|
15
|
+
get_display_cloud_host,
|
|
16
|
+
sys_exit,
|
|
17
|
+
)
|
|
14
18
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
15
19
|
from tinybird.tb.modules.project import Project
|
|
16
20
|
|
|
@@ -27,10 +31,12 @@ def api_fetch(url: str, headers: dict) -> dict:
|
|
|
27
31
|
error = result.get("error")
|
|
28
32
|
logging.debug(json.dumps(result, indent=2))
|
|
29
33
|
click.echo(FeedbackManager.error(message=f"Error: {error}"))
|
|
30
|
-
|
|
34
|
+
sys_exit("deployment_error", error)
|
|
31
35
|
except Exception:
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
message = "Error parsing response from API"
|
|
37
|
+
click.echo(FeedbackManager.error(message=message))
|
|
38
|
+
sys_exit("deployment_error", message)
|
|
39
|
+
return {}
|
|
34
40
|
|
|
35
41
|
|
|
36
42
|
def api_post(
|
|
@@ -50,11 +56,13 @@ def api_post(
|
|
|
50
56
|
error = result.get("error")
|
|
51
57
|
if error:
|
|
52
58
|
click.echo(FeedbackManager.error(message=f"Error: {error}"))
|
|
53
|
-
|
|
59
|
+
sys_exit("deployment_error", error)
|
|
54
60
|
return result
|
|
55
61
|
except Exception:
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
message = "Error parsing response from API"
|
|
63
|
+
click.echo(FeedbackManager.error(message=message))
|
|
64
|
+
sys_exit("deployment_error", message)
|
|
65
|
+
return {}
|
|
58
66
|
|
|
59
67
|
|
|
60
68
|
# TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for promoting a deployment
|
|
@@ -65,12 +73,16 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
|
|
|
65
73
|
|
|
66
74
|
deployments = result.get("deployments")
|
|
67
75
|
if not deployments:
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
message = "No deployments found"
|
|
77
|
+
click.echo(FeedbackManager.error(message=message))
|
|
78
|
+
sys_exit("deployment_error", message)
|
|
79
|
+
return
|
|
70
80
|
|
|
71
81
|
if len(deployments) < 2:
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
message = "Only one deployment found"
|
|
83
|
+
click.echo(FeedbackManager.error(message=message))
|
|
84
|
+
sys_exit("deployment_error", message)
|
|
85
|
+
return
|
|
74
86
|
|
|
75
87
|
last_deployment, candidate_deployment = deployments[0], deployments[1]
|
|
76
88
|
|
|
@@ -79,17 +91,16 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
|
|
|
79
91
|
deploy_errors = candidate_deployment.get("errors", [])
|
|
80
92
|
for deploy_error in deploy_errors:
|
|
81
93
|
click.echo(FeedbackManager.error(message=f"* {deploy_error}"))
|
|
82
|
-
|
|
94
|
+
sys_exit("deployment_error", "Current deployment is not ready: " + str(deploy_errors))
|
|
95
|
+
return
|
|
83
96
|
|
|
84
97
|
if candidate_deployment.get("live"):
|
|
85
98
|
click.echo(FeedbackManager.error(message="Candidate deployment is already live"))
|
|
86
99
|
else:
|
|
87
|
-
click.echo(FeedbackManager.success(message="Setting candidate deployment as live"))
|
|
88
|
-
|
|
89
100
|
TINYBIRD_API_URL = f"{host}/v1/deployments/{candidate_deployment.get('id')}/set-live"
|
|
90
101
|
result = api_post(TINYBIRD_API_URL, headers=headers)
|
|
91
102
|
|
|
92
|
-
click.echo(FeedbackManager.
|
|
103
|
+
click.echo(FeedbackManager.highlight(message="» Removing old deployment"))
|
|
93
104
|
|
|
94
105
|
TINYBIRD_API_URL = f"{host}/v1/deployments/{last_deployment.get('id')}"
|
|
95
106
|
r = requests.delete(TINYBIRD_API_URL, headers=headers)
|
|
@@ -97,9 +108,10 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
|
|
|
97
108
|
logging.debug(json.dumps(result, indent=2))
|
|
98
109
|
if result.get("error"):
|
|
99
110
|
click.echo(FeedbackManager.error(message=result.get("error")))
|
|
100
|
-
|
|
111
|
+
sys_exit("deployment_error", result.get("error", "Unknown error"))
|
|
112
|
+
click.echo(FeedbackManager.info(message="✓ Old deployment removed"))
|
|
101
113
|
|
|
102
|
-
click.echo(FeedbackManager.
|
|
114
|
+
click.echo(FeedbackManager.highlight(message="» Waiting for deployment to be promoted..."))
|
|
103
115
|
|
|
104
116
|
if wait:
|
|
105
117
|
while True:
|
|
@@ -108,7 +120,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
|
|
|
108
120
|
|
|
109
121
|
last_deployment = result.get("deployment")
|
|
110
122
|
if last_deployment.get("status") == "deleted":
|
|
111
|
-
click.echo(FeedbackManager.success(message="Deployment
|
|
123
|
+
click.echo(FeedbackManager.success(message="✓ Deployment is live!"))
|
|
112
124
|
break
|
|
113
125
|
|
|
114
126
|
time.sleep(5)
|
|
@@ -154,7 +166,7 @@ def discard_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
|
|
|
154
166
|
logging.debug(json.dumps(result, indent=2))
|
|
155
167
|
if result.get("error"):
|
|
156
168
|
click.echo(FeedbackManager.error(message=result.get("error")))
|
|
157
|
-
|
|
169
|
+
sys_exit("deployment_error", result.get("error", "Unknown error"))
|
|
158
170
|
|
|
159
171
|
click.echo(FeedbackManager.success(message="Discard process successfully started"))
|
|
160
172
|
|
|
@@ -404,7 +416,7 @@ def create_deployment(
|
|
|
404
416
|
sys.exit(0)
|
|
405
417
|
|
|
406
418
|
click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
|
|
407
|
-
|
|
419
|
+
sys_exit("deployment_error", "Deployment is not valid: " + str(deployment.get("errors")))
|
|
408
420
|
|
|
409
421
|
status = result.get("result")
|
|
410
422
|
if status == "success":
|
|
@@ -415,15 +427,15 @@ def create_deployment(
|
|
|
415
427
|
)
|
|
416
428
|
|
|
417
429
|
if wait:
|
|
418
|
-
click.echo(FeedbackManager.info(message="\n
|
|
430
|
+
click.echo(FeedbackManager.info(message="\n* Deployment submitted"))
|
|
419
431
|
else:
|
|
420
432
|
click.echo(FeedbackManager.success(message="\n✓ Deployment submitted successfully"))
|
|
421
433
|
elif status == "no_changes":
|
|
422
|
-
click.echo(FeedbackManager.
|
|
434
|
+
click.echo(FeedbackManager.warning(message="△ Not deploying. No changes."))
|
|
423
435
|
sys.exit(0)
|
|
424
436
|
elif status == "failed":
|
|
425
437
|
click.echo(FeedbackManager.error(message="Deployment failed"))
|
|
426
|
-
|
|
438
|
+
sys_exit("deployment_error", "Deployment failed" + str(deployment.get("errors")))
|
|
427
439
|
else:
|
|
428
440
|
click.echo(FeedbackManager.error(message=f"Unknown deployment result {status}"))
|
|
429
441
|
except Exception as e:
|
|
@@ -433,16 +445,17 @@ def create_deployment(
|
|
|
433
445
|
fd.close()
|
|
434
446
|
|
|
435
447
|
if not deployment and not check:
|
|
436
|
-
|
|
448
|
+
sys_exit("deployment_error", "Deployment failed")
|
|
437
449
|
|
|
438
450
|
if deployment and wait and not check:
|
|
451
|
+
click.echo(FeedbackManager.highlight(message="» Waiting for deployment to be ready..."))
|
|
439
452
|
while True:
|
|
440
453
|
url = f"{client.host}/v1/deployments/{deployment.get('id')}"
|
|
441
454
|
res = api_fetch(url, HEADERS)
|
|
442
455
|
deployment = res.get("deployment")
|
|
443
456
|
if not deployment:
|
|
444
457
|
click.echo(FeedbackManager.error(message="Error parsing deployment from response"))
|
|
445
|
-
|
|
458
|
+
sys_exit("deployment_error", "Error parsing deployment from response")
|
|
446
459
|
if deployment.get("status") == "failed":
|
|
447
460
|
click.echo(FeedbackManager.error(message="Deployment failed"))
|
|
448
461
|
deploy_errors = deployment.get("errors")
|
|
@@ -452,14 +465,14 @@ def create_deployment(
|
|
|
452
465
|
if auto:
|
|
453
466
|
click.echo(FeedbackManager.error(message="Rolling back deployment"))
|
|
454
467
|
discard_deployment(client.host, HEADERS, wait=wait)
|
|
455
|
-
|
|
468
|
+
sys_exit("deployment_error", "Deployment failed: " + str(deployment.get("errors")))
|
|
456
469
|
|
|
457
470
|
if deployment.get("status") == "data_ready":
|
|
458
471
|
break
|
|
459
472
|
|
|
460
473
|
time.sleep(5)
|
|
461
474
|
|
|
462
|
-
click.echo(FeedbackManager.
|
|
475
|
+
click.echo(FeedbackManager.info(message="✓ Deployment is ready"))
|
|
463
476
|
|
|
464
477
|
if auto:
|
|
465
478
|
promote_deployment(client.host, HEADERS, wait=wait)
|
|
@@ -513,12 +526,12 @@ def print_changes(result: dict, project: Project) -> None:
|
|
|
513
526
|
tokens.append((change_type, token_name, "\n".join(added_perms), "\n".join(removed_perms)))
|
|
514
527
|
|
|
515
528
|
if resources:
|
|
516
|
-
click.echo(FeedbackManager.
|
|
529
|
+
click.echo(FeedbackManager.info(message="\n* Changes to be deployed:"))
|
|
517
530
|
echo_safe_humanfriendly_tables_format_smart_table(resources, column_names=resources_columns)
|
|
518
531
|
else:
|
|
519
|
-
click.echo(FeedbackManager.
|
|
532
|
+
click.echo(FeedbackManager.info(message="\n* No changes to be deployed"))
|
|
520
533
|
if tokens:
|
|
521
|
-
click.echo(FeedbackManager.
|
|
534
|
+
click.echo(FeedbackManager.info(message="\n* Changes in tokens to be deployed:"))
|
|
522
535
|
echo_safe_humanfriendly_tables_format_smart_table(tokens, column_names=tokens_columns)
|
|
523
536
|
else:
|
|
524
|
-
click.echo(FeedbackManager.
|
|
537
|
+
click.echo(FeedbackManager.info(message="* No changes in tokens to be deployed"))
|
|
@@ -15,7 +15,8 @@ class CLIException(click.exceptions.ClickException):
|
|
|
15
15
|
|
|
16
16
|
def __init__(self, message: str, telemetry_event: Optional[str] = None, **kw_telemetry_event_data: Any) -> None:
|
|
17
17
|
telemetry_event = telemetry_event or "error"
|
|
18
|
-
|
|
18
|
+
message_without_color = message.replace("\033[91m", "").replace("\033[0m", "")
|
|
19
|
+
data: Dict[str, Any] = {"error": message_without_color}
|
|
19
20
|
data.update(kw_telemetry_event_data)
|
|
20
21
|
add_telemetry_event(telemetry_event, **data)
|
|
21
22
|
super().__init__(message)
|
|
@@ -89,3 +90,52 @@ class CLITokenException(CLIException):
|
|
|
89
90
|
|
|
90
91
|
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
91
92
|
super().__init__(message, "token_error", **kw_telemetry_event_data)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class CLIBuildException(CLIException):
|
|
96
|
+
"""Exceptions generated by the build commands"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
99
|
+
super().__init__(message, "build_error", **kw_telemetry_event_data)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class CLIDeploymentException(CLIException):
|
|
103
|
+
"""Exceptions generated by the deployment commands"""
|
|
104
|
+
|
|
105
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
106
|
+
super().__init__(message, "deployment_error", **kw_telemetry_event_data)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class CLITestException(CLIException):
|
|
110
|
+
"""Exceptions generated by the test commands"""
|
|
111
|
+
|
|
112
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
113
|
+
super().__init__(message, "test_error", **kw_telemetry_event_data)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class CLICreateException(CLIException):
|
|
117
|
+
"""Exceptions generated by the test commands"""
|
|
118
|
+
|
|
119
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
120
|
+
super().__init__(message, "create_error", **kw_telemetry_event_data)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class CLIMockException(CLIException):
|
|
124
|
+
"""Exceptions generated by the mock commands"""
|
|
125
|
+
|
|
126
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
127
|
+
super().__init__(message, "mock_error", **kw_telemetry_event_data)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class CLILoginException(CLIException):
|
|
131
|
+
"""Exceptions generated by the login commands"""
|
|
132
|
+
|
|
133
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
134
|
+
super().__init__(message, "login_error", **kw_telemetry_event_data)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class CLILocalException(CLIException):
|
|
138
|
+
"""Exceptions generated by the local commands"""
|
|
139
|
+
|
|
140
|
+
def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
|
|
141
|
+
super().__init__(message, "local_error", **kw_telemetry_event_data)
|
|
@@ -686,7 +686,6 @@ Please enter the ARN of the role you just created"""
|
|
|
686
686
|
warning_confirm_delete_rows_datasource = prompt_message(
|
|
687
687
|
"Do you want to delete {datasource}'s rows matching condition \"{delete_condition}\"? Once deleted, they can't be recovered"
|
|
688
688
|
)
|
|
689
|
-
|
|
690
689
|
warning_confirm_delete_pipe = prompt_message('Do you want to remove the pipe "{pipe}"?')
|
|
691
690
|
warning_confirm_copy_pipe = prompt_message('Do you want to run a copy job from the pipe "{pipe}"?')
|
|
692
691
|
warning_confirm_sink_job = prompt_message('Do you want to run a sink job from the pipe "{pipe}"?')
|
|
@@ -1005,9 +1004,6 @@ Please enter the ARN of the role you just created"""
|
|
|
1005
1004
|
success_delete_rows_datasource = success_message(
|
|
1006
1005
|
"** Data Source '{datasource}' rows deleted matching condition \"{delete_condition}\""
|
|
1007
1006
|
)
|
|
1008
|
-
success_delete_rows_datasource_no_rows = success_message(
|
|
1009
|
-
"** Data Source '{datasource}' no rows to delete matching condition \"{delete_condition}\""
|
|
1010
|
-
)
|
|
1011
1007
|
success_dry_run_delete_rows_datasource = success_message(
|
|
1012
1008
|
"** [DRY RUN] Data Source '{datasource}' rows '{rows}' matching condition \"{delete_condition}\" to be deleted"
|
|
1013
1009
|
)
|
|
@@ -11,7 +11,7 @@ from docker.client import DockerClient
|
|
|
11
11
|
from docker.models.containers import Container
|
|
12
12
|
from tinybird.tb.modules.cli import cli
|
|
13
13
|
from tinybird.tb.modules.common import coro
|
|
14
|
-
from tinybird.tb.modules.exceptions import CLIException
|
|
14
|
+
from tinybird.tb.modules.exceptions import CLIException, CLILocalException
|
|
15
15
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
16
16
|
from tinybird.tb.modules.local_common import TB_CONTAINER_NAME, TB_IMAGE_NAME, TB_LOCAL_PORT
|
|
17
17
|
|
|
@@ -71,7 +71,11 @@ def start_tinybird_local(
|
|
|
71
71
|
if health == "healthy":
|
|
72
72
|
break
|
|
73
73
|
if health == "unhealthy":
|
|
74
|
-
raise
|
|
74
|
+
raise CLILocalException(
|
|
75
|
+
FeedbackManager.error(
|
|
76
|
+
message="Tinybird Local is unhealthy. Try running `tb local restart` in a few seconds."
|
|
77
|
+
)
|
|
78
|
+
)
|
|
75
79
|
|
|
76
80
|
time.sleep(5)
|
|
77
81
|
|
|
@@ -125,8 +129,10 @@ def get_docker_client() -> DockerClient:
|
|
|
125
129
|
client.ping()
|
|
126
130
|
return client
|
|
127
131
|
except Exception:
|
|
128
|
-
raise
|
|
129
|
-
|
|
132
|
+
raise CLILocalException(
|
|
133
|
+
FeedbackManager.error(
|
|
134
|
+
message="No container runtime is running. Make sure a Docker-compatible runtime is installed and running."
|
|
135
|
+
)
|
|
130
136
|
)
|
|
131
137
|
|
|
132
138
|
|
|
@@ -7,7 +7,8 @@ import requests
|
|
|
7
7
|
|
|
8
8
|
from tinybird.tb.client import AuthNoTokenException, TinyB
|
|
9
9
|
from tinybird.tb.modules.config import CLIConfig
|
|
10
|
-
from tinybird.tb.modules.exceptions import
|
|
10
|
+
from tinybird.tb.modules.exceptions import CLILocalException
|
|
11
|
+
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
11
12
|
|
|
12
13
|
TB_IMAGE_NAME = "tinybirdco/tinybird-local:latest"
|
|
13
14
|
TB_CONTAINER_NAME = "tinybird-local"
|
|
@@ -34,7 +35,9 @@ async def get_tinybird_local_config(config_obj: Dict[str, Any], build: bool = Fa
|
|
|
34
35
|
# ruff: noqa: ASYNC210
|
|
35
36
|
tokens = requests.get(f"{TB_LOCAL_HOST}/tokens").json()
|
|
36
37
|
except Exception:
|
|
37
|
-
raise
|
|
38
|
+
raise CLILocalException(
|
|
39
|
+
FeedbackManager.error(message="Tinybird local is not running. Please run `tb local start` first.")
|
|
40
|
+
)
|
|
38
41
|
|
|
39
42
|
user_token = tokens["user_token"]
|
|
40
43
|
admin_token = tokens["admin_token"]
|