tinybird 0.0.1.dev16__py3-none-any.whl → 0.0.1.dev17__py3-none-any.whl
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.
- tinybird/tb/cli.py +0 -1
- tinybird/tb/modules/build.py +33 -24
- tinybird/tb/modules/build_shell.py +36 -20
- tinybird/tb/modules/cli.py +4 -89
- tinybird/tb/modules/common.py +7 -98
- tinybird/tb/modules/config.py +0 -10
- tinybird/tb/modules/create.py +53 -218
- tinybird/tb/modules/datafile/build_pipe.py +1 -1
- tinybird/tb/modules/datasource.py +0 -10
- tinybird/tb/modules/pipe.py +0 -4
- {tinybird-0.0.1.dev16.dist-info → tinybird-0.0.1.dev17.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev16.dist-info → tinybird-0.0.1.dev17.dist-info}/RECORD +15 -16
- tinybird/tb/modules/branch.py +0 -1023
- {tinybird-0.0.1.dev16.dist-info → tinybird-0.0.1.dev17.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev16.dist-info → tinybird-0.0.1.dev17.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev16.dist-info → tinybird-0.0.1.dev17.dist-info}/top_level.txt +0 -0
tinybird/tb/cli.py
CHANGED
|
@@ -5,7 +5,6 @@ if sys.platform == "win32":
|
|
|
5
5
|
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
6
6
|
|
|
7
7
|
import tinybird.tb.modules.auth
|
|
8
|
-
import tinybird.tb.modules.branch
|
|
9
8
|
import tinybird.tb.modules.build
|
|
10
9
|
import tinybird.tb.modules.cli
|
|
11
10
|
import tinybird.tb.modules.common
|
tinybird/tb/modules/build.py
CHANGED
|
@@ -27,9 +27,10 @@ from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class FileChangeHandler(FileSystemEventHandler):
|
|
30
|
-
def __init__(self, filenames: List[str], process: Callable[[List[str]], None]):
|
|
30
|
+
def __init__(self, filenames: List[str], process: Callable[[List[str]], None], build_ok: bool):
|
|
31
31
|
self.filenames = filenames
|
|
32
32
|
self.process = process
|
|
33
|
+
self.build_ok = build_ok
|
|
33
34
|
|
|
34
35
|
def on_modified(self, event: Any) -> None:
|
|
35
36
|
is_not_vendor = "vendor/" not in event.src_path
|
|
@@ -41,7 +42,9 @@ class FileChangeHandler(FileSystemEventHandler):
|
|
|
41
42
|
filename = event.src_path.split("/")[-1]
|
|
42
43
|
click.echo(FeedbackManager.highlight(message=f"\n\n⟲ Changes detected in {filename}\n"))
|
|
43
44
|
try:
|
|
44
|
-
|
|
45
|
+
to_process = [event.src_path] if self.build_ok else self.filenames
|
|
46
|
+
self.process(to_process)
|
|
47
|
+
self.build_ok = True
|
|
45
48
|
except Exception as e:
|
|
46
49
|
click.echo(FeedbackManager.error_exception(error=e))
|
|
47
50
|
|
|
@@ -51,6 +54,7 @@ def watch_files(
|
|
|
51
54
|
process: Union[Callable[[List[str]], None], Callable[[List[str]], Awaitable[None]]],
|
|
52
55
|
shell: BuildShell,
|
|
53
56
|
folder: str,
|
|
57
|
+
build_ok: bool,
|
|
54
58
|
) -> None:
|
|
55
59
|
# Handle both sync and async process functions
|
|
56
60
|
async def process_wrapper(files: List[str]) -> None:
|
|
@@ -68,7 +72,7 @@ def watch_files(
|
|
|
68
72
|
)
|
|
69
73
|
shell.reprint_prompt()
|
|
70
74
|
|
|
71
|
-
event_handler = FileChangeHandler(filenames, lambda f: asyncio.run(process_wrapper(f)))
|
|
75
|
+
event_handler = FileChangeHandler(filenames, lambda f: asyncio.run(process_wrapper(f)), build_ok)
|
|
72
76
|
observer = Observer()
|
|
73
77
|
|
|
74
78
|
observer.schedule(event_handler, path=folder, recursive=True)
|
|
@@ -110,7 +114,6 @@ async def build(
|
|
|
110
114
|
ignore_sql_errors = FeatureFlags.ignore_sql_errors()
|
|
111
115
|
context.disable_template_security_validation.set(True)
|
|
112
116
|
is_internal = has_internal_datafiles(folder)
|
|
113
|
-
|
|
114
117
|
folder_path = os.path.abspath(folder)
|
|
115
118
|
tb_client = await get_tinybird_local_client(folder_path)
|
|
116
119
|
|
|
@@ -143,30 +146,31 @@ async def build(
|
|
|
143
146
|
is_internal=is_internal,
|
|
144
147
|
watch=watch,
|
|
145
148
|
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
149
|
+
if len(filenames) > 0:
|
|
150
|
+
filename = filenames[0]
|
|
151
|
+
if filename.endswith(".ndjson"):
|
|
152
|
+
fixture_path = Path(filename)
|
|
153
|
+
name = "_".join(fixture_path.stem.split("_")[:-1])
|
|
154
|
+
ds_path = Path(folder) / "datasources" / f"{name}.datasource"
|
|
155
|
+
if ds_path.exists():
|
|
156
|
+
await append_datasource({}, tb_client, name, str(fixture_path), silent=True)
|
|
157
|
+
|
|
158
|
+
if watch:
|
|
159
|
+
if filename.endswith(".datasource"):
|
|
160
|
+
ds_path = Path(filename)
|
|
161
|
+
name = build_fixture_name(filename, ds_path.stem, ds_path.read_text())
|
|
162
|
+
fixture_path = get_fixture_dir() / f"{name}.ndjson"
|
|
163
|
+
if fixture_path.exists():
|
|
164
|
+
await append_datasource({}, tb_client, ds_path.stem, str(fixture_path), silent=True)
|
|
165
|
+
if not filename.endswith(".ndjson"):
|
|
166
|
+
await build_and_print_resource(tb_client, filename)
|
|
164
167
|
|
|
165
168
|
datafiles = get_project_filenames(folder)
|
|
166
169
|
fixtures = get_project_fixtures(folder)
|
|
167
170
|
filenames = datafiles + fixtures
|
|
168
171
|
|
|
169
172
|
async def build_once(filenames: List[str]):
|
|
173
|
+
ok = False
|
|
170
174
|
try:
|
|
171
175
|
click.echo("⚡ Building project...\n")
|
|
172
176
|
time_start = time.time()
|
|
@@ -181,15 +185,20 @@ async def build(
|
|
|
181
185
|
if fixture_path.exists():
|
|
182
186
|
await append_datasource({}, tb_client, ds_path.stem, str(fixture_path), silent=True)
|
|
183
187
|
click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s\n"))
|
|
188
|
+
ok = True
|
|
184
189
|
except Exception as e:
|
|
185
190
|
click.echo(FeedbackManager.error(message=str(e)))
|
|
191
|
+
ok = False
|
|
192
|
+
return ok
|
|
186
193
|
|
|
187
|
-
await build_once(filenames)
|
|
194
|
+
build_ok = await build_once(filenames)
|
|
188
195
|
|
|
189
196
|
if watch:
|
|
190
197
|
shell = BuildShell(folder=folder, client=tb_client)
|
|
191
198
|
click.echo(FeedbackManager.highlight(message="◎ Watching for changes..."))
|
|
192
|
-
watcher_thread = threading.Thread(
|
|
199
|
+
watcher_thread = threading.Thread(
|
|
200
|
+
target=watch_files, args=(filenames, process, shell, folder, build_ok), daemon=True
|
|
201
|
+
)
|
|
193
202
|
watcher_thread.start()
|
|
194
203
|
shell.cmdloop()
|
|
195
204
|
|
|
@@ -14,7 +14,7 @@ from tinybird.tb.modules.table import format_table
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class BuildShell(cmd.Cmd):
|
|
17
|
-
prompt = "\n\001\033[1;32m\
|
|
17
|
+
prompt = "\n\001\033[1;32m\002tb > \001\033[0m\002"
|
|
18
18
|
|
|
19
19
|
def __init__(self, folder: str, client: TinyB):
|
|
20
20
|
super().__init__()
|
|
@@ -27,28 +27,44 @@ class BuildShell(cmd.Cmd):
|
|
|
27
27
|
def do_quit(self, arg):
|
|
28
28
|
sys.exit(0)
|
|
29
29
|
|
|
30
|
+
def do_build(self, arg):
|
|
31
|
+
click.echo(FeedbackManager.error(message=f"'tb {arg}' command is not available in watch mode"))
|
|
32
|
+
|
|
33
|
+
def do_auth(self, arg):
|
|
34
|
+
click.echo(FeedbackManager.error(message=f"'tb {arg}' command is not available in watch mode"))
|
|
35
|
+
|
|
36
|
+
def do_workspace(self, arg):
|
|
37
|
+
click.echo(FeedbackManager.error(message=f"'tb {arg}' command is not available in watch mode"))
|
|
38
|
+
|
|
39
|
+
def do_mock(self, arg):
|
|
40
|
+
subprocess.run(f"tb mock {arg} --folder {self.folder}", shell=True, text=True)
|
|
41
|
+
|
|
42
|
+
def do_tb(self, arg):
|
|
43
|
+
click.echo("")
|
|
44
|
+
arg = arg.strip().lower()
|
|
45
|
+
if arg.startswith("build"):
|
|
46
|
+
self.do_build(arg)
|
|
47
|
+
elif arg.startswith("auth"):
|
|
48
|
+
self.do_auth(arg)
|
|
49
|
+
elif arg.startswith("workspace"):
|
|
50
|
+
self.do_workspace(arg)
|
|
51
|
+
elif arg.startswith("mock"):
|
|
52
|
+
self.do_mock(arg)
|
|
53
|
+
else:
|
|
54
|
+
subprocess.run(f"tb --local {arg}", shell=True, text=True)
|
|
55
|
+
|
|
30
56
|
def default(self, argline):
|
|
31
57
|
click.echo("")
|
|
32
|
-
|
|
33
|
-
|
|
58
|
+
arg = argline.strip().lower()
|
|
59
|
+
if not arg:
|
|
60
|
+
return
|
|
61
|
+
if arg.startswith("with") or arg.startswith("select"):
|
|
62
|
+
try:
|
|
63
|
+
self.run_sql(argline)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
click.echo(FeedbackManager.error(message=str(e)))
|
|
34
66
|
else:
|
|
35
|
-
|
|
36
|
-
if not arg_stripped:
|
|
37
|
-
return
|
|
38
|
-
if arg_stripped.startswith("tb"):
|
|
39
|
-
arg_stripped = arg_stripped.replace("tb", "tb --local")
|
|
40
|
-
extra_args = f" --folder {self.folder}" if arg_stripped.startswith("tb mock") else ""
|
|
41
|
-
subprocess.run(arg_stripped + extra_args, shell=True, text=True)
|
|
42
|
-
elif arg_stripped.startswith("with") or arg_stripped.startswith("select"):
|
|
43
|
-
try:
|
|
44
|
-
self.run_sql(self.client, argline)
|
|
45
|
-
except Exception as e:
|
|
46
|
-
click.echo(FeedbackManager.error(message=str(e)))
|
|
47
|
-
|
|
48
|
-
elif arg_stripped.startswith("mock "):
|
|
49
|
-
subprocess.run(f"tb {arg_stripped} --folder {self.folder}", shell=True, text=True)
|
|
50
|
-
else:
|
|
51
|
-
click.echo(FeedbackManager.error(message="Invalid command"))
|
|
67
|
+
subprocess.run(f"tb --local {arg}", shell=True, text=True)
|
|
52
68
|
|
|
53
69
|
def reprint_prompt(self):
|
|
54
70
|
self.stdout.write(self.prompt)
|
tinybird/tb/modules/cli.py
CHANGED
|
@@ -36,7 +36,6 @@ from tinybird.tb.modules.common import (
|
|
|
36
36
|
coro,
|
|
37
37
|
create_tb_client,
|
|
38
38
|
echo_safe_format_table,
|
|
39
|
-
folder_init,
|
|
40
39
|
get_current_main_workspace,
|
|
41
40
|
getenv_bool,
|
|
42
41
|
is_major_semver,
|
|
@@ -81,7 +80,6 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
|
|
|
81
80
|
)
|
|
82
81
|
@click.option("--token", help="Use auth token, defaults to TB_TOKEN envvar, then to the .tinyb file")
|
|
83
82
|
@click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
|
|
84
|
-
@click.option("--semver", help="Semver of a Release to run the command. Example: 1.0.0", hidden=True)
|
|
85
83
|
@click.option("--gcp-project-id", help="The Google Cloud project ID", hidden=True)
|
|
86
84
|
@click.option(
|
|
87
85
|
"--gcs-bucket", help="The Google Cloud Storage bucket to write temp files when using the connectors", hidden=True
|
|
@@ -118,7 +116,6 @@ async def cli(
|
|
|
118
116
|
debug: bool,
|
|
119
117
|
token: str,
|
|
120
118
|
host: str,
|
|
121
|
-
semver: str,
|
|
122
119
|
gcp_project_id: str,
|
|
123
120
|
gcs_bucket: str,
|
|
124
121
|
google_application_credentials: str,
|
|
@@ -140,7 +137,7 @@ async def cli(
|
|
|
140
137
|
"""
|
|
141
138
|
|
|
142
139
|
# We need to unpatch for our tests not to break
|
|
143
|
-
if show_tokens:
|
|
140
|
+
if show_tokens or local or ctx.invoked_subcommand == "build":
|
|
144
141
|
__unpatch_click_output()
|
|
145
142
|
else:
|
|
146
143
|
__patch_click_output()
|
|
@@ -156,9 +153,7 @@ async def cli(
|
|
|
156
153
|
config_temp.set_token(token)
|
|
157
154
|
if host:
|
|
158
155
|
config_temp.set_host(host)
|
|
159
|
-
if
|
|
160
|
-
config_temp.set_semver(semver)
|
|
161
|
-
if token or host or semver:
|
|
156
|
+
if token or host:
|
|
162
157
|
await try_update_config_with_remote(config_temp, auto_persist=False, raise_on_errors=False)
|
|
163
158
|
|
|
164
159
|
# Overwrite token and host with env vars manually, without resorting to click.
|
|
@@ -170,10 +165,8 @@ async def cli(
|
|
|
170
165
|
token = os.environ.get("TB_TOKEN", "")
|
|
171
166
|
if not host and "TB_HOST" in os.environ:
|
|
172
167
|
host = os.environ.get("TB_HOST", "")
|
|
173
|
-
if not semver and "TB_SEMVER" in os.environ:
|
|
174
|
-
semver = os.environ.get("TB_SEMVER", "")
|
|
175
168
|
|
|
176
|
-
config = await get_config(host, token
|
|
169
|
+
config = await get_config(host, token)
|
|
177
170
|
client = _get_tb_client(config.get("token", None), config["host"])
|
|
178
171
|
|
|
179
172
|
# If they have passed a token or host as paramter and it's different that record in .tinyb, refresh the workspace id
|
|
@@ -232,88 +225,13 @@ async def cli(
|
|
|
232
225
|
logging.debug("debug enabled")
|
|
233
226
|
|
|
234
227
|
ctx.ensure_object(dict)["client"] = (
|
|
235
|
-
await get_tinybird_local_client()
|
|
236
|
-
if local
|
|
237
|
-
else _get_tb_client(config.get("token", None), config["host"], semver)
|
|
228
|
+
await get_tinybird_local_client() if local else _get_tb_client(config.get("token", None), config["host"])
|
|
238
229
|
)
|
|
239
230
|
|
|
240
231
|
for connector in SUPPORTED_CONNECTORS:
|
|
241
232
|
load_connector_config(ctx, connector, debug, check_uninstalled=True)
|
|
242
233
|
|
|
243
234
|
|
|
244
|
-
@cli.command()
|
|
245
|
-
@click.option(
|
|
246
|
-
"--generate-datasources",
|
|
247
|
-
is_flag=True,
|
|
248
|
-
default=False,
|
|
249
|
-
help="Generate datasources based on CSV, NDJSON and Parquet files in this folder",
|
|
250
|
-
)
|
|
251
|
-
@click.option(
|
|
252
|
-
"--folder",
|
|
253
|
-
default=None,
|
|
254
|
-
type=click.Path(exists=True, file_okay=False),
|
|
255
|
-
help="Folder where datafiles will be placed",
|
|
256
|
-
)
|
|
257
|
-
@click.option("-f", "--force", is_flag=True, default=False, help="Overrides existing files")
|
|
258
|
-
@click.option(
|
|
259
|
-
"-ir",
|
|
260
|
-
"--ignore-remote",
|
|
261
|
-
is_flag=True,
|
|
262
|
-
default=False,
|
|
263
|
-
help="Ignores remote files not present in the local data project on git init",
|
|
264
|
-
)
|
|
265
|
-
@click.option(
|
|
266
|
-
"--git",
|
|
267
|
-
is_flag=True,
|
|
268
|
-
default=False,
|
|
269
|
-
help="Init workspace with git releases. Generates CI/CD files for your git provider",
|
|
270
|
-
)
|
|
271
|
-
@click.option(
|
|
272
|
-
"--override-commit",
|
|
273
|
-
default=None,
|
|
274
|
-
help="Use this option to manually override the reference commit of your workspace. This is useful if a commit is not recognized in your git log, such as after a force push (git push -f).",
|
|
275
|
-
)
|
|
276
|
-
@click.option(
|
|
277
|
-
"--cicd", is_flag=True, default=False, help="Generates only CI/CD files for your git provider", hidden=True
|
|
278
|
-
)
|
|
279
|
-
@click.pass_context
|
|
280
|
-
@coro
|
|
281
|
-
async def init(
|
|
282
|
-
ctx: Context,
|
|
283
|
-
generate_datasources: bool,
|
|
284
|
-
folder: Optional[str],
|
|
285
|
-
force: bool,
|
|
286
|
-
ignore_remote: bool,
|
|
287
|
-
git: bool,
|
|
288
|
-
override_commit: Optional[str],
|
|
289
|
-
cicd: Optional[bool],
|
|
290
|
-
) -> None:
|
|
291
|
-
"""Initialize folder layout."""
|
|
292
|
-
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
293
|
-
config = CLIConfig.get_project_config()
|
|
294
|
-
if config.get("token") is None:
|
|
295
|
-
raise AuthNoTokenException
|
|
296
|
-
folder = folder if folder else getcwd()
|
|
297
|
-
|
|
298
|
-
workspaces: List[Dict[str, Any]] = (await client.user_workspaces_and_branches()).get("workspaces", [])
|
|
299
|
-
current_ws: Dict[str, Any] = next(
|
|
300
|
-
(workspace for workspace in workspaces if config and workspace.get("id", ".") == config.get("id", "..")), {}
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
if current_ws.get("is_branch"):
|
|
304
|
-
raise CLIException(FeedbackManager.error_not_allowed_in_branch())
|
|
305
|
-
|
|
306
|
-
await folder_init(client, folder, generate_datasources, generate_releases=True, force=force)
|
|
307
|
-
|
|
308
|
-
error = False
|
|
309
|
-
final_response = None
|
|
310
|
-
|
|
311
|
-
if final_response:
|
|
312
|
-
if error:
|
|
313
|
-
raise CLIException(final_response)
|
|
314
|
-
click.echo(final_response)
|
|
315
|
-
|
|
316
|
-
|
|
317
235
|
@cli.command()
|
|
318
236
|
@click.argument("filenames", type=click.Path(exists=True), nargs=-1, default=None)
|
|
319
237
|
@click.option("--debug", is_flag=True, default=False, help="Print internal representation")
|
|
@@ -1347,9 +1265,6 @@ async def deploy(
|
|
|
1347
1265
|
check_backfill_required = getenv_bool("TB_CHECK_BACKFILL_REQUIRED", True)
|
|
1348
1266
|
try:
|
|
1349
1267
|
tb_client = create_tb_client(ctx)
|
|
1350
|
-
if dry_run:
|
|
1351
|
-
config.set_semver(None)
|
|
1352
|
-
tb_client.semver = None
|
|
1353
1268
|
await folder_push(
|
|
1354
1269
|
tb_client=tb_client,
|
|
1355
1270
|
dry_run=dry_run,
|
tinybird/tb/modules/common.py
CHANGED
|
@@ -218,19 +218,6 @@ async def get_current_environment(client, config):
|
|
|
218
218
|
return next((workspace for workspace in workspaces if workspace["id"] == config["id"]), None)
|
|
219
219
|
|
|
220
220
|
|
|
221
|
-
async def get_current_workspace_branches(config: CLIConfig) -> List[Dict[str, Any]]:
|
|
222
|
-
current_main_workspace: Optional[Dict[str, Any]] = await get_current_main_workspace(config)
|
|
223
|
-
if not current_main_workspace:
|
|
224
|
-
raise CLIException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
225
|
-
|
|
226
|
-
client = config.get_client()
|
|
227
|
-
user_branches: List[Dict[str, Any]] = (await client.user_workspace_branches()).get("workspaces", [])
|
|
228
|
-
all_branches: List[Dict[str, Any]] = (await client.branches()).get("environments", [])
|
|
229
|
-
branches = user_branches + [branch for branch in all_branches if branch not in user_branches]
|
|
230
|
-
|
|
231
|
-
return [branch for branch in branches if branch.get("main") == current_main_workspace["id"]]
|
|
232
|
-
|
|
233
|
-
|
|
234
221
|
class AliasedGroup(click.Group):
|
|
235
222
|
def get_command(self, ctx, cmd_name):
|
|
236
223
|
# Step one: built-in commands as normal
|
|
@@ -320,16 +307,15 @@ def getenv_bool(key: str, default: bool) -> bool:
|
|
|
320
307
|
return v.lower() == "true" or v == "1"
|
|
321
308
|
|
|
322
309
|
|
|
323
|
-
def _get_tb_client(token: str, host: str
|
|
310
|
+
def _get_tb_client(token: str, host: str) -> TinyB:
|
|
324
311
|
disable_ssl: bool = getenv_bool("TB_DISABLE_SSL_CHECKS", False)
|
|
325
|
-
return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True
|
|
312
|
+
return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True)
|
|
326
313
|
|
|
327
314
|
|
|
328
315
|
def create_tb_client(ctx: Context) -> TinyB:
|
|
329
316
|
token = ctx.ensure_object(dict)["config"].get("token", "")
|
|
330
317
|
host = ctx.ensure_object(dict)["config"].get("host", DEFAULT_API_HOST)
|
|
331
|
-
|
|
332
|
-
return _get_tb_client(token, host, semver=semver)
|
|
318
|
+
return _get_tb_client(token, host)
|
|
333
319
|
|
|
334
320
|
|
|
335
321
|
async def _analyze(filename: str, client: TinyB, format: str, connector: Optional["Connector"] = None):
|
|
@@ -776,77 +762,6 @@ async def create_workspace_interactive(
|
|
|
776
762
|
await create_workspace_non_interactive(ctx, workspace_name, starterkit, user_token, fork) # type: ignore
|
|
777
763
|
|
|
778
764
|
|
|
779
|
-
async def create_workspace_branch(
|
|
780
|
-
branch_name: Optional[str],
|
|
781
|
-
last_partition: bool,
|
|
782
|
-
all: bool,
|
|
783
|
-
ignore_datasources: Optional[List[str]],
|
|
784
|
-
wait: Optional[bool],
|
|
785
|
-
) -> None:
|
|
786
|
-
"""
|
|
787
|
-
Creates a workspace branch
|
|
788
|
-
"""
|
|
789
|
-
config = CLIConfig.get_project_config()
|
|
790
|
-
_ = await try_update_config_with_remote(config)
|
|
791
|
-
|
|
792
|
-
try:
|
|
793
|
-
workspace = await get_current_workspace(config)
|
|
794
|
-
if not workspace:
|
|
795
|
-
raise CLIWorkspaceException(FeedbackManager.error_workspace())
|
|
796
|
-
|
|
797
|
-
if not branch_name:
|
|
798
|
-
click.echo(FeedbackManager.info_workspace_branch_create_greeting())
|
|
799
|
-
default_name = f"{workspace['name']}_{uuid.uuid4().hex[0:4]}"
|
|
800
|
-
branch_name = click.prompt("\Branch name", default=default_name, err=True, type=str)
|
|
801
|
-
assert isinstance(branch_name, str)
|
|
802
|
-
|
|
803
|
-
response = await config.get_client().create_workspace_branch(
|
|
804
|
-
branch_name,
|
|
805
|
-
last_partition,
|
|
806
|
-
all,
|
|
807
|
-
ignore_datasources,
|
|
808
|
-
)
|
|
809
|
-
assert isinstance(response, dict)
|
|
810
|
-
|
|
811
|
-
is_job: bool = "job" in response
|
|
812
|
-
is_summary: bool = "partitions" in response
|
|
813
|
-
|
|
814
|
-
if not is_job and not is_summary:
|
|
815
|
-
raise CLIException(str(response))
|
|
816
|
-
|
|
817
|
-
if all and not is_job:
|
|
818
|
-
raise CLIException(str(response))
|
|
819
|
-
|
|
820
|
-
click.echo(
|
|
821
|
-
FeedbackManager.success_workspace_branch_created(workspace_name=workspace["name"], branch_name=branch_name)
|
|
822
|
-
)
|
|
823
|
-
|
|
824
|
-
job_id: Optional[str] = None
|
|
825
|
-
|
|
826
|
-
if is_job:
|
|
827
|
-
job_id = response["job"]["job_id"]
|
|
828
|
-
job_url = response["job"]["job_url"]
|
|
829
|
-
click.echo(FeedbackManager.info_data_branch_job_url(url=job_url))
|
|
830
|
-
|
|
831
|
-
if wait and is_job:
|
|
832
|
-
assert isinstance(job_id, str)
|
|
833
|
-
|
|
834
|
-
# Await the job to finish and get the result dict
|
|
835
|
-
job_response = await wait_job(config.get_client(), job_id, job_url, "Branch creation")
|
|
836
|
-
if job_response is None:
|
|
837
|
-
raise CLIException(f"Empty job API response (job_id: {job_id}, job_url: {job_url})")
|
|
838
|
-
else:
|
|
839
|
-
response = job_response.get("result", {})
|
|
840
|
-
is_summary = "partitions" in response
|
|
841
|
-
|
|
842
|
-
await switch_workspace(config, branch_name, only_environments=True)
|
|
843
|
-
if is_summary and (bool(last_partition) or bool(all)):
|
|
844
|
-
await print_data_branch_summary(config.get_client(), None, response)
|
|
845
|
-
|
|
846
|
-
except Exception as e:
|
|
847
|
-
raise CLIException(FeedbackManager.error_exception(error=str(e)))
|
|
848
|
-
|
|
849
|
-
|
|
850
765
|
async def print_data_branch_summary(client, job_id, response=None):
|
|
851
766
|
response = await client.job(job_id) if job_id else response or {"partitions": []}
|
|
852
767
|
columns = ["Data Source", "Partition", "Status", "Error"]
|
|
@@ -1327,13 +1242,10 @@ def _get_setting_value(connection, setting, sensitive_settings):
|
|
|
1327
1242
|
return connection.get(setting, "")
|
|
1328
1243
|
|
|
1329
1244
|
|
|
1330
|
-
async def switch_workspace(config: CLIConfig, workspace_name_or_id: str
|
|
1245
|
+
async def switch_workspace(config: CLIConfig, workspace_name_or_id: str) -> None:
|
|
1331
1246
|
try:
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
else:
|
|
1335
|
-
response = await config.get_client().user_workspaces()
|
|
1336
|
-
workspaces = response["workspaces"]
|
|
1247
|
+
response = await config.get_client().user_workspaces()
|
|
1248
|
+
workspaces = response["workspaces"]
|
|
1337
1249
|
|
|
1338
1250
|
workspace = next(
|
|
1339
1251
|
(
|
|
@@ -1345,10 +1257,7 @@ async def switch_workspace(config: CLIConfig, workspace_name_or_id: str, only_en
|
|
|
1345
1257
|
)
|
|
1346
1258
|
|
|
1347
1259
|
if not workspace:
|
|
1348
|
-
|
|
1349
|
-
raise CLIException(FeedbackManager.error_branch(branch=workspace_name_or_id))
|
|
1350
|
-
else:
|
|
1351
|
-
raise CLIException(FeedbackManager.error_workspace(workspace=workspace_name_or_id))
|
|
1260
|
+
raise CLIException(FeedbackManager.error_workspace(workspace=workspace_name_or_id))
|
|
1352
1261
|
|
|
1353
1262
|
config.set_token(workspace["token"])
|
|
1354
1263
|
config.set_token_for_host(workspace["token"], config.get_host())
|
tinybird/tb/modules/config.py
CHANGED
|
@@ -72,7 +72,6 @@ class CLIConfig:
|
|
|
72
72
|
"token": "TB_TOKEN",
|
|
73
73
|
"user_token": "TB_USER_TOKEN",
|
|
74
74
|
"host": "TB_HOST",
|
|
75
|
-
"semver": "TB_SEMVER",
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
DEFAULTS: Dict[str, str] = {"host": DEFAULT_API_HOST if not FeatureFlags.is_localhost() else DEFAULT_LOCALHOST}
|
|
@@ -178,15 +177,6 @@ class CLIConfig:
|
|
|
178
177
|
except KeyError:
|
|
179
178
|
return None
|
|
180
179
|
|
|
181
|
-
def set_semver(self, semver: Optional[str]) -> None:
|
|
182
|
-
self["semver"] = semver
|
|
183
|
-
|
|
184
|
-
def get_semver(self) -> Optional[str]:
|
|
185
|
-
try:
|
|
186
|
-
return self["semver"]
|
|
187
|
-
except KeyError:
|
|
188
|
-
return None
|
|
189
|
-
|
|
190
180
|
def set_token_for_host(self, token: Optional[str], host: Optional[str]) -> None:
|
|
191
181
|
"""Sets the token for the specified host.
|
|
192
182
|
|