nextmv 1.0.0.dev2__py3-none-any.whl → 1.0.0.dev4__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.
- nextmv/__about__.py +1 -1
- nextmv/cli/CONTRIBUTING.md +81 -29
- nextmv/cli/cloud/__init__.py +2 -0
- nextmv/cli/cloud/acceptance/create.py +20 -22
- nextmv/cli/cloud/acceptance/delete.py +7 -8
- nextmv/cli/cloud/acceptance/get.py +9 -10
- nextmv/cli/cloud/acceptance/list.py +3 -3
- nextmv/cli/cloud/acceptance/update.py +6 -6
- nextmv/cli/cloud/account/__init__.py +3 -3
- nextmv/cli/cloud/account/create.py +11 -11
- nextmv/cli/cloud/account/delete.py +6 -7
- nextmv/cli/cloud/account/get.py +3 -3
- nextmv/cli/cloud/account/update.py +5 -5
- nextmv/cli/cloud/app/create.py +25 -26
- nextmv/cli/cloud/app/delete.py +5 -6
- nextmv/cli/cloud/app/exists.py +2 -2
- nextmv/cli/cloud/app/get.py +2 -2
- nextmv/cli/cloud/app/list.py +3 -3
- nextmv/cli/cloud/app/push.py +269 -45
- nextmv/cli/cloud/app/update.py +12 -12
- nextmv/cli/cloud/batch/create.py +26 -28
- nextmv/cli/cloud/batch/delete.py +5 -6
- nextmv/cli/cloud/batch/get.py +8 -8
- nextmv/cli/cloud/batch/list.py +3 -3
- nextmv/cli/cloud/batch/metadata.py +4 -4
- nextmv/cli/cloud/batch/update.py +6 -6
- nextmv/cli/cloud/data/__init__.py +1 -1
- nextmv/cli/cloud/data/upload.py +15 -15
- nextmv/cli/cloud/ensemble/__init__.py +2 -0
- nextmv/cli/cloud/ensemble/create.py +21 -22
- nextmv/cli/cloud/ensemble/delete.py +5 -6
- nextmv/cli/cloud/ensemble/get.py +4 -4
- nextmv/cli/cloud/ensemble/list.py +63 -0
- nextmv/cli/cloud/ensemble/update.py +9 -9
- nextmv/cli/cloud/input_set/create.py +20 -22
- nextmv/cli/cloud/input_set/get.py +3 -3
- nextmv/cli/cloud/input_set/list.py +3 -3
- nextmv/cli/cloud/input_set/update.py +24 -24
- nextmv/cli/cloud/instance/create.py +14 -15
- nextmv/cli/cloud/instance/delete.py +5 -6
- nextmv/cli/cloud/instance/exists.py +2 -2
- nextmv/cli/cloud/instance/get.py +2 -2
- nextmv/cli/cloud/instance/list.py +3 -3
- nextmv/cli/cloud/instance/update.py +14 -14
- nextmv/cli/cloud/managed_input/create.py +14 -16
- nextmv/cli/cloud/managed_input/delete.py +6 -7
- nextmv/cli/cloud/managed_input/get.py +3 -3
- nextmv/cli/cloud/managed_input/list.py +3 -3
- nextmv/cli/cloud/managed_input/update.py +9 -9
- nextmv/cli/cloud/run/cancel.py +2 -2
- nextmv/cli/cloud/run/create.py +32 -33
- nextmv/cli/cloud/run/get.py +8 -8
- nextmv/cli/cloud/run/input.py +4 -4
- nextmv/cli/cloud/run/list.py +6 -6
- nextmv/cli/cloud/run/logs.py +9 -10
- nextmv/cli/cloud/run/metadata.py +4 -4
- nextmv/cli/cloud/run/track.py +32 -33
- nextmv/cli/cloud/scenario/create.py +21 -21
- nextmv/cli/cloud/scenario/delete.py +5 -6
- nextmv/cli/cloud/scenario/get.py +8 -8
- nextmv/cli/cloud/scenario/list.py +3 -3
- nextmv/cli/cloud/scenario/metadata.py +4 -4
- nextmv/cli/cloud/scenario/update.py +6 -6
- nextmv/cli/cloud/secrets/create.py +17 -17
- nextmv/cli/cloud/secrets/delete.py +5 -6
- nextmv/cli/cloud/secrets/get.py +4 -4
- nextmv/cli/cloud/secrets/list.py +3 -3
- nextmv/cli/cloud/secrets/update.py +17 -20
- nextmv/cli/cloud/shadow/__init__.py +1 -1
- nextmv/cli/cloud/shadow/create.py +32 -32
- nextmv/cli/cloud/shadow/delete.py +5 -6
- nextmv/cli/cloud/shadow/get.py +2 -2
- nextmv/cli/cloud/shadow/list.py +3 -3
- nextmv/cli/cloud/shadow/metadata.py +4 -4
- nextmv/cli/cloud/shadow/start.py +3 -3
- nextmv/cli/cloud/shadow/stop.py +8 -10
- nextmv/cli/cloud/shadow/update.py +7 -6
- nextmv/cli/cloud/switchback/__init__.py +33 -0
- nextmv/cli/cloud/switchback/create.py +151 -0
- nextmv/cli/cloud/switchback/delete.py +67 -0
- nextmv/cli/cloud/switchback/get.py +62 -0
- nextmv/cli/cloud/switchback/list.py +63 -0
- nextmv/cli/cloud/switchback/metadata.py +68 -0
- nextmv/cli/cloud/switchback/start.py +43 -0
- nextmv/cli/cloud/switchback/stop.py +41 -0
- nextmv/cli/cloud/switchback/update.py +96 -0
- nextmv/cli/cloud/upload/create.py +2 -2
- nextmv/cli/cloud/version/create.py +9 -10
- nextmv/cli/cloud/version/delete.py +5 -6
- nextmv/cli/cloud/version/exists.py +2 -2
- nextmv/cli/cloud/version/get.py +2 -2
- nextmv/cli/cloud/version/list.py +3 -3
- nextmv/cli/cloud/version/update.py +8 -8
- nextmv/cli/community/clone.py +12 -10
- nextmv/cli/community/list.py +9 -9
- nextmv/cli/configuration/config.py +43 -10
- nextmv/cli/configuration/create.py +3 -3
- nextmv/cli/configuration/delete.py +7 -7
- nextmv/cli/configuration/list.py +3 -3
- nextmv/cli/confirm.py +32 -0
- nextmv/cli/main.py +27 -36
- nextmv/cli/message.py +2 -2
- nextmv/cli/options.py +14 -0
- nextmv/cli/version.py +1 -1
- nextmv/cloud/__init__.py +5 -0
- nextmv/cloud/application/__init__.py +192 -54
- nextmv/cloud/application/_batch_scenario.py +2 -2
- nextmv/cloud/application/_instance.py +2 -2
- nextmv/cloud/application/_managed_input.py +1 -1
- nextmv/cloud/application/_shadow.py +1 -1
- nextmv/cloud/application/_switchback.py +323 -0
- nextmv/cloud/application/_version.py +3 -2
- nextmv/cloud/shadow.py +43 -4
- nextmv/cloud/switchback.py +226 -0
- {nextmv-1.0.0.dev2.dist-info → nextmv-1.0.0.dev4.dist-info}/METADATA +1 -1
- nextmv-1.0.0.dev4.dist-info/RECORD +183 -0
- nextmv-1.0.0.dev2.dist-info/RECORD +0 -170
- {nextmv-1.0.0.dev2.dist-info → nextmv-1.0.0.dev4.dist-info}/WHEEL +0 -0
- {nextmv-1.0.0.dev2.dist-info → nextmv-1.0.0.dev4.dist-info}/entry_points.txt +0 -0
- {nextmv-1.0.0.dev2.dist-info → nextmv-1.0.0.dev4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines the cloud switchback update command for the Nextmv CLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from nextmv.cli.configuration.config import build_app
|
|
11
|
+
from nextmv.cli.message import in_progress, print_json, success
|
|
12
|
+
from nextmv.cli.options import AppIDOption, ProfileOption, SwitchbackTestIDOption
|
|
13
|
+
|
|
14
|
+
# Set up subcommand application.
|
|
15
|
+
app = typer.Typer()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command()
|
|
19
|
+
def update(
|
|
20
|
+
app_id: AppIDOption,
|
|
21
|
+
switchback_test_id: SwitchbackTestIDOption,
|
|
22
|
+
description: Annotated[
|
|
23
|
+
str | None,
|
|
24
|
+
typer.Option(
|
|
25
|
+
"--description",
|
|
26
|
+
"-d",
|
|
27
|
+
help="Updated description of the switchback test.",
|
|
28
|
+
metavar="DESCRIPTION",
|
|
29
|
+
),
|
|
30
|
+
] = None,
|
|
31
|
+
name: Annotated[
|
|
32
|
+
str | None,
|
|
33
|
+
typer.Option(
|
|
34
|
+
"--name",
|
|
35
|
+
"-n",
|
|
36
|
+
help="Updated name of the switchback test.",
|
|
37
|
+
metavar="NAME",
|
|
38
|
+
),
|
|
39
|
+
] = None,
|
|
40
|
+
output: Annotated[
|
|
41
|
+
str | None,
|
|
42
|
+
typer.Option(
|
|
43
|
+
"--output",
|
|
44
|
+
"-o",
|
|
45
|
+
help="Saves the updated switchback test information to this location.",
|
|
46
|
+
metavar="OUTPUT_PATH",
|
|
47
|
+
),
|
|
48
|
+
] = None,
|
|
49
|
+
profile: ProfileOption = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Update a Nextmv Cloud switchback test.
|
|
53
|
+
|
|
54
|
+
Update the name and/or description of a switchback test. Any fields not
|
|
55
|
+
specified will remain unchanged.
|
|
56
|
+
|
|
57
|
+
[bold][underline]Examples[/underline][/bold]
|
|
58
|
+
|
|
59
|
+
- Update the name of a switchback test.
|
|
60
|
+
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id carrot-feast \\
|
|
61
|
+
--name "Spring Carrot Harvest"[/dim]
|
|
62
|
+
|
|
63
|
+
- Update the description of a switchback test.
|
|
64
|
+
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id bunny-hop-routes \\
|
|
65
|
+
--description "Optimizing hop paths through the meadow"[/dim]
|
|
66
|
+
|
|
67
|
+
- Update both name and description and save the result.
|
|
68
|
+
$ [dim]nextmv cloud switchback update --app-id hare-app --switchback-test-id lettuce-delivery \\
|
|
69
|
+
--name "Warren Lettuce Express" --description "Fast lettuce delivery to all burrows" \\
|
|
70
|
+
--output updated-switchback-test.json[/dim]
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
74
|
+
|
|
75
|
+
in_progress(msg="Updating switchback test...")
|
|
76
|
+
switchback_test = cloud_app.update_switchback_test(
|
|
77
|
+
switchback_test_id=switchback_test_id,
|
|
78
|
+
name=name,
|
|
79
|
+
description=description,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
switchback_test_dict = switchback_test.to_dict()
|
|
83
|
+
success(
|
|
84
|
+
f"Switchback test [magenta]{switchback_test_id}[/magenta] updated successfully "
|
|
85
|
+
f"in application [magenta]{app_id}[/magenta]."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if output is not None and output != "":
|
|
89
|
+
with open(output, "w") as f:
|
|
90
|
+
json.dump(switchback_test_dict, f, indent=2)
|
|
91
|
+
|
|
92
|
+
success(msg=f"Updated switchback test information saved to [magenta]{output}[/magenta].")
|
|
93
|
+
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
print_json(switchback_test_dict)
|
|
@@ -23,10 +23,10 @@ def create(
|
|
|
23
23
|
[bold][underline]Examples[/underline][/bold]
|
|
24
24
|
|
|
25
25
|
- Create an upload URL for application [magenta]hare-app[/magenta].
|
|
26
|
-
$ [
|
|
26
|
+
$ [dim]nextmv cloud upload create --app-id hare-app[/dim]
|
|
27
27
|
|
|
28
28
|
- Create an upload URL for application [magenta]hare-app[/magenta] using profile [magenta]hare[/magenta].
|
|
29
|
-
$ [
|
|
29
|
+
$ [dim]nextmv cloud upload create --app-id hare-app --profile hare[/dim]
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
@@ -58,28 +58,27 @@ def create(
|
|
|
58
58
|
"""
|
|
59
59
|
Create a new Nextmv Cloud application version.
|
|
60
60
|
|
|
61
|
-
Use the
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
created previously.
|
|
61
|
+
Use the --exist-ok flag to avoid errors when creating a version with an ID
|
|
62
|
+
that already exists. This is useful for scripts that need to ensure a
|
|
63
|
+
version exists without worrying about whether it was created previously.
|
|
65
64
|
|
|
66
65
|
[bold][underline]Examples[/underline][/bold]
|
|
67
66
|
|
|
68
67
|
- Create a version for application [magenta]hare-app[/magenta]. A random ID will be generated.
|
|
69
|
-
$ [
|
|
68
|
+
$ [dim]nextmv cloud version create --app-id hare-app[/dim]
|
|
70
69
|
|
|
71
70
|
- Create a version with a specific name.
|
|
72
|
-
$ [
|
|
71
|
+
$ [dim]nextmv cloud version create --app-id hare-app --name "v1.0.0"[/dim]
|
|
73
72
|
|
|
74
73
|
- Create a version with a specific ID.
|
|
75
|
-
$ [
|
|
74
|
+
$ [dim]nextmv cloud version create --app-id hare-app --version-id v1[/dim]
|
|
76
75
|
|
|
77
76
|
- Create a version with a name and description.
|
|
78
|
-
$ [
|
|
79
|
-
--description "Initial release with routing optimization"[/
|
|
77
|
+
$ [dim]nextmv cloud version create --app-id hare-app --name "v1.0.0" \\
|
|
78
|
+
--description "Initial release with routing optimization"[/dim]
|
|
80
79
|
|
|
81
80
|
- Create a version, or get it if it already exists.
|
|
82
|
-
$ [
|
|
81
|
+
$ [dim]nextmv cloud version create --app-id hare-app --version-id v1 --exist-ok[/dim]
|
|
83
82
|
"""
|
|
84
83
|
|
|
85
84
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
@@ -5,9 +5,9 @@ This module defines the cloud version delete command for the Nextmv CLI.
|
|
|
5
5
|
from typing import Annotated
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from rich.prompt import Confirm
|
|
9
8
|
|
|
10
9
|
from nextmv.cli.configuration.config import build_app
|
|
10
|
+
from nextmv.cli.confirm import get_confirmation
|
|
11
11
|
from nextmv.cli.message import info, success
|
|
12
12
|
from nextmv.cli.options import AppIDOption, ProfileOption, VersionIDOption
|
|
13
13
|
|
|
@@ -32,23 +32,22 @@ def delete(
|
|
|
32
32
|
"""
|
|
33
33
|
Deletes a Nextmv Cloud application version.
|
|
34
34
|
|
|
35
|
-
This action is permanent and cannot be undone. Use the
|
|
35
|
+
This action is permanent and cannot be undone. Use the --yes
|
|
36
36
|
flag to skip the confirmation prompt.
|
|
37
37
|
|
|
38
38
|
[bold][underline]Examples[/underline][/bold]
|
|
39
39
|
|
|
40
40
|
- Delete the version with the ID [magenta]v1[/magenta] from application [magenta]hare-app[/magenta].
|
|
41
|
-
$ [
|
|
41
|
+
$ [dim]nextmv cloud version delete --app-id hare-app --version-id v1[/dim]
|
|
42
42
|
|
|
43
43
|
- Delete the version without confirmation prompt.
|
|
44
|
-
$ [
|
|
44
|
+
$ [dim]nextmv cloud version delete --app-id hare-app --version-id v1 --yes[/dim]
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
if not yes:
|
|
48
|
-
confirm =
|
|
48
|
+
confirm = get_confirmation(
|
|
49
49
|
f"Are you sure you want to delete version [magenta]{version_id}[/magenta] "
|
|
50
50
|
f"from application [magenta]{app_id}[/magenta]? This action cannot be undone.",
|
|
51
|
-
default=False,
|
|
52
51
|
)
|
|
53
52
|
|
|
54
53
|
if not confirm:
|
|
@@ -27,10 +27,10 @@ def exists(
|
|
|
27
27
|
[bold][underline]Examples[/underline][/bold]
|
|
28
28
|
|
|
29
29
|
- Check if the version with the ID [magenta]v1[/magenta] exists in application [magenta]hare-app[/magenta].
|
|
30
|
-
$ [
|
|
30
|
+
$ [dim]nextmv cloud version exists --app-id hare-app --version-id v1[/dim]
|
|
31
31
|
|
|
32
32
|
- Check if the version exists using the profile named [magenta]hare[/magenta].
|
|
33
|
-
$ [
|
|
33
|
+
$ [dim]nextmv cloud version exists --app-id hare-app --version-id v1 --profile hare[/dim]
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
36
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
nextmv/cli/cloud/version/get.py
CHANGED
|
@@ -39,11 +39,11 @@ def get(
|
|
|
39
39
|
[bold][underline]Examples[/underline][/bold]
|
|
40
40
|
|
|
41
41
|
- Get the version with the ID [magenta]v1[/magenta] from application [magenta]hare-app[/magenta].
|
|
42
|
-
$ [
|
|
42
|
+
$ [dim]nextmv cloud version get --app-id hare-app --version-id v1[/dim]
|
|
43
43
|
|
|
44
44
|
- Get the version with the ID [magenta]v1[/magenta] and save the information to a
|
|
45
45
|
[magenta]version.json[/magenta] file.
|
|
46
|
-
$ [
|
|
46
|
+
$ [dim]nextmv cloud version get --app-id hare-app --version-id v1 --output version.json[/dim]
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
nextmv/cli/cloud/version/list.py
CHANGED
|
@@ -35,13 +35,13 @@ def list(
|
|
|
35
35
|
[bold][underline]Examples[/underline][/bold]
|
|
36
36
|
|
|
37
37
|
- List all versions of application [magenta]hare-app[/magenta].
|
|
38
|
-
$ [
|
|
38
|
+
$ [dim]nextmv cloud version list --app-id hare-app[/dim]
|
|
39
39
|
|
|
40
40
|
- List all versions using the profile named [magenta]hare[/magenta].
|
|
41
|
-
$ [
|
|
41
|
+
$ [dim]nextmv cloud version list --app-id hare-app --profile hare[/dim]
|
|
42
42
|
|
|
43
43
|
- List all versions and save the information to a [magenta]versions.json[/magenta] file.
|
|
44
|
-
$ [
|
|
44
|
+
$ [dim]nextmv cloud version list --app-id hare-app --output versions.json[/dim]
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
@@ -54,23 +54,23 @@ def update(
|
|
|
54
54
|
[bold][underline]Examples[/underline][/bold]
|
|
55
55
|
|
|
56
56
|
- Update a version's name.
|
|
57
|
-
$ [
|
|
57
|
+
$ [dim]nextmv cloud version update --app-id hare-app --version-id v1 --name "Version 1.0"[/dim]
|
|
58
58
|
|
|
59
59
|
- Update a version's description.
|
|
60
|
-
$ [
|
|
61
|
-
--description "Initial stable release"[/
|
|
60
|
+
$ [dim]nextmv cloud version update --app-id hare-app --version-id v1 \\
|
|
61
|
+
--description "Initial stable release"[/dim]
|
|
62
62
|
|
|
63
63
|
- Update a version's name and description at once.
|
|
64
|
-
$ [
|
|
65
|
-
--name "Version 1.0" --description "Initial stable release"[/
|
|
64
|
+
$ [dim]nextmv cloud version update --app-id hare-app --version-id v1 \\
|
|
65
|
+
--name "Version 1.0" --description "Initial stable release"[/dim]
|
|
66
66
|
|
|
67
67
|
- Update a version and save the updated information to a [magenta]updated_version.json[/magenta] file.
|
|
68
|
-
$ [
|
|
69
|
-
--name "Version 1.0" --output updated_version.json[/
|
|
68
|
+
$ [dim]nextmv cloud version update --app-id hare-app --version-id v1 \\
|
|
69
|
+
--name "Version 1.0" --output updated_version.json[/dim]
|
|
70
70
|
"""
|
|
71
71
|
|
|
72
72
|
if name is None and description is None:
|
|
73
|
-
error("Provide at least one option to update:
|
|
73
|
+
error("Provide at least one option to update: --name or --description.")
|
|
74
74
|
|
|
75
75
|
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
76
76
|
updated_version = cloud_app.update_version(
|
nextmv/cli/community/clone.py
CHANGED
|
@@ -53,35 +53,35 @@ def clone(
|
|
|
53
53
|
Clone a community app locally.
|
|
54
54
|
|
|
55
55
|
By default, the [magenta]latest[/magenta] version will be used. You can
|
|
56
|
-
specify a version with the
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
specify a version with the --version flag, and customize the output
|
|
57
|
+
directory with the --directory flag. If you want to list the available
|
|
58
|
+
apps, use the [code]nextmv community list[/code] command.
|
|
59
59
|
|
|
60
60
|
[bold][underline]Examples[/underline][/bold]
|
|
61
61
|
|
|
62
62
|
- Clone the [magenta]go-nextroute[/magenta] community app (under the
|
|
63
63
|
[magenta]"go-nextroute"[/magenta] directory), using the [magenta]latest[/magenta] version.
|
|
64
|
-
$ [
|
|
64
|
+
$ [dim]nextmv community clone --app go-nextroute[/dim]
|
|
65
65
|
|
|
66
66
|
- Clone the [magenta]go-nextroute[/magenta] community app under the
|
|
67
67
|
[magenta]"~/sample/my_app"[/magenta] directory, using the [magenta]latest[/magenta] version.
|
|
68
|
-
$ [
|
|
68
|
+
$ [dim]nextmv community clone --app go-nextroute --directory ~/sample/my_app[/dim]
|
|
69
69
|
|
|
70
70
|
- Clone the [magenta]go-nextroute[/magenta] community app (under the
|
|
71
71
|
[magenta]"go-nextroute"[/magenta] directory), using version [magenta]v1.2.0[/magenta].
|
|
72
|
-
$ [
|
|
72
|
+
$ [dim]nextmv community clone --app go-nextroute --version v1.2.0[/dim]
|
|
73
73
|
|
|
74
74
|
- Clone the [magenta]go-nextroute[/magenta] community app (under the
|
|
75
75
|
[magenta]"go-nextroute"[/magenta] directory), using the [magenta]latest[/magenta] version
|
|
76
76
|
and a profile named [magenta]hare[/magenta].
|
|
77
|
-
$ [
|
|
77
|
+
$ [dim]nextmv community clone --app go-nextroute --profile hare[/dim]
|
|
78
78
|
"""
|
|
79
79
|
|
|
80
80
|
manifest = download_manifest(profile=profile)
|
|
81
81
|
app_obj = find_app(manifest, app)
|
|
82
82
|
|
|
83
83
|
if version is not None and version == "":
|
|
84
|
-
error("The
|
|
84
|
+
error("The --version flag cannot be an empty string.")
|
|
85
85
|
|
|
86
86
|
if not app_has_version(app_obj, version):
|
|
87
87
|
# We don't use error() here to allow printing something before exiting.
|
|
@@ -97,8 +97,10 @@ def clone(
|
|
|
97
97
|
if version == LATEST_VERSION:
|
|
98
98
|
version = app_obj.get("latest_app_version")
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
if directory is None
|
|
100
|
+
# Clean and normalize directory path in an OS-independent way
|
|
101
|
+
if directory is not None and directory != "":
|
|
102
|
+
destination = os.path.normpath(directory)
|
|
103
|
+
else:
|
|
102
104
|
destination = app
|
|
103
105
|
|
|
104
106
|
full_destination = get_valid_path(destination, os.stat)
|
nextmv/cli/community/list.py
CHANGED
|
@@ -37,30 +37,30 @@ def list(
|
|
|
37
37
|
"""
|
|
38
38
|
List the available community apps
|
|
39
39
|
|
|
40
|
-
Use the
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
Use the --app flag to list that app's versions. Use the --flat flag to
|
|
41
|
+
flatten the list of names/versions. If you want to clone a community app
|
|
42
|
+
locally, use the [code]nextmv community clone[/code] command.
|
|
43
43
|
|
|
44
44
|
[bold][underline]Examples[/underline][/bold]
|
|
45
45
|
|
|
46
46
|
- List the available community apps.
|
|
47
|
-
$ [
|
|
47
|
+
$ [dim]nextmv community list[/dim]
|
|
48
48
|
|
|
49
49
|
- List the available versions of the [magenta]go-nextroute[/magenta] community app.
|
|
50
|
-
$ [
|
|
50
|
+
$ [dim]nextmv community list --app go-nextroute[/dim]
|
|
51
51
|
|
|
52
52
|
- List the names of the available community apps as a flat list.
|
|
53
|
-
$ [
|
|
53
|
+
$ [dim]nextmv community list --flat[/dim]
|
|
54
54
|
|
|
55
55
|
- List the available versions of the [magenta]go-nextroute[/magenta] community app as a flat list.
|
|
56
|
-
$ [
|
|
56
|
+
$ [dim]nextmv community list --app go-nextroute --flat[/dim]
|
|
57
57
|
|
|
58
58
|
- List the available community apps using a profile named [magenta]hare[/magenta].
|
|
59
|
-
$ [
|
|
59
|
+
$ [dim]nextmv community list --profile hare[/dim]
|
|
60
60
|
"""
|
|
61
61
|
|
|
62
62
|
if app is not None and app == "":
|
|
63
|
-
error("The
|
|
63
|
+
error("The --app flag cannot be an empty string.")
|
|
64
64
|
|
|
65
65
|
manifest = download_manifest(profile=profile)
|
|
66
66
|
if flat and app is None:
|
|
@@ -7,7 +7,8 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
import yaml
|
|
9
9
|
|
|
10
|
-
from nextmv.cli.
|
|
10
|
+
from nextmv.cli.confirm import get_confirmation
|
|
11
|
+
from nextmv.cli.message import error, success, warning
|
|
11
12
|
from nextmv.cloud.account import Account
|
|
12
13
|
from nextmv.cloud.application import Application
|
|
13
14
|
from nextmv.cloud.client import Client
|
|
@@ -59,6 +60,18 @@ def save_config(config: dict[str, Any]) -> None:
|
|
|
59
60
|
yaml.safe_dump(config, file)
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
def non_profile_keys() -> set[str]:
|
|
64
|
+
"""
|
|
65
|
+
Returns the set of keys that are not profile names in the configuration.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
set[str]
|
|
70
|
+
The set of non-profile keys.
|
|
71
|
+
"""
|
|
72
|
+
return {API_KEY_KEY, ENDPOINT_KEY}
|
|
73
|
+
|
|
74
|
+
|
|
62
75
|
def build_client(profile: str | None = None) -> Client:
|
|
63
76
|
"""
|
|
64
77
|
Builds a `cloud.Client` using the API key and endpoint for the given
|
|
@@ -91,23 +104,35 @@ def build_client(profile: str | None = None) -> Client:
|
|
|
91
104
|
|
|
92
105
|
if profile is not None:
|
|
93
106
|
if profile not in config:
|
|
94
|
-
error(
|
|
107
|
+
error(
|
|
108
|
+
f"Profile [magenta]{profile}[/magenta] does not exist. "
|
|
109
|
+
"Create it using [code]nextmv configuration create[/code] with the --profile option."
|
|
110
|
+
)
|
|
95
111
|
|
|
96
112
|
api_key = config[profile].get(API_KEY_KEY)
|
|
97
113
|
if api_key is None or api_key == "":
|
|
98
|
-
error(
|
|
114
|
+
error(
|
|
115
|
+
f"API key for profile [magenta]{profile}[/magenta] is not set or is empty. "
|
|
116
|
+
"Set it using [code]nextmv configuration create[/code] with the --profile and --api-key options."
|
|
117
|
+
)
|
|
99
118
|
|
|
100
119
|
endpoint = config[profile].get(ENDPOINT_KEY)
|
|
101
120
|
if endpoint is None or endpoint == "":
|
|
102
|
-
error(
|
|
121
|
+
error(
|
|
122
|
+
f"Endpoint for profile [magenta]{profile}[/magenta] is not set or is empty. "
|
|
123
|
+
"Please run [code]nextmv configuration create[/code]."
|
|
124
|
+
)
|
|
103
125
|
else:
|
|
104
126
|
api_key = config.get(API_KEY_KEY)
|
|
105
127
|
if api_key is None or api_key == "":
|
|
106
|
-
error(
|
|
128
|
+
error(
|
|
129
|
+
"Default API key is not set or is empty. "
|
|
130
|
+
"Please run [code]nextmv configuration create[/code] with the --api-key option."
|
|
131
|
+
)
|
|
107
132
|
|
|
108
133
|
endpoint = config.get(ENDPOINT_KEY)
|
|
109
134
|
if endpoint is None or endpoint == "":
|
|
110
|
-
error("Default endpoint is not set or is empty.")
|
|
135
|
+
error("Default endpoint is not set or is empty. Please run [code]nextmv configuration create[/code].")
|
|
111
136
|
|
|
112
137
|
return Client(api_key=api_key, url=f"https://{endpoint}")
|
|
113
138
|
|
|
@@ -137,13 +162,21 @@ def build_app(app_id: str, profile: str | None = None) -> Application:
|
|
|
137
162
|
"""
|
|
138
163
|
client = build_client(profile)
|
|
139
164
|
exists = Application.exists(client=client, id=app_id)
|
|
140
|
-
if
|
|
165
|
+
if exists:
|
|
166
|
+
return Application(client=client, id=app_id)
|
|
167
|
+
|
|
168
|
+
warning(f"Application with ID [magenta]{app_id}[/magenta] does not exist.")
|
|
169
|
+
should_create = get_confirmation(f"Do you want to create a new application with ID [magenta]{app_id}[/magenta]?")
|
|
170
|
+
if not should_create:
|
|
141
171
|
error(
|
|
142
|
-
f"Application with ID [magenta]{app_id}[/magenta] does not exist. "
|
|
143
|
-
"Use [code]nextmv cloud app create[/code] to create a new
|
|
172
|
+
f"Application with ID [magenta]{app_id}[/magenta] was not created and does not exist. "
|
|
173
|
+
"Use [code]nextmv cloud app create[/code] to create a new app."
|
|
144
174
|
)
|
|
145
175
|
|
|
146
|
-
|
|
176
|
+
app = Application.new(client=client, id=app_id, name=app_id)
|
|
177
|
+
success(f"Application with ID and name [magenta]{app_id}[/magenta] created successfully.")
|
|
178
|
+
|
|
179
|
+
return app
|
|
147
180
|
|
|
148
181
|
|
|
149
182
|
def build_account(account_id: str | None = None, profile: str | None = None) -> Account:
|
|
@@ -58,14 +58,14 @@ def create(
|
|
|
58
58
|
[bold][underline]Examples[/underline][/bold]
|
|
59
59
|
|
|
60
60
|
- Default configuration.
|
|
61
|
-
$ [
|
|
61
|
+
$ [dim]nextmv configuration create --api-key NEXTMV_API_KEY[/dim]
|
|
62
62
|
|
|
63
63
|
- Configure a profile named [magenta]hare[/magenta].
|
|
64
|
-
$ [
|
|
64
|
+
$ [dim]nextmv configuration create --api-key NEXTMV_API_KEY --profile hare[/dim]
|
|
65
65
|
"""
|
|
66
66
|
|
|
67
67
|
if profile is not None and profile.strip().lower() == "default":
|
|
68
|
-
error("[
|
|
68
|
+
error("[magenta]default[/magenta] is a reserved profile name.")
|
|
69
69
|
|
|
70
70
|
endpoint = str(endpoint)
|
|
71
71
|
if endpoint.startswith("https://"):
|
|
@@ -5,9 +5,9 @@ This module defines the configuration delete command for the Nextmv CLI.
|
|
|
5
5
|
from typing import Annotated
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from rich.prompt import Confirm
|
|
9
8
|
|
|
10
9
|
from nextmv.cli.configuration.config import load_config, save_config
|
|
10
|
+
from nextmv.cli.confirm import get_confirmation
|
|
11
11
|
from nextmv.cli.message import error, info, success
|
|
12
12
|
|
|
13
13
|
# Set up subcommand application.
|
|
@@ -36,25 +36,25 @@ def delete(
|
|
|
36
36
|
] = False,
|
|
37
37
|
) -> None:
|
|
38
38
|
"""
|
|
39
|
-
Delete a profile from the configuration.
|
|
40
|
-
|
|
39
|
+
Delete a profile from the configuration.
|
|
40
|
+
|
|
41
|
+
Use the --yes flag to skip the confirmation prompt.
|
|
41
42
|
|
|
42
43
|
[bold][underline]Examples[/underline][/bold]
|
|
43
44
|
|
|
44
45
|
- Delete a profile named [magenta]hare[/magenta].
|
|
45
|
-
$ [
|
|
46
|
+
$ [dim]nextmv configuration delete --profile hare[/dim]
|
|
46
47
|
|
|
47
48
|
- Delete a profile named [magenta]hare[/magenta] without confirmation prompt.
|
|
48
|
-
$ [
|
|
49
|
+
$ [dim]nextmv configuration delete --profile hare --yes[/dim]
|
|
49
50
|
"""
|
|
50
51
|
config = load_config()
|
|
51
52
|
if profile not in config:
|
|
52
53
|
error(f"Profile [magenta]{profile}[/magenta] does not exist.")
|
|
53
54
|
|
|
54
55
|
if not yes:
|
|
55
|
-
confirm =
|
|
56
|
+
confirm = get_confirmation(
|
|
56
57
|
f"Are you sure you want to delete profile [magenta]{profile}[/magenta]? This action cannot be undone.",
|
|
57
|
-
default=False,
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
if not confirm:
|
nextmv/cli/configuration/list.py
CHANGED
|
@@ -6,7 +6,7 @@ import typer
|
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
from rich.table import Table
|
|
8
8
|
|
|
9
|
-
from nextmv.cli.configuration.config import API_KEY_KEY, ENDPOINT_KEY, load_config, obscure_api_key
|
|
9
|
+
from nextmv.cli.configuration.config import API_KEY_KEY, ENDPOINT_KEY, load_config, non_profile_keys, obscure_api_key
|
|
10
10
|
from nextmv.cli.message import error
|
|
11
11
|
|
|
12
12
|
# Set up subcommand application.
|
|
@@ -22,7 +22,7 @@ def list() -> None:
|
|
|
22
22
|
[bold][underline]Examples[/underline][/bold]
|
|
23
23
|
|
|
24
24
|
- Show current configuration and all profiles.
|
|
25
|
-
$ [
|
|
25
|
+
$ [dim]nextmv configuration list[/dim]
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
config = load_config()
|
|
@@ -38,7 +38,7 @@ def list() -> None:
|
|
|
38
38
|
|
|
39
39
|
for k, v in config.items():
|
|
40
40
|
# Skip default configuration.
|
|
41
|
-
if k in
|
|
41
|
+
if k in non_profile_keys():
|
|
42
42
|
continue
|
|
43
43
|
|
|
44
44
|
profile = {
|
nextmv/cli/confirm.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from rich.prompt import Confirm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_confirmation(msg: str) -> bool:
|
|
7
|
+
"""
|
|
8
|
+
Method to get a yes/no confirmation from the user.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
msg : str
|
|
13
|
+
The message to display to the user.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
bool
|
|
18
|
+
True if the user confirmed, False otherwise.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# If this is not an interactive terminal, do not ask for confirmation, to
|
|
22
|
+
# avoid hanging indefinitely waiting for a user response.
|
|
23
|
+
if not sys.stdin.isatty():
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
return Confirm.ask(
|
|
27
|
+
msg,
|
|
28
|
+
default=False,
|
|
29
|
+
case_sensitive=False,
|
|
30
|
+
show_default=True,
|
|
31
|
+
show_choices=True,
|
|
32
|
+
)
|