steve-cli 0.3.13__tar.gz → 0.3.14__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.
- {steve_cli-0.3.13 → steve_cli-0.3.14}/PKG-INFO +1 -1
- {steve_cli-0.3.13 → steve_cli-0.3.14}/pyproject.toml +1 -1
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/cli.py +143 -4
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/PKG-INFO +1 -1
- {steve_cli-0.3.13 → steve_cli-0.3.14}/README.md +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/setup.cfg +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/decorators/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/decorators/lineage_job.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/adapters/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/adapters/logging.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/adapters/null.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/adapters/openlineage.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/collector.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/port.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/registry.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/lineage/storage.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/csv.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/excel.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/generic.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/json.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/extractors/parquet.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/port.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/metadata/registry.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/parquet.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/protocol.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage/s3.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/storage.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/adapters/__init__.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/adapters/great_expectations.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/adapters/null.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/adapters/validoopsie.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/port.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli/validation/registry.py +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/SOURCES.txt +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/dependency_links.txt +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/entry_points.txt +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/requires.txt +0 -0
- {steve_cli-0.3.13 → steve_cli-0.3.14}/steve_cli.egg-info/top_level.txt +0 -0
|
@@ -300,6 +300,34 @@ def apps(ctx: click.Context, apps_file: Optional[Path]):
|
|
|
300
300
|
ctx.invoke(apps_start, app_name=choice, apps_file=apps_file)
|
|
301
301
|
|
|
302
302
|
|
|
303
|
+
@apps.command('status')
|
|
304
|
+
@click.argument('app_name', required=False, default=None)
|
|
305
|
+
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
306
|
+
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
307
|
+
def apps_status(app_name: Optional[str], apps_file: Optional[Path]):
|
|
308
|
+
"""Show status of one or all apps."""
|
|
309
|
+
config = AppsConfig(apps_file)
|
|
310
|
+
if not config.apps:
|
|
311
|
+
click.echo("❌ No apps found in apps.yaml")
|
|
312
|
+
return
|
|
313
|
+
apps_to_show = [a for a in config.apps if a.get('name') == app_name] if app_name else config.apps
|
|
314
|
+
if not apps_to_show:
|
|
315
|
+
click.echo(f"❌ App '{app_name}' not found", err=True)
|
|
316
|
+
sys.exit(1)
|
|
317
|
+
for app_data in apps_to_show:
|
|
318
|
+
name = app_data.get('name', 'unnamed')
|
|
319
|
+
port = app_data.get('port', '?')
|
|
320
|
+
pid = _get_running_pid(name)
|
|
321
|
+
if pid:
|
|
322
|
+
uf = _url_file(name)
|
|
323
|
+
url = uf.read_text().strip() if uf.exists() else f'http://localhost:{port}'
|
|
324
|
+
status = click.style('● running', fg='green')
|
|
325
|
+
click.echo(f" {click.style(name, fg='blue', bold=True)} {status} {click.style(url, fg='cyan')} (PID {pid})")
|
|
326
|
+
else:
|
|
327
|
+
status = click.style('○ stopped', fg='yellow')
|
|
328
|
+
click.echo(f" {click.style(name, fg='blue', bold=True)} {status}")
|
|
329
|
+
|
|
330
|
+
|
|
303
331
|
@apps.command('ls')
|
|
304
332
|
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
305
333
|
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
@@ -335,12 +363,31 @@ def apps_list(apps_file: Optional[Path]):
|
|
|
335
363
|
|
|
336
364
|
|
|
337
365
|
@apps.command('start')
|
|
338
|
-
@click.argument('app_name')
|
|
366
|
+
@click.argument('app_name', required=False, default=None)
|
|
339
367
|
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
340
368
|
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
341
|
-
def apps_start(app_name: str, apps_file: Optional[Path]):
|
|
369
|
+
def apps_start(app_name: Optional[str], apps_file: Optional[Path]):
|
|
342
370
|
"""Start an app by name and register it with the auth-proxy."""
|
|
343
371
|
config = AppsConfig(apps_file)
|
|
372
|
+
if app_name is None:
|
|
373
|
+
all_names = config.list_apps()
|
|
374
|
+
if not all_names:
|
|
375
|
+
click.echo("❌ No apps found in apps.yaml")
|
|
376
|
+
sys.exit(1)
|
|
377
|
+
choices = [
|
|
378
|
+
questionary.Choice(title=n, value=n, disabled="running")
|
|
379
|
+
if _get_running_pid(n) else questionary.Choice(title=n, value=n)
|
|
380
|
+
for n in all_names
|
|
381
|
+
]
|
|
382
|
+
if all(c.disabled for c in choices):
|
|
383
|
+
click.echo("⚠️ All apps are already running")
|
|
384
|
+
return
|
|
385
|
+
app_name = questionary.select(
|
|
386
|
+
"Select an app to start:",
|
|
387
|
+
choices=choices,
|
|
388
|
+
).ask()
|
|
389
|
+
if app_name is None:
|
|
390
|
+
sys.exit(0)
|
|
344
391
|
app_def = config.get_app(app_name)
|
|
345
392
|
if not app_def:
|
|
346
393
|
available = config.list_apps()
|
|
@@ -426,13 +473,34 @@ def apps_start(app_name: str, apps_file: Optional[Path]):
|
|
|
426
473
|
|
|
427
474
|
|
|
428
475
|
@apps.command('stop')
|
|
429
|
-
@click.argument('app_name')
|
|
476
|
+
@click.argument('app_name', required=False, default=None)
|
|
430
477
|
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
431
478
|
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
432
|
-
def apps_stop(app_name: str, apps_file: Optional[Path]):
|
|
479
|
+
def apps_stop(app_name: Optional[str], apps_file: Optional[Path]):
|
|
433
480
|
"""Stop a running app and deregister it from the auth-proxy."""
|
|
434
481
|
session_name = _get_session_name()
|
|
435
482
|
|
|
483
|
+
if app_name is None:
|
|
484
|
+
config = AppsConfig(apps_file)
|
|
485
|
+
all_names = config.list_apps()
|
|
486
|
+
if not all_names:
|
|
487
|
+
click.echo("❌ No apps found in apps.yaml")
|
|
488
|
+
sys.exit(1)
|
|
489
|
+
choices = [
|
|
490
|
+
questionary.Choice(title=n, value=n)
|
|
491
|
+
if _get_running_pid(n) else questionary.Choice(title=n, value=n, disabled="stopped")
|
|
492
|
+
for n in all_names
|
|
493
|
+
]
|
|
494
|
+
if all(c.disabled for c in choices):
|
|
495
|
+
click.echo("⚠️ No apps are running")
|
|
496
|
+
return
|
|
497
|
+
app_name = questionary.select(
|
|
498
|
+
"Select an app to stop:",
|
|
499
|
+
choices=choices,
|
|
500
|
+
).ask()
|
|
501
|
+
if app_name is None:
|
|
502
|
+
sys.exit(0)
|
|
503
|
+
|
|
436
504
|
pid = _get_running_pid(app_name)
|
|
437
505
|
if not pid:
|
|
438
506
|
click.echo(f"⚠️ App '{app_name}' is not running")
|
|
@@ -452,6 +520,77 @@ def apps_stop(app_name: str, apps_file: Optional[Path]):
|
|
|
452
520
|
click.echo(f"🔌 Deregistered from auth-proxy")
|
|
453
521
|
|
|
454
522
|
|
|
523
|
+
@apps.command('restart')
|
|
524
|
+
@click.argument('app_name', required=False, default=None)
|
|
525
|
+
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
526
|
+
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
527
|
+
@click.pass_context
|
|
528
|
+
def apps_restart(ctx: click.Context, app_name: Optional[str], apps_file: Optional[Path]):
|
|
529
|
+
"""Restart a running app."""
|
|
530
|
+
if app_name is None:
|
|
531
|
+
config = AppsConfig(apps_file)
|
|
532
|
+
all_names = config.list_apps()
|
|
533
|
+
if not all_names:
|
|
534
|
+
click.echo("❌ No apps found in apps.yaml")
|
|
535
|
+
sys.exit(1)
|
|
536
|
+
choices = [
|
|
537
|
+
questionary.Choice(title=n, value=n)
|
|
538
|
+
if _get_running_pid(n) else questionary.Choice(title=n, value=n, disabled="stopped")
|
|
539
|
+
for n in all_names
|
|
540
|
+
]
|
|
541
|
+
if all(c.disabled for c in choices):
|
|
542
|
+
click.echo("⚠️ No apps are running")
|
|
543
|
+
return
|
|
544
|
+
app_name = questionary.select(
|
|
545
|
+
"Select an app to restart:",
|
|
546
|
+
choices=choices,
|
|
547
|
+
).ask()
|
|
548
|
+
if app_name is None:
|
|
549
|
+
sys.exit(0)
|
|
550
|
+
ctx.invoke(apps_stop, app_name=app_name, apps_file=apps_file)
|
|
551
|
+
ctx.invoke(apps_start, app_name=app_name, apps_file=apps_file)
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
@apps.command('logs')
|
|
555
|
+
@click.argument('app_name', required=False, default=None)
|
|
556
|
+
@click.option('--apps-file', '-f', type=click.Path(exists=True, path_type=Path),
|
|
557
|
+
help='Path to apps.yaml file (default: ./apps.yaml)')
|
|
558
|
+
@click.option('--lines', '-n', default=50, show_default=True, help='Number of lines to show initially')
|
|
559
|
+
def apps_logs(app_name: Optional[str], apps_file: Optional[Path], lines: int):
|
|
560
|
+
"""Tail the log file for an app."""
|
|
561
|
+
if app_name is None:
|
|
562
|
+
config = AppsConfig(apps_file)
|
|
563
|
+
all_names = config.list_apps()
|
|
564
|
+
if not all_names:
|
|
565
|
+
click.echo("❌ No apps found in apps.yaml")
|
|
566
|
+
sys.exit(1)
|
|
567
|
+
choices = [
|
|
568
|
+
questionary.Choice(title=n, value=n)
|
|
569
|
+
if (APPS_DIR / f"{n}.log").exists() else questionary.Choice(title=n, value=n, disabled="no logs")
|
|
570
|
+
for n in all_names
|
|
571
|
+
]
|
|
572
|
+
if all(c.disabled for c in choices):
|
|
573
|
+
click.echo("⚠️ No log files found")
|
|
574
|
+
return
|
|
575
|
+
app_name = questionary.select(
|
|
576
|
+
"Select an app to view logs:",
|
|
577
|
+
choices=choices,
|
|
578
|
+
).ask()
|
|
579
|
+
if app_name is None:
|
|
580
|
+
sys.exit(0)
|
|
581
|
+
|
|
582
|
+
log_file = APPS_DIR / f"{app_name}.log"
|
|
583
|
+
if not log_file.exists():
|
|
584
|
+
click.echo(f"❌ No log file found for '{app_name}' at {log_file}", err=True)
|
|
585
|
+
sys.exit(1)
|
|
586
|
+
|
|
587
|
+
click.echo(f"📄 Logs for {click.style(app_name, fg='blue', bold=True)} ({log_file}):\n")
|
|
588
|
+
try:
|
|
589
|
+
subprocess.call(["tail", f"-n{lines}", "-f", str(log_file)])
|
|
590
|
+
except KeyboardInterrupt:
|
|
591
|
+
pass
|
|
592
|
+
|
|
593
|
+
|
|
455
594
|
SETUP_IGNORE = [".env.example", ".env.template"]
|
|
456
595
|
|
|
457
596
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|