tinybird 0.0.1.dev224__tar.gz → 0.0.1.dev226__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 (111) hide show
  1. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datafile/common.py +2 -0
  3. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/prompts.py +91 -5
  4. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/__cli__.py +2 -2
  5. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/common.py +1 -10
  6. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/connection.py +10 -3
  7. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/create.py +29 -3
  8. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/feedback_manager.py +9 -1
  9. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/login.py +88 -27
  10. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird.egg-info/PKG-INFO +1 -1
  11. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/setup.cfg +0 -0
  12. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/__cli__.py +0 -0
  13. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/ch_utils/constants.py +0 -0
  14. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/ch_utils/engine.py +0 -0
  15. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/check_pypi.py +0 -0
  16. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/client.py +0 -0
  17. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/config.py +0 -0
  18. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/connectors.py +0 -0
  19. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/context.py +0 -0
  20. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datafile/exceptions.py +0 -0
  21. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datafile/parse_connection.py +0 -0
  22. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datafile/parse_datasource.py +0 -0
  23. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datafile/parse_pipe.py +0 -0
  24. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/datatypes.py +0 -0
  25. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/feedback_manager.py +0 -0
  26. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/git_settings.py +0 -0
  27. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/sql.py +0 -0
  28. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/sql_template.py +0 -0
  29. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/sql_template_fmt.py +0 -0
  30. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/sql_toolset.py +0 -0
  31. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/syncasync.py +0 -0
  32. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/check_pypi.py +0 -0
  33. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/cli.py +0 -0
  34. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/client.py +0 -0
  35. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/config.py +0 -0
  36. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/build.py +0 -0
  37. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/cicd.py +0 -0
  38. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/cli.py +0 -0
  39. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/config.py +0 -0
  40. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/copy.py +0 -0
  41. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/build.py +0 -0
  42. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/build_common.py +0 -0
  43. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  44. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  45. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/diff.py +0 -0
  46. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/fixture.py +0 -0
  47. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/format_common.py +0 -0
  48. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  49. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  50. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  51. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/playground.py +0 -0
  52. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datafile/pull.py +0 -0
  53. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/datasource.py +0 -0
  54. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/deployment.py +0 -0
  55. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/deprecations.py +0 -0
  56. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/dev_server.py +0 -0
  57. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/endpoint.py +0 -0
  58. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/exceptions.py +0 -0
  59. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/info.py +0 -0
  60. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/infra.py +0 -0
  61. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/job.py +0 -0
  62. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/llm.py +0 -0
  63. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/llm_utils.py +0 -0
  64. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/local.py +0 -0
  65. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/local_common.py +0 -0
  66. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/logout.py +0 -0
  67. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/materialization.py +0 -0
  68. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/mock.py +0 -0
  69. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/open.py +0 -0
  70. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/pipe.py +0 -0
  71. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/project.py +0 -0
  72. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/regions.py +0 -0
  73. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/secret.py +0 -0
  74. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/shell.py +0 -0
  75. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/sink.py +0 -0
  76. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/table.py +0 -0
  77. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/telemetry.py +0 -0
  78. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/test.py +0 -0
  79. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  80. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  81. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/token.py +0 -0
  82. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/watch.py +0 -0
  83. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/workspace.py +0 -0
  84. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb/modules/workspace_members.py +0 -0
  85. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli.py +0 -0
  86. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/auth.py +0 -0
  87. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/branch.py +0 -0
  88. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/cicd.py +0 -0
  89. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/cli.py +0 -0
  90. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/common.py +0 -0
  91. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/config.py +0 -0
  92. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/connection.py +0 -0
  93. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/datasource.py +0 -0
  94. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/exceptions.py +0 -0
  95. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/fmt.py +0 -0
  96. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/job.py +0 -0
  97. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/pipe.py +0 -0
  98. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/regions.py +0 -0
  99. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/tag.py +0 -0
  100. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/telemetry.py +0 -0
  101. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/test.py +0 -0
  102. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  103. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  104. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/workspace.py +0 -0
  105. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  106. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird/tornado_template.py +0 -0
  107. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird.egg-info/SOURCES.txt +0 -0
  108. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird.egg-info/dependency_links.txt +0 -0
  109. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird.egg-info/entry_points.txt +0 -0
  110. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/tinybird.egg-info/requires.txt +0 -0
  111. {tinybird-0.0.1.dev224 → tinybird-0.0.1.dev226}/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.dev224
3
+ Version: 0.0.1.dev226
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -1710,6 +1710,8 @@ def parse(
1710
1710
  "s3_access_key": assign_var("s3_access_key"),
1711
1711
  "s3_secret": assign_var("s3_secret"),
1712
1712
  "gcs_service_account_credentials_json": assign_var_json("gcs_service_account_credentials_json"),
1713
+ "gcs_access_id": assign_var("gcs_hmac_access_id"),
1714
+ "gcs_secret": assign_var("gcs_hmac_secret"),
1713
1715
  "gcs_hmac_access_id": assign_var("gcs_hmac_access_id"),
1714
1716
  "gcs_hmac_secret": assign_var("gcs_hmac_secret"),
1715
1717
  "include": include,
@@ -896,11 +896,10 @@ You have commands at your disposal to develop a tinybird project:
896
896
  - {base_command} build: to build the project locally and check it works.
897
897
  - {base_command} deployment create --wait --auto: to create a deployment and promote it automatically
898
898
  - {base_command} test run: to run existing tests
899
- - {base_command} --build endpoint url <pipe_name>: to get the url of an endpoint, token included.
900
- - {base_command} --build endpoint data <pipe_name>: to get the data of an endpoint. You can pass parameters to the endpoint like this: {base_command} --build endpoint data <pipe_name> --param1 value1 --param2 value2
901
- - {base_command} --build token ls: to list all the tokens
899
+ - {base_command} endpoint url <pipe_name>: to get the url of an endpoint, token included.
900
+ - {base_command} endpoint data <pipe_name>: to get the data of an endpoint. You can pass parameters to the endpoint like this: {base_command} endpoint data <pipe_name> --param1 value1 --param2 value2
901
+ - {base_command} token ls: to list all the tokens
902
902
  There are other commands that you can use, but these are the most common ones. Run `{base_command} -h` to see all the commands if needed.
903
- When you need to work with resources or data in the Tinybird environment that you updated with the build command, add always the --build flag before the command. Example: {base_command} --build datasource ls
904
903
  When you need to work with resources or data in cloud, add always the --cloud flag before the command. Example: {base_command} --cloud datasource ls
905
904
  </command_calling>
906
905
  <development_instructions>
@@ -925,7 +924,7 @@ When asking for ingesting data, adding data or appending data do the following d
925
924
  - When building locally, create a .ndjson file with the data you want to ingest and do `{base_command} build` to ingest the data in the build env.
926
925
  - We call `cloud` the production environment.
927
926
  - When appending data in cloud, use `{base_command} --cloud datasource append <datasource_name> <file_name>`
928
- - When you have a response that says “there are rows in quarantine”, do `{base_command} --build|--cloud datasource data <datasource_name>_quarantine` to understand what is the problem.
927
+ - When you have a response that says “there are rows in quarantine”, do `{base_command} [--cloud] datasource data <datasource_name>_quarantine` to understand what is the problem.
929
928
  </ingest_data_instructions>
930
929
  <datasource_file_instructions>
931
930
  Follow these instructions when creating or updating .datasource files:
@@ -975,6 +974,93 @@ Follow these instructions when evolving a datasource schema:
975
974
  )
976
975
 
977
976
 
977
+ def claude_rules_prompt(source: Optional[str] = None) -> str:
978
+ base_command = source or "tb"
979
+ return """
980
+ # Tinybird CLI rules
981
+
982
+ ## Commands
983
+ You have commands at your disposal to develop a tinybird project:
984
+ - {base_command} build: to build the project locally and check it works.
985
+ - {base_command} deployment create --wait --auto: to create a deployment and promote it automatically
986
+ - {base_command} test run: to run existing tests
987
+ - {base_command} endpoint url <pipe_name>: to get the url of an endpoint, token included.
988
+ - {base_command} endpoint data <pipe_name>: to get the data of an endpoint. You can pass parameters to the endpoint like this: {base_command} endpoint data <pipe_name> --param1 value1 --param2 value2
989
+ - {base_command} token ls: to list all the tokens
990
+ There are other commands that you can use, but these are the most common ones. Run `{base_command} -h` to see all the commands if needed.
991
+ When you need to work with resources or data in cloud, add always the --cloud flag before the command. Example: {base_command} --cloud datasource ls
992
+
993
+ ## Development instructions
994
+ - When asking to create a tinybird data project, if the needed folders are not already created, use the following structure:
995
+ ├── connections
996
+ ├── copies
997
+ ├── sinks
998
+ ├── datasources
999
+ ├── endpoints
1000
+ ├── fixtures
1001
+ ├── materializations
1002
+ ├── pipes
1003
+ └── tests
1004
+ - The local development server will be available at http://localhost:7181. Even if some response uses another base url, use always http://localhost:7181.
1005
+ - After every change in your .datasource, .pipe or .ndjson files, run `{base_command} build` to build the project locally.
1006
+ - When you need to ingest data locally in a datasource, create a .ndjson file with the same name of the datasource and the data you want and run `{base_command} build` so the data is ingested.
1007
+ - The format of the generated api endpoint urls is: http://localhost:7181/v0/pipe/<pipe_name>.json?token=<token>
1008
+ - Before running the tests, remember to have the project built with `{base_command} build` with the latest changes.
1009
+ </development_instructions>
1010
+ When asking for ingesting data, adding data or appending data do the following depending on the environment you want to work with:
1011
+
1012
+ ## Ingestion instructions
1013
+ - When building locally, create a .ndjson file with the data you want to ingest and do `{base_command} build` to ingest the data in the build env.
1014
+ - We call `cloud` the production environment.
1015
+ - When appending data in cloud, use `{base_command} --cloud datasource append <datasource_name> <file_name>`
1016
+ - When you have a response that says “there are rows in quarantine”, do `{base_command} [--cloud] datasource data <datasource_name>_quarantine` to understand what is the problem.
1017
+
1018
+ ## .datasource file instructions
1019
+ Follow these instructions when creating or updating .datasource files:
1020
+ {datasource_instructions}
1021
+
1022
+ ## .pipe file instructions
1023
+ Follow these instructions when creating or updating .pipe files:
1024
+ {pipe_instructions}
1025
+ {sql_instructions}
1026
+ {datasource_example}
1027
+ {pipe_example}
1028
+ {copy_pipe_instructions}
1029
+ {materialized_pipe_instructions}
1030
+ {sink_pipe_instructions}
1031
+ {connection_instructions}
1032
+ {kafka_connection_example}
1033
+ {gcs_connection_example}
1034
+ {gcs_hmac_connection_example}
1035
+ {s3_connection_example}
1036
+
1037
+ ## .test file instructions
1038
+ Follow these instructions when creating or updating .yaml files for tests:
1039
+ {test_instructions}
1040
+
1041
+ ## Deployment instructions
1042
+ Follow these instructions when evolving a datasource schema:
1043
+ {deployment_instructions}
1044
+ """.format(
1045
+ base_command=base_command,
1046
+ datasource_instructions=datasource_instructions,
1047
+ pipe_instructions=pipe_instructions,
1048
+ sql_instructions=sql_instructions,
1049
+ datasource_example=datasource_example,
1050
+ pipe_example=pipe_example,
1051
+ copy_pipe_instructions=copy_pipe_instructions,
1052
+ materialized_pipe_instructions=materialized_pipe_instructions,
1053
+ sink_pipe_instructions=sink_pipe_instructions,
1054
+ test_instructions=test_instructions,
1055
+ deployment_instructions=deployment_instructions,
1056
+ connection_instructions=connection_instructions,
1057
+ kafka_connection_example=kafka_connection_example,
1058
+ gcs_connection_example=gcs_connection_example,
1059
+ gcs_hmac_connection_example=gcs_hmac_connection_example,
1060
+ s3_connection_example=s3_connection_example,
1061
+ )
1062
+
1063
+
978
1064
  test_instructions = """
979
1065
  - The test file name must match the name of the pipe it is testing.
980
1066
  - Every scenario name must be unique inside the test file.
@@ -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__ = '0.0.1.dev224'
8
- __revision__ = 'c632cc3'
7
+ __version__ = '0.0.1.dev226'
8
+ __revision__ = '7ee5a2e'
@@ -1761,18 +1761,11 @@ async def run_aws_iamrole_connection_flow(
1761
1761
 
1762
1762
  async def run_gcp_svc_account_connection_flow(
1763
1763
  environment: str,
1764
- ) -> Tuple[str, str, str]:
1765
- bucket_name = click.prompt(
1766
- "📦 Bucket name (specific name recommended, use '*' for unrestricted access in IAM policy)",
1767
- prompt_suffix="\n> ",
1768
- )
1769
- validate_string_connector_param("Bucket", bucket_name)
1770
-
1764
+ ) -> None:
1771
1765
  click.echo(FeedbackManager.prompt_gcs_svc_account_login_gcp())
1772
1766
  click.echo(FeedbackManager.click_enter_to_continue())
1773
1767
  input()
1774
1768
 
1775
- # Display message and wait for user to press Enter
1776
1769
  click.echo(FeedbackManager.prompt_gcs_service_account_creation_flow(environment=environment))
1777
1770
  click.echo(FeedbackManager.click_enter_to_continue())
1778
1771
  input()
@@ -1781,8 +1774,6 @@ async def run_gcp_svc_account_connection_flow(
1781
1774
  click.echo(FeedbackManager.click_enter_to_continue())
1782
1775
  input()
1783
1776
 
1784
- return bucket_name
1785
-
1786
1777
 
1787
1778
  async def production_aws_iamrole_only(
1788
1779
  prod_client: TinyB,
@@ -203,7 +203,10 @@ async def connection_create_s3(ctx: Context) -> None:
203
203
  )
204
204
  unique_suffix = uuid.uuid4().hex[:8] # Use first 8 chars of a UUID for brevity
205
205
  secret_name = f"s3_role_arn_{connection_name}_{unique_suffix}"
206
- save_secret_to_env_file(project=project, name=secret_name, value=role_arn)
206
+ if obj["env"] == "local":
207
+ save_secret_to_env_file(project=project, name=secret_name, value=role_arn)
208
+ else:
209
+ await client.create_secret(name=secret_name, value=role_arn)
207
210
 
208
211
  create_in_cloud = (
209
212
  click.confirm(FeedbackManager.prompt_connection_in_cloud_confirmation(), default=True)
@@ -267,15 +270,19 @@ async def connection_create_gcs(ctx: Context) -> None:
267
270
  """
268
271
  project: Project = ctx.ensure_object(dict)["project"]
269
272
  obj: Dict[str, Any] = ctx.ensure_object(dict)
273
+ client: TinyB = obj["client"]
270
274
 
271
275
  service = DataConnectorType.GCLOUD_STORAGE
272
276
  click.echo(FeedbackManager.prompt_gcs_connection_header())
273
277
  connection_name = get_gcs_connection_name(project.folder)
274
- _ = await run_gcp_svc_account_connection_flow(environment=obj["env"])
278
+ await run_gcp_svc_account_connection_flow(environment=obj["env"])
275
279
  creds_json = get_gcs_svc_account_creds()
276
280
  unique_suffix = uuid.uuid4().hex[:8] # Use first 8 chars of a UUID for brevity
277
281
  secret_name = f"gcs_svc_account_creds_{connection_name}_{unique_suffix}"
278
- save_secret_to_env_file(project=project, name=secret_name, value=creds_json)
282
+ if obj["env"] == "local":
283
+ save_secret_to_env_file(project=project, name=secret_name, value=creds_json)
284
+ else:
285
+ await client.create_secret(name=secret_name, value=creds_json)
279
286
 
280
287
  connection_path = await generate_gcs_connection_file_with_secrets(
281
288
  name=connection_name,
@@ -1,6 +1,7 @@
1
1
  import glob
2
2
  import os
3
3
  import re
4
+ import shutil
4
5
  from pathlib import Path
5
6
  from typing import Any, Dict, List, Optional
6
7
  from urllib.parse import urlparse
@@ -8,7 +9,7 @@ from urllib.parse import urlparse
8
9
  import click
9
10
  import requests
10
11
 
11
- from tinybird.prompts import create_prompt, readme_prompt, rules_prompt
12
+ from tinybird.prompts import claude_rules_prompt, create_prompt, readme_prompt, rules_prompt
12
13
  from tinybird.tb.client import TinyB
13
14
  from tinybird.tb.modules.cicd import init_cicd
14
15
  from tinybird.tb.modules.cli import cli
@@ -144,6 +145,13 @@ async def create(
144
145
  click.echo(FeedbackManager.success(message="✓ Done!\n"))
145
146
  created_something = True
146
147
 
148
+ if not already_has_claude_rules(root_folder):
149
+ click.echo(FeedbackManager.highlight(message="\n» Creating Claude Code rules..."))
150
+ create_claude_rules(root_folder, "tb")
151
+ click.echo(FeedbackManager.info(message="CLAUDE.md"))
152
+ click.echo(FeedbackManager.success(message="✓ Done!\n"))
153
+ created_something = True
154
+
147
155
  if should_generate_fixtures(result):
148
156
  click.echo(FeedbackManager.highlight(message="\n» Generating fixtures..."))
149
157
 
@@ -246,6 +254,11 @@ def already_has_cursor_rules(folder: str) -> bool:
246
254
  return any((Path(folder) / path).exists() for path in cursor_rules_paths)
247
255
 
248
256
 
257
+ def already_has_claude_rules(folder: str) -> bool:
258
+ claude_rules_path = "CLAUDE.md"
259
+ return (Path(folder) / claude_rules_path).exists()
260
+
261
+
249
262
  def already_has_env_file(folder: str) -> bool:
250
263
  env_file_pattern = ".env.*"
251
264
  return any((Path(folder) / path).exists() for path in glob.glob(env_file_pattern))
@@ -466,9 +479,22 @@ def create_rules(folder: str, source: str, agent: str):
466
479
  elif agent == "windsurf":
467
480
  extension = ".windsurfrules"
468
481
  else:
469
- extension = ".txt"
482
+ extension = ".md"
483
+
470
484
  rules_file = Path(folder) / extension
471
- rules_file.write_text(rules_prompt(source))
485
+ rules_content = rules_prompt(source)
486
+ rules_file.write_text(rules_content)
487
+
488
+
489
+ def create_claude_rules(folder: str, source: str):
490
+ try:
491
+ is_claude_code_installed = shutil.which("claude") is not None
492
+ if is_claude_code_installed:
493
+ rules_content = claude_rules_prompt(source)
494
+ claude_file = Path(folder) / "CLAUDE.md"
495
+ claude_file.write_text(rules_content)
496
+ except Exception:
497
+ pass
472
498
 
473
499
 
474
500
  def get_context_file() -> Path:
@@ -631,7 +631,13 @@ STEP 2: CREATE GCP SERVICE ACCOUNT
631
631
  1. Go to IAM & Admin > Service Accounts > + Create Service Account: https://console.cloud.google.com/iam-admin/serviceaccounts/create
632
632
  2. Provide a service account name. Name the service account something meaningful (e.g., TinybirdGCS-{environment}-svc-account)
633
633
  3. Click "Create and continue"
634
- 4. Click the "Select a role" drop down menu and select "Storage Object Viewer" (You can add IAM condition to provide access to selected buckets. More info in IAM Conditions: https://www.tinybird.co/docs/forward/get-data-in/connectors/gcs)
634
+ 4. Click the "Select a role" drop down menu and select:
635
+ - "Storage Object Viewer" for GCS Data Source (reading from GCS)
636
+ - For GCS Sink (writing to GCS), select all three roles:
637
+ • "Storage Object Creator" - Allows users to create objects
638
+ • "Storage Object Viewer" - Grants access to view objects and their metadata
639
+ • "Storage Bucket Viewer" - Grants access to view buckets and their metadata
640
+ (You can add IAM condition to provide access to selected buckets. More info in IAM Conditions: https://cloud.google.com/iam/docs/conditions-overview)
635
641
  5. Click "Done"
636
642
  """
637
643
  )
@@ -654,7 +660,9 @@ STEP 3: ADD KEY TO SERVICE ACCOUNT
654
660
 
655
661
  • File created at: {connection_path}
656
662
  • You can now use this connection in your Data Sources with: IMPORT_CONNECTION_NAME '{connection_name}'
663
+ • You can also use this connection in your Pipes with: EXPORT_CONNECTION_NAME '{connection_name}'
657
664
  • Learn more about our GCS Connector: https://www.tinybird.co/docs/forward/get-data-in/connectors/gcs
665
+ • Learn more about our GCS Sinks: https://www.tinybird.co/docs/forward/work-with-data/publish-data/gcs-sinks
658
666
  """)
659
667
 
660
668
  prompt_init_git_release_pull = prompt_message(
@@ -1,8 +1,10 @@
1
1
  import http.server
2
2
  import os
3
3
  import platform
4
+ import random
4
5
  import shutil
5
6
  import socketserver
7
+ import string
6
8
  import subprocess
7
9
  import sys
8
10
  import threading
@@ -127,8 +129,14 @@ def start_server(auth_callback, auth_host):
127
129
  default=False,
128
130
  help="Show available regions and select where to authenticate to",
129
131
  )
132
+ @click.option(
133
+ "--method",
134
+ type=click.Choice(["browser", "code"]),
135
+ default="browser",
136
+ help="Set the authentication method to use. Default: browser.",
137
+ )
130
138
  @coro
131
- async def login(host: Optional[str], auth_host: str, workspace: str, interactive: bool):
139
+ async def login(host: Optional[str], auth_host: str, workspace: str, interactive: bool, method: str):
132
140
  """Authenticate using the browser."""
133
141
  try:
134
142
  cli_config = CLIConfig.get_project_config()
@@ -154,6 +162,49 @@ async def login(host: Optional[str], auth_host: str, workspace: str, interactive
154
162
  host = host.rstrip("/")
155
163
  auth_host = auth_host.rstrip("/")
156
164
 
165
+ if method == "code":
166
+ display_code, one_time_code = create_one_time_code()
167
+ click.echo(FeedbackManager.info(message=f"First, copy your one-time code: {display_code}"))
168
+ click.echo(FeedbackManager.info(message="Press [Enter] to continue in the browser..."))
169
+ input()
170
+ click.echo(FeedbackManager.highlight(message="» Opening browser for authentication..."))
171
+ params = {
172
+ "apiHost": host,
173
+ "code": one_time_code,
174
+ "method": "code",
175
+ }
176
+ auth_url = f"{auth_host}/api/cli-login?{urlencode(params)}"
177
+ open_url(auth_url)
178
+ click.echo(
179
+ FeedbackManager.info(message="\nIf browser does not open, please open the following URL manually:")
180
+ )
181
+ click.echo(FeedbackManager.info(message=auth_url))
182
+
183
+ async def poll_for_tokens():
184
+ while True:
185
+ params = {
186
+ "apiHost": host,
187
+ "cliCode": one_time_code,
188
+ "method": "code",
189
+ }
190
+ response = requests.get(f"{auth_host}/api/cli-login?{urlencode(params)}") # noqa: ASYNC210
191
+
192
+ try:
193
+ if response.status_code == 200:
194
+ data = response.json()
195
+ user_token = data.get("user_token", "")
196
+ workspace_token = data.get("workspace_token", "")
197
+ if user_token and workspace_token:
198
+ await authenticate_with_tokens(data, host, cli_config)
199
+ break
200
+ except Exception:
201
+ pass
202
+
203
+ time.sleep(2) # noqa: ASYNC251
204
+
205
+ await poll_for_tokens()
206
+ return
207
+
157
208
  auth_event = threading.Event()
158
209
  auth_code: list[str] = [] # Using a list to store the code, as it's mutable
159
210
 
@@ -190,32 +241,7 @@ async def login(host: Optional[str], auth_host: str, workspace: str, interactive
190
241
  )
191
242
 
192
243
  data = response.json()
193
- cli_config.set_token(data.get("workspace_token", ""))
194
- cli_config.set_token_for_host(data.get("workspace_token", ""), host)
195
- cli_config.set_user_token(data.get("user_token", ""))
196
- host = data.get("api_host", host)
197
- cli_config.set_host(host)
198
- ws = await cli_config.get_client(token=data.get("workspace_token", ""), host=host).workspace_info(
199
- version="v1"
200
- )
201
- for k in ("id", "name", "user_email", "user_id", "scope"):
202
- if k in ws:
203
- cli_config[k] = ws[k]
204
-
205
- path = os.path.join(os.getcwd(), ".tinyb")
206
- cli_config.persist_to_file(override_with_path=path)
207
-
208
- auth_info: Dict[str, Any] = await cli_config.get_user_client().check_auth_login()
209
- if not auth_info.get("is_valid", False):
210
- raise Exception(FeedbackManager.error_auth_login_not_valid(host=cli_config.get_host()))
211
-
212
- if not auth_info.get("is_user", False):
213
- raise Exception(FeedbackManager.error_auth_login_not_user(host=cli_config.get_host()))
214
-
215
- click.echo(FeedbackManager.gray(message="\nWorkspace: ") + FeedbackManager.info(message=ws["name"]))
216
- click.echo(FeedbackManager.gray(message="User: ") + FeedbackManager.info(message=ws["user_email"]))
217
- click.echo(FeedbackManager.gray(message="Host: ") + FeedbackManager.info(message=host))
218
- click.echo(FeedbackManager.success(message="\n✓ Authentication successful!"))
244
+ await authenticate_with_tokens(data, host, cli_config)
219
245
  else:
220
246
  raise Exception("Authentication failed or timed out.")
221
247
  except Exception as e:
@@ -272,3 +298,38 @@ def open_url(url: str, *, new_tab: bool = False) -> bool:
272
298
 
273
299
  # 5. If everything failed, let the caller know.
274
300
  return False
301
+
302
+
303
+ def create_one_time_code():
304
+ """Create a random one-time code for the authentication process in the format of A2C4-D2G4 (only uppercase letters and digits)"""
305
+ seperator = "-"
306
+ full_code = "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
307
+ parts = [full_code[:4], full_code[4:]]
308
+ return seperator.join(parts), full_code
309
+
310
+
311
+ async def authenticate_with_tokens(data: Dict[str, Any], host: Optional[str], cli_config: CLIConfig):
312
+ cli_config.set_token(data.get("workspace_token", ""))
313
+ host = host or data.get("api_host", "")
314
+ cli_config.set_token_for_host(data.get("workspace_token", ""), host)
315
+ cli_config.set_user_token(data.get("user_token", ""))
316
+ cli_config.set_host(host)
317
+ ws = await cli_config.get_client(token=data.get("workspace_token", ""), host=host).workspace_info(version="v1")
318
+ for k in ("id", "name", "user_email", "user_id", "scope"):
319
+ if k in ws:
320
+ cli_config[k] = ws[k]
321
+
322
+ path = os.path.join(os.getcwd(), ".tinyb")
323
+ cli_config.persist_to_file(override_with_path=path)
324
+
325
+ auth_info: Dict[str, Any] = await cli_config.get_user_client().check_auth_login()
326
+ if not auth_info.get("is_valid", False):
327
+ raise Exception(FeedbackManager.error_auth_login_not_valid(host=cli_config.get_host()))
328
+
329
+ if not auth_info.get("is_user", False):
330
+ raise Exception(FeedbackManager.error_auth_login_not_user(host=cli_config.get_host()))
331
+
332
+ click.echo(FeedbackManager.gray(message="\nWorkspace: ") + FeedbackManager.info(message=ws["name"]))
333
+ click.echo(FeedbackManager.gray(message="User: ") + FeedbackManager.info(message=ws["user_email"]))
334
+ click.echo(FeedbackManager.gray(message="Host: ") + FeedbackManager.info(message=host))
335
+ click.echo(FeedbackManager.success(message="\n✓ Authentication successful!"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev224
3
+ Version: 0.0.1.dev226
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird