tinybird-cli 2.0.0.dev1__tar.gz → 2.0.1.dev0__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.
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/PKG-INFO +18 -2
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/__cli__.py +2 -2
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/check_pypi.py +2 -2
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/datafile.py +19 -17
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/feedback_manager.py +1 -1
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/branch.py +12 -21
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/cli.py +13 -17
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/common.py +19 -27
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/datasource.py +18 -28
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/job.py +4 -3
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/pipe.py +6 -20
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/test.py +4 -4
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +2 -2
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/workspace.py +9 -9
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/PKG-INFO +18 -2
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/setup.cfg +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/client.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/config.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/connector_settings.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/connectors.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/context.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/datatypes.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/sql.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/sql_template.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/syncasync.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tornado_template.py +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/requires.txt +0 -0
- {tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,10 +19,26 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
2.0.0
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
Released new version 2.0.0 with all these changes:
|
|
26
|
+
|
|
27
|
+
- `Changed` All commands exit with 1 when there's an exception
|
|
28
|
+
- `Removed` Prefixes are not supported anymore ([context](https://www.tinybird.co/changelog/2023-10-09-versions), and [how to migrate](https://www.tinybird.co/docs/guides/staging-and-production-workspaces.html#migrating-from-prefixes))
|
|
29
|
+
- `Removed` `tb pipe create`
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
2.0.0.dev2
|
|
33
|
+
************
|
|
34
|
+
|
|
35
|
+
- `Changed` All commands exit with 1 when there's an exception
|
|
36
|
+
- `Removed` `tb pipe create`
|
|
37
|
+
|
|
22
38
|
2.0.0.dev1
|
|
23
39
|
************
|
|
24
40
|
|
|
25
|
-
- `
|
|
41
|
+
- `Removed` Prefixes are not supported anymore
|
|
26
42
|
|
|
27
43
|
|
|
28
44
|
1.3.0
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://docs.tinybird.co/cli.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '2.0.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '2.0.1.dev0'
|
|
8
|
+
__revision__ = '40c7bee'
|
|
@@ -15,9 +15,9 @@ class CheckPypi:
|
|
|
15
15
|
disable_ssl: bool = getenv_bool("TB_DISABLE_SSL_CHECKS", False)
|
|
16
16
|
response: requests.Response = await requests_get(PYPY_URL, verify=not disable_ssl)
|
|
17
17
|
if response.status_code != 200:
|
|
18
|
-
CLIException(FeedbackManager.error_exception(error=response.content.decode("utf-8")))
|
|
18
|
+
raise CLIException(FeedbackManager.error_exception(error=response.content.decode("utf-8")))
|
|
19
19
|
version = response.json()["info"]["version"]
|
|
20
20
|
except Exception as e:
|
|
21
|
-
CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
21
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
22
22
|
|
|
23
23
|
return version
|
|
@@ -1045,7 +1045,7 @@ async def process_file(
|
|
|
1045
1045
|
]
|
|
1046
1046
|
|
|
1047
1047
|
if not all(required_params):
|
|
1048
|
-
raise
|
|
1048
|
+
raise click.ClickException(FeedbackManager.error_unknown_kafka_connection(datasource=name))
|
|
1049
1049
|
|
|
1050
1050
|
connector = await tb_client.connection_create_kafka(**connector_params)
|
|
1051
1051
|
except Exception as e:
|
|
@@ -1076,7 +1076,7 @@ async def process_file(
|
|
|
1076
1076
|
|
|
1077
1077
|
if service and service.lower() == "bigquery":
|
|
1078
1078
|
if not await tb_client.check_gcp_read_permissions():
|
|
1079
|
-
raise
|
|
1079
|
+
raise click.ClickException(FeedbackManager.error_unknown_bq_connection(datasource=datasource["name"]))
|
|
1080
1080
|
|
|
1081
1081
|
# Bigquery doesn't have a datalink, so we can stop here
|
|
1082
1082
|
return params
|
|
@@ -1086,7 +1086,7 @@ async def process_file(
|
|
|
1086
1086
|
connector_id: Optional[str] = node.get("import_connector", None)
|
|
1087
1087
|
connector_name: Optional[str] = node.get("import_connection_name", None)
|
|
1088
1088
|
if not connector_name and not connector_id:
|
|
1089
|
-
raise
|
|
1089
|
+
raise click.ClickException(FeedbackManager.error_missing_connection_name(datasource=datasource["name"]))
|
|
1090
1090
|
|
|
1091
1091
|
if not connector_id:
|
|
1092
1092
|
assert isinstance(connector_name, str)
|
|
@@ -1107,10 +1107,12 @@ async def process_file(
|
|
|
1107
1107
|
|
|
1108
1108
|
if service in PREVIEW_CONNECTOR_SERVICES:
|
|
1109
1109
|
if not params.get("import_bucket_uri", None):
|
|
1110
|
-
raise
|
|
1110
|
+
raise click.ClickException(FeedbackManager.error_missing_bucket_uri(datasource=datasource["name"]))
|
|
1111
1111
|
else:
|
|
1112
1112
|
if not params.get("import_external_datasource", None):
|
|
1113
|
-
raise
|
|
1113
|
+
raise click.ClickException(
|
|
1114
|
+
FeedbackManager.error_missing_external_datasource(datasource=datasource["name"])
|
|
1115
|
+
)
|
|
1114
1116
|
|
|
1115
1117
|
return params
|
|
1116
1118
|
|
|
@@ -1392,7 +1394,7 @@ async def process_file(
|
|
|
1392
1394
|
}
|
|
1393
1395
|
]
|
|
1394
1396
|
else:
|
|
1395
|
-
raise
|
|
1397
|
+
raise click.ClickException(FeedbackManager.error_file_extension(filename=filename))
|
|
1396
1398
|
|
|
1397
1399
|
|
|
1398
1400
|
def full_path_by_name(
|
|
@@ -2024,7 +2026,7 @@ async def check_pipe(
|
|
|
2024
2026
|
node["params"]["type"] = PipeNodeTypes.STANDARD
|
|
2025
2027
|
|
|
2026
2028
|
if populate:
|
|
2027
|
-
raise
|
|
2029
|
+
raise click.ClickException(FeedbackManager.error_check_pipes_populate())
|
|
2028
2030
|
|
|
2029
2031
|
runner = PipeCheckerRunner(pipe["name"], host)
|
|
2030
2032
|
headers = (
|
|
@@ -2053,7 +2055,7 @@ async def check_pipe(
|
|
|
2053
2055
|
)
|
|
2054
2056
|
|
|
2055
2057
|
if not r or r.status_code != 200:
|
|
2056
|
-
raise
|
|
2058
|
+
raise click.ClickException(FeedbackManager.error_check_pipes_api(pipe=pipe["name"]))
|
|
2057
2059
|
|
|
2058
2060
|
pipe_requests_to_check: List[Dict[str, str]] = []
|
|
2059
2061
|
for x in r.json().get("data", []):
|
|
@@ -2410,7 +2412,7 @@ async def new_pipe(
|
|
|
2410
2412
|
f"/v0/pipes?{urlencode(params)}", method="POST", headers=post_headers, data=json.dumps(body)
|
|
2411
2413
|
)
|
|
2412
2414
|
except Exception as e:
|
|
2413
|
-
raise
|
|
2415
|
+
raise click.ClickException(FeedbackManager.error_pushing_pipe(pipe=p["name"], error=str(e)))
|
|
2414
2416
|
|
|
2415
2417
|
datasource = data.get("datasource", None)
|
|
2416
2418
|
created_datasource = data.get("created_datasource", None)
|
|
@@ -2505,7 +2507,7 @@ async def new_pipe(
|
|
|
2505
2507
|
r = await tb_client.create_token(token_name, f"PIPES:{tk['permissions']}:{p['name']}", "P", p["name"])
|
|
2506
2508
|
token = r["token"] # type: ignore
|
|
2507
2509
|
except Exception as e:
|
|
2508
|
-
raise
|
|
2510
|
+
raise click.ClickException(FeedbackManager.error_creating_pipe(error=e))
|
|
2509
2511
|
else:
|
|
2510
2512
|
click.echo(FeedbackManager.info_create_found_token(token=token_name))
|
|
2511
2513
|
scopes = [f"PIPES:{tk['permissions']}:{p['name']}"]
|
|
@@ -2516,7 +2518,7 @@ async def new_pipe(
|
|
|
2516
2518
|
r = await tb_client.alter_tokens(token_name, scopes)
|
|
2517
2519
|
token = r["token"] # type: ignore
|
|
2518
2520
|
except Exception as e:
|
|
2519
|
-
raise
|
|
2521
|
+
raise click.ClickException(FeedbackManager.error_creating_pipe(error=e))
|
|
2520
2522
|
click.echo(FeedbackManager.success_test_endpoint(host=host, pipe=p["name"], token=token))
|
|
2521
2523
|
|
|
2522
2524
|
|
|
@@ -2679,7 +2681,7 @@ async def new_ds(
|
|
|
2679
2681
|
)
|
|
2680
2682
|
|
|
2681
2683
|
except Exception as e:
|
|
2682
|
-
raise
|
|
2684
|
+
raise click.ClickException(FeedbackManager.error_creating_datasource(error=str(e)))
|
|
2683
2685
|
return
|
|
2684
2686
|
|
|
2685
2687
|
if not force:
|
|
@@ -2779,7 +2781,7 @@ async def new_ds(
|
|
|
2779
2781
|
if current_connector["name"] != ds_params["connection"]:
|
|
2780
2782
|
param = "connection"
|
|
2781
2783
|
datafile_param = ImportReplacements.get_datafile_param_for_linker_param(service, param) or param
|
|
2782
|
-
raise
|
|
2784
|
+
raise click.ClickException(FeedbackManager.error_updating_connector_not_supported(param=datafile_param))
|
|
2783
2785
|
|
|
2784
2786
|
linkers = current_connector.get("linkers", [])
|
|
2785
2787
|
linker = next((linker for linker in linkers if linker["datasource_id"] == existing_ds["id"]), None)
|
|
@@ -2827,7 +2829,7 @@ async def new_ds(
|
|
|
2827
2829
|
await client.datasource_delete(ds_name)
|
|
2828
2830
|
click.echo(FeedbackManager.success_delete_datasource(datasource=ds_name))
|
|
2829
2831
|
except Exception:
|
|
2830
|
-
raise
|
|
2832
|
+
raise click.ClickException(FeedbackManager.error_removing_datasource(datasource=ds_name))
|
|
2831
2833
|
return
|
|
2832
2834
|
else:
|
|
2833
2835
|
if alter_error_message:
|
|
@@ -2942,7 +2944,7 @@ async def exec_file(
|
|
|
2942
2944
|
elif r["resource"] == "tokens":
|
|
2943
2945
|
await new_token(r, tb_client, force)
|
|
2944
2946
|
else:
|
|
2945
|
-
raise
|
|
2947
|
+
raise click.ClickException(FeedbackManager.error_unknown_resource(resource=r["resource"]))
|
|
2946
2948
|
|
|
2947
2949
|
|
|
2948
2950
|
def get_name_version(ds: str) -> Dict[str, Any]:
|
|
@@ -3769,7 +3771,7 @@ async def check_fixtures_data(
|
|
|
3769
3771
|
else:
|
|
3770
3772
|
click.echo(FeedbackManager.warning_fixture_not_found(datasource_name=name))
|
|
3771
3773
|
else:
|
|
3772
|
-
raise
|
|
3774
|
+
raise click.ClickException(FeedbackManager.error_unknown_resource(resource=resource["resource"]))
|
|
3773
3775
|
|
|
3774
3776
|
|
|
3775
3777
|
DATAFILE_NEW_LINE = "\n"
|
|
@@ -4187,7 +4189,7 @@ async def folder_pull(
|
|
|
4187
4189
|
if verbose:
|
|
4188
4190
|
click.echo(FeedbackManager.info_skip_already_exists())
|
|
4189
4191
|
except Exception as e:
|
|
4190
|
-
raise
|
|
4192
|
+
raise click.ClickException(FeedbackManager.error_exception(error=e))
|
|
4191
4193
|
return
|
|
4192
4194
|
|
|
4193
4195
|
try:
|
|
@@ -235,7 +235,6 @@ class FeedbackManager:
|
|
|
235
235
|
error_missing_datasource_name = error_message(
|
|
236
236
|
"Missing datasource name for pipe creation after the DATASOURCE label"
|
|
237
237
|
)
|
|
238
|
-
error_no_test_results = error_message("Error: No test results to show")
|
|
239
238
|
error_running_test = error_message("There was a problem running test file {file} (use -v for more info)")
|
|
240
239
|
error_processing_blocks = error_message("There was been an error while processing some blocks: {error}")
|
|
241
240
|
error_switching_to_main = error_message(
|
|
@@ -342,6 +341,7 @@ Ready? """
|
|
|
342
341
|
"You are going to manually update workspace release commit reference manually, this is just for special ocasions. Do you want to update current commit release reference '{current_commit}' to '{new_commit}'?"
|
|
343
342
|
)
|
|
344
343
|
|
|
344
|
+
warning_no_test_results = warning_message("Warning: No test results to show")
|
|
345
345
|
warning_using_environment_token = warning_message("** You're using the token defined in $TB_TOKEN.")
|
|
346
346
|
warning_using_environment_host = warning_message("** You're using the token defined in $TB_HOST.")
|
|
347
347
|
|
|
@@ -396,8 +396,7 @@ async def create_branch(
|
|
|
396
396
|
ctx: Context, env_name: str, last_partition: bool, all: bool, ignore_datasources: List[str], wait: bool
|
|
397
397
|
) -> None:
|
|
398
398
|
if last_partition and all:
|
|
399
|
-
|
|
400
|
-
return
|
|
399
|
+
raise CLIException(FeedbackManager.error_exception(error="Use --last-partition or --all but not both"))
|
|
401
400
|
await create_workspace_branch(ctx, env_name, last_partition, all, list(ignore_datasources), wait)
|
|
402
401
|
|
|
403
402
|
|
|
@@ -413,8 +412,7 @@ async def delete_branch(ctx: Context, env_name_or_id: str, yes: bool) -> None:
|
|
|
413
412
|
config, _, _ = await get_config_and_hosts(ctx)
|
|
414
413
|
|
|
415
414
|
if env_name_or_id == MAIN_BRANCH:
|
|
416
|
-
|
|
417
|
-
return
|
|
415
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
418
416
|
|
|
419
417
|
try:
|
|
420
418
|
workspace_branches = await get_current_workspace_branches(client, config)
|
|
@@ -453,7 +451,7 @@ async def delete_branch(ctx: Context, env_name_or_id: str, yes: bool) -> None:
|
|
|
453
451
|
if workspace_main:
|
|
454
452
|
await switch_to_workspace_by_user_workspace_data(ctx, workspace_main)
|
|
455
453
|
else:
|
|
456
|
-
|
|
454
|
+
raise CLIException(FeedbackManager.error_switching_to_main())
|
|
457
455
|
|
|
458
456
|
|
|
459
457
|
@env.command(
|
|
@@ -490,12 +488,10 @@ async def delete_branch(ctx: Context, env_name_or_id: str, yes: bool) -> None:
|
|
|
490
488
|
@coro
|
|
491
489
|
async def data_branch(ctx: Context, last_partition: bool, all: bool, ignore_datasources: List[str], wait: bool) -> None:
|
|
492
490
|
if last_partition and all:
|
|
493
|
-
|
|
494
|
-
return
|
|
491
|
+
raise CLIException(FeedbackManager.error_exception(error="Use --last-partition or --all but not both"))
|
|
495
492
|
|
|
496
493
|
if not last_partition and not all:
|
|
497
|
-
|
|
498
|
-
return
|
|
494
|
+
raise CLIException(FeedbackManager.error_exception(error="Use --last-partition or --all"))
|
|
499
495
|
|
|
500
496
|
obj: Dict[str, Any] = ctx.ensure_object(dict)
|
|
501
497
|
client = obj["client"]
|
|
@@ -506,8 +502,7 @@ async def data_branch(ctx: Context, last_partition: bool, all: bool, ignore_data
|
|
|
506
502
|
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
507
503
|
|
|
508
504
|
if current_main_workspace["id"] == config["id"]:
|
|
509
|
-
|
|
510
|
-
return
|
|
505
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
511
506
|
|
|
512
507
|
try:
|
|
513
508
|
response = await client.branch_workspace_data(config["id"], last_partition, all, ignore_datasources)
|
|
@@ -597,7 +592,7 @@ async def regression_tests(
|
|
|
597
592
|
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
598
593
|
|
|
599
594
|
if current_main_workspace["id"] == config["id"]:
|
|
600
|
-
|
|
595
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
601
596
|
return
|
|
602
597
|
try:
|
|
603
598
|
response = await client.branch_regression_tests_file(
|
|
@@ -647,7 +642,7 @@ async def _run_regression(
|
|
|
647
642
|
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
648
643
|
|
|
649
644
|
if current_main_workspace["id"] == config["id"]:
|
|
650
|
-
|
|
645
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
651
646
|
return
|
|
652
647
|
try:
|
|
653
648
|
response = await client.branch_regression_tests(
|
|
@@ -1025,20 +1020,17 @@ async def datasource_copy_from_main(
|
|
|
1025
1020
|
config = ctx.ensure_object(dict)["config"]
|
|
1026
1021
|
|
|
1027
1022
|
if sql and sql_from_main:
|
|
1028
|
-
|
|
1029
|
-
return
|
|
1023
|
+
raise CLIException(FeedbackManager.error_exception(error="Use --sql or --sql-from-main but not both"))
|
|
1030
1024
|
|
|
1031
1025
|
if not sql and not sql_from_main:
|
|
1032
|
-
|
|
1033
|
-
return
|
|
1026
|
+
raise CLIException(FeedbackManager.error_exception(error="Use --sql or --sql-from-main"))
|
|
1034
1027
|
|
|
1035
1028
|
current_main_workspace = await get_current_main_workspace(client, config)
|
|
1036
1029
|
if not current_main_workspace:
|
|
1037
1030
|
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
1038
1031
|
|
|
1039
1032
|
if current_main_workspace["id"] == config["id"] and sql_from_main:
|
|
1040
|
-
|
|
1041
|
-
return
|
|
1033
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
1042
1034
|
|
|
1043
1035
|
response = await client.datasource_query_copy(
|
|
1044
1036
|
datasource_name, sql if sql else f"SELECT * FROM main.{datasource_name}"
|
|
@@ -1088,8 +1080,7 @@ async def deploy_env(ctx: Context, semver: str, wait: bool, verbose: bool, dry_r
|
|
|
1088
1080
|
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
1089
1081
|
|
|
1090
1082
|
if current_main_workspace["id"] == config["id"]:
|
|
1091
|
-
|
|
1092
|
-
return
|
|
1083
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_main_branch())
|
|
1093
1084
|
|
|
1094
1085
|
workspaces: List[Dict[str, Any]] = (await client.user_workspaces_and_branches()).get("workspaces", [])
|
|
1095
1086
|
current_ws: Dict[str, Any] = next(
|
|
@@ -319,8 +319,7 @@ async def init(
|
|
|
319
319
|
)
|
|
320
320
|
|
|
321
321
|
if current_ws.get("is_branch"):
|
|
322
|
-
|
|
323
|
-
return
|
|
322
|
+
raise CLIException(FeedbackManager.error_not_allowed_in_branch())
|
|
324
323
|
|
|
325
324
|
await folder_init(client, folder, generate_datasources, generate_releases=True, force=force)
|
|
326
325
|
|
|
@@ -328,6 +327,7 @@ async def init(
|
|
|
328
327
|
return
|
|
329
328
|
|
|
330
329
|
cli_git_release = None
|
|
330
|
+
error = False
|
|
331
331
|
try:
|
|
332
332
|
cli_git_release = CLIGitRelease(path=folder)
|
|
333
333
|
except CLIGitReleaseException:
|
|
@@ -358,6 +358,7 @@ async def init(
|
|
|
358
358
|
final_response = FeedbackManager.error_release_already_set(
|
|
359
359
|
workspace=current_ws["name"], commit=current_ws["release"]["commit"]
|
|
360
360
|
)
|
|
361
|
+
error = True
|
|
361
362
|
|
|
362
363
|
elif override_commit:
|
|
363
364
|
if click.confirm(
|
|
@@ -425,6 +426,8 @@ async def init(
|
|
|
425
426
|
client, current_ws, config, path=cli_git_release.working_dir(), data_project_dir=data_project_dir
|
|
426
427
|
)
|
|
427
428
|
|
|
429
|
+
if error:
|
|
430
|
+
raise CLIException(final_response)
|
|
428
431
|
click.echo(final_response)
|
|
429
432
|
|
|
430
433
|
|
|
@@ -861,22 +864,19 @@ async def diff(
|
|
|
861
864
|
for workspace in response["workspaces"]:
|
|
862
865
|
if config["id"] == workspace["id"]:
|
|
863
866
|
if not workspace.get("is_branch"):
|
|
864
|
-
|
|
865
|
-
return
|
|
867
|
+
raise CLIException(FeedbackManager.error_not_a_branch())
|
|
866
868
|
|
|
867
869
|
origin = workspace["main"]
|
|
868
870
|
workspace = await get_current_main_workspace(client, config)
|
|
869
871
|
|
|
870
872
|
if not workspace:
|
|
871
|
-
|
|
872
|
-
return
|
|
873
|
+
raise CLIException(FeedbackManager.error_workspace(workspace=origin))
|
|
873
874
|
|
|
874
875
|
ws_client = _get_tb_client(workspace["token"], config["host"])
|
|
875
876
|
break
|
|
876
877
|
|
|
877
878
|
if not ws_client:
|
|
878
|
-
|
|
879
|
-
return
|
|
879
|
+
raise CLIException(FeedbackManager.error_workspace(workspace=origin))
|
|
880
880
|
changed = await diff_command(
|
|
881
881
|
list(filename) if filename else None, fmt, ws_client, no_color, with_print=not only_resources_changed
|
|
882
882
|
)
|
|
@@ -924,12 +924,10 @@ async def sql(
|
|
|
924
924
|
if query:
|
|
925
925
|
q = query.lower().strip()
|
|
926
926
|
if q.startswith("insert"):
|
|
927
|
-
click.echo(FeedbackManager.error_invalid_query())
|
|
928
927
|
click.echo(FeedbackManager.info_append_data())
|
|
929
|
-
|
|
928
|
+
raise CLIException(FeedbackManager.error_invalid_query())
|
|
930
929
|
if q.startswith("delete"):
|
|
931
|
-
|
|
932
|
-
return
|
|
930
|
+
raise CLIException(FeedbackManager.error_invalid_query())
|
|
933
931
|
res = await client.query(
|
|
934
932
|
f"SELECT * FROM ({query}) LIMIT {rows_limit} FORMAT {req_format}", pipeline=pipeline
|
|
935
933
|
)
|
|
@@ -979,12 +977,10 @@ async def sql(
|
|
|
979
977
|
f"SELECT * FROM ({query}) LIMIT {rows_limit} FORMAT {req_format}", pipeline=pipeline
|
|
980
978
|
)
|
|
981
979
|
except Exception as e:
|
|
982
|
-
|
|
983
|
-
return
|
|
980
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
984
981
|
|
|
985
982
|
if "error" in res:
|
|
986
|
-
|
|
987
|
-
return
|
|
983
|
+
raise CLIException(FeedbackManager.error_exception(error=res["error"]))
|
|
988
984
|
|
|
989
985
|
if stats:
|
|
990
986
|
stats_query = f"SELECT * FROM ({query}) LIMIT {rows_limit} FORMAT JSON"
|
|
@@ -1292,7 +1288,7 @@ async def materialize(
|
|
|
1292
1288
|
await _populate(pipe, node_name, f_pipe)
|
|
1293
1289
|
click.echo(FeedbackManager.success_created_matview(name=datasource_name))
|
|
1294
1290
|
except Exception as e:
|
|
1295
|
-
|
|
1291
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1296
1292
|
|
|
1297
1293
|
|
|
1298
1294
|
def __patch_click_output():
|
|
@@ -427,8 +427,7 @@ fi
|
|
|
427
427
|
|
|
428
428
|
async def configure_connector(connector):
|
|
429
429
|
if connector not in SUPPORTED_CONNECTORS:
|
|
430
|
-
|
|
431
|
-
return
|
|
430
|
+
raise CLIException(FeedbackManager.error_invalid_connector(connectors=", ".join(SUPPORTED_CONNECTORS)))
|
|
432
431
|
|
|
433
432
|
file_name = f".tinyb_{connector}"
|
|
434
433
|
config_file = Path(getcwd()) / file_name
|
|
@@ -815,8 +814,7 @@ async def get_available_starterkits(ctx: Context) -> List[Dict[str, Any]]:
|
|
|
815
814
|
ctx_dict["available_starterkits"] = available_starterkits
|
|
816
815
|
return available_starterkits
|
|
817
816
|
except Exception as ex:
|
|
818
|
-
|
|
819
|
-
return []
|
|
817
|
+
raise CLIException(FeedbackManager.error_exception(error=ex))
|
|
820
818
|
|
|
821
819
|
|
|
822
820
|
async def get_starterkit(ctx: Context, name: str) -> Optional[Dict[str, Any]]:
|
|
@@ -1095,7 +1093,7 @@ async def print_branch_regression_tests_summary(client, job_id, host, response=N
|
|
|
1095
1093
|
for failure in step["run"]["failed"]:
|
|
1096
1094
|
click.echo(f"❌ FAILED {failure['name']}\n")
|
|
1097
1095
|
if failed:
|
|
1098
|
-
raise
|
|
1096
|
+
raise CLIException(
|
|
1099
1097
|
"Check Failures Detail above for more information. If the results are expected, skip asserts or increase thresholds, see 💡 Hints above (note skip asserts flags are applied to all regression tests, so use them when it makes sense).\n\nIf you are using the CI template for GitHub or GitLab you can add skip asserts flags as labels to the MR and they are automatically applied. Find available flags to skip asserts and thresholds here => https://www.tinybird.co/docs/guides/continuous-integration.html#run-the-tests"
|
|
1100
1098
|
)
|
|
1101
1099
|
|
|
@@ -1147,8 +1145,7 @@ async def deploy_environment(
|
|
|
1147
1145
|
)
|
|
1148
1146
|
await switch_workspace(ctx, config["name"], only_environments=True)
|
|
1149
1147
|
except Exception as e:
|
|
1150
|
-
|
|
1151
|
-
await switch_workspace(ctx, config["name"], only_environments=True)
|
|
1148
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1152
1149
|
|
|
1153
1150
|
|
|
1154
1151
|
class MergeBranchStatus:
|
|
@@ -1277,8 +1274,7 @@ async def push_data(
|
|
|
1277
1274
|
if connector and sql:
|
|
1278
1275
|
load_connector_config(ctx, connector, False, check_uninstalled=False)
|
|
1279
1276
|
if connector not in ctx.obj:
|
|
1280
|
-
|
|
1281
|
-
return
|
|
1277
|
+
raise CLIException(FeedbackManager.error_connector_not_configured(connector=connector))
|
|
1282
1278
|
else:
|
|
1283
1279
|
_connector: Connector = ctx.obj[connector]
|
|
1284
1280
|
click.echo(FeedbackManager.info_starting_export_process(connector=connector))
|
|
@@ -1346,19 +1342,18 @@ async def push_data(
|
|
|
1346
1342
|
try:
|
|
1347
1343
|
datasource = await client.get_datasource(datasource_name)
|
|
1348
1344
|
except DoesNotExistException:
|
|
1349
|
-
|
|
1345
|
+
raise CLIException(FeedbackManager.error_datasource_does_not_exist(datasource=datasource_name))
|
|
1350
1346
|
except Exception as e:
|
|
1351
|
-
|
|
1352
|
-
return
|
|
1347
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1353
1348
|
|
|
1354
1349
|
total_rows = (datasource.get("statistics", {}) or {}).get("row_count", 0)
|
|
1355
1350
|
appended_rows = 0
|
|
1356
1351
|
parser = None
|
|
1357
1352
|
|
|
1358
1353
|
if "error" in res and res["error"]:
|
|
1359
|
-
|
|
1354
|
+
raise CLIException(FeedbackManager.error_exception(error=res["error"]))
|
|
1360
1355
|
if "errors" in res and res["errors"]:
|
|
1361
|
-
|
|
1356
|
+
raise CLIException(FeedbackManager.error_exception(error=res["errors"]))
|
|
1362
1357
|
if "blocks" in res and res["blocks"]:
|
|
1363
1358
|
for block in res["blocks"]:
|
|
1364
1359
|
if "process_return" in block and block["process_return"] is not None:
|
|
@@ -1386,10 +1381,9 @@ async def push_data(
|
|
|
1386
1381
|
output = await gather_with_concurrency(concurrency, *tasks)
|
|
1387
1382
|
parser, total_rows, appended_rows = list(output)[-1]
|
|
1388
1383
|
except OperationCanNotBePerformed as e:
|
|
1389
|
-
|
|
1384
|
+
raise CLIException(FeedbackManager.error_operation_can_not_be_performed(error=e))
|
|
1390
1385
|
except Exception as e:
|
|
1391
|
-
|
|
1392
|
-
sys.exit(1)
|
|
1386
|
+
raise CLIException(FeedbackManager.error_exception(error=e))
|
|
1393
1387
|
else:
|
|
1394
1388
|
click.echo(FeedbackManager.success_progress_blocks())
|
|
1395
1389
|
if mode == "append":
|
|
@@ -1554,9 +1548,9 @@ async def switch_workspace(ctx, workspace_name_or_id, only_environments=False):
|
|
|
1554
1548
|
|
|
1555
1549
|
if not workspace:
|
|
1556
1550
|
if only_environments:
|
|
1557
|
-
|
|
1551
|
+
raise CLIException(FeedbackManager.error_branch(branch=workspace_name_or_id))
|
|
1558
1552
|
else:
|
|
1559
|
-
|
|
1553
|
+
raise CLIException(FeedbackManager.error_workspace(workspace=workspace_name_or_id))
|
|
1560
1554
|
return
|
|
1561
1555
|
|
|
1562
1556
|
client = _get_tb_client(workspace["token"], config["host"])
|
|
@@ -1577,8 +1571,7 @@ async def switch_workspace(ctx, workspace_name_or_id, only_environments=False):
|
|
|
1577
1571
|
await write_config(config)
|
|
1578
1572
|
click.echo(FeedbackManager.success_now_using_config(name=config["name"], id=config["id"]))
|
|
1579
1573
|
except Exception as e:
|
|
1580
|
-
|
|
1581
|
-
return
|
|
1574
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1582
1575
|
|
|
1583
1576
|
|
|
1584
1577
|
async def switch_to_workspace_by_user_workspace_data(ctx, user_workspace_data: Dict):
|
|
@@ -1605,8 +1598,7 @@ async def switch_to_workspace_by_user_workspace_data(ctx, user_workspace_data: D
|
|
|
1605
1598
|
await write_config(config)
|
|
1606
1599
|
click.echo(FeedbackManager.success_now_using_config(name=config["name"], id=config["id"]))
|
|
1607
1600
|
except Exception as e:
|
|
1608
|
-
|
|
1609
|
-
return
|
|
1601
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1610
1602
|
|
|
1611
1603
|
|
|
1612
1604
|
async def print_current_workspace(ctx):
|
|
@@ -1943,14 +1935,14 @@ async def wait_job(
|
|
|
1943
1935
|
# TODO: Simplify this as it's not needed to use two functions for
|
|
1944
1936
|
result = await wait_job_no_ui(tb_client, job_id, timeout, progressbar_cb)
|
|
1945
1937
|
if result["status"] != "done":
|
|
1946
|
-
|
|
1938
|
+
raise CLIException(FeedbackManager.error_while_running_job(error=result["error"]))
|
|
1947
1939
|
return result
|
|
1948
1940
|
except asyncio.TimeoutError:
|
|
1949
|
-
raise
|
|
1941
|
+
raise CLIException(FeedbackManager.error_while_running_job(error="Reach timeout, job cancelled"))
|
|
1950
1942
|
except JobException as e:
|
|
1951
|
-
raise
|
|
1943
|
+
raise CLIException(FeedbackManager.error_while_running_job(error=str(e)))
|
|
1952
1944
|
except Exception as e:
|
|
1953
|
-
raise
|
|
1945
|
+
raise CLIException(FeedbackManager.error_getting_job_info(error=str(e), url=job_url))
|
|
1954
1946
|
|
|
1955
1947
|
|
|
1956
1948
|
async def wait_job_no_ui(
|
|
@@ -113,7 +113,7 @@ async def datasource_ls(ctx: Context, match: Optional[str], format_: str):
|
|
|
113
113
|
elif format_ == "json":
|
|
114
114
|
click.echo(json.dumps({"datasources": table_machine_readable}, indent=2))
|
|
115
115
|
else:
|
|
116
|
-
|
|
116
|
+
raise CLIDatasourceException(FeedbackManager.error_datasource_ls_type())
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
@datasource.command(name="append")
|
|
@@ -163,12 +163,10 @@ async def datasource_append(
|
|
|
163
163
|
"""
|
|
164
164
|
|
|
165
165
|
if not url and not connector:
|
|
166
|
-
|
|
167
|
-
return
|
|
166
|
+
raise CLIDatasourceException(FeedbackManager.error_missing_url_or_connector(datasource=datasource_name))
|
|
168
167
|
|
|
169
168
|
if incremental and not connector:
|
|
170
|
-
|
|
171
|
-
return
|
|
169
|
+
raise CLIDatasourceException(FeedbackManager.error_incremental_not_supported())
|
|
172
170
|
|
|
173
171
|
if incremental:
|
|
174
172
|
date = None
|
|
@@ -255,8 +253,7 @@ async def datasource_analyze(ctx, url_or_file, connector):
|
|
|
255
253
|
if connector:
|
|
256
254
|
load_connector_config(ctx, connector, False, check_uninstalled=False)
|
|
257
255
|
if connector not in ctx.obj:
|
|
258
|
-
|
|
259
|
-
return
|
|
256
|
+
raise CLIDatasourceException(FeedbackManager.error_connector_not_configured(connector=connector))
|
|
260
257
|
else:
|
|
261
258
|
_connector = ctx.obj[connector]
|
|
262
259
|
|
|
@@ -396,9 +393,11 @@ async def datasource_truncate(ctx, datasource_name, yes, cascade):
|
|
|
396
393
|
try:
|
|
397
394
|
await client.datasource_truncate(cascade_ds)
|
|
398
395
|
except DoesNotExistException:
|
|
399
|
-
|
|
396
|
+
raise CLIDatasourceException(
|
|
397
|
+
FeedbackManager.error_datasource_does_not_exist(datasource=datasource_name)
|
|
398
|
+
)
|
|
400
399
|
except Exception as e:
|
|
401
|
-
|
|
400
|
+
raise CLIDatasourceException(FeedbackManager.error_exception(error=e))
|
|
402
401
|
click.echo(FeedbackManager.success_truncate_datasource(datasource=cascade_ds))
|
|
403
402
|
|
|
404
403
|
|
|
@@ -453,8 +452,7 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
453
452
|
try:
|
|
454
453
|
res = await client._req(f"v0/jobs/{job_id}")
|
|
455
454
|
except Exception:
|
|
456
|
-
|
|
457
|
-
break
|
|
455
|
+
raise CLIDatasourceException(FeedbackManager.error_job_status(url=job_url))
|
|
458
456
|
if res["status"] == "done":
|
|
459
457
|
print("\n")
|
|
460
458
|
click.echo(
|
|
@@ -465,8 +463,7 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
465
463
|
break
|
|
466
464
|
elif res["status"] == "error":
|
|
467
465
|
print("\n")
|
|
468
|
-
|
|
469
|
-
break
|
|
466
|
+
raise CLIDatasourceException(FeedbackManager.error_exception(error=res["error"]))
|
|
470
467
|
await asyncio.sleep(1)
|
|
471
468
|
i += 1
|
|
472
469
|
progress_line(i)
|
|
@@ -499,8 +496,7 @@ async def generate_datasource(ctx: Context, connector: str, filenames, force: bo
|
|
|
499
496
|
if connector:
|
|
500
497
|
load_connector_config(ctx, connector, False, check_uninstalled=False)
|
|
501
498
|
if connector not in ctx.ensure_object(dict):
|
|
502
|
-
|
|
503
|
-
return
|
|
499
|
+
raise CLIDatasourceException(FeedbackManager.error_connector_not_configured(connector=connector))
|
|
504
500
|
else:
|
|
505
501
|
_connector = ctx.ensure_object(dict)[connector]
|
|
506
502
|
|
|
@@ -571,7 +567,7 @@ async def datasource_connect(ctx, connection, datasource_name, topic, group, aut
|
|
|
571
567
|
datasource_id = resp["datasource"]["id"]
|
|
572
568
|
click.echo(FeedbackManager.success_datasource_kafka_connected(id=datasource_id))
|
|
573
569
|
else:
|
|
574
|
-
|
|
570
|
+
raise CLIDatasourceException(FeedbackManager.error_unknown_connection_service(service=service))
|
|
575
571
|
|
|
576
572
|
|
|
577
573
|
@datasource.command(name="share")
|
|
@@ -607,12 +603,10 @@ async def datasource_share(ctx: Context, datasource_name: str, workspace_name_or
|
|
|
607
603
|
current_workspace = next((workspace for workspace in workspaces if workspace["id"] == config["id"]), None)
|
|
608
604
|
|
|
609
605
|
if not destination_workspace:
|
|
610
|
-
|
|
611
|
-
return
|
|
606
|
+
raise CLIDatasourceException(FeedbackManager.error_workspace(workspace=workspace_name_or_id))
|
|
612
607
|
|
|
613
608
|
if not current_workspace:
|
|
614
|
-
|
|
615
|
-
return
|
|
609
|
+
raise CLIDatasourceException(FeedbackManager.error_not_authenticated())
|
|
616
610
|
|
|
617
611
|
if not user_token:
|
|
618
612
|
user_token = ask_for_user_token("share a Data Source", ui_host)
|
|
@@ -638,8 +632,7 @@ async def datasource_share(ctx: Context, datasource_name: str, workspace_name_or
|
|
|
638
632
|
)
|
|
639
633
|
)
|
|
640
634
|
except Exception as e:
|
|
641
|
-
|
|
642
|
-
return
|
|
635
|
+
raise CLIDatasourceException(FeedbackManager.error_exception(error=str(e)))
|
|
643
636
|
|
|
644
637
|
|
|
645
638
|
@datasource.command(name="unshare")
|
|
@@ -675,12 +668,10 @@ async def datasource_unshare(ctx: Context, datasource_name: str, workspace_name_
|
|
|
675
668
|
current_workspace = next((workspace for workspace in workspaces if workspace["id"] == config["id"]), None)
|
|
676
669
|
|
|
677
670
|
if not destination_workspace:
|
|
678
|
-
|
|
679
|
-
return
|
|
671
|
+
raise CLIDatasourceException(FeedbackManager.error_workspace(workspace=workspace_name_or_id))
|
|
680
672
|
|
|
681
673
|
if not current_workspace:
|
|
682
|
-
|
|
683
|
-
return
|
|
674
|
+
raise CLIDatasourceException(FeedbackManager.error_not_authenticated())
|
|
684
675
|
|
|
685
676
|
if not user_token:
|
|
686
677
|
user_token = ask_for_user_token("unshare a Data Source", ui_host)
|
|
@@ -706,8 +697,7 @@ async def datasource_unshare(ctx: Context, datasource_name: str, workspace_name_
|
|
|
706
697
|
)
|
|
707
698
|
)
|
|
708
699
|
except Exception as e:
|
|
709
|
-
|
|
710
|
-
return
|
|
700
|
+
raise CLIDatasourceException(FeedbackManager.error_exception(error=str(e)))
|
|
711
701
|
|
|
712
702
|
|
|
713
703
|
@datasource.command(name="sync")
|
|
@@ -11,6 +11,7 @@ from tinybird.feedback_manager import FeedbackManager
|
|
|
11
11
|
from tinybird.client import DoesNotExistException, TinyB
|
|
12
12
|
|
|
13
13
|
from tinybird.tb_cli_modules.cli import cli
|
|
14
|
+
from tinybird.tb_cli_modules.exceptions import CLIException
|
|
14
15
|
from tinybird.tb_cli_modules.common import coro, echo_safe_humanfriendly_tables_format_smart_table
|
|
15
16
|
|
|
16
17
|
|
|
@@ -72,9 +73,9 @@ async def job_cancel(ctx: Context, job_id: str) -> None:
|
|
|
72
73
|
try:
|
|
73
74
|
result = await client.job_cancel(job_id)
|
|
74
75
|
except DoesNotExistException:
|
|
75
|
-
|
|
76
|
+
raise CLIException(FeedbackManager.error_job_does_not_exist(job_id=job_id))
|
|
76
77
|
except Exception as e:
|
|
77
|
-
|
|
78
|
+
raise CLIException(FeedbackManager.error_exception(error=e))
|
|
78
79
|
else:
|
|
79
80
|
current_job_status = result["status"]
|
|
80
81
|
if current_job_status == "cancelling":
|
|
@@ -82,5 +83,5 @@ async def job_cancel(ctx: Context, job_id: str) -> None:
|
|
|
82
83
|
elif current_job_status == "cancelled":
|
|
83
84
|
click.echo(FeedbackManager.success_job_cancellation_cancelled(job_id=job_id))
|
|
84
85
|
else:
|
|
85
|
-
|
|
86
|
+
raise CLIException(FeedbackManager.error_job_cancelled_but_status_unknown(job_id=job_id))
|
|
86
87
|
click.echo("\n")
|
|
@@ -66,7 +66,9 @@ SQL >
|
|
|
66
66
|
file.write(pipefile)
|
|
67
67
|
click.echo(FeedbackManager.success_generated_pipe(file=f))
|
|
68
68
|
else:
|
|
69
|
-
|
|
69
|
+
raise CLIPipeException(
|
|
70
|
+
FeedbackManager.error_exception(error=f"File {f} already exists, use --force to override")
|
|
71
|
+
)
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
@pipe.command(name="stats")
|
|
@@ -122,8 +124,7 @@ async def pipe_stats(ctx: click.Context, pipes: Tuple[str, ...], format_: str):
|
|
|
122
124
|
res = await client.query(sql)
|
|
123
125
|
|
|
124
126
|
if res and "error" in res:
|
|
125
|
-
|
|
126
|
-
return
|
|
127
|
+
raise CLIPipeException(FeedbackManager.error_exception(error=str(res["error"])))
|
|
127
128
|
|
|
128
129
|
columns = ["version", "name", "request count", "error count", "avg latency"]
|
|
129
130
|
table_human_readable: List[Tuple] = []
|
|
@@ -204,7 +205,7 @@ async def pipe_ls(ctx: Context, match: str, format_: str):
|
|
|
204
205
|
elif format_ == "json":
|
|
205
206
|
click.echo(json.dumps({"pipes": table_machine_readable}, indent=2))
|
|
206
207
|
else:
|
|
207
|
-
|
|
208
|
+
raise CLIPipeException(FeedbackManager.error_pipe_ls_type())
|
|
208
209
|
|
|
209
210
|
|
|
210
211
|
@pipe.command(name="populate")
|
|
@@ -264,20 +265,6 @@ async def pipe_populate(
|
|
|
264
265
|
await wait_job(cl, job_id, job_url, "Populating")
|
|
265
266
|
|
|
266
267
|
|
|
267
|
-
@pipe.command(name="new", hidden=True)
|
|
268
|
-
@click.argument("pipe_name")
|
|
269
|
-
@click.argument("sql")
|
|
270
|
-
@click.pass_context
|
|
271
|
-
@coro
|
|
272
|
-
async def pipe_create(ctx: click.Context, pipe_name: str, sql: str):
|
|
273
|
-
"""Create a new pipe"""
|
|
274
|
-
click.echo(FeedbackManager.warning_deprecated(warning="This command is deprecated."))
|
|
275
|
-
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
276
|
-
host = ctx.ensure_object(dict)["config"].get("host", DEFAULT_API_HOST)
|
|
277
|
-
res = await client.pipe_create(pipe_name, sql)
|
|
278
|
-
click.echo(FeedbackManager.success_created_pipe(pipe=pipe_name, node_id=res["nodes"][0]["id"], host=host))
|
|
279
|
-
|
|
280
|
-
|
|
281
268
|
@pipe.command(name="append")
|
|
282
269
|
@click.argument("pipe_name_or_uid")
|
|
283
270
|
@click.argument("sql")
|
|
@@ -444,8 +431,7 @@ async def print_pipe(ctx: Context, pipe: str, query: str, format_: str):
|
|
|
444
431
|
try:
|
|
445
432
|
res = await client.pipe_data(pipe, format=req_format, sql=query, params=params)
|
|
446
433
|
except Exception as e:
|
|
447
|
-
|
|
448
|
-
return
|
|
434
|
+
raise CLIPipeException(FeedbackManager.error_exception(error=str(e)))
|
|
449
435
|
|
|
450
436
|
if not format_:
|
|
451
437
|
stats = res["statistics"]
|
|
@@ -9,6 +9,7 @@ from tinybird.feedback_manager import FeedbackManager
|
|
|
9
9
|
from typing import Iterable, List, Tuple
|
|
10
10
|
|
|
11
11
|
from tinybird.tb_cli_modules.cli import cli
|
|
12
|
+
from tinybird.tb_cli_modules.exceptions import CLIException
|
|
12
13
|
from tinybird.tb_cli_modules.common import coro, create_tb_client
|
|
13
14
|
from tinybird.tb_cli_modules.tinyunit.tinyunit import (
|
|
14
15
|
TestSummaryResults,
|
|
@@ -37,8 +38,7 @@ async def test_run(ctx: click.Context, file: Tuple[str, ...], verbose: bool, onl
|
|
|
37
38
|
try:
|
|
38
39
|
tb_client = create_tb_client(ctx)
|
|
39
40
|
except Exception as e:
|
|
40
|
-
|
|
41
|
-
raise e
|
|
41
|
+
raise CLIException(FeedbackManager.error_exception(error=e))
|
|
42
42
|
|
|
43
43
|
file_list: Iterable[str] = file if len(file) > 0 else glob.glob("./tests/**/*.y*ml", recursive=True)
|
|
44
44
|
file_list = [f for f in file_list if not f.endswith("regression.yaml")]
|
|
@@ -47,12 +47,12 @@ async def test_run(ctx: click.Context, file: Tuple[str, ...], verbose: bool, onl
|
|
|
47
47
|
test_result = await run_test_file(tb_client, test_file)
|
|
48
48
|
results.append(TestSummaryResults(filename=test_file, results=test_result))
|
|
49
49
|
except Exception as e:
|
|
50
|
-
click.echo(FeedbackManager.error_running_test(file=test_file))
|
|
51
50
|
if verbose:
|
|
52
51
|
click.echo(FeedbackManager.error_exception(error=e))
|
|
52
|
+
raise CLIException(FeedbackManager.error_running_test(file=test_file))
|
|
53
53
|
|
|
54
54
|
if len(results) <= 0:
|
|
55
|
-
click.echo(FeedbackManager.
|
|
55
|
+
click.echo(FeedbackManager.warning_no_test_results())
|
|
56
56
|
else:
|
|
57
57
|
test_run_summary(results, only_fail=only_fail, verbose_level=int(verbose))
|
|
58
58
|
|
{tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
@@ -150,7 +150,7 @@ def parse_file(file: str) -> Iterable[TestCase]:
|
|
|
150
150
|
properties.get("pipe", None),
|
|
151
151
|
)
|
|
152
152
|
except Exception as e:
|
|
153
|
-
|
|
153
|
+
raise CLIException(
|
|
154
154
|
f"""Error: {FeedbackManager.error_exception(error=e)} reading file, check "{file}"->"{definition.get('name')}" """
|
|
155
155
|
)
|
|
156
156
|
|
|
@@ -184,7 +184,7 @@ def generate_file(file: str, overwrite: bool = False) -> None:
|
|
|
184
184
|
yaml.safe_dump(definitions, f)
|
|
185
185
|
click.echo(FeedbackManager.success_generated_local_file(file=p))
|
|
186
186
|
else:
|
|
187
|
-
|
|
187
|
+
raise CLIException(FeedbackManager.error_file_already_exists(file=p))
|
|
188
188
|
|
|
189
189
|
return
|
|
190
190
|
|
|
@@ -26,7 +26,7 @@ from tinybird.tb_cli_modules.common import (
|
|
|
26
26
|
echo_safe_humanfriendly_tables_format_smart_table,
|
|
27
27
|
get_current_main_workspace,
|
|
28
28
|
)
|
|
29
|
-
from tinybird.tb_cli_modules.exceptions import
|
|
29
|
+
from tinybird.tb_cli_modules.exceptions import CLIWorkspaceException
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
@cli.group()
|
|
@@ -51,7 +51,7 @@ async def workspace_ls(ctx: Context) -> None:
|
|
|
51
51
|
|
|
52
52
|
current_main_workspace = await get_current_main_workspace(client, config)
|
|
53
53
|
if not current_main_workspace:
|
|
54
|
-
raise
|
|
54
|
+
raise CLIWorkspaceException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
55
55
|
|
|
56
56
|
columns = ["name", "id", "role", "plan", "current"]
|
|
57
57
|
table = []
|
|
@@ -114,7 +114,7 @@ async def clear_workspace(ctx: Context, yes: bool, dry_run: bool) -> None:
|
|
|
114
114
|
for workspace in response["workspaces"]:
|
|
115
115
|
if config["id"] == workspace["id"]:
|
|
116
116
|
if workspace.get("is_branch"):
|
|
117
|
-
|
|
117
|
+
raise CLIWorkspaceException(FeedbackManager.error_not_allowed_in_branch())
|
|
118
118
|
return
|
|
119
119
|
else:
|
|
120
120
|
click.echo(FeedbackManager.info_current_workspace())
|
|
@@ -154,10 +154,12 @@ async def clear_workspace(ctx: Context, yes: bool, dry_run: bool) -> None:
|
|
|
154
154
|
except DoesNotExistException:
|
|
155
155
|
click.echo(FeedbackManager.info_removing_datasource_not_found(datasource=ds_name))
|
|
156
156
|
except CanNotBeDeletedException as e:
|
|
157
|
-
|
|
157
|
+
raise CLIWorkspaceException(
|
|
158
|
+
FeedbackManager.error_datasource_can_not_be_deleted(datasource=ds_name, error=e)
|
|
159
|
+
)
|
|
158
160
|
except Exception as e:
|
|
159
161
|
if "is a Shared Data Source" in str(e):
|
|
160
|
-
|
|
162
|
+
raise CLIWorkspaceException(FeedbackManager.error_operation_can_not_be_performed(error=e))
|
|
161
163
|
else:
|
|
162
164
|
raise CLIWorkspaceException(FeedbackManager.error_exception(error=e))
|
|
163
165
|
else:
|
|
@@ -182,8 +184,7 @@ async def create_workspace(
|
|
|
182
184
|
) -> None:
|
|
183
185
|
if starter_kit:
|
|
184
186
|
if not await is_valid_starterkit(ctx, starter_kit):
|
|
185
|
-
|
|
186
|
-
return
|
|
187
|
+
raise CLIWorkspaceException(FeedbackManager.error_starterkit_name(starterkit_name=starter_kit))
|
|
187
188
|
|
|
188
189
|
if not user_token:
|
|
189
190
|
_, _, ui_host = await get_config_and_hosts(ctx)
|
|
@@ -244,5 +245,4 @@ async def delete_workspace(
|
|
|
244
245
|
await client.delete_workspace(workspace_to_delete["id"], confirm_hard_delete)
|
|
245
246
|
click.echo(FeedbackManager.success_workspace_deleted(workspace_name=workspace_to_delete["name"]))
|
|
246
247
|
except Exception as e:
|
|
247
|
-
|
|
248
|
-
return
|
|
248
|
+
raise CLIWorkspaceException(FeedbackManager.error_exception(error=str(e)))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,10 +19,26 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
2.0.0
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
Released new version 2.0.0 with all these changes:
|
|
26
|
+
|
|
27
|
+
- `Changed` All commands exit with 1 when there's an exception
|
|
28
|
+
- `Removed` Prefixes are not supported anymore ([context](https://www.tinybird.co/changelog/2023-10-09-versions), and [how to migrate](https://www.tinybird.co/docs/guides/staging-and-production-workspaces.html#migrating-from-prefixes))
|
|
29
|
+
- `Removed` `tb pipe create`
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
2.0.0.dev2
|
|
33
|
+
************
|
|
34
|
+
|
|
35
|
+
- `Changed` All commands exit with 1 when there's an exception
|
|
36
|
+
- `Removed` `tb pipe create`
|
|
37
|
+
|
|
22
38
|
2.0.0.dev1
|
|
23
39
|
************
|
|
24
40
|
|
|
25
|
-
- `
|
|
41
|
+
- `Removed` Prefixes are not supported anymore
|
|
26
42
|
|
|
27
43
|
|
|
28
44
|
1.3.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.0.dev1 → tinybird-cli-2.0.1.dev0}/tinybird_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|