nextmv 1.0.0.dev4__py3-none-any.whl → 1.0.0.dev6__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/__entrypoint__.py +1 -2
- nextmv/__init__.py +0 -4
- nextmv/cli/cloud/app/push.py +294 -204
- nextmv/cli/cloud/input_set/__init__.py +2 -0
- nextmv/cli/cloud/input_set/delete.py +67 -0
- nextmv/cli/cloud/run/create.py +4 -9
- nextmv/cli/cloud/shadow/stop.py +14 -2
- nextmv/cli/cloud/switchback/stop.py +14 -2
- nextmv/cli/community/clone.py +11 -197
- nextmv/cli/community/list.py +46 -116
- nextmv/cli/confirm.py +5 -3
- nextmv/cloud/__init__.py +4 -38
- nextmv/cloud/acceptance_test.py +1 -65
- nextmv/cloud/account.py +1 -6
- nextmv/cloud/application/__init__.py +1 -198
- nextmv/cloud/application/_batch_scenario.py +2 -17
- nextmv/cloud/application/_input_set.py +42 -6
- nextmv/cloud/application/_instance.py +1 -1
- nextmv/cloud/application/_managed_input.py +1 -1
- nextmv/cloud/application/_shadow.py +10 -4
- nextmv/cloud/application/_switchback.py +11 -2
- nextmv/cloud/application/_version.py +1 -1
- nextmv/cloud/batch_experiment.py +3 -1
- nextmv/cloud/community.py +441 -0
- nextmv/cloud/shadow.py +25 -0
- nextmv/deprecated.py +5 -3
- nextmv/input.py +0 -52
- nextmv/local/runner.py +1 -1
- nextmv/options.py +11 -256
- nextmv/output.py +0 -62
- nextmv/run.py +1 -10
- nextmv/status.py +1 -51
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev6.dist-info}/METADATA +3 -1
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev6.dist-info}/RECORD +38 -36
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev6.dist-info}/WHEEL +0 -0
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev6.dist-info}/entry_points.txt +0 -0
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev6.dist-info}/licenses/LICENSE +0 -0
nextmv/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "v1.0.0.
|
|
1
|
+
__version__ = "v1.0.0.dev6"
|
nextmv/__entrypoint__.py
CHANGED
|
@@ -10,13 +10,12 @@ human to use it during local development. It is the standard way in which a
|
|
|
10
10
|
from mlflow.pyfunc import load_model
|
|
11
11
|
|
|
12
12
|
import nextmv
|
|
13
|
-
from nextmv import cloud
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
def main() -> None:
|
|
17
16
|
"""Entry point for the program."""
|
|
18
17
|
|
|
19
|
-
manifest =
|
|
18
|
+
manifest = nextmv.Manifest.from_yaml(".")
|
|
20
19
|
|
|
21
20
|
# Load the options from the manifest.
|
|
22
21
|
options = manifest.extract_options()
|
nextmv/__init__.py
CHANGED
|
@@ -11,7 +11,6 @@ from .input import LocalInputLoader as LocalInputLoader
|
|
|
11
11
|
from .input import csv_data_file as csv_data_file
|
|
12
12
|
from .input import json_data_file as json_data_file
|
|
13
13
|
from .input import load as load
|
|
14
|
-
from .input import load_local as load_local
|
|
15
14
|
from .input import text_data_file as text_data_file
|
|
16
15
|
from .logger import log as log
|
|
17
16
|
from .logger import redirect_stdout as redirect_stdout
|
|
@@ -31,7 +30,6 @@ from .model import Model as Model
|
|
|
31
30
|
from .model import ModelConfiguration as ModelConfiguration
|
|
32
31
|
from .options import Option as Option
|
|
33
32
|
from .options import Options as Options
|
|
34
|
-
from .options import Parameter as Parameter
|
|
35
33
|
from .output import Asset as Asset
|
|
36
34
|
from .output import DataPoint as DataPoint
|
|
37
35
|
from .output import LocalOutputWriter as LocalOutputWriter
|
|
@@ -50,7 +48,6 @@ from .output import csv_solution_file as csv_solution_file
|
|
|
50
48
|
from .output import json_solution_file as json_solution_file
|
|
51
49
|
from .output import text_solution_file as text_solution_file
|
|
52
50
|
from .output import write as write
|
|
53
|
-
from .output import write_local as write_local
|
|
54
51
|
from .polling import DEFAULT_POLLING_OPTIONS as DEFAULT_POLLING_OPTIONS
|
|
55
52
|
from .polling import PollingOptions as PollingOptions
|
|
56
53
|
from .polling import default_polling_options as default_polling_options
|
|
@@ -79,7 +76,6 @@ from .run import TrackedRunStatus as TrackedRunStatus
|
|
|
79
76
|
from .run import run_duration as run_duration
|
|
80
77
|
from .safe import safe_id as safe_id
|
|
81
78
|
from .safe import safe_name_and_id as safe_name_and_id
|
|
82
|
-
from .status import Status as Status
|
|
83
79
|
from .status import StatusV2 as StatusV2
|
|
84
80
|
|
|
85
81
|
VERSION = __version__
|
nextmv/cli/cloud/app/push.py
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
This module defines the cloud app push command for the Nextmv CLI.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
from datetime import datetime, timezone
|
|
6
7
|
from typing import Annotated
|
|
7
8
|
|
|
8
9
|
import typer
|
|
10
|
+
from rich.prompt import Prompt
|
|
9
11
|
|
|
10
12
|
from nextmv.cli.configuration.config import build_app
|
|
11
13
|
from nextmv.cli.confirm import get_confirmation
|
|
12
14
|
from nextmv.cli.message import error, in_progress, info, success
|
|
13
15
|
from nextmv.cli.options import AppIDOption, ProfileOption
|
|
14
16
|
from nextmv.cloud.application import Application
|
|
15
|
-
from nextmv.cloud.instance import Instance
|
|
16
17
|
from nextmv.manifest import Manifest
|
|
17
18
|
|
|
18
19
|
# Set up subcommand application.
|
|
@@ -40,109 +41,48 @@ def push(
|
|
|
40
41
|
metavar="MANIFEST_PATH",
|
|
41
42
|
),
|
|
42
43
|
] = None,
|
|
43
|
-
# Options for
|
|
44
|
-
auto_create_yes: Annotated[
|
|
45
|
-
bool,
|
|
46
|
-
typer.Option(
|
|
47
|
-
"--auto-create-yes",
|
|
48
|
-
"-cy",
|
|
49
|
-
help="Create a new version and instance after push. "
|
|
50
|
-
"Skips confirmation prompt with [magenta]yes[/magenta]. Useful for non-interactive sessions.",
|
|
51
|
-
rich_help_panel="Automatic creation and updating",
|
|
52
|
-
),
|
|
53
|
-
] = False,
|
|
54
|
-
auto_create_no: Annotated[
|
|
55
|
-
bool,
|
|
56
|
-
typer.Option(
|
|
57
|
-
"--auto-create-no",
|
|
58
|
-
"-cn",
|
|
59
|
-
help="Do not create a new version and instance after push. "
|
|
60
|
-
"Skips confirmation prompt with [magenta]no[/magenta]. Useful for non-interactive sessions.",
|
|
61
|
-
rich_help_panel="Automatic creation and updating",
|
|
62
|
-
),
|
|
63
|
-
] = False,
|
|
64
|
-
update_default_instance_yes: Annotated[
|
|
65
|
-
bool,
|
|
66
|
-
typer.Option(
|
|
67
|
-
"--update-default-instance-yes",
|
|
68
|
-
"-uy",
|
|
69
|
-
help="Update the default instance of the app after version/instance creation. "
|
|
70
|
-
"Skips confirmation prompt with [magenta]yes[/magenta]. "
|
|
71
|
-
"Useful for non-interactive sessions. Activates --auto-create-yes.",
|
|
72
|
-
rich_help_panel="Automatic creation and updating",
|
|
73
|
-
),
|
|
74
|
-
] = False,
|
|
75
|
-
update_default_instance_no: Annotated[
|
|
76
|
-
bool,
|
|
77
|
-
typer.Option(
|
|
78
|
-
"--update-default-instance-no",
|
|
79
|
-
"-un",
|
|
80
|
-
help="Do not update the default instance of the app after version/instance creation. "
|
|
81
|
-
"Skips confirmation prompt with [magenta]no[/magenta]. "
|
|
82
|
-
"Useful for non-interactive sessions. Activates --auto-create-yes.",
|
|
83
|
-
rich_help_panel="Automatic creation and updating",
|
|
84
|
-
),
|
|
85
|
-
] = False,
|
|
86
|
-
# Options for version creation.
|
|
44
|
+
# Options for version control.
|
|
87
45
|
version_id: Annotated[
|
|
88
46
|
str | None,
|
|
89
47
|
typer.Option(
|
|
90
48
|
"--version-id",
|
|
91
|
-
|
|
92
|
-
"
|
|
93
|
-
|
|
49
|
+
"-v",
|
|
50
|
+
help="Custom ID for version creation after app push. Automatically generated if not provided. "
|
|
51
|
+
"Activates --version-yes.",
|
|
94
52
|
metavar="VERSION_ID",
|
|
95
|
-
),
|
|
96
|
-
] = None,
|
|
97
|
-
version_description: Annotated[
|
|
98
|
-
str | None,
|
|
99
|
-
typer.Option(
|
|
100
|
-
"--version-description",
|
|
101
|
-
help="Custom version description when pushing the application. Automatically generated if not provided. "
|
|
102
|
-
"Activates --auto-create-yes.",
|
|
103
53
|
rich_help_panel="Version control",
|
|
104
|
-
metavar="VERSION_DESCRIPTION",
|
|
105
54
|
),
|
|
106
55
|
] = None,
|
|
107
|
-
|
|
108
|
-
|
|
56
|
+
version_yes: Annotated[
|
|
57
|
+
bool,
|
|
109
58
|
typer.Option(
|
|
110
|
-
"--version-
|
|
111
|
-
|
|
112
|
-
"
|
|
59
|
+
"--version-yes",
|
|
60
|
+
"-y",
|
|
61
|
+
help="Create a new version after push. Skips confirmation prompt. Useful for non-interactive sessions.",
|
|
113
62
|
rich_help_panel="Version control",
|
|
114
|
-
metavar="VERSION_NAME",
|
|
115
63
|
),
|
|
116
|
-
] =
|
|
117
|
-
# Options for instance
|
|
118
|
-
|
|
119
|
-
str | None,
|
|
120
|
-
typer.Option(
|
|
121
|
-
"--instance-id",
|
|
122
|
-
help="Custom instance ID when pushing the application. Automatically generated if not provided. "
|
|
123
|
-
"Activates --auto-create-yes.",
|
|
124
|
-
rich_help_panel="Instance control",
|
|
125
|
-
metavar="INSTANCE_ID",
|
|
126
|
-
),
|
|
127
|
-
] = None,
|
|
128
|
-
instance_description: Annotated[
|
|
64
|
+
] = False,
|
|
65
|
+
# Options for instance control.
|
|
66
|
+
create_instance_id: Annotated[
|
|
129
67
|
str | None,
|
|
130
68
|
typer.Option(
|
|
131
|
-
"--instance-
|
|
132
|
-
|
|
133
|
-
"
|
|
69
|
+
"--create-instance-id",
|
|
70
|
+
"-c",
|
|
71
|
+
help="Link the newly created version to a [yellow]new[/yellow] instance with this ID. "
|
|
72
|
+
"Skips prompt to provide an instance ID. Useful for non-interactive sessions.",
|
|
73
|
+
metavar="CREATE_INSTANCE_ID",
|
|
134
74
|
rich_help_panel="Instance control",
|
|
135
|
-
metavar="INSTANCE_DESCRIPTION",
|
|
136
75
|
),
|
|
137
76
|
] = None,
|
|
138
|
-
|
|
77
|
+
update_instance_id: Annotated[
|
|
139
78
|
str | None,
|
|
140
79
|
typer.Option(
|
|
141
|
-
"--instance-
|
|
142
|
-
|
|
143
|
-
"
|
|
80
|
+
"--update-instance-id",
|
|
81
|
+
"-u",
|
|
82
|
+
help="Link the newly created version to an [yellow]existing[/yellow] instance with this ID. "
|
|
83
|
+
"Skips prompt to provide an instance ID. Useful for non-interactive sessions.",
|
|
84
|
+
metavar="UPDATE_INSTANCE_ID",
|
|
144
85
|
rich_help_panel="Instance control",
|
|
145
|
-
metavar="INSTANCE_NAME",
|
|
146
86
|
),
|
|
147
87
|
] = None,
|
|
148
88
|
profile: ProfileOption = None,
|
|
@@ -157,23 +97,13 @@ def push(
|
|
|
157
97
|
not provided, the CLI will look for a file named
|
|
158
98
|
[magenta]app.yaml[/magenta] in the application's root.
|
|
159
99
|
|
|
160
|
-
|
|
161
100
|
By default, this command only pushes the app. After the push, you will be
|
|
162
|
-
prompted to create a new version
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
--instance-description options allow you to customize the new instance. If
|
|
169
|
-
any of these options are provided, --auto-create-yes is automatically
|
|
170
|
-
activated.
|
|
171
|
-
|
|
172
|
-
After version/instance creation, you will be prompted to set the new
|
|
173
|
-
instance as the default. Use --update-default-instance-yes to automatically
|
|
174
|
-
update the default instance (skipping the prompt), or
|
|
175
|
-
--update-default-instance-no to skip updating. Providing either of these
|
|
176
|
-
options automatically activates --auto-create-yes.
|
|
101
|
+
prompted to create a new version. If a new version is created, you will be
|
|
102
|
+
prompted to link it to an instance. If the instance exists, you will be
|
|
103
|
+
asked if you want to update it. If it doesn't, you will be asked to create
|
|
104
|
+
it. You can use the following flags to skip the prompts, useful in
|
|
105
|
+
non-interactive sessions like in a CI/CD pipeline: --version-yes,
|
|
106
|
+
--version-id, --create-instance-id, and --update-instance-id.
|
|
177
107
|
|
|
178
108
|
[bold][underline]Examples[/underline][/bold]
|
|
179
109
|
|
|
@@ -186,40 +116,50 @@ def push(
|
|
|
186
116
|
- Push an application, with ID [magenta]hare-app[/magenta], using a custom manifest file.
|
|
187
117
|
$ [dim]nextmv cloud app push --app-id hare-app --manifest ./custom-manifest.yaml[/dim]
|
|
188
118
|
|
|
189
|
-
- Push
|
|
190
|
-
|
|
191
|
-
$ [dim]nextmv cloud app push --app-id hare-app --app-dir ./my-app --manifest ./custom-manifest.yaml[/dim]
|
|
119
|
+
- Push and automatically create a new version (no prompt).
|
|
120
|
+
$ [dim]nextmv cloud app push --app-id hare-app --version-yes[/dim]
|
|
192
121
|
|
|
193
|
-
- Push and
|
|
194
|
-
$ [dim]nextmv cloud app push --app-id hare-app --
|
|
122
|
+
- Push and create a new version with a custom version ID (no prompt).
|
|
123
|
+
$ [dim]nextmv cloud app push --app-id hare-app --version-id v1.0.0[/dim]
|
|
195
124
|
|
|
196
|
-
- Push and
|
|
197
|
-
$ [dim]nextmv cloud app push --app-id hare-app --
|
|
125
|
+
- Push and create a new version, then link it to a new instance with a specific ID (no prompt).
|
|
126
|
+
$ [dim]nextmv cloud app push --app-id hare-app --version-yes --create-instance-id inst-1[/dim]
|
|
198
127
|
|
|
199
|
-
- Push and
|
|
200
|
-
$ [dim]nextmv cloud app push --app-id hare-app --
|
|
128
|
+
- Push and create a new version, then link it to an existing instance (no prompt).
|
|
129
|
+
$ [dim]nextmv cloud app push --app-id hare-app --version-yes --update-instance-id inst-1[/dim]
|
|
130
|
+
"""
|
|
201
131
|
|
|
202
|
-
|
|
203
|
-
$ [dim]nextmv cloud app push --app-id hare-app --version-id v1.0.0[/dim]
|
|
132
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
204
133
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
--instance-description "Main deployment" \\
|
|
213
|
-
--update-default-instance-yes[/dim]
|
|
214
|
-
"""
|
|
134
|
+
# If a version already exists, we cannot create it.
|
|
135
|
+
if version_id is not None and version_id != "":
|
|
136
|
+
exists = cloud_app.version_exists(version_id=version_id)
|
|
137
|
+
if exists:
|
|
138
|
+
error(
|
|
139
|
+
f"Version [magenta]{version_id}[/magenta] already exists for application [magenta]{app_id}[/magenta]."
|
|
140
|
+
)
|
|
215
141
|
|
|
216
|
-
|
|
217
|
-
|
|
142
|
+
# We cannot create and update an instance at the same time.
|
|
143
|
+
update_defined = update_instance_id is not None and update_instance_id != ""
|
|
144
|
+
create_defined = create_instance_id is not None and create_instance_id != ""
|
|
145
|
+
if update_defined and create_defined:
|
|
146
|
+
error("Cannot use --update-instance-id and --create-instance-id at the same time.")
|
|
147
|
+
|
|
148
|
+
# We cannot update an instance that does not exist.
|
|
149
|
+
if update_defined and not cloud_app.instance_exists(instance_id=update_instance_id):
|
|
150
|
+
error(
|
|
151
|
+
f"Used option --update-instance-id but the instance [magenta]{update_instance_id}[/magenta] "
|
|
152
|
+
"does not exist. Use --create-instance-id instead."
|
|
153
|
+
)
|
|
218
154
|
|
|
219
|
-
|
|
220
|
-
|
|
155
|
+
# We cannot create an instance that already exists.
|
|
156
|
+
if create_defined and cloud_app.instance_exists(instance_id=create_instance_id):
|
|
157
|
+
error(
|
|
158
|
+
f"Used option --create-instance-id but the instance [magenta]{create_instance_id}[/magenta] "
|
|
159
|
+
"already exists. Use --update-instance-id instead."
|
|
160
|
+
)
|
|
221
161
|
|
|
222
|
-
|
|
162
|
+
# Do the normal push first.
|
|
223
163
|
loaded_manifest = Manifest.from_yaml(dirpath=manifest) if manifest is not None and manifest != "" else None
|
|
224
164
|
cloud_app.push(
|
|
225
165
|
manifest=loaded_manifest,
|
|
@@ -228,134 +168,284 @@ def push(
|
|
|
228
168
|
rich_print=True,
|
|
229
169
|
)
|
|
230
170
|
|
|
231
|
-
|
|
171
|
+
now = datetime.now(timezone.utc)
|
|
172
|
+
version_id, should_continue = _handle_version_creation(
|
|
232
173
|
cloud_app=cloud_app,
|
|
233
174
|
app_id=app_id,
|
|
234
|
-
auto_create_yes=auto_create_yes,
|
|
235
|
-
auto_create_no=auto_create_no,
|
|
236
|
-
update_default_instance_yes=update_default_instance_yes,
|
|
237
|
-
update_default_instance_no=update_default_instance_no,
|
|
238
175
|
version_id=version_id,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
instance_id=instance_id,
|
|
242
|
-
instance_name=instance_name,
|
|
243
|
-
instance_description=instance_description,
|
|
176
|
+
version_yes=version_yes,
|
|
177
|
+
now=now,
|
|
244
178
|
)
|
|
245
|
-
|
|
179
|
+
if not should_continue:
|
|
180
|
+
return
|
|
181
|
+
|
|
182
|
+
# If the override for updating an instance was used, we update the instance
|
|
183
|
+
# and we are done.
|
|
184
|
+
if update_defined:
|
|
185
|
+
info("Used option --update-instance-id to link version to existing instance.", emoji=":bulb:")
|
|
186
|
+
_update_instance(
|
|
187
|
+
cloud_app=cloud_app,
|
|
188
|
+
app_id=app_id,
|
|
189
|
+
version_id=version_id,
|
|
190
|
+
instance_id=update_instance_id,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
# If the override for creating a new instance was used, we create the
|
|
196
|
+
# instance and we are done.
|
|
197
|
+
if create_defined:
|
|
198
|
+
info("Used option --create-instance-id to link version to new instance.", emoji=":bulb:")
|
|
199
|
+
_create_instance(
|
|
200
|
+
cloud_app=cloud_app,
|
|
201
|
+
app_id=app_id,
|
|
202
|
+
version_id=version_id,
|
|
203
|
+
instance_id=create_instance_id,
|
|
204
|
+
now=now,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
# If no overrides are used, we handle instance prompting.
|
|
210
|
+
_handle_instance_prompting(
|
|
246
211
|
cloud_app=cloud_app,
|
|
247
212
|
app_id=app_id,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
update_default_instance_yes=update_default_instance_yes,
|
|
251
|
-
update_default_instance_no=update_default_instance_no,
|
|
213
|
+
version_id=version_id,
|
|
214
|
+
now=now,
|
|
252
215
|
)
|
|
253
216
|
|
|
254
217
|
|
|
255
|
-
def
|
|
218
|
+
def _handle_version_creation(
|
|
256
219
|
cloud_app: Application,
|
|
257
220
|
app_id: str,
|
|
258
|
-
auto_create_yes: bool,
|
|
259
|
-
auto_create_no: bool,
|
|
260
|
-
update_default_instance_yes: bool,
|
|
261
|
-
update_default_instance_no: bool,
|
|
262
221
|
version_id: str | None,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
222
|
+
version_yes: bool,
|
|
223
|
+
now: datetime,
|
|
224
|
+
) -> tuple[str, bool]:
|
|
225
|
+
"""
|
|
226
|
+
Handle the logic for version creation after pushing an application.
|
|
227
|
+
|
|
228
|
+
If a version ID is provided and exists, it is used directly. If not, the user is prompted (unless auto-confirmed)
|
|
229
|
+
to create a new version. If confirmed, a new version is created with an automatic description.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
cloud_app : Application
|
|
234
|
+
The cloud application object to interact with Nextmv Cloud.
|
|
235
|
+
app_id : str
|
|
236
|
+
The application ID.
|
|
237
|
+
version_id : str or None
|
|
238
|
+
The version ID to use or check for existence. If None or empty, a new version may be created.
|
|
239
|
+
version_yes : bool
|
|
240
|
+
Whether to skip the prompt and auto-create a new version.
|
|
241
|
+
now : datetime
|
|
242
|
+
The current datetime, used for version description.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
tuple[str, bool]
|
|
247
|
+
A tuple containing the version ID (empty string if not created) and a boolean indicating
|
|
248
|
+
whether to continue with subsequent steps (True if a version is selected or created, False otherwise).
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
# If the user provides a version, and it exists, we use it directly and we
|
|
252
|
+
# are done.
|
|
253
|
+
if version_id is not None and version_id != "":
|
|
270
254
|
info(
|
|
271
|
-
msg="
|
|
255
|
+
msg=f"Version [magenta]{version_id}[/magenta] does not exist. A new version will be created.",
|
|
272
256
|
emoji=":bulb:",
|
|
273
257
|
)
|
|
274
|
-
return None, False
|
|
275
258
|
|
|
276
|
-
|
|
277
|
-
version_provided = version_id is not None or version_name is not None or version_description is not None
|
|
278
|
-
instance_provided = instance_id is not None or instance_name is not None or instance_description is not None
|
|
279
|
-
if version_provided or instance_provided or update_default_instance_yes or update_default_instance_no:
|
|
280
|
-
auto_create_yes = True
|
|
259
|
+
version_yes = True # Activate auto-confirm since user provided a version ID.
|
|
281
260
|
|
|
282
|
-
|
|
261
|
+
# If we are not auto-confirming version creation, ask the user.
|
|
262
|
+
if not version_yes:
|
|
283
263
|
should_create = get_confirmation(
|
|
284
|
-
f"Do you want to create a new version
|
|
264
|
+
msg=f"Do you want to create a new version for application [magenta]{app_id}[/magenta] now?",
|
|
265
|
+
default=True,
|
|
285
266
|
)
|
|
286
267
|
|
|
268
|
+
# If the user does not want to create a new version, we are done.
|
|
287
269
|
if not should_create:
|
|
288
270
|
info(
|
|
289
|
-
msg="Will not create a new version
|
|
271
|
+
msg="Will not create a new version.",
|
|
290
272
|
emoji=":bulb:",
|
|
291
273
|
)
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
in_progress("Creating a new version and instance...")
|
|
295
|
-
now = datetime.now(timezone.utc)
|
|
296
|
-
|
|
297
|
-
if version_description is None or version_description == "":
|
|
298
|
-
version_description = f"Version created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
274
|
+
return "", False
|
|
299
275
|
|
|
276
|
+
# Create a new version if either the user confirms by prompt or by using
|
|
277
|
+
# the flag.
|
|
278
|
+
in_progress("Creating a new version...")
|
|
279
|
+
version_description = f"Version created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
300
280
|
version = cloud_app.new_version(
|
|
301
281
|
id=version_id,
|
|
302
|
-
name=version_name,
|
|
303
282
|
description=version_description,
|
|
304
283
|
)
|
|
305
|
-
|
|
284
|
+
version_id = version.id
|
|
285
|
+
success(f"New version [magenta]{version_id}[/magenta] created for application [magenta]{app_id}[/magenta].")
|
|
306
286
|
|
|
307
|
-
|
|
308
|
-
instance_description = f"Instance created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
287
|
+
return version_id, True
|
|
309
288
|
|
|
310
|
-
instance = cloud_app.new_instance(
|
|
311
|
-
version_id=version.id,
|
|
312
|
-
id=instance_id,
|
|
313
|
-
name=instance_name,
|
|
314
|
-
description=instance_description,
|
|
315
|
-
)
|
|
316
|
-
success(
|
|
317
|
-
f"New instance [magenta]{instance.id}[/magenta] created using version [magenta]{version.id}[/magenta] "
|
|
318
|
-
f"for application [magenta]{app_id}[/magenta]."
|
|
319
|
-
)
|
|
320
|
-
|
|
321
|
-
return instance, True
|
|
322
289
|
|
|
323
|
-
|
|
324
|
-
def _handle_instance_update(
|
|
290
|
+
def _handle_instance_prompting(
|
|
325
291
|
cloud_app: Application,
|
|
326
292
|
app_id: str,
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
update_default_instance_yes: bool,
|
|
330
|
-
update_default_instance_no: bool,
|
|
293
|
+
version_id: str,
|
|
294
|
+
now: datetime,
|
|
331
295
|
) -> None:
|
|
332
|
-
|
|
296
|
+
"""
|
|
297
|
+
Handle interactive prompting for linking a version to an instance after a push.
|
|
298
|
+
|
|
299
|
+
In interactive terminals, prompts the user to link the new version to an existing or new instance.
|
|
300
|
+
If the terminal is non-interactive, skips prompting. Handles both updating existing instances and creating new ones.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
cloud_app : Application
|
|
305
|
+
The cloud application object to interact with Nextmv Cloud.
|
|
306
|
+
app_id : str
|
|
307
|
+
The application ID.
|
|
308
|
+
version_id : str
|
|
309
|
+
The version ID to link to an instance.
|
|
310
|
+
now : datetime
|
|
311
|
+
The current datetime, used for instance description if a new instance is created.
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
# If this is not an interactive terminal, do not ask for instance linking,
|
|
315
|
+
# to avoid hanging indefinitely waiting for a user response.
|
|
316
|
+
if not sys.stdin.isatty():
|
|
317
|
+
info(
|
|
318
|
+
msg="Non-interactive terminal detected. Skipping instance linking.",
|
|
319
|
+
emoji=":bulb:",
|
|
320
|
+
)
|
|
321
|
+
|
|
333
322
|
return
|
|
334
323
|
|
|
335
|
-
|
|
324
|
+
# Prompt the user for an instance ID to link the new version to.
|
|
325
|
+
instance_id = Prompt.ask(
|
|
326
|
+
f"Do you want to link version [magenta]{version_id}[/magenta] to an instance? If so, enter the instance ID. "
|
|
327
|
+
"Leave blank to abort",
|
|
328
|
+
case_sensitive=False,
|
|
329
|
+
)
|
|
330
|
+
if instance_id == "":
|
|
336
331
|
info(
|
|
337
|
-
msg="
|
|
332
|
+
msg="No instance ID provided. Skipping instance linking.",
|
|
338
333
|
emoji=":bulb:",
|
|
339
334
|
)
|
|
340
335
|
return
|
|
341
336
|
|
|
342
|
-
|
|
337
|
+
# Based on whether the instance exists or not, ask the user if they want to
|
|
338
|
+
# update or create it.
|
|
339
|
+
exists = cloud_app.instance_exists(instance_id=instance_id)
|
|
340
|
+
|
|
341
|
+
# If the instance exists, ask if we want to update it.
|
|
342
|
+
if exists:
|
|
343
343
|
should_update = get_confirmation(
|
|
344
|
-
f"
|
|
345
|
-
f"
|
|
344
|
+
msg=f"Instance [magenta]{instance_id}[/magenta] exists. "
|
|
345
|
+
f"Do you want to link it to version [magenta]{version_id}[/magenta]?",
|
|
346
|
+
default=True,
|
|
346
347
|
)
|
|
347
348
|
|
|
348
349
|
if not should_update:
|
|
349
350
|
info(
|
|
350
|
-
msg=f"
|
|
351
|
+
msg=f"Will not update instance [magenta]{instance_id}[/magenta].",
|
|
351
352
|
emoji=":bulb:",
|
|
352
353
|
)
|
|
353
354
|
return
|
|
354
355
|
|
|
355
|
-
|
|
356
|
-
|
|
356
|
+
_update_instance(
|
|
357
|
+
cloud_app=cloud_app,
|
|
358
|
+
app_id=app_id,
|
|
359
|
+
version_id=version_id,
|
|
360
|
+
instance_id=instance_id,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
return
|
|
364
|
+
|
|
365
|
+
# If the instance does not exist, ask if we want to create it.
|
|
366
|
+
should_create = get_confirmation(
|
|
367
|
+
msg=f"Instance [magenta]{instance_id}[/magenta] does not exist. "
|
|
368
|
+
f"Do you want to create it using version [magenta]{version_id}[/magenta]?",
|
|
369
|
+
default=True,
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
if not should_create:
|
|
373
|
+
info(
|
|
374
|
+
msg=f"Will not create instance [magenta]{instance_id}[/magenta].",
|
|
375
|
+
emoji=":bulb:",
|
|
376
|
+
)
|
|
377
|
+
return
|
|
378
|
+
|
|
379
|
+
_create_instance(
|
|
380
|
+
cloud_app=cloud_app,
|
|
381
|
+
app_id=app_id,
|
|
382
|
+
version_id=version_id,
|
|
383
|
+
instance_id=instance_id,
|
|
384
|
+
now=now,
|
|
357
385
|
)
|
|
358
|
-
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _update_instance(
|
|
389
|
+
cloud_app: Application,
|
|
390
|
+
app_id: str,
|
|
391
|
+
version_id: str,
|
|
392
|
+
instance_id: str,
|
|
393
|
+
) -> None:
|
|
394
|
+
"""
|
|
395
|
+
Update an existing instance to use a new version.
|
|
396
|
+
|
|
397
|
+
Parameters
|
|
398
|
+
----------
|
|
399
|
+
cloud_app : Application
|
|
400
|
+
The cloud application object to interact with Nextmv Cloud.
|
|
401
|
+
app_id : str
|
|
402
|
+
The application ID.
|
|
403
|
+
version_id : str
|
|
404
|
+
The version ID to link to the instance.
|
|
405
|
+
instance_id : str
|
|
406
|
+
The instance ID to update.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
in_progress(f"Updating instance [magenta]{instance_id}[/magenta] to use version [magenta]{version_id}[/magenta]...")
|
|
410
|
+
cloud_app.update_instance(id=instance_id, version_id=version_id)
|
|
359
411
|
success(
|
|
360
|
-
f"
|
|
412
|
+
f"Instance [magenta]{instance_id}[/magenta] updated to use version [magenta]{version_id}[/magenta] "
|
|
413
|
+
f"for application [magenta]{app_id}[/magenta]."
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def _create_instance(
|
|
418
|
+
cloud_app: Application,
|
|
419
|
+
app_id: str,
|
|
420
|
+
version_id: str,
|
|
421
|
+
instance_id: str,
|
|
422
|
+
now: datetime,
|
|
423
|
+
) -> None:
|
|
424
|
+
"""
|
|
425
|
+
Create a new instance linked to a specific version.
|
|
426
|
+
|
|
427
|
+
Parameters
|
|
428
|
+
----------
|
|
429
|
+
cloud_app : Application
|
|
430
|
+
The cloud application object to interact with Nextmv Cloud.
|
|
431
|
+
app_id : str
|
|
432
|
+
The application ID.
|
|
433
|
+
version_id : str
|
|
434
|
+
The version ID to link to the new instance.
|
|
435
|
+
instance_id : str
|
|
436
|
+
The instance ID to create.
|
|
437
|
+
now : datetime
|
|
438
|
+
The current datetime, used for the instance description.
|
|
439
|
+
"""
|
|
440
|
+
|
|
441
|
+
in_progress(f"Creating a new instance with ID [magenta]{instance_id}[/magenta]...")
|
|
442
|
+
instance_description = f"Instance created automatically from push at {now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
443
|
+
instance = cloud_app.new_instance(
|
|
444
|
+
version_id=version_id,
|
|
445
|
+
id=instance_id,
|
|
446
|
+
description=instance_description,
|
|
447
|
+
)
|
|
448
|
+
success(
|
|
449
|
+
f"New instance [magenta]{instance.id}[/magenta] created using version [magenta]{version_id}[/magenta] "
|
|
450
|
+
f"for application [magenta]{app_id}[/magenta]."
|
|
361
451
|
)
|