Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions nextmv/nextmv/cli/local/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
This module defines the local command tree for the Nextmv CLI.
"""

import typer

from nextmv.cli.local.app import app as app_app
from nextmv.cli.local.run import app as run_app

# Set up subcommand application.
app = typer.Typer()
app.add_typer(app_app, name="app")
app.add_typer(run_app, name="run")


@app.callback()
def callback() -> None:
"""
Interact with local Nextmv apps and make runs.
"""
pass
31 changes: 31 additions & 0 deletions nextmv/nextmv/cli/local/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
This module defines the local app command tree for the Nextmv CLI.
"""

import typer

from nextmv.cli.local.app.delete import app as delete_app
from nextmv.cli.local.app.exists import app as exists_app
from nextmv.cli.local.app.get import app as get_app
from nextmv.cli.local.app.list import app as list_app
from nextmv.cli.local.app.sync import app as sync_app

# Set up subcommand application.
app = typer.Typer()
app.add_typer(delete_app)
app.add_typer(exists_app)
app.add_typer(get_app)
app.add_typer(list_app)
app.add_typer(sync_app)


@app.callback()
def callback() -> None:
"""
Manage and sync local Nextmv applications.

A Nextmv application is an entity that contains a decision model as
executable code. An application can make a run by taking an input,
executing the decision model, and producing an output.
"""
pass
71 changes: 71 additions & 0 deletions nextmv/nextmv/cli/local/app/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
This module defines the local app delete command for the Nextmv CLI.
"""

from typing import Annotated

import typer

from nextmv.cli.confirm import get_confirmation
from nextmv.cli.message import info, success
from nextmv.cli.options import AppIDOption, ProfileOption
from nextmv.local.application import Application
from nextmv.local.registry import read_local_registry

# Set up subcommand application.
app = typer.Typer()


@app.command()
def delete(
app_id: AppIDOption,
yes: Annotated[
bool,
typer.Option(
"--yes",
"-y",
help="Agree to deletion confirmation prompt. Useful for non-interactive sessions.",
),
] = False,
profile: ProfileOption = None,
) -> None:
"""
Deletes a local Nextmv application.

This action is permanent and cannot be undone. Use the --yes
flag to skip the confirmation prompt.

[bold][underline]Examples[/underline][/bold]

- Delete the application with the ID [magenta]hare-app[/magenta].
$ [dim]nextmv local app delete --app-id hare-app[/dim]

- Delete the application with the ID [magenta]hare-app[/magenta] without confirmation prompt.
$ [dim]nextmv local app delete --app-id hare-app --yes[/dim]
"""

if not yes:
confirm = get_confirmation(
f"Are you sure you want to delete application [magenta]{app_id}[/magenta]? This action cannot be undone.",
)

if not confirm:
info(msg=f"Application [magenta]{app_id}[/magenta] will not be deleted.", emoji=":bulb:")
return

# Find app in registry.
registry = read_local_registry()
app_entry = next((app for app in registry.apps if app.app_id == app_id), None)
if app_entry is None:
typer.echo(f"Application with ID '{app_id}' not found.")
raise typer.Exit(code=1)
app = Application(src=app_entry.path)

# Make sure the app exists before attempting to delete.
if not app.exists():
typer.echo(f"Application with ID '{app_id}' not found at path '{app_entry.path}'.")
raise typer.Exit(code=1)

# Delete the app.
app.delete()
success(f"Application [magenta]{app_id}[/magenta] deleted successfully.")
35 changes: 35 additions & 0 deletions nextmv/nextmv/cli/local/app/exists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
This module defines the cloud app exists command for the Nextmv CLI.
"""

import typer

from nextmv.cli.message import in_progress, print_json
from nextmv.cli.options import AppIDOption
from nextmv.local.registry import read_local_registry

# Set up subcommand application.
app = typer.Typer()


@app.command()
def exists(
app_id: AppIDOption,
) -> None:
"""
Check if a local Nextmv application exists.

This command is useful in scripting applications to verify the existence of
a local application by its ID.

[bold][underline]Examples[/underline][/bold]

- Check if the application with the ID [magenta]hare-app[/magenta] exists.
$ [dim]nextmv local app exists --app-id hare-app[/dim]
"""

registry = read_local_registry()
in_progress(msg="Checking if application exists...")

ok = any(app.app_id == app_id for app in registry.apps)
print_json({"exists": ok})
68 changes: 68 additions & 0 deletions nextmv/nextmv/cli/local/app/get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
This module defines the cloud app get command for the Nextmv CLI.
"""

import json
import os
from typing import Annotated

import typer

from nextmv.cli.message import in_progress, print_json, success, warning
from nextmv.cli.options import AppIDOption
from nextmv.local.registry import read_local_registry

# Set up subcommand application.
app = typer.Typer()


@app.command()
def get(
app_id: AppIDOption,
output: Annotated[
str | None,
typer.Option(
"--output",
"-o",
help="Saves the app information to this location.",
metavar="OUTPUT_PATH",
),
] = None,
) -> None:
"""
Get a local Nextmv application.

This command is useful to get the attributes of an existing local Nextmv
application by its ID.

[bold][underline]Examples[/underline][/bold]

- Get the application with the ID [magenta]hare-app[/magenta].
$ [dim]nextmv local app get --app-id hare-app[/dim]

- Get the application with the ID [magenta]hare-app[/magenta] and save the information to an
[magenta]app.json[/magenta] file.
$ [dim]nextmv local app get --app-id hare-app --output app.json[/dim]
"""

registry = read_local_registry()
in_progress(msg="Getting application...")

app_entry = next((app for app in registry.apps if app.app_id == app_id), None)

if app_entry is None:
typer.echo(f"Application with ID '{app_id}' not found.")
raise typer.Exit(code=1)
elif not os.path.exists(app_entry.path):
warning(f"Application with ID '{app_id}' found in registry but path does not exist.")

app_dict = app_entry.to_dict()

if output is not None and output != "":
with open(output, "w") as f:
json.dump(app_dict, f, indent=2)
success(msg=f"Application information saved to [magenta]{output}[/magenta].")

return

print_json(app_dict)
52 changes: 52 additions & 0 deletions nextmv/nextmv/cli/local/app/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
This module defines the cloud app list command for the Nextmv CLI.
"""

import json
from typing import Annotated

import typer

from nextmv.cli.message import print_json, success
from nextmv.local.registry import read_local_registry

# Set up subcommand application.
app = typer.Typer()


@app.command()
def list(
output: Annotated[
str | None,
typer.Option(
"--output",
"-o",
help="Saves the app list information to this location.",
metavar="OUTPUT_PATH",
),
] = None,
) -> None:
"""
List all local Nextmv applications.

[bold][underline]Examples[/underline][/bold]

- List all applications.
$ [dim]nextmv local app list[/dim]

- List all applications and save the information to an [magenta]apps.json[/magenta] file.
$ [dim]nextmv local app list --output apps.json[/dim]
"""

registry = read_local_registry()
apps_dicts = [app.to_dict() for app in registry.apps]

if output is not None and output != "":
with open(output, "w") as f:
json.dump(apps_dicts, f, indent=2)

success(msg=f"Application list information saved to [magenta]{output}[/magenta].")

return

print_json(apps_dicts)
40 changes: 40 additions & 0 deletions nextmv/nextmv/cli/local/app/sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
This module defines the cloud app push command for the Nextmv CLI.
"""

from typing import Annotated

import typer

from nextmv.cli.options import ProfileOption

# Set up subcommand application.
app = typer.Typer()


@app.command()
def sync(
output: Annotated[
str | None,
typer.Option(
"--output",
"-o",
help="Saves the app list information to this location.",
metavar="OUTPUT_PATH",
),
] = None,
profile: ProfileOption = None,
) -> None:
"""
Sync local Nextmv applications to the Nextmv Cloud.

[bold][underline]Examples[/underline][/bold]

- Sync local applications to the Nextmv Cloud.
$ [dim]nextmv local app sync[/dim]

- Sync local applications using the profile named [magenta]hare[/magenta].
$ [dim]nextmv local app sync --profile hare[/dim]
"""

# TODO: replace copied code with actual logic / connect to actual logic
37 changes: 37 additions & 0 deletions nextmv/nextmv/cli/local/run/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
This module defines the local run command tree for the Nextmv CLI.
"""

import typer

from nextmv.cli.local.run.cancel import app as cancel_app
from nextmv.cli.local.run.create import app as create_app
from nextmv.cli.local.run.get import app as get_app
from nextmv.cli.local.run.input import app as input_app
from nextmv.cli.local.run.list import app as list_app
from nextmv.cli.local.run.logs import app as logs_app
from nextmv.cli.local.run.metadata import app as metadata_app
from nextmv.cli.local.run.visuals import app as visuals_app

# Set up subcommand application.
app = typer.Typer()
app.add_typer(cancel_app)
app.add_typer(create_app)
app.add_typer(get_app)
app.add_typer(input_app)
app.add_typer(list_app)
app.add_typer(logs_app)
app.add_typer(metadata_app)
app.add_typer(visuals_app)


@app.callback()
def callback() -> None:
"""
Create and manage Nextmv Local application runs.

A run represents the execution of a decision model within a Nextmv Local
application. Each run takes an input, processes it using the decision model,
and produces an output.
"""
pass
31 changes: 31 additions & 0 deletions nextmv/nextmv/cli/local/run/cancel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
This module defines the local run cancel command for the Nextmv CLI.
"""

import typer

from nextmv.cli.options import AppIDOption, RunIDOption

# Set up subcommand application.
app = typer.Typer()


@app.command()
def cancel(
app_id: AppIDOption,
run_id: RunIDOption,
) -> None:
"""
Cancel a queued/running Nextmv Local application run.

[bold][underline]Examples[/underline][/bold]

- Cancel the run with ID [magenta]burrow-123[/magenta] belonging to an app with ID [magenta]hare-app[/magenta].
$ [dim]nextmv local run cancel --app-id hare-app --run-id burrow-123[/dim]

- Cancel the run with ID [magenta]burrow-123[/magenta] belonging to an app with ID [magenta]hare-app[/magenta].
Use the profile named [magenta]hare[/magenta].
$ [dim]nextmv local run cancel --app-id hare-app --run-id burrow-123 --profile hare[/dim]
"""

# TODO: replace copied code with actual logic / connect to actual logic
Loading