tinybird 4.5.6.dev0__tar.gz → 4.5.7.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.
Files changed (126) hide show
  1. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/PKG-INFO +5 -1
  2. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/__cli__.py +2 -2
  3. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/cli.py +1 -1
  4. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/deployment.py +148 -0
  5. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/deployment_common.py +92 -8
  6. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/PKG-INFO +5 -1
  7. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/setup.cfg +0 -0
  8. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/__cli__.py +0 -0
  9. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/ch_utils/constants.py +0 -0
  10. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/ch_utils/engine.py +0 -0
  11. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/check_pypi.py +0 -0
  12. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/client.py +0 -0
  13. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/config.py +0 -0
  14. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/context.py +0 -0
  15. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datafile/common.py +0 -0
  16. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datafile/exceptions.py +0 -0
  17. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datafile/parse_connection.py +0 -0
  18. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datafile/parse_datasource.py +0 -0
  19. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datafile/parse_pipe.py +0 -0
  20. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/datatypes.py +0 -0
  21. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/feedback_manager.py +0 -0
  22. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/git_settings.py +0 -0
  23. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/prompts.py +0 -0
  24. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/service_datasources.py +0 -0
  25. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/sql.py +0 -0
  26. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/sql_template.py +0 -0
  27. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/sql_template_fmt.py +0 -0
  28. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/sql_toolset.py +0 -0
  29. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/syncasync.py +0 -0
  30. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/check_pypi.py +0 -0
  31. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/cli.py +0 -0
  32. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/client.py +0 -0
  33. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/config.py +0 -0
  34. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/branch.py +0 -0
  35. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/build.py +0 -0
  36. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/build_common.py +0 -0
  37. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/cicd.py +0 -0
  38. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/common.py +0 -0
  39. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/config.py +0 -0
  40. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/connection.py +0 -0
  41. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/connection_kafka.py +0 -0
  42. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/connection_s3.py +0 -0
  43. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/copy.py +0 -0
  44. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/create.py +0 -0
  45. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/build.py +0 -0
  46. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/build_common.py +0 -0
  47. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  48. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  49. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/diff.py +0 -0
  50. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/fixture.py +0 -0
  51. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/format_common.py +0 -0
  52. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/format_connection.py +0 -0
  53. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  54. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  55. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  56. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/playground.py +0 -0
  57. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datafile/pull.py +0 -0
  58. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/datasource.py +0 -0
  59. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/deprecations.py +0 -0
  60. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/endpoint.py +0 -0
  61. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/exceptions.py +0 -0
  62. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/feedback_manager.py +0 -0
  63. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/fmt.py +0 -0
  64. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/info.py +0 -0
  65. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/infra.py +0 -0
  66. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/job.py +0 -0
  67. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/job_common.py +0 -0
  68. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/llm.py +0 -0
  69. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/llm_utils.py +0 -0
  70. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/local.py +0 -0
  71. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/local_common.py +0 -0
  72. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/local_logs.py +0 -0
  73. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/login.py +0 -0
  74. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/login_common.py +0 -0
  75. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/logout.py +0 -0
  76. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/logs.py +0 -0
  77. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/materialization.py +0 -0
  78. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/open.py +0 -0
  79. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/pipe.py +0 -0
  80. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/preview.py +0 -0
  81. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/project.py +0 -0
  82. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/project_commands.py +0 -0
  83. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/py_project.py +0 -0
  84. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/query_output.py +0 -0
  85. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/regions.py +0 -0
  86. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/secret.py +0 -0
  87. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/secret_common.py +0 -0
  88. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/sink.py +0 -0
  89. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/table.py +0 -0
  90. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/telemetry.py +0 -0
  91. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/test.py +0 -0
  92. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/test_common.py +0 -0
  93. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  94. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  95. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/token.py +0 -0
  96. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/ts_project.py +0 -0
  97. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/watch.py +0 -0
  98. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/workspace.py +0 -0
  99. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb/modules/workspace_members.py +0 -0
  100. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli.py +0 -0
  101. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
  102. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/branch.py +0 -0
  103. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
  104. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/cli.py +0 -0
  105. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/common.py +0 -0
  106. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/config.py +0 -0
  107. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/connection.py +0 -0
  108. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/datasource.py +0 -0
  109. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
  110. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/fmt.py +0 -0
  111. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/job.py +0 -0
  112. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/pipe.py +0 -0
  113. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/regions.py +0 -0
  114. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/tag.py +0 -0
  115. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
  116. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/test.py +0 -0
  117. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  118. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  119. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/workspace.py +0 -0
  120. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  121. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird/tornado_template.py +0 -0
  122. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/SOURCES.txt +0 -0
  123. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/dependency_links.txt +0 -0
  124. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/entry_points.txt +0 -0
  125. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/requires.txt +0 -0
  126. {tinybird-4.5.6.dev0 → tinybird-4.5.7.dev0}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 4.5.6.dev0
3
+ Version: 4.5.7.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,6 +52,10 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
52
52
  Changelog
53
53
  ----------
54
54
 
55
+ 4.5.6
56
+ *******
57
+
58
+ - `Fixed` Issue when executing command `tb migrate-to-forward`
55
59
 
56
60
  4.5.5
57
61
  *******
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '4.5.6.dev0'
8
- __revision__ = 'a651a4a'
7
+ __version__ = '4.5.7.dev0'
8
+ __revision__ = 'ce508ab'
@@ -63,7 +63,7 @@ DEV_MODE_VALUES = {DEV_MODE_MANUAL, DEV_MODE_LOCAL, DEV_MODE_BRANCH}
63
63
  DEV_MODE_ROUTED_COMMANDS = {"build", "deploy"}
64
64
  SDK_PROJECT_ROUTED_COMMANDS = {"build", "deploy", "preview"}
65
65
  TS_PROJECT_ROUTED_COMMANDS = SDK_PROJECT_ROUTED_COMMANDS
66
- COMMANDS_ALWAYS_CLOUD = {"infra", "branch", "environment", "workspace", "preview"}
66
+ COMMANDS_ALWAYS_CLOUD = {"infra", "branch", "environment", "workspace", "preview", "migrate-to-forward"}
67
67
  PROJECT_TYPE_TYPESCRIPT = "ts-sdk"
68
68
  PROJECT_TYPE_PYTHON = "python-sdk"
69
69
  PROJECT_TYPE_CLI = "cli"
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import logging
3
+ import os
3
4
  from datetime import datetime, timedelta, timezone
4
5
  from pathlib import Path
5
6
  from typing import Any, Dict, Optional
@@ -7,14 +8,17 @@ from typing import Any, Dict, Optional
7
8
  import click
8
9
  import requests
9
10
 
11
+ from tinybird.tb.client import TinyB
10
12
  from tinybird.tb.modules.cli import cli
11
13
  from tinybird.tb.modules.common import (
12
14
  echo_safe_humanfriendly_tables_format_smart_table,
13
15
  sys_exit,
14
16
  )
17
+ from tinybird.tb.modules.create import persist_tinybird_config
15
18
  from tinybird.tb.modules.deployment_common import (
16
19
  create_deployment,
17
20
  discard_deployment,
21
+ migrate_to_forward_workspace,
18
22
  promote_deployment,
19
23
  )
20
24
  from tinybird.tb.modules.feedback_manager import FeedbackManager
@@ -151,6 +155,47 @@ def api_fetch(url: str, headers: dict, request_from: Optional[str] = None) -> di
151
155
  return {}
152
156
 
153
157
 
158
+ def _get_classic_workspace_branches(client: TinyB, workspace_id: str) -> list[dict[str, Any]]:
159
+ branches: list[dict[str, Any]] = client.user_workspace_branches(version="v0").get("workspaces", [])
160
+ return [branch for branch in branches if str(branch.get("main")) == workspace_id]
161
+
162
+
163
+ def _cleanup_classic_migration_blockers(client: TinyB, config: Dict[str, Any]) -> None:
164
+ workspace_id = str(config["id"])
165
+
166
+ try:
167
+ branches = _get_classic_workspace_branches(client, workspace_id)
168
+ if not branches:
169
+ return
170
+
171
+ for branch in branches:
172
+ client.delete_branch(id=str(branch["id"]))
173
+ except Exception as e:
174
+ message = f"Error cleaning up Classic branches or releases before migration: {str(e)}"
175
+ click.echo(FeedbackManager.error(message=message))
176
+ sys_exit("migration_error", message)
177
+
178
+
179
+ def _persist_migrate_to_forward_config(project: Project) -> None:
180
+ root_folder = os.getcwd()
181
+ project_folder = os.path.relpath(project.path.resolve(), root_folder)
182
+
183
+ config_changed, config_created = persist_tinybird_config(
184
+ root_folder=root_folder,
185
+ project_type="cli",
186
+ dev_mode="manual",
187
+ folder=project_folder,
188
+ )
189
+
190
+ if not config_changed:
191
+ return
192
+
193
+ message = "Created tinybird.config.json for the Forward CLI"
194
+ if not config_created:
195
+ message = "Updated tinybird.config.json for the Forward CLI"
196
+ click.echo(FeedbackManager.info(message=message))
197
+
198
+
154
199
  @cli.group(name="deployment")
155
200
  def deployment_group() -> None:
156
201
  """
@@ -371,6 +416,107 @@ def deploy(
371
416
  create_deployment_cmd(ctx, wait, auto, check, allow_destructive_operations, template, verbose)
372
417
 
373
418
 
419
+ @cli.command(name="migrate-to-forward")
420
+ @click.option(
421
+ "--allow-destructive-operations/--no-allow-destructive-operations",
422
+ is_flag=True,
423
+ default=False,
424
+ help="Allow destructive operations in deployments (for example replacing a Pipe with a Data Source).",
425
+ )
426
+ @click.pass_context
427
+ def migrate_to_forward(ctx: click.Context, allow_destructive_operations: bool) -> None:
428
+ """Migrate a Tinybird Classic cloud workspace to Tinybird Forward."""
429
+ client = ctx.ensure_object(dict)["client"]
430
+ project: Project = ctx.ensure_object(dict)["project"]
431
+ config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
432
+ env = ctx.ensure_object(dict)["env"]
433
+ output = ctx.ensure_object(dict)["output"]
434
+
435
+ try:
436
+ client.workspace_info(version="v1")
437
+ message = "This command is unavailable for Tinybird Forward workspaces."
438
+ click.echo(FeedbackManager.error(message=message))
439
+ sys_exit("migration_error", message)
440
+ except Exception:
441
+ pass
442
+
443
+ try:
444
+ client.workspace_info(version="v0")
445
+ except Exception as e:
446
+ message = f"Error checking workspace status: {str(e)}"
447
+ click.echo(FeedbackManager.error(message=message))
448
+ sys_exit("migration_error", message)
449
+
450
+ click.echo(
451
+ FeedbackManager.warning(
452
+ message=(
453
+ "This operation is irreversible: once your workspace is migrated to Tinybird Forward, "
454
+ "you cannot switch it back to Tinybird Classic. It will also run your first Forward deployment."
455
+ )
456
+ )
457
+ )
458
+
459
+ if not click.confirm("Do you want to proceed and run the deployment check now?", default=False):
460
+ click.echo(FeedbackManager.info(message="Migration cancelled."))
461
+ return
462
+
463
+ check_result = create_deployment(
464
+ project,
465
+ client,
466
+ config,
467
+ wait=False,
468
+ auto=False,
469
+ verbose=False,
470
+ check=True,
471
+ allow_destructive_operations=allow_destructive_operations,
472
+ output=output,
473
+ env=env,
474
+ show_migrate_to_forward_hint=False,
475
+ return_check_result=True,
476
+ validate_forward_workspace=False,
477
+ )
478
+ if not check_result:
479
+ message = "Deployment check did not complete. Migration cancelled."
480
+ click.echo(FeedbackManager.error(message=message))
481
+ sys_exit("migration_error", message)
482
+
483
+ if check_result and check_result.get("status") == "no_changes":
484
+ click.echo(
485
+ FeedbackManager.warning(
486
+ message=(
487
+ "No deployment changes were detected. Add this dummy pipe to your workspace and run "
488
+ "`tb migrate-to-forward` again:"
489
+ )
490
+ )
491
+ )
492
+ click.echo("NODE n\nSQL >\n select 'Forward'")
493
+ return
494
+
495
+ if not click.confirm(
496
+ "Do you want to continue with the migration? This will also delete your branches, releases and switch your workspace from Classic to Forward.",
497
+ default=False,
498
+ ):
499
+ click.echo(FeedbackManager.info(message="Migration cancelled."))
500
+ return
501
+
502
+ _cleanup_classic_migration_blockers(client, config)
503
+ _persist_migrate_to_forward_config(project)
504
+ migrate_to_forward_workspace(client=client, output=output, dry_run=False)
505
+ create_deployment(
506
+ project,
507
+ client,
508
+ config,
509
+ wait=True,
510
+ auto=True,
511
+ verbose=False,
512
+ check=False,
513
+ allow_destructive_operations=allow_destructive_operations,
514
+ output=output,
515
+ env=env,
516
+ validate_forward_workspace=False,
517
+ )
518
+
519
+
374
520
  def create_deployment_cmd(
375
521
  ctx: click.Context,
376
522
  wait: bool,
@@ -381,6 +527,7 @@ def create_deployment_cmd(
381
527
  verbose: bool = False,
382
528
  ) -> None:
383
529
  output = ctx.ensure_object(dict)["output"]
530
+ env = ctx.ensure_object(dict)["env"]
384
531
  project: Project = ctx.ensure_object(dict)["project"]
385
532
  if template:
386
533
  if project.get_project_files():
@@ -416,6 +563,7 @@ def create_deployment_cmd(
416
563
  allow_destructive_operations,
417
564
  ingest_hint=not is_web_analytics_starter_kit,
418
565
  output=output,
566
+ env=env,
419
567
  )
420
568
  show_web_analytics_starter_kit_hints(client, is_web_analytics_starter_kit)
421
569
 
@@ -99,6 +99,22 @@ def api_post(
99
99
  return {}
100
100
 
101
101
 
102
+ def _get_migrate_to_forward_error_message(result: dict[str, Any]) -> str:
103
+ error = result.get("error")
104
+ if error:
105
+ return str(error)
106
+
107
+ deployment = result.get("deployment") or {}
108
+ deployment_errors = deployment.get("errors") or []
109
+ error_messages = [
110
+ str(item.get("error")) for item in deployment_errors if isinstance(item, dict) and item.get("error")
111
+ ]
112
+ if error_messages:
113
+ return "; ".join(error_messages)
114
+
115
+ return "Migration to Tinybird Forward failed"
116
+
117
+
102
118
  def _is_first_deployment_with_seed_live(host: Optional[str], headers: dict) -> bool:
103
119
  """Best-effort check for first real deployment when seed deployment (id=0) is still live."""
104
120
  try:
@@ -134,8 +150,49 @@ def _get_deployment_job(client: TinyB, deployment_id: Optional[Union[str, int]])
134
150
  return None
135
151
 
136
152
 
153
+ def migrate_to_forward_workspace(client: TinyB, output: str = "human", dry_run: bool = False) -> None:
154
+ headers = {"Authorization": f"Bearer {client.token}"}
155
+ params = {"dry_run": dry_run}
156
+ result = api_post(f"{client.host}/v1/migrate-to-forward", headers=headers, params=params)
157
+
158
+ if result.get("result") != "success":
159
+ error_message = _get_migrate_to_forward_error_message(result)
160
+ if output == "json":
161
+ echo_json(result)
162
+ else:
163
+ click.echo(FeedbackManager.error(message=error_message))
164
+ sys_exit("deployment_error", error_message)
165
+
166
+ if dry_run:
167
+ return
168
+
169
+ if output == "json":
170
+ echo_json(result)
171
+ return
172
+
173
+ click.echo(FeedbackManager.success(message="✓ Workspace migrated to Tinybird Forward"))
174
+
175
+
176
+ def _should_show_migrate_to_forward_hint(client: TinyB, env: Optional[str]) -> bool:
177
+ if env != "cloud":
178
+ return False
179
+
180
+ try:
181
+ client.workspace_info(version="v1")
182
+ return False
183
+ except Exception:
184
+ pass
185
+
186
+ try:
187
+ workspace_info = client.workspace_info(version="v0")
188
+ except Exception:
189
+ logging.exception("Error reading workspace info while deciding migrate-to-forward hint")
190
+ return False
191
+
192
+ return not workspace_info.get("is_forward", False) and not workspace_info.get("is_branch", False)
193
+
194
+
137
195
  # TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for promoting a deployment
138
- # potato
139
196
  def promote_deployment(
140
197
  host: Optional[str],
141
198
  headers: dict,
@@ -285,9 +342,12 @@ def create_deployment(
285
342
  check: Optional[bool] = None,
286
343
  allow_destructive_operations: Optional[bool] = None,
287
344
  ingest_hint: Optional[bool] = True,
345
+ show_migrate_to_forward_hint: bool = True,
288
346
  output: Optional[str] = "human",
289
347
  env: Optional[str] = "cloud",
290
- ) -> None:
348
+ return_check_result: bool = False,
349
+ validate_forward_workspace: bool = True,
350
+ ) -> Optional[Dict[str, Any]]:
291
351
  # TODO: This code is duplicated in build_server.py
292
352
  # Should be refactored to be shared
293
353
  MULTIPART_BOUNDARY_DATA_PROJECT = "data_project://"
@@ -342,6 +402,8 @@ def create_deployment(
342
402
  params["auto_promote"] = "true"
343
403
  if allow_destructive_operations:
344
404
  params["allow_destructive_operations"] = "true"
405
+ if not validate_forward_workspace:
406
+ params["validate_forward_workspace"] = "false"
345
407
 
346
408
  deployment_request_sent = True
347
409
  result = api_post(
@@ -388,10 +450,27 @@ def create_deployment(
388
450
 
389
451
  status = result.get("result")
390
452
  if check:
391
- if status == "success":
392
- click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
393
- sys.exit(0)
394
- elif status == "no_changes":
453
+ if status in {"success", "no_changes"}:
454
+ if status == "success":
455
+ click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
456
+
457
+ if (
458
+ output == "human"
459
+ and show_migrate_to_forward_hint
460
+ and _should_show_migrate_to_forward_hint(client, env)
461
+ ):
462
+ click.echo(
463
+ FeedbackManager.info(
464
+ message=(
465
+ "You can now migrate this Tinybird Classic workspace to Forward "
466
+ "with `tb migrate-to-forward`."
467
+ )
468
+ )
469
+ )
470
+
471
+ if return_check_result:
472
+ return {"status": status, "deployment": deployment}
473
+
395
474
  sys.exit(0)
396
475
 
397
476
  click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
@@ -439,7 +518,10 @@ def create_deployment(
439
518
  except Exception as e:
440
519
  click.echo(FeedbackManager.error_exception(error=e))
441
520
 
442
- if not deployment and not check:
521
+ if check:
522
+ sys_exit("deployment_error", "Deployment check failed")
523
+
524
+ if not deployment:
443
525
  sys_exit("deployment_error", "Deployment failed")
444
526
  except KeyboardInterrupt:
445
527
  if deployment_request_sent and not check:
@@ -468,7 +550,7 @@ def create_deployment(
468
550
  if not deployment:
469
551
  click.echo(FeedbackManager.error(message="Error parsing deployment from response"))
470
552
  sys_exit("deployment_error", "Error parsing deployment from response")
471
- return
553
+ return None
472
554
 
473
555
  status = deployment.get("status")
474
556
  errors = deployment.get("errors")
@@ -563,6 +645,8 @@ def create_deployment(
563
645
  if output == "json" and deployment:
564
646
  echo_json(deployment, 8)
565
647
 
648
+ return None
649
+
566
650
 
567
651
  def _build_data_movement_message(kind: str, source_mv_name: Optional[str]) -> str:
568
652
  if kind == "backfill_with_mv_queries":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 4.5.6.dev0
3
+ Version: 4.5.7.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,6 +52,10 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
52
52
  Changelog
53
53
  ----------
54
54
 
55
+ 4.5.6
56
+ *******
57
+
58
+ - `Fixed` Issue when executing command `tb migrate-to-forward`
55
59
 
56
60
  4.5.5
57
61
  *******
File without changes