tinybird 0.0.1.dev103__tar.gz → 0.0.1.dev104__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

Files changed (108) hide show
  1. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/sql_template.py +21 -2
  3. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/common.py +5 -19
  5. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/common.py +8 -1
  6. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/deployment.py +45 -35
  7. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/infra.py +27 -36
  8. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/PKG-INFO +1 -1
  9. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/setup.cfg +0 -0
  10. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/__cli__.py +0 -0
  11. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/ch_utils/constants.py +0 -0
  12. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/ch_utils/engine.py +0 -0
  13. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/check_pypi.py +0 -0
  14. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/client.py +0 -0
  15. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/config.py +0 -0
  16. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/connectors.py +0 -0
  17. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/context.py +0 -0
  18. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/datafile.py +0 -0
  19. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/datatypes.py +0 -0
  20. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/feedback_manager.py +0 -0
  21. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/git_settings.py +0 -0
  22. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/prompts.py +0 -0
  23. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/sql.py +0 -0
  24. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/sql_template_fmt.py +0 -0
  25. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/sql_toolset.py +0 -0
  26. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/syncasync.py +0 -0
  27. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/cli.py +0 -0
  28. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/auth.py +0 -0
  29. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/build.py +0 -0
  30. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/cicd.py +0 -0
  31. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/cli.py +0 -0
  32. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/config.py +0 -0
  33. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/connection.py +0 -0
  34. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/copy.py +0 -0
  35. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/create.py +0 -0
  36. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/build.py +0 -0
  37. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/build_common.py +0 -0
  38. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  39. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  40. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/diff.py +0 -0
  41. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  42. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/fixture.py +0 -0
  43. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/format_common.py +0 -0
  44. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  45. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  46. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  47. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  48. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  49. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/playground.py +0 -0
  50. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datafile/pull.py +0 -0
  51. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/datasource.py +0 -0
  52. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/endpoint.py +0 -0
  53. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/exceptions.py +0 -0
  54. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/feedback_manager.py +0 -0
  55. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/fmt.py +0 -0
  56. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/job.py +0 -0
  57. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/llm.py +0 -0
  58. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/llm_utils.py +0 -0
  59. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/local.py +0 -0
  60. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/local_common.py +0 -0
  61. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/login.py +0 -0
  62. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/logout.py +0 -0
  63. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/materialization.py +0 -0
  64. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/mock.py +0 -0
  65. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/open.py +0 -0
  66. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/pipe.py +0 -0
  67. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/playground.py +0 -0
  68. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/project.py +0 -0
  69. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/regions.py +0 -0
  70. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/secret.py +0 -0
  71. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/shell.py +0 -0
  72. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/table.py +0 -0
  73. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/tag.py +0 -0
  74. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/telemetry.py +0 -0
  75. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/test.py +0 -0
  76. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  77. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  78. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/token.py +0 -0
  79. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/watch.py +0 -0
  80. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/workspace.py +0 -0
  81. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb/modules/workspace_members.py +0 -0
  82. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli.py +0 -0
  83. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/auth.py +0 -0
  84. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/branch.py +0 -0
  85. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/cicd.py +0 -0
  86. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/cli.py +0 -0
  87. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/common.py +0 -0
  88. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/config.py +0 -0
  89. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/connection.py +0 -0
  90. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/datasource.py +0 -0
  91. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/exceptions.py +0 -0
  92. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/fmt.py +0 -0
  93. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/job.py +0 -0
  94. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/pipe.py +0 -0
  95. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/regions.py +0 -0
  96. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/tag.py +0 -0
  97. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/telemetry.py +0 -0
  98. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/test.py +0 -0
  99. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  100. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  101. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/workspace.py +0 -0
  102. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  103. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird/tornado_template.py +0 -0
  104. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/SOURCES.txt +0 -0
  105. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/dependency_links.txt +0 -0
  106. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/entry_points.txt +0 -0
  107. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/requires.txt +0 -0
  108. {tinybird-0.0.1.dev103 → tinybird-0.0.1.dev104}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev103
3
+ Version: 0.0.1.dev104
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -2427,6 +2427,20 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2427
2427
  ... )
2428
2428
  'KAFKA_BOOTSTRAP_SERVERS localhost:9092'
2429
2429
 
2430
+ >>> render_template_with_secrets(
2431
+ ... "my_kafka_connection",
2432
+ ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET', '') }}",
2433
+ ... secrets = {}
2434
+ ... )
2435
+ 'KAFKA_BOOTSTRAP_SERVERS ""'
2436
+
2437
+ >>> render_template_with_secrets(
2438
+ ... "my_kafka_connection",
2439
+ ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET', 0) }}",
2440
+ ... secrets = {}
2441
+ ... )
2442
+ 'KAFKA_BOOTSTRAP_SERVERS 0'
2443
+
2430
2444
  >>> render_template_with_secrets(
2431
2445
  ... "my_kafka_connection",
2432
2446
  ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET') }}",
@@ -2453,8 +2467,13 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2453
2467
  SQLTemplateException: If the secret is not found and no default is provided
2454
2468
  """
2455
2469
  if secret_name in secrets:
2456
- return secrets[secret_name]
2470
+ value = secrets[secret_name]
2471
+ if isinstance(value, str) and len(value) == 0:
2472
+ return '""'
2473
+ return value
2457
2474
  elif default is not None:
2475
+ if isinstance(default, str) and len(default) == 0:
2476
+ return '""'
2458
2477
  return default
2459
2478
  else:
2460
2479
  raise SQLTemplateException(
@@ -2462,7 +2481,7 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2462
2481
  )
2463
2482
 
2464
2483
  # Create the template
2465
- t = Template(content, name=name)
2484
+ t = Template(content, name=name, autoescape=None)
2466
2485
 
2467
2486
  try:
2468
2487
  # Create namespace with our tb_secret function
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev103'
8
- __revision__ = 'e2e3b60'
7
+ __version__ = '0.0.1.dev104'
8
+ __revision__ = 'f6c1941'
@@ -81,8 +81,6 @@ SUPPORTED_FORMATS = ["csv", "ndjson", "json", "parquet"]
81
81
  OLDEST_ROLLBACK = "oldest_rollback"
82
82
  MAIN_BRANCH = "main"
83
83
 
84
- CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
85
-
86
84
 
87
85
  def obfuscate_token(value: Optional[str]) -> Optional[str]:
88
86
  if not value:
@@ -2178,36 +2176,24 @@ async def ask_for_organization(
2178
2176
 
2179
2177
  if organization_id:
2180
2178
  if organizations and len(organizations) > 0:
2181
- organization = next(
2182
- (org for org in organizations if org.get("id") == organization_id), None
2183
- )
2179
+ organization = next((org for org in organizations if org.get("id") == organization_id), None)
2184
2180
  if not organization:
2185
- raise CLIException(
2186
- FeedbackManager.error_organization_not_found(
2187
- organization_id=organization_id
2188
- )
2189
- )
2181
+ raise CLIException(FeedbackManager.error_organization_not_found(organization_id=organization_id))
2190
2182
  organization_name = organization.get("name")
2191
2183
  return organization_id, organization_name
2192
2184
 
2193
2185
  if organizations is None or len(organizations) == 0:
2194
2186
  organization_name = await ask_for_organization_name(config)
2195
2187
  user_token = await get_user_token(config, user_token)
2196
- organization = await create_organization_and_add_workspaces(
2197
- config, organization_name, user_token
2198
- )
2188
+ organization = await create_organization_and_add_workspaces(config, organization_name, user_token)
2199
2189
  organization_id = organization.get("id")
2200
2190
  else:
2201
2191
  if len(organizations) == 1:
2202
2192
  organization_name = organizations[0]["name"]
2203
2193
  organization_id = organizations[0]["id"]
2204
2194
  else:
2205
- sorted_organizations = sort_organizations_by_user(
2206
- organizations, user_email=user_email
2207
- )
2208
- current_organization = await ask_for_organization_interactively(
2209
- sorted_organizations
2210
- )
2195
+ sorted_organizations = sort_organizations_by_user(organizations, user_email=user_email)
2196
+ current_organization = await ask_for_organization_interactively(sorted_organizations)
2211
2197
  if current_organization:
2212
2198
  organization_id = current_organization.get("id")
2213
2199
  organization_name = current_organization.get("name")
@@ -1241,6 +1241,13 @@ def parse(
1241
1241
 
1242
1242
  return _f
1243
1243
 
1244
+ def kafka_key_avro_deserialization(*args: str, **kwargs: Any):
1245
+ raise DatafileSyntaxError(
1246
+ f'{kwargs["cmd"].upper()} has been deprecated. Use "KAFKA_KEY_FORMAT avro" instead',
1247
+ lineno=kwargs["lineno"],
1248
+ pos=1,
1249
+ )
1250
+
1244
1251
  @deprecated
1245
1252
  def sources(x: str, **kwargs: Any) -> None:
1246
1253
  pass # Deprecated
@@ -1459,7 +1466,7 @@ def parse(
1459
1466
  "kafka_store_raw_value": assign_var("kafka_store_raw_value"),
1460
1467
  "kafka_store_headers": assign_var("kafka_store_headers"),
1461
1468
  "kafka_store_binary_headers": assign_var("kafka_store_binary_headers"),
1462
- "kafka_key_avro_deserialization": assign_var("kafka_key_avro_deserialization"),
1469
+ "kafka_key_avro_deserialization": kafka_key_avro_deserialization,
1463
1470
  "kafka_ssl_ca_pem": assign_var("kafka_ssl_ca_pem"),
1464
1471
  "kafka_security_protocol": assign_var("kafka_security_protocol"),
1465
1472
  "kafka_sasl_mechanism": assign_var("kafka_sasl_mechanism"),
@@ -19,6 +19,7 @@ from tinybird.tb.modules.project import Project
19
19
  def api_fetch(url: str, headers: dict) -> dict:
20
20
  r = requests.get(url, headers=headers)
21
21
  if r.status_code == 200:
22
+ logging.debug(json.dumps(r.json(), indent=2))
22
23
  return r.json()
23
24
  # Try to parse and print the error from the response
24
25
  try:
@@ -32,13 +33,33 @@ def api_fetch(url: str, headers: dict) -> dict:
32
33
  sys.exit(1)
33
34
 
34
35
 
36
+ def api_post(
37
+ url: str,
38
+ headers: dict,
39
+ files: Optional[list] = None,
40
+ params: Optional[dict] = None,
41
+ ) -> dict:
42
+ r = requests.post(url, headers=headers, files=files, params=params)
43
+ if r.status_code == 200:
44
+ logging.debug(json.dumps(r.json(), indent=2))
45
+ return r.json()
46
+ # Try to parse and print the error from the response
47
+ try:
48
+ result = r.json()
49
+ logging.debug(json.dumps(result, indent=2))
50
+ error = result.get("error")
51
+ click.echo(FeedbackManager.error(message=f"Error: {error}"))
52
+ sys.exit(1)
53
+ except Exception:
54
+ click.echo(FeedbackManager.error(message="Error parsing response from API"))
55
+ sys.exit(1)
56
+
57
+
35
58
  # TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for promoting a deployment
36
59
  # potato
37
60
  def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
38
61
  TINYBIRD_API_URL = f"{host}/v1/deployments"
39
- r = requests.get(TINYBIRD_API_URL, headers=headers)
40
- result = r.json()
41
- logging.debug(json.dumps(result, indent=2))
62
+ result = api_fetch(TINYBIRD_API_URL, headers)
42
63
 
43
64
  deployments = result.get("deployments")
44
65
  if not deployments:
@@ -64,12 +85,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
64
85
  click.echo(FeedbackManager.success(message="Setting candidate deployment as live"))
65
86
 
66
87
  TINYBIRD_API_URL = f"{host}/v1/deployments/{candidate_deployment.get('id')}/set-live"
67
- r = requests.post(TINYBIRD_API_URL, headers=headers)
68
- result = r.json()
69
- logging.debug(json.dumps(result, indent=2))
70
- if result.get("error"):
71
- click.echo(FeedbackManager.error(message=result.get("error")))
72
- sys.exit(1)
88
+ result = api_post(TINYBIRD_API_URL, headers=headers)
73
89
 
74
90
  click.echo(FeedbackManager.success(message="Removing old deployment"))
75
91
 
@@ -86,9 +102,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
86
102
  if wait:
87
103
  while True:
88
104
  TINYBIRD_API_URL = f"{host}/v1/deployments/{last_deployment.get('id')}"
89
- r = requests.get(TINYBIRD_API_URL, headers=headers)
90
- result = r.json()
91
- logging.debug(json.dumps(result, indent=2))
105
+ result = api_fetch(TINYBIRD_API_URL, headers=headers)
92
106
 
93
107
  last_deployment = result.get("deployment")
94
108
  if last_deployment.get("status") == "deleted":
@@ -102,9 +116,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
102
116
  # deployment
103
117
  def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
104
118
  TINYBIRD_API_URL = f"{host}/v1/deployments"
105
- r = requests.get(TINYBIRD_API_URL, headers=headers)
106
- result = r.json()
107
- logging.debug(json.dumps(result, indent=2))
119
+ result = api_fetch(TINYBIRD_API_URL, headers=headers)
108
120
 
109
121
  deployments = result.get("deployments")
110
122
  if not deployments:
@@ -130,12 +142,7 @@ def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
130
142
  click.echo(FeedbackManager.success(message="Promoting previous deployment"))
131
143
 
132
144
  TINYBIRD_API_URL = f"{host}/v1/deployments/{previous_deployment.get('id')}/set-live"
133
- r = requests.post(TINYBIRD_API_URL, headers=headers)
134
- result = r.json()
135
- logging.debug(json.dumps(result, indent=2))
136
- if result.get("error"):
137
- click.echo(FeedbackManager.error(message=result.get("error")))
138
- sys.exit(1)
145
+ result = api_post(TINYBIRD_API_URL, headers=headers)
139
146
 
140
147
  click.echo(FeedbackManager.success(message="Removing current deployment"))
141
148
 
@@ -152,9 +159,7 @@ def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
152
159
  if wait:
153
160
  while True:
154
161
  TINYBIRD_API_URL = f"{host}/v1/deployments/{current_deployment.get('id')}"
155
- r = requests.get(TINYBIRD_API_URL, headers=headers)
156
- result = r.json()
157
- logging.debug(json.dumps(result, indent=2))
162
+ result = api_fetch(TINYBIRD_API_URL, headers)
158
163
 
159
164
  current_deployment = result.get("deployment")
160
165
  if current_deployment.get("status") == "deleted":
@@ -219,7 +224,6 @@ def deployment_ls(ctx: click.Context) -> None:
219
224
  url = f"{client.host}/v1/deployments"
220
225
 
221
226
  result = api_fetch(url, HEADERS)
222
- logging.debug(json.dumps(result, indent=2))
223
227
 
224
228
  status_map = {"data_ready": "Ready", "failed": "Failed"}
225
229
  columns = ["ID", "Status", "Created at", "Live"]
@@ -354,13 +358,13 @@ def create_deployment(
354
358
  params["check"] = "true"
355
359
  if allow_destructive_operations:
356
360
  params["allow_destructive_operations"] = "true"
357
- r = requests.post(TINYBIRD_API_URL, files=files, headers=HEADERS, params=params)
358
- result = r.json()
359
- logging.debug(json.dumps(result, indent=2))
361
+
362
+ result = api_post(TINYBIRD_API_URL, headers=HEADERS, files=files, params=params)
360
363
 
361
364
  print_changes(result, project)
362
365
 
363
- feedback = result.get("deployment", {}).get("feedback", [])
366
+ deployment = result.get("deployment", {})
367
+ feedback = deployment.get("feedback", [])
364
368
  for f in feedback:
365
369
  if f.get("level", "").upper() == "ERROR":
366
370
  feedback_func = FeedbackManager.error
@@ -372,7 +376,7 @@ def create_deployment(
372
376
  resource_bit = f"{resource}: " if resource else ""
373
377
  click.echo(feedback_func(message=f"{feedback_icon}{f.get('level')}: {resource_bit}{f.get('message')}"))
374
378
 
375
- deploy_errors = result.get("deployment", {}).get("errors")
379
+ deploy_errors = deployment.get("errors")
376
380
  for deploy_error in deploy_errors:
377
381
  if deploy_error.get("filename", None):
378
382
  click.echo(
@@ -380,19 +384,21 @@ def create_deployment(
380
384
  )
381
385
  else:
382
386
  click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
387
+ click.echo() # For spacing
383
388
 
384
389
  status = result.get("result")
385
390
  if check:
386
391
  if status == "success":
387
392
  click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
388
393
  sys.exit(0)
394
+ elif status == "no_changes":
395
+ sys.exit(0)
389
396
 
390
397
  click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
391
398
  sys.exit(1)
392
399
 
393
400
  status = result.get("result")
394
401
  if status == "success":
395
- deployment = result.get("deployment", {})
396
402
  # TODO: This is a hack to show the url in the case of region is public. The URL should be returned by the API
397
403
  if client.host == "https://api.europe-west2.gcp.tinybird.co":
398
404
  click.echo(
@@ -406,10 +412,14 @@ def create_deployment(
406
412
  click.echo(FeedbackManager.info(message="\n✓ Deployment submitted successfully"))
407
413
  else:
408
414
  click.echo(FeedbackManager.success(message="\n✓ Deployment submitted successfully"))
415
+ elif status == "no_changes":
416
+ click.echo(FeedbackManager.highlight(message="Not deploying. No changes."))
417
+ sys.exit(0)
409
418
  elif status == "failed":
410
419
  click.echo(FeedbackManager.error(message="Deployment failed"))
420
+ sys.exit(1)
411
421
  else:
412
- click.echo(FeedbackManager.error(message=f"Unknown build result {status}"))
422
+ click.echo(FeedbackManager.error(message=f"Unknown deployment result {status}"))
413
423
  except Exception as e:
414
424
  click.echo(FeedbackManager.error_exception(error=e))
415
425
  finally:
@@ -463,7 +473,7 @@ def print_changes(result: dict, project: Project) -> None:
463
473
  resources.append(["new", p, project.get_resource_path(p, "pipe")])
464
474
 
465
475
  for dc in deployment.get("new_data_connector_names", []):
466
- resources.append(["new", dc, project.get_resource_path(dc, "data_connector")])
476
+ resources.append(["new", dc, project.get_resource_path(dc, "connection")])
467
477
 
468
478
  for ds in deployment.get("changed_datasource_names", []):
469
479
  resources.append(["modified", ds, project.get_resource_path(ds, "datasource")])
@@ -472,7 +482,7 @@ def print_changes(result: dict, project: Project) -> None:
472
482
  resources.append(["modified", p, project.get_resource_path(p, "pipe")])
473
483
 
474
484
  for dc in deployment.get("changed_data_connector_names", []):
475
- resources.append(["modified", dc, project.get_resource_path(dc, "data_connector")])
485
+ resources.append(["modified", dc, project.get_resource_path(dc, "connection")])
476
486
 
477
487
  for ds in deployment.get("deleted_datasource_names", []):
478
488
  resources.append(["deleted", ds, project.get_resource_path(ds, "datasource")])
@@ -481,7 +491,7 @@ def print_changes(result: dict, project: Project) -> None:
481
491
  resources.append(["deleted", p, project.get_resource_path(p, "pipe")])
482
492
 
483
493
  for dc in deployment.get("deleted_data_connector_names", []):
484
- resources.append(["deleted", dc, project.get_resource_path(dc, "data_connector")])
494
+ resources.append(["deleted", dc, project.get_resource_path(dc, "connection")])
485
495
 
486
496
  for token_change in deployment.get("token_changes", []):
487
497
  token_name = token_change.get("token_name")
@@ -1,5 +1,7 @@
1
+ import asyncio
1
2
  import json
2
3
  import subprocess
4
+ import sys
3
5
  import time
4
6
  import uuid
5
7
  from pathlib import Path
@@ -15,7 +17,7 @@ from tinybird.tb.modules.common import coro, echo_safe_humanfriendly_tables_form
15
17
  from tinybird.tb.modules.config import CLIConfig
16
18
  from tinybird.tb.modules.feedback_manager import FeedbackManager
17
19
 
18
- from .common import CONTEXT_SETTINGS, ask_for_organization, get_organizations_by_user
20
+ from .common import ask_for_organization, get_organizations_by_user
19
21
 
20
22
  K8S_YML = """
21
23
  ---
@@ -226,13 +228,9 @@ class Infrastructure:
226
228
  async def get_organizations_info(self, config: CLIConfig):
227
229
  self.orgs = await get_organizations_by_user(config)
228
230
 
229
- async def create_infra(
230
- self, name: str, host: str, organization_id: str
231
- ) -> Dict[str, Any]:
231
+ async def create_infra(self, name: str, host: str, organization_id: str) -> Dict[str, Any]:
232
232
  """Create a new infrastructure."""
233
- infra = await self.client.infra_create(
234
- organization_id=organization_id, name=name, host=host
235
- )
233
+ infra = await self.client.infra_create(organization_id=organization_id, name=name, host=host)
236
234
  return infra
237
235
 
238
236
  async def list_infras(self) -> None:
@@ -253,9 +251,7 @@ class Infrastructure:
253
251
  organization = infra["organization"]
254
252
 
255
253
  table_human_readable.append((name, host, organization))
256
- table_machine_readable.append(
257
- {"name": name, "host": host, "organization": organization}
258
- )
254
+ table_machine_readable.append({"name": name, "host": host, "organization": organization})
259
255
 
260
256
  click.echo(FeedbackManager.info(message="\n** Infras:"))
261
257
  echo_safe_humanfriendly_tables_format_smart_table(table_human_readable, column_names=columns)
@@ -269,17 +265,13 @@ class Infrastructure:
269
265
  if not infra:
270
266
  raise CLIException(f"Infrastructure '{name}' not found")
271
267
  await self.client.infra_delete(infra["id"], infra["organization_id"])
272
- click.echo(
273
- FeedbackManager.success(message=f"\n✓ Infrastructure '{name}' deleted")
274
- )
268
+ click.echo(FeedbackManager.success(message=f"\n✓ Infrastructure '{name}' deleted"))
275
269
  except Exception as e:
276
270
  click.echo(FeedbackManager.error(message=f"✗ Error: {e}"))
277
271
 
278
272
  async def update(self, infra_name: str, name: str, host: str):
279
273
  infras_list = await self.get_infra_list()
280
- infra = next(
281
- (infra for infra in infras_list if infra["name"] == infra_name), None
282
- )
274
+ infra = next((infra for infra in infras_list if infra["name"] == infra_name), None)
283
275
  if not infra:
284
276
  return None
285
277
  await self.client.infra_update(
@@ -312,30 +304,25 @@ class Infrastructure:
312
304
  all_infras.append(infra)
313
305
  except Exception as e:
314
306
  click.echo(
315
- FeedbackManager.warning(
316
- message=f"Could not fetch infras for organization {org_name}: {str(e)}"
317
- )
307
+ FeedbackManager.warning(message=f"Could not fetch infras for organization {org_name}: {str(e)}")
318
308
  )
319
309
  continue
320
310
  return all_infras
321
311
  except Exception as e:
322
- click.echo(
323
- FeedbackManager.error(
324
- message=f"Failed to list infrastructures: {str(e)}"
325
- )
326
- )
312
+ click.echo(FeedbackManager.error(message=f"Failed to list infrastructures: {str(e)}"))
327
313
  return []
328
314
 
329
315
 
330
- @cli.group(context_settings=CONTEXT_SETTINGS, hidden=True)
316
+ @cli.group(hidden=True)
331
317
  @click.pass_context
332
- @coro
333
- async def infra(ctx: Context) -> None:
318
+ def infra(ctx: Context) -> None:
334
319
  """Infra commands."""
320
+ if "--help" in sys.argv or "-h" in sys.argv:
321
+ return
335
322
  client: TinyB = ctx.ensure_object(dict)["client"]
336
323
  config = CLIConfig.get_project_config()
337
324
  infra = Infrastructure(client)
338
- await infra.get_organizations_info(config)
325
+ asyncio.run(infra.get_organizations_info(config))
339
326
  ctx.ensure_object(dict)["infra"] = infra
340
327
 
341
328
 
@@ -732,24 +719,28 @@ async def infra_list(ctx: click.Context):
732
719
  @click.option("--host", type=str, help="Host for the self-managed region")
733
720
  @click.option("--organization-id", type=str, help="Organization ID for the self-managed region")
734
721
  @click.pass_context
735
- @coro
736
- async def infra_create(ctx: click.Context, name: str, host: str, organization_id: Optional[str] = None):
722
+ def infra_add(ctx: click.Context, name: str, host: Optional[str] = None, organization_id: Optional[str] = None):
737
723
  """Creates a new self-managed region from an existing infrastructure URL."""
738
724
  infra: Infrastructure = ctx.ensure_object(dict)["infra"]
739
725
 
740
- organization_id, organization_name = await ask_for_organization(
741
- infra.orgs, organization_id
742
- )
726
+ organization_id, organization_name = asyncio.run(ask_for_organization(infra.orgs, organization_id))
743
727
  if not organization_id:
744
728
  return
745
729
 
746
730
  name = name or click.prompt("Enter name", type=str)
747
- host = host or click.prompt("Enter host", type=str)
731
+ host = host or click.prompt(
732
+ "Enter host URL (e.g., https://tinybird.example.com) (leave empty for None)",
733
+ type=str,
734
+ default="",
735
+ show_default=False,
736
+ )
748
737
 
749
738
  click.echo(FeedbackManager.highlight(message=f"» Adding self-managed region '{name}' in Tinybird..."))
750
- new_infra = await infra.create_infra(name, host, organization_id)
739
+ new_infra = asyncio.run(infra.create_infra(name, host, organization_id))
751
740
  infra_token = new_infra["token"]
752
- click.echo(FeedbackManager.success(message=f"\n✓ Self-managed region '{name}' added in '{organization_name}' Organization"))
741
+ click.echo(
742
+ FeedbackManager.success(message=f"\n✓ Self-managed region '{name}' added in '{organization_name}' Organization")
743
+ )
753
744
 
754
745
  # Get CLI config to access workspace and user information
755
746
  cli_config = CLIConfig.get_project_config()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev103
3
+ Version: 0.0.1.dev104
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird