tinybird-cli 3.3.1.dev9__tar.gz → 3.3.1.dev11__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 (48) hide show
  1. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/PKG-INFO +11 -1
  2. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/__cli__.py +2 -2
  3. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/datafile.py +23 -2
  4. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/feedback_manager.py +4 -0
  5. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/git_settings.py +3 -0
  6. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql.py +91 -3
  7. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/cli.py +5 -0
  8. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/PKG-INFO +11 -1
  9. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/setup.cfg +0 -0
  10. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/ch_utils/constants.py +0 -0
  11. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/ch_utils/engine.py +0 -0
  12. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/check_pypi.py +0 -0
  13. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/client.py +0 -0
  14. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/config.py +0 -0
  15. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/connector_settings.py +0 -0
  16. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/connectors.py +0 -0
  17. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/context.py +0 -0
  18. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/data_connectors/credentials.py +0 -0
  19. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/datatypes.py +0 -0
  20. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_template.py +0 -0
  21. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_template_fmt.py +0 -0
  22. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/sql_toolset.py +0 -0
  23. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/syncasync.py +0 -0
  24. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli.py +0 -0
  25. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/auth.py +0 -0
  26. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/branch.py +0 -0
  27. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/cicd.py +0 -0
  28. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/common.py +0 -0
  29. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/config.py +0 -0
  30. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/connection.py +0 -0
  31. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/datasource.py +0 -0
  32. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/exceptions.py +0 -0
  33. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/job.py +0 -0
  34. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/pipe.py +0 -0
  35. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/regions.py +0 -0
  36. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/telemetry.py +0 -0
  37. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/test.py +0 -0
  38. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  39. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  40. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/token.py +0 -0
  41. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/workspace.py +0 -0
  42. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  43. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird/tornado_template.py +0 -0
  44. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/SOURCES.txt +0 -0
  45. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/dependency_links.txt +0 -0
  46. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/entry_points.txt +0 -0
  47. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/tinybird_cli.egg-info/requires.txt +0 -0
  48. {tinybird-cli-3.3.1.dev9 → tinybird-cli-3.3.1.dev11}/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: 3.3.1.dev9
3
+ Version: 3.3.1.dev11
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
+ 3.3.1.dev11
23
+ ************
24
+
25
+ - `Add` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
26
+
27
+ 3.3.1.dev10
28
+ ************
29
+
30
+ - `Fixed` Fixed bug when a Data Source was created using an INDEX
31
+
22
32
  3.3.1.dev9
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__ = '3.3.1.dev9'
8
- __revision__ = 'fbdd4be'
7
+ __version__ = '3.3.1.dev11'
8
+ __revision__ = '6db530d'
@@ -3745,6 +3745,8 @@ async def folder_push(
3745
3745
  fork: Optional[bool] = False,
3746
3746
  is_internal: Optional[bool] = False,
3747
3747
  release_created: Optional[bool] = False,
3748
+ auto_promote: Optional[bool] = False,
3749
+ check_backfill_required: bool = False,
3748
3750
  ): # noqa: C901
3749
3751
  workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
3750
3752
  current_ws: Dict[str, Any] = next(
@@ -3879,6 +3881,7 @@ async def folder_push(
3879
3881
  dry_run: bool,
3880
3882
  fork_downstream: Optional[bool] = False,
3881
3883
  fork: Optional[bool] = False,
3884
+ check_backfill_required: bool = False,
3882
3885
  ):
3883
3886
  if name in to_run:
3884
3887
  if not dry_run:
@@ -3970,10 +3973,23 @@ async def folder_push(
3970
3973
  latest_version=resource_versions.get(name),
3971
3974
  )
3972
3975
  )
3976
+ if (
3977
+ check_backfill_required
3978
+ and auto_promote
3979
+ and release_created
3980
+ and "resource" in to_run[name]
3981
+ and to_run[name]["resource"] == "datasources"
3982
+ ):
3983
+ error_msg = FeedbackManager.error_check_backfill_required(resource_name=name)
3984
+ raise click.ClickException(error_msg)
3973
3985
  else:
3974
3986
  click.echo(FeedbackManager.warning_dry_name_already_exists(name=name))
3975
3987
 
3976
- async def push_files(dependency_graph: GraphDependencies, dry_run: bool = False):
3988
+ async def push_files(
3989
+ dependency_graph: GraphDependencies,
3990
+ dry_run: bool = False,
3991
+ check_backfill_required: bool = False,
3992
+ ):
3977
3993
  endpoints_dep_map = dict()
3978
3994
  processed = set()
3979
3995
 
@@ -4057,6 +4073,7 @@ async def folder_push(
4057
4073
  dry_run,
4058
4074
  fork_downstream,
4059
4075
  fork,
4076
+ check_backfill_required=False, # keep it always to false for new resources
4060
4077
  )
4061
4078
  else:
4062
4079
  await push(
@@ -4067,6 +4084,7 @@ async def folder_push(
4067
4084
  dry_run,
4068
4085
  fork_downstream,
4069
4086
  fork,
4087
+ check_backfill_required=check_backfill_required,
4070
4088
  )
4071
4089
  processed.add(name)
4072
4090
 
@@ -4104,6 +4122,7 @@ async def folder_push(
4104
4122
  dry_run,
4105
4123
  fork_downstream,
4106
4124
  fork,
4125
+ check_backfill_required=check_backfill_required,
4107
4126
  )
4108
4127
  processed.add(name)
4109
4128
 
@@ -4124,6 +4143,7 @@ async def folder_push(
4124
4143
  dry_run,
4125
4144
  fork_downstream,
4126
4145
  fork,
4146
+ check_backfill_required=check_backfill_required,
4127
4147
  )
4128
4148
  processed.add(name)
4129
4149
 
@@ -4144,12 +4164,13 @@ async def folder_push(
4144
4164
  dry_run,
4145
4165
  fork_downstream,
4146
4166
  fork,
4167
+ check_backfill_required=check_backfill_required,
4147
4168
  )
4148
4169
  processed.add(name)
4149
4170
 
4150
4171
  if deployment.is_git_release:
4151
4172
  deployment.deploying_dry_run()
4152
- await push_files(dependencies_graph, dry_run=True)
4173
+ await push_files(dependencies_graph, dry_run=True, check_backfill_required=check_backfill_required)
4153
4174
 
4154
4175
  await deployment.delete_resources(deleted, pipes, dry_run=True)
4155
4176
  if not deployment.dry_run:
@@ -326,6 +326,10 @@ class FeedbackManager:
326
326
  error_unsupported_diff = error_message(
327
327
  "There are resources renamed. `tb deploy` can't deploy renamed resources, create new resources instead."
328
328
  )
329
+ error_check_backfill_required = error_message(
330
+ "Not safe to deploy to live resource '{resource_name}', backfill might be required. Consider to deploy to preview bumping semver to major or disable 'TB_AUTO_PROMOTE'. In case you want to disable this check use 'TB_CHECK_BACKFILL_REQUIRED=0'"
331
+ )
332
+
329
333
  info_ignoring_incl_file = info_message(
330
334
  "** Ignoring file {filename}. .incl files are not checked independently. They are checked as part of the file that includes them. Please check the file that includes this .incl file."
331
335
  )
@@ -70,6 +70,9 @@ VERSION=0.0.0
70
70
  # Deploy a new Release in preview status (default is 1)
71
71
  # TB_AUTO_PROMOTE=0
72
72
 
73
+ # Check if deploy requires backfilling on preview (default is 1)
74
+ # TB_CHECK_BACKFILL_REQUIRED=0
75
+
73
76
  # Force old Releases deletion on promote (default is 0)
74
77
  # Setting it to 1 will remove oldest rollback Releases even when some resource is still in use
75
78
  # TB_FORCE_REMOVE_OLDEST_ROLLBACK=0
@@ -1,8 +1,41 @@
1
1
  import re
2
2
  import string
3
3
  from collections import namedtuple
4
+ from dataclasses import dataclass
4
5
  from typing import Any, Dict, Iterable, List, Optional
5
6
 
7
+ valid_chars_name: str = string.ascii_letters + string.digits + "._`*<>+-'"
8
+ valid_chars_fn: str = valid_chars_name + "[](),=!?:/ \n\t\r"
9
+
10
+
11
+ @dataclass
12
+ class TableIndex:
13
+ """Defines a CH table INDEX"""
14
+
15
+ name: str
16
+ expr: str
17
+ type_full: str
18
+ granularity: Optional[str] = None
19
+
20
+ def to_datafile(self):
21
+ granularity_expr = f"GRANULARITY {self.granularity}" if self.granularity else ""
22
+ return f"{self.name} {self.expr} TYPE {self.type_full} {granularity_expr}"
23
+
24
+ def to_sql(self):
25
+ return f"INDEX {self.to_datafile()}"
26
+
27
+ def add_index_sql(self):
28
+ return f"ADD {self.to_sql()}"
29
+
30
+ def drop_index_sql(self):
31
+ return f"DROP INDEX IF EXISTS {self.name}"
32
+
33
+ def materialize_index_sql(self):
34
+ return f"MATERIALIZE INDEX IF EXISTS {self.name}"
35
+
36
+ def clear_index_sql(self):
37
+ return f"CLEAR INDEX IF EXISTS {self.name}"
38
+
6
39
 
7
40
  def as_subquery(sql: str) -> str:
8
41
  return f"""(\n{sql}\n)"""
@@ -177,6 +210,49 @@ def format_parse_error(
177
210
  return message
178
211
 
179
212
 
213
+ def parse_indices_structure(indices: List[str]) -> List[TableIndex]:
214
+ """
215
+ >>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
216
+ [TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
217
+ >>> parse_indices_structure(["INDEX index_name a TYPE set(100) GRANULARITY 100", " INDEX index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
218
+ [TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
219
+ >>> parse_indices_structure(["index_name type TYPE set(100) GRANULARITY 100", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
220
+ [TableIndex(name='index_name', expr='type', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
221
+ >>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100,", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
222
+ [TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
223
+ >>> parse_indices_structure(["index_name a TYPE set(100)", "index_name_bf mapValues(d) TYPE bloom_filter(0.001)"])
224
+ [TableIndex(name='index_name', expr='a', type_full='set(100)', granularity=None), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity=None)]
225
+ >>> parse_indices_structure(["index_name u64 * length(s) TYPE set(100)", "index_name_bf mapValues(d) TYPE bloom_filter"])
226
+ [TableIndex(name='index_name', expr='u64 * length(s)', type_full='set(100)', granularity=None), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter', granularity=None)]
227
+ >>> parse_indices_structure(["index_name u64 * length(s)"])
228
+ Traceback (most recent call last):
229
+ ...
230
+ ValueError: invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`
231
+ >>> parse_indices_structure(["index_name a TYPE set(100) GRANULARITY 100, index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
232
+ Traceback (most recent call last):
233
+ ...
234
+ ValueError: invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`
235
+ """
236
+ parsed_indices: List[TableIndex] = []
237
+ if not indices:
238
+ return parsed_indices
239
+
240
+ for index in indices:
241
+ index = index.strip().rstrip(",")
242
+ index = index.lstrip("INDEX").strip()
243
+ if index.count("TYPE") != 1:
244
+ raise ValueError("invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`")
245
+
246
+ match = re.match(r"(\w+)\s+([\w\s*()]+)\s+TYPE\s+(\w+)(?:\(([\w.]+)\))?(?:\s+GRANULARITY\s+(\d+))?", index)
247
+ if match:
248
+ index_name, a, index_type, value, granularity = match.groups()
249
+ index_expr = f"{index_type}({value})" if value else index_type
250
+ parsed_indices.append(TableIndex(index_name, a.strip(), f"{index_expr}", granularity))
251
+ else:
252
+ raise ValueError("invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`")
253
+ return parsed_indices
254
+
255
+
180
256
  def parse_table_structure(schema: str) -> List[Dict[str, Any]]:
181
257
  """This parses the SQL schema for a CREATE TABLE
182
258
  Columns follow the syntax: name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1][,]
@@ -308,6 +384,12 @@ def parse_table_structure(schema: str) -> List[Dict[str, Any]]:
308
384
  [{'name': 'arr', 'type': 'Array(String)', 'codec': None, 'default_value': "DEFAULT array('-')", 'jsonpath': None, 'nullable': False, 'normalized_name': 'arr'}]
309
385
  >>> parse_table_structure('`a2` Float32 CODEC(Delta, ZSTD(4)) `json:$.a2`, `a3` String `json:$.a3`\\n')
310
386
  [{'name': 'a2', 'type': 'Float32', 'codec': 'CODEC(Delta, ZSTD(4))', 'default_value': None, 'jsonpath': '$.a2', 'nullable': False, 'normalized_name': 'a2'}, {'name': 'a3', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': '$.a3', 'nullable': False, 'normalized_name': 'a3'}]
387
+ >>> parse_table_structure('`a` String, INDEX index_name a TYPE set(100) GRANULARITY 100')
388
+ [{'name': 'a', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'a'}]
389
+ >>> parse_table_structure('`a` String, INDEX index_name a TYPE set(100, 1) GRANULARITY 100')
390
+ [{'name': 'a', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'a'}]
391
+ >>> parse_table_structure('`index` String, INDEX index_name a TYPE set(100, 1) GRANULARITY 100')
392
+ [{'name': 'index', 'type': 'String', 'codec': None, 'default_value': None, 'jsonpath': None, 'nullable': False, 'normalized_name': 'index'}]
311
393
  """
312
394
  return _parse_table_structure(schema)
313
395
 
@@ -367,9 +449,6 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
367
449
  for _ in s:
368
450
  advance_single_char()
369
451
 
370
- valid_chars_name: str = string.ascii_letters + string.digits + "._`*<>+-'"
371
- valid_chars_fn: str = valid_chars_name + "[](),=!?:/ \n\t\r"
372
-
373
452
  def get_backticked() -> str:
374
453
  begin = i
375
454
  while i < len(schema):
@@ -447,6 +526,8 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
447
526
 
448
527
  def add_column(found: str) -> None:
449
528
  nonlocal name, _type, default, materialized, codec, jsonpath
529
+ if name == "INDEX":
530
+ return
450
531
  if not name:
451
532
  raise ValueError(
452
533
  format_parse_error(schema, i, pos, f"Syntax error: expecting NAME, found {found}", line=line)
@@ -479,6 +560,8 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
479
560
  continue
480
561
  found = lookahead_matches(
481
562
  [NULL, NOTNULL, DEFAULT, MATERIALIZED, ALIAS, CODEC, TTL, JSONPATH, COMMA, NEW_LINE, TYPE]
563
+ if name != "INDEX"
564
+ else [COMMA, NEW_LINE]
482
565
  )
483
566
  if found and found not in valid_next:
484
567
  after = f" after {last.name}" if last else ""
@@ -531,11 +614,16 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]: # noqa: C901
531
614
  advance("`json:")
532
615
  jsonpath = get_backticked()
533
616
  elif found == COMMA:
617
+ if name == "INDEX":
618
+ advance(",")
619
+ continue
534
620
  advance(",")
535
621
  valid_next = []
536
622
  add_column("COMMA")
537
623
  elif found == NEW_LINE:
538
624
  i += 1
625
+ elif name == "INDEX" and not found:
626
+ i += 1
539
627
  else:
540
628
  raise ValueError(
541
629
  format_parse_error(
@@ -1494,6 +1494,7 @@ async def deploy(
1494
1494
 
1495
1495
  release_created = False
1496
1496
  new_release = False
1497
+ check_backfill_required = False
1497
1498
  if semver and current_semver:
1498
1499
  new_version = version.parse(semver.split("-snapshot")[0])
1499
1500
  current_version = version.parse(current_semver.split("-snapshot")[0])
@@ -1531,6 +1532,8 @@ async def deploy(
1531
1532
  raise CLIException(FeedbackManager.error_exception(error=str(e)))
1532
1533
  release_created = True
1533
1534
  fork_downstream = True
1535
+ # allows TB_CHECK_BACKFILL_REQUIRED=0 so it is not checked
1536
+ check_backfill_required = getenv_bool("TB_CHECK_BACKFILL_REQUIRED", True)
1534
1537
  try:
1535
1538
  await folder_push(
1536
1539
  tb_client=create_tb_client(ctx),
@@ -1560,6 +1563,8 @@ async def deploy(
1560
1563
  fork=fork,
1561
1564
  is_internal=is_internal,
1562
1565
  release_created=release_created,
1566
+ auto_promote=auto_promote,
1567
+ check_backfill_required=check_backfill_required,
1563
1568
  )
1564
1569
  except Exception as e:
1565
1570
  if release_created and not dry_run:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird-cli
3
- Version: 3.3.1.dev9
3
+ Version: 3.3.1.dev11
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
+ 3.3.1.dev11
23
+ ************
24
+
25
+ - `Add` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
26
+
27
+ 3.3.1.dev10
28
+ ************
29
+
30
+ - `Fixed` Fixed bug when a Data Source was created using an INDEX
31
+
22
32
  3.3.1.dev9
23
33
  ************
24
34