tinybird-cli 2.0.1.dev0__tar.gz → 2.1.0.dev2__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.1.dev0 → tinybird-cli-2.1.0.dev2}/PKG-INFO +11 -1
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/__cli__.py +2 -2
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/client.py +3 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/datafile.py +94 -7
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/feedback_manager.py +13 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/branch.py +4 -11
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/cli.py +97 -41
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/PKG-INFO +11 -1
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/setup.cfg +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/config.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/connector_settings.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/connectors.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/context.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/datatypes.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/sql.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/sql_template.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/syncasync.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tornado_template.py +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/requires.txt +0 -0
- {tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/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.1.0.dev2
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,16 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
2.1.0.dev2
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Changed` Internal changes in `tb deploy`
|
|
26
|
+
|
|
27
|
+
2.1.0.dev1
|
|
28
|
+
************
|
|
29
|
+
|
|
30
|
+
- `Added` `tb deploy` removes resources from datafiles deleted
|
|
31
|
+
|
|
22
32
|
2.0.0
|
|
23
33
|
************
|
|
24
34
|
|
|
@@ -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.1.0.dev2'
|
|
8
|
+
__revision__ = '8400007'
|
|
@@ -1084,6 +1084,9 @@ class TinyB(object):
|
|
|
1084
1084
|
}
|
|
1085
1085
|
return await self._req(f"/v0/workspaces/{workspace_id}/releases/?{urlencode(params)}", method="POST", data="")
|
|
1086
1086
|
|
|
1087
|
+
async def release_failed(self, workspace_id: str, semver: str):
|
|
1088
|
+
return await self._req(f"/v0/workspaces/{workspace_id}/releases/{semver}?status=failed", method="PUT")
|
|
1089
|
+
|
|
1087
1090
|
async def release_preview(self, workspace_id: str, semver: str):
|
|
1088
1091
|
return await self._req(f"/v0/workspaces/{workspace_id}/releases/{semver}?status=preview", method="PUT")
|
|
1089
1092
|
|
|
@@ -52,7 +52,7 @@ from tinybird.tb_cli_modules.common import _get_tb_client, get_current_main_work
|
|
|
52
52
|
|
|
53
53
|
from .tornado_template import UnClosedIfError
|
|
54
54
|
from .sql import parse_table_structure, schema_to_sql_columns
|
|
55
|
-
from .client import TinyB, DoesNotExistException
|
|
55
|
+
from .client import TinyB, DoesNotExistException, AuthException, CanNotBeDeletedException
|
|
56
56
|
from .sql_template import render_sql_template, get_used_tables_in_template
|
|
57
57
|
from tinybird.sql_template_fmt import format_sql_template
|
|
58
58
|
from .feedback_manager import FeedbackManager
|
|
@@ -410,6 +410,9 @@ class CLIGitRelease:
|
|
|
410
410
|
for filename in filenames
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
+
def get_deleted_from_diffs(self, diffs: List[Diff]) -> List[str]:
|
|
414
|
+
return [diff.a_path for diff in diffs if diff.change_type == self.ChangeType.DELETED.value and diff.a_path]
|
|
415
|
+
|
|
413
416
|
async def update_release(
|
|
414
417
|
self, tb_client: TinyB, current_ws: Dict[str, Any], commit: Optional[str] = None
|
|
415
418
|
) -> Dict[str, Any]:
|
|
@@ -454,6 +457,7 @@ class Deployment:
|
|
|
454
457
|
if not diffs:
|
|
455
458
|
click.echo(FeedbackManager.info_git_release_no_diffs())
|
|
456
459
|
changed = self.cli_git_release.get_changes_from_diffs(diffs, filenames)
|
|
460
|
+
deleted = self.cli_git_release.get_deleted_from_diffs(diffs)
|
|
457
461
|
|
|
458
462
|
else:
|
|
459
463
|
# only changes flow
|
|
@@ -462,7 +466,8 @@ class Deployment:
|
|
|
462
466
|
if config
|
|
463
467
|
else None
|
|
464
468
|
)
|
|
465
|
-
|
|
469
|
+
deleted = []
|
|
470
|
+
return changed, deleted
|
|
466
471
|
|
|
467
472
|
def preparing_release(self):
|
|
468
473
|
if not self.is_git_release:
|
|
@@ -499,11 +504,70 @@ class Deployment:
|
|
|
499
504
|
if not self.is_git_release or self.dry_run or has_semver:
|
|
500
505
|
return
|
|
501
506
|
self.cli_git_release = self.cli_git_release or CLIGitRelease()
|
|
502
|
-
release = await self.tb_client.
|
|
503
|
-
self.current_ws["id"], self.cli_git_release.head().commit.hexsha if not commit else commit
|
|
504
|
-
)
|
|
507
|
+
release = await self.cli_git_release.update_release(self.tb_client, self.current_ws, commit)
|
|
505
508
|
click.echo(FeedbackManager.success_git_release(release_commit=release["commit"]))
|
|
506
509
|
|
|
510
|
+
async def delete_resources(self, deleted: List[str], remote_pipes: List[Dict[str, Any]], dry_run: bool = False):
|
|
511
|
+
async def delete_pipe(resource_name_or_id: str, dry_run: bool = False):
|
|
512
|
+
if dry_run:
|
|
513
|
+
click.echo(
|
|
514
|
+
FeedbackManager.info_deleting_resource(dry_run="[DRY RUN] ", resource_name=resource_name_or_id)
|
|
515
|
+
)
|
|
516
|
+
else:
|
|
517
|
+
click.echo(FeedbackManager.info_deleting_resource(dry_run="", resource_name=resource_name_or_id))
|
|
518
|
+
try:
|
|
519
|
+
await self.tb_client.pipe_delete(resource_name_or_id)
|
|
520
|
+
except AuthException as e:
|
|
521
|
+
raise CLIGitReleaseException(str(e))
|
|
522
|
+
else:
|
|
523
|
+
click.echo(FeedbackManager.success_delete(name=resource_name_or_id))
|
|
524
|
+
|
|
525
|
+
async def delete_datasource(resource_name_or_id: str, dry_run: bool = False):
|
|
526
|
+
if dry_run:
|
|
527
|
+
click.echo(
|
|
528
|
+
FeedbackManager.info_deleting_resource(dry_run="[DRY RUN] ", resource_name=resource_name_or_id)
|
|
529
|
+
)
|
|
530
|
+
else:
|
|
531
|
+
click.echo(FeedbackManager.info_deleting_resource(dry_run="", resource_name=resource_name_or_id))
|
|
532
|
+
try:
|
|
533
|
+
await self.tb_client.datasource_delete(resource_name_or_id)
|
|
534
|
+
except CanNotBeDeletedException as e:
|
|
535
|
+
raise CLIGitReleaseException(str(e))
|
|
536
|
+
else:
|
|
537
|
+
click.echo(FeedbackManager.success_delete(name=resource_name_or_id))
|
|
538
|
+
|
|
539
|
+
resource_extension_processor = {".datasource": delete_datasource, ".pipe": delete_pipe}
|
|
540
|
+
|
|
541
|
+
# builds pipes deps the other way around from API to use with toposort
|
|
542
|
+
# i.e {'analytics_hits': ['analytics_pages', 'trend', 'analytics_sources', 'analytics_sessions']}
|
|
543
|
+
pipes_deps: Dict[str, List[str]] = {}
|
|
544
|
+
remote_pipes_type: Dict[str, str] = {}
|
|
545
|
+
for pipe in remote_pipes:
|
|
546
|
+
pipes_deps[pipe["name"]] = []
|
|
547
|
+
remote_pipes_type[pipe["name"]] = pipe["type"]
|
|
548
|
+
for node in pipe["nodes"]:
|
|
549
|
+
for dep in node["dependencies"]:
|
|
550
|
+
if dep in [pipe["name"] for pipe in remote_pipes]:
|
|
551
|
+
pipes_deps.setdefault(dep, []).append(pipe["name"])
|
|
552
|
+
deleted_resources: Dict[str, str] = {Path(resource).resolve().stem: resource for resource in deleted}
|
|
553
|
+
|
|
554
|
+
for group in toposort(pipes_deps):
|
|
555
|
+
# for each level keep materialized for the end
|
|
556
|
+
for pipe_name in sorted(group, key=lambda x: remote_pipes_type[x] == "materialized"):
|
|
557
|
+
if pipe_name in deleted_resources:
|
|
558
|
+
resource_path = deleted_resources.pop(pipe_name)
|
|
559
|
+
try:
|
|
560
|
+
await resource_extension_processor[Path(resource_path).suffix](pipe_name, dry_run)
|
|
561
|
+
except KeyError:
|
|
562
|
+
raise CLIGitReleaseException(FeedbackManager.error_file_extension(resource_path))
|
|
563
|
+
|
|
564
|
+
# Delete pending resources (datasources)
|
|
565
|
+
for name, path in deleted_resources.items():
|
|
566
|
+
try:
|
|
567
|
+
await resource_extension_processor[Path(path).suffix](name, dry_run)
|
|
568
|
+
except KeyError:
|
|
569
|
+
raise CLIGitReleaseException(FeedbackManager.error_file_extension(path))
|
|
570
|
+
|
|
507
571
|
|
|
508
572
|
class Datafile:
|
|
509
573
|
def __init__(self) -> None:
|
|
@@ -3407,7 +3471,7 @@ async def folder_push(
|
|
|
3407
3471
|
workspace_lib_paths.append((x.name, x))
|
|
3408
3472
|
|
|
3409
3473
|
datasources: List[Dict[str, Any]] = await tb_client.datasources()
|
|
3410
|
-
pipes: List[Dict[str, Any]] = await tb_client.pipes()
|
|
3474
|
+
pipes: List[Dict[str, Any]] = await tb_client.pipes(dependencies=True)
|
|
3411
3475
|
|
|
3412
3476
|
existing_resources: List[str] = [x["name"] for x in datasources] + [x["name"] for x in pipes]
|
|
3413
3477
|
# replace workspace mapping names
|
|
@@ -3429,7 +3493,7 @@ async def folder_push(
|
|
|
3429
3493
|
filenames = get_project_filenames(folder)
|
|
3430
3494
|
|
|
3431
3495
|
# get the list of changes
|
|
3432
|
-
changed = await deployment.detect_changes(filenames, only_changes, config)
|
|
3496
|
+
changed, deleted = await deployment.detect_changes(filenames, only_changes, config)
|
|
3433
3497
|
|
|
3434
3498
|
deployment.preparing_release()
|
|
3435
3499
|
|
|
@@ -3668,9 +3732,12 @@ async def folder_push(
|
|
|
3668
3732
|
if deployment.is_git_release:
|
|
3669
3733
|
deployment.deploying_dry_run()
|
|
3670
3734
|
await push_files(dry_run=True)
|
|
3735
|
+
|
|
3736
|
+
await deployment.delete_resources(deleted, pipes, dry_run=True)
|
|
3671
3737
|
if not deployment.dry_run:
|
|
3672
3738
|
deployment.deploying()
|
|
3673
3739
|
await push_files(dry_run)
|
|
3740
|
+
await deployment.delete_resources(deleted, pipes)
|
|
3674
3741
|
else:
|
|
3675
3742
|
await push_files(dry_run)
|
|
3676
3743
|
|
|
@@ -4427,3 +4494,23 @@ def is_datasource(resource: Dict[str, Any]) -> bool:
|
|
|
4427
4494
|
if resource and resource.get("resource") == "datasources":
|
|
4428
4495
|
return True
|
|
4429
4496
|
return False
|
|
4497
|
+
|
|
4498
|
+
|
|
4499
|
+
async def create_release(client: TinyB, config: Dict[str, Any], semver: str, folder: Optional[str] = None) -> None:
|
|
4500
|
+
if not folder:
|
|
4501
|
+
folder = getcwd()
|
|
4502
|
+
cli_git_release = None
|
|
4503
|
+
try:
|
|
4504
|
+
cli_git_release = CLIGitRelease(path=folder)
|
|
4505
|
+
commit = cli_git_release.head_commit()
|
|
4506
|
+
except CLIGitReleaseException:
|
|
4507
|
+
raise CLIGitReleaseException(FeedbackManager.error_no_git_repo_for_init(repo_path=folder))
|
|
4508
|
+
|
|
4509
|
+
await client.release_new(config["id"], semver, commit)
|
|
4510
|
+
click.echo(FeedbackManager.success_deployment_release(semver=semver))
|
|
4511
|
+
|
|
4512
|
+
|
|
4513
|
+
def has_internal_datafiles(folder: str) -> bool:
|
|
4514
|
+
folder = folder or "."
|
|
4515
|
+
filenames = get_project_filenames(folder)
|
|
4516
|
+
return any([f for f in filenames if "spans" in str(f) and "vendor" not in str(f)])
|
|
@@ -313,6 +313,15 @@ class FeedbackManager:
|
|
|
313
313
|
"There are resources renamed. `tb deploy` can't deploy renamed resources, create new resources instead."
|
|
314
314
|
)
|
|
315
315
|
|
|
316
|
+
info_create_release = info_message(
|
|
317
|
+
"** Release semver is bumped. Will use --fork-downstream to deploy changes. 💡 Hint: --fork-downstream creates new versions of the dependent downstream resources of the changed resources."
|
|
318
|
+
)
|
|
319
|
+
info_alter_release = info_message(
|
|
320
|
+
"** Release semver is not bumped. Changes are deployed to the current live Release. 💡 Hint: To deploy to a new Release edit the VERSION env variable in the .tinyenv file of the Data Project."
|
|
321
|
+
)
|
|
322
|
+
info_releases_detected = info_message(
|
|
323
|
+
"** Live Release: {current_semver} => New Release: {semver} 💡 Hint: To deploy to a new Release edit the VERSION env variable in the .tinyenv file of the Data Project."
|
|
324
|
+
)
|
|
316
325
|
info_pre_prompt_auth_login_user_token = info_message(
|
|
317
326
|
"ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here."
|
|
318
327
|
)
|
|
@@ -436,7 +445,9 @@ Ready? """
|
|
|
436
445
|
)
|
|
437
446
|
warning_for_cicd_file = warning_message("** 🚨 Warning 🚨: {warning_message}")
|
|
438
447
|
warning_unknown_response = warning_message("** Warning. Unknown response from server: {response}")
|
|
448
|
+
warning_resource_not_in_workspace = warning_message("** Warning: '{resource_name}' not found in workspace")
|
|
439
449
|
|
|
450
|
+
info_fixtures_branch = info_message("** Data Fixtures are only pushed to Branches")
|
|
440
451
|
info_materialize_push_datasource_exists = warning_message("** Data Source {name} already exists")
|
|
441
452
|
info_materialize_push_datasource_override = prompt_message(
|
|
442
453
|
"Delete the Data Source from the workspace and push {name} again?"
|
|
@@ -589,6 +600,7 @@ Ready? """
|
|
|
589
600
|
info_detected_changes_from_includes = info_message("** Changes from includes:")
|
|
590
601
|
info_processing_from_include = info_message("\t{include_filename} => {filename}")
|
|
591
602
|
info_deps_for_resource = info_message("\t{resource} => '{dep}'")
|
|
603
|
+
info_deleting_resource = info_message("** {dry_run}Deleting '{resource_name}'")
|
|
592
604
|
|
|
593
605
|
info_cicd_generation_cancelled_by_user = info_message("** CI/CD files generation cancelled by user.")
|
|
594
606
|
info_skipping_sharing_datasources_environment = info_message(
|
|
@@ -697,6 +709,7 @@ Ready? """
|
|
|
697
709
|
success_sink_job_finished = success_message("""** Data sinked to '{bucket_path}'""")
|
|
698
710
|
success_print_pipe = success_message("** Pipe: {pipe}")
|
|
699
711
|
success_create = success_message("** '{name}' created")
|
|
712
|
+
success_delete = success_message("** '{name}' deleted")
|
|
700
713
|
success_progress_blocks = success_message("** \N{front-facing baby chick} done")
|
|
701
714
|
success_now_using_config = success_message("** Now using {name} ({id})")
|
|
702
715
|
success_connector_config = success_message(
|
|
@@ -34,7 +34,7 @@ from tinybird.tb_cli_modules.common import (
|
|
|
34
34
|
get_current_workspace,
|
|
35
35
|
)
|
|
36
36
|
from tinybird.feedback_manager import FeedbackManager
|
|
37
|
-
from tinybird.datafile import wait_job, CLIGitRelease, CLIGitReleaseException
|
|
37
|
+
from tinybird.datafile import wait_job, CLIGitRelease, CLIGitReleaseException, create_release
|
|
38
38
|
from tinybird.tb_cli_modules.exceptions import CLIBranchException, CLIException, CLIReleaseException
|
|
39
39
|
|
|
40
40
|
|
|
@@ -145,15 +145,7 @@ async def release_create(ctx: Context, semver: str) -> None:
|
|
|
145
145
|
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
146
146
|
config = ctx.ensure_object(dict)["config"]
|
|
147
147
|
folder = getcwd()
|
|
148
|
-
|
|
149
|
-
try:
|
|
150
|
-
cli_git_release = CLIGitRelease(path=folder)
|
|
151
|
-
commit = cli_git_release.head_commit()
|
|
152
|
-
except CLIGitReleaseException:
|
|
153
|
-
raise CLIGitReleaseException(FeedbackManager.error_no_git_repo_for_init(repo_path=folder))
|
|
154
|
-
|
|
155
|
-
await client.release_new(config["id"], semver, commit)
|
|
156
|
-
click.echo(FeedbackManager.success_deployment_release(semver=semver))
|
|
148
|
+
await create_release(client, config, semver, folder)
|
|
157
149
|
|
|
158
150
|
|
|
159
151
|
@release.command(name="promote", short_help="Promotes to live status a preview Release")
|
|
@@ -177,8 +169,9 @@ async def release_promote(ctx: Context, semver: str) -> None:
|
|
|
177
169
|
client = _get_tb_client(config["token"], config["host"])
|
|
178
170
|
|
|
179
171
|
try:
|
|
180
|
-
await client.release_promote(config["id"], semver)
|
|
172
|
+
release = await client.release_promote(config["id"], semver)
|
|
181
173
|
click.echo(FeedbackManager.success_release_promote(semver=semver))
|
|
174
|
+
click.echo(FeedbackManager.success_git_release(release_commit=release["commit"]))
|
|
182
175
|
except Exception as e:
|
|
183
176
|
raise CLIReleaseException(FeedbackManager.error_exception(error=str(e)))
|
|
184
177
|
|
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
import shutil
|
|
15
15
|
import sys
|
|
16
16
|
import click
|
|
17
|
+
from packaging import version
|
|
17
18
|
from click import Context
|
|
18
19
|
|
|
19
20
|
from pathlib import Path
|
|
@@ -29,6 +30,7 @@ from tinybird.datafile import (
|
|
|
29
30
|
AlreadyExistsException,
|
|
30
31
|
Datafile,
|
|
31
32
|
ParseException,
|
|
33
|
+
create_release,
|
|
32
34
|
build_graph,
|
|
33
35
|
folder_push,
|
|
34
36
|
folder_pull,
|
|
@@ -45,6 +47,7 @@ from tinybird.datafile import (
|
|
|
45
47
|
peek,
|
|
46
48
|
color_diff,
|
|
47
49
|
parse_token,
|
|
50
|
+
has_internal_datafiles,
|
|
48
51
|
)
|
|
49
52
|
import tinybird.context as context
|
|
50
53
|
from tinybird.config import FeatureFlags, get_config, VERSION, CURRENT_VERSION, SUPPORTED_CONNECTORS
|
|
@@ -114,12 +117,6 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
|
|
|
114
117
|
default=True,
|
|
115
118
|
help="Don't print version warning message if there's a new available version. You can use TB_VERSION_WARNING envar",
|
|
116
119
|
)
|
|
117
|
-
@click.option(
|
|
118
|
-
"--hide-tokens",
|
|
119
|
-
is_flag=True,
|
|
120
|
-
default=False,
|
|
121
|
-
help="Disable the output of tokens [DEPRECATED: tokens are hidden by default]",
|
|
122
|
-
)
|
|
123
120
|
@click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
|
|
124
121
|
@click.version_option(version=VERSION)
|
|
125
122
|
@click.pass_context
|
|
@@ -144,18 +141,11 @@ async def cli(
|
|
|
144
141
|
sf_stage,
|
|
145
142
|
with_headers: bool,
|
|
146
143
|
version_warning: bool,
|
|
147
|
-
hide_tokens: bool,
|
|
148
144
|
show_tokens: bool,
|
|
149
145
|
) -> None:
|
|
150
146
|
"""
|
|
151
147
|
Use `OBFUSCATE_REGEX_PATTERN` and `OBFUSCATE_PATTERN_SEPARATOR` environment variables to define a regex pattern and a separator (in case of a single string with multiple regex) to obfuscate secrets in the CLI output.
|
|
152
148
|
"""
|
|
153
|
-
if hide_tokens:
|
|
154
|
-
click.echo(
|
|
155
|
-
FeedbackManager.warning_deprecated(
|
|
156
|
-
warning="The `--hide-tokens` flag is deprecated. Tokens are hidden by default, see `tb --help` for more info."
|
|
157
|
-
)
|
|
158
|
-
)
|
|
159
149
|
|
|
160
150
|
# We need to unpatch for our tests not to break
|
|
161
151
|
if show_tokens:
|
|
@@ -586,13 +576,6 @@ def check(filenames: List[str], debug: bool) -> None:
|
|
|
586
576
|
help="The user token is required for sharing a datasource that contains the SHARED_WITH entry.",
|
|
587
577
|
type=click.types.STRING,
|
|
588
578
|
)
|
|
589
|
-
@click.option(
|
|
590
|
-
"--is-internal",
|
|
591
|
-
is_flag=True,
|
|
592
|
-
default=False,
|
|
593
|
-
help="Use when working with the Internal workspace as by default users can not create MV from internal datasources",
|
|
594
|
-
hidden=True,
|
|
595
|
-
)
|
|
596
579
|
@click.pass_context
|
|
597
580
|
@coro
|
|
598
581
|
async def push(
|
|
@@ -625,12 +608,14 @@ async def push(
|
|
|
625
608
|
check_requests_from_main: bool,
|
|
626
609
|
folder: str,
|
|
627
610
|
user_token: Optional[str],
|
|
628
|
-
is_internal: bool,
|
|
629
611
|
) -> None:
|
|
630
612
|
"""Push files to Tinybird."""
|
|
631
613
|
|
|
632
614
|
ignore_sql_errors = FeatureFlags.ignore_sql_errors()
|
|
633
615
|
context.disable_template_security_validation.set(True)
|
|
616
|
+
|
|
617
|
+
is_internal = has_internal_datafiles(folder)
|
|
618
|
+
|
|
634
619
|
await folder_push(
|
|
635
620
|
create_tb_client(ctx),
|
|
636
621
|
filenames,
|
|
@@ -833,25 +818,14 @@ async def fmt(
|
|
|
833
818
|
help="Diffs local datafiles to the corresponding remote files in the main workspace. Only works when authenticated on an Environment.",
|
|
834
819
|
hidden=True,
|
|
835
820
|
)
|
|
836
|
-
@click.option(
|
|
837
|
-
"--production",
|
|
838
|
-
is_flag=True,
|
|
839
|
-
default=False,
|
|
840
|
-
help="Diffs local datafiles to the corresponding remote files in the main workspace. Only works when authenticated on an Environment. (deprecated)",
|
|
841
|
-
hidden=True,
|
|
842
|
-
)
|
|
843
821
|
@click.pass_context
|
|
844
822
|
@coro
|
|
845
823
|
async def diff(
|
|
846
|
-
ctx: Context, filename: Optional[Tuple], fmt: bool, no_color: bool, no_verbose: bool, main: bool
|
|
824
|
+
ctx: Context, filename: Optional[Tuple], fmt: bool, no_color: bool, no_verbose: bool, main: bool
|
|
847
825
|
) -> None:
|
|
848
826
|
only_resources_changed = no_verbose
|
|
849
827
|
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
850
828
|
|
|
851
|
-
if production:
|
|
852
|
-
click.echo(FeedbackManager.warning_deprecated(warning="--production flag is deprecated, use --main instead"))
|
|
853
|
-
|
|
854
|
-
main = main or production
|
|
855
829
|
if not main:
|
|
856
830
|
changed = await diff_command(
|
|
857
831
|
list(filename) if filename else None, fmt, client, no_color, with_print=not only_resources_changed
|
|
@@ -1420,17 +1394,17 @@ async def prompt(_ctx: Context) -> None:
|
|
|
1420
1394
|
hidden=True,
|
|
1421
1395
|
)
|
|
1422
1396
|
@click.option(
|
|
1423
|
-
"--
|
|
1397
|
+
"--only-changes",
|
|
1424
1398
|
is_flag=True,
|
|
1425
1399
|
default=False,
|
|
1426
|
-
help="
|
|
1400
|
+
help="Deprecated, remove when we use `tb deploy` to deploy to main. See => https://gitlab.com/tinybird/analytics/-/issues/9669",
|
|
1427
1401
|
hidden=True,
|
|
1428
1402
|
)
|
|
1429
1403
|
@click.option(
|
|
1430
|
-
"--
|
|
1404
|
+
"--v3",
|
|
1431
1405
|
is_flag=True,
|
|
1432
1406
|
default=False,
|
|
1433
|
-
help="
|
|
1407
|
+
help="Some specific logic to deploy using Releases. Will remove once we go to GA",
|
|
1434
1408
|
hidden=True,
|
|
1435
1409
|
)
|
|
1436
1410
|
@click.pass_context
|
|
@@ -1455,13 +1429,80 @@ async def deploy(
|
|
|
1455
1429
|
user_token: Optional[str],
|
|
1456
1430
|
fork_downstream: bool,
|
|
1457
1431
|
fork: bool,
|
|
1458
|
-
is_internal: bool,
|
|
1459
1432
|
only_changes: bool,
|
|
1433
|
+
v3: bool,
|
|
1460
1434
|
) -> None:
|
|
1461
1435
|
"""Deploy in tinybird pushing resources changed from previous release using git"""
|
|
1462
1436
|
|
|
1463
1437
|
ignore_sql_errors = FeatureFlags.ignore_sql_errors()
|
|
1464
1438
|
context.disable_template_security_validation.set(True)
|
|
1439
|
+
|
|
1440
|
+
is_internal = has_internal_datafiles(folder)
|
|
1441
|
+
|
|
1442
|
+
if not v3:
|
|
1443
|
+
await folder_push(
|
|
1444
|
+
tb_client=create_tb_client(ctx),
|
|
1445
|
+
dry_run=dry_run,
|
|
1446
|
+
check=False,
|
|
1447
|
+
push_deps=True,
|
|
1448
|
+
debug=debug,
|
|
1449
|
+
force=True,
|
|
1450
|
+
git_release=True,
|
|
1451
|
+
only_changes=only_changes,
|
|
1452
|
+
override_datasource=override_datasource,
|
|
1453
|
+
populate=populate,
|
|
1454
|
+
populate_subset=subset,
|
|
1455
|
+
populate_condition=sql_condition,
|
|
1456
|
+
unlink_on_populate_error=unlink_on_populate_error,
|
|
1457
|
+
upload_fixtures=fixtures,
|
|
1458
|
+
wait=wait,
|
|
1459
|
+
ignore_sql_errors=ignore_sql_errors,
|
|
1460
|
+
skip_confirmation=yes,
|
|
1461
|
+
workspace_map=dict(workspace_map),
|
|
1462
|
+
workspace_lib_paths=workspace,
|
|
1463
|
+
timeout=timeout,
|
|
1464
|
+
run_tests=False,
|
|
1465
|
+
folder=folder,
|
|
1466
|
+
config=ctx.ensure_object(dict)["config"],
|
|
1467
|
+
user_token=user_token,
|
|
1468
|
+
fork_downstream=fork_downstream,
|
|
1469
|
+
fork=fork,
|
|
1470
|
+
is_internal=is_internal,
|
|
1471
|
+
)
|
|
1472
|
+
return
|
|
1473
|
+
|
|
1474
|
+
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
1475
|
+
config = ctx.ensure_object(dict)["config"]
|
|
1476
|
+
workspaces: List[Dict[str, Any]] = (await client.user_workspaces_and_branches()).get("workspaces", [])
|
|
1477
|
+
current_ws: Dict[str, Any] = next(
|
|
1478
|
+
(workspace for workspace in workspaces if config and workspace.get("id", ".") == config.get("id", "..")), {}
|
|
1479
|
+
)
|
|
1480
|
+
|
|
1481
|
+
semver = config.get("semver")
|
|
1482
|
+
is_environment = current_ws.get("is_branch")
|
|
1483
|
+
# FIXME decide when to auto-promote
|
|
1484
|
+
auto_promote = False
|
|
1485
|
+
release = current_ws.get("release", {})
|
|
1486
|
+
current_semver: Optional[str] = "no release in remote Workspace"
|
|
1487
|
+
if release and isinstance(release, dict):
|
|
1488
|
+
current_semver = release.get("semver")
|
|
1489
|
+
|
|
1490
|
+
if not is_environment:
|
|
1491
|
+
# TODO upload fixtures on tb test
|
|
1492
|
+
fixtures = False
|
|
1493
|
+
click.echo(FeedbackManager.info_fixtures_branch())
|
|
1494
|
+
|
|
1495
|
+
release_created = False
|
|
1496
|
+
if semver and current_semver:
|
|
1497
|
+
click.echo(FeedbackManager.info_releases_detected(current_semver=current_semver, semver=semver))
|
|
1498
|
+
if version.parse(semver.split("-snapshot")[0]) > version.parse(current_semver.split("-snapshot")[0]):
|
|
1499
|
+
click.echo(FeedbackManager.info_create_release())
|
|
1500
|
+
await create_release(client, config, semver)
|
|
1501
|
+
release_created = True
|
|
1502
|
+
fork_downstream = True
|
|
1503
|
+
else:
|
|
1504
|
+
click.echo(FeedbackManager.info_alter_release())
|
|
1505
|
+
yes = True
|
|
1465
1506
|
try:
|
|
1466
1507
|
await folder_push(
|
|
1467
1508
|
tb_client=create_tb_client(ctx),
|
|
@@ -1492,9 +1533,9 @@ async def deploy(
|
|
|
1492
1533
|
fork=fork,
|
|
1493
1534
|
is_internal=is_internal,
|
|
1494
1535
|
)
|
|
1495
|
-
except
|
|
1496
|
-
|
|
1497
|
-
|
|
1536
|
+
except Exception as e:
|
|
1537
|
+
if release_created:
|
|
1538
|
+
await client.release_failed(config["id"], semver)
|
|
1498
1539
|
if "--override-datasource" in str(e):
|
|
1499
1540
|
new_exception = type(e)(
|
|
1500
1541
|
f"{str(e).replace('. If you want to try to force override the Materialized View, please use the `--override-datasource` flag', '')} If you are creating a new Release update the related .datasource files and use --fork-downstream"
|
|
@@ -1502,3 +1543,18 @@ async def deploy(
|
|
|
1502
1543
|
raise new_exception
|
|
1503
1544
|
else:
|
|
1504
1545
|
raise e
|
|
1546
|
+
|
|
1547
|
+
if release_created:
|
|
1548
|
+
try:
|
|
1549
|
+
await client.release_preview(config["id"], semver)
|
|
1550
|
+
click.echo(FeedbackManager.success_release_preview(semver=semver))
|
|
1551
|
+
if auto_promote:
|
|
1552
|
+
# TODO: define when auto-promote in the main Environment
|
|
1553
|
+
try:
|
|
1554
|
+
release = await client.release_promote(config["id"], semver)
|
|
1555
|
+
click.echo(FeedbackManager.success_release_promote(semver=semver))
|
|
1556
|
+
click.echo(FeedbackManager.success_git_release(release_commit=release["commit"]))
|
|
1557
|
+
except Exception as e:
|
|
1558
|
+
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
1559
|
+
except Exception as e:
|
|
1560
|
+
raise CLIException(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.1.0.dev2
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,16 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
2.1.0.dev2
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Changed` Internal changes in `tb deploy`
|
|
26
|
+
|
|
27
|
+
2.1.0.dev1
|
|
28
|
+
************
|
|
29
|
+
|
|
30
|
+
- `Added` `tb deploy` removes resources from datafiles deleted
|
|
31
|
+
|
|
22
32
|
2.0.0
|
|
23
33
|
************
|
|
24
34
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
File without changes
|
{tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-2.0.1.dev0 → tinybird-cli-2.1.0.dev2}/tinybird_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|