nextmv 1.0.0.dev4__py3-none-any.whl → 1.0.0.dev5__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/_serialization.py +1 -1
- nextmv/cli/cloud/acceptance/create.py +12 -12
- nextmv/cli/cloud/app/push.py +294 -204
- nextmv/cli/confirm.py +5 -3
- nextmv/cloud/__init__.py +0 -38
- nextmv/cloud/acceptance_test.py +1 -65
- nextmv/cloud/account.py +1 -6
- nextmv/cloud/application/__init__.py +2 -0
- nextmv/cloud/application/_batch_scenario.py +2 -17
- nextmv/cloud/application/_instance.py +1 -1
- nextmv/cloud/application/_managed_input.py +1 -1
- nextmv/cloud/application/_run.py +8 -1
- nextmv/cloud/application/_shadow.py +1 -1
- nextmv/cloud/application/_switchback.py +1 -1
- nextmv/cloud/application/_version.py +1 -1
- nextmv/cloud/client.py +1 -1
- nextmv/default_app/main.py +4 -6
- nextmv/deprecated.py +5 -3
- nextmv/input.py +0 -52
- nextmv/local/executor.py +83 -3
- nextmv/local/geojson_handler.py +1 -1
- nextmv/local/runner.py +1 -1
- nextmv/manifest.py +11 -7
- nextmv/model.py +2 -2
- nextmv/options.py +10 -255
- nextmv/output.py +57 -83
- nextmv/run.py +13 -13
- nextmv/status.py +1 -51
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev5.dist-info}/METADATA +1 -1
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev5.dist-info}/RECORD +36 -36
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev5.dist-info}/WHEEL +0 -0
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev5.dist-info}/entry_points.txt +0 -0
- {nextmv-1.0.0.dev4.dist-info → nextmv-1.0.0.dev5.dist-info}/licenses/LICENSE +0 -0
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,42 @@ 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
|
-
|
|
132
|
+
# We cannot create and update an instance at the same time.
|
|
133
|
+
update_defined = update_instance_id is not None and update_instance_id != ""
|
|
134
|
+
create_defined = create_instance_id is not None and create_instance_id != ""
|
|
135
|
+
if update_defined and create_defined:
|
|
136
|
+
error("Cannot use --update-instance-id and --create-instance-id at the same time.")
|
|
204
137
|
|
|
205
|
-
|
|
206
|
-
$ [dim]nextmv cloud app push --app-id hare-app \\
|
|
207
|
-
--version-id v1.0.0 \\
|
|
208
|
-
--version-name "Release 1.0.0" \\
|
|
209
|
-
--version-description "First stable release" \\
|
|
210
|
-
--instance-id inst-1 \\
|
|
211
|
-
--instance-name "Production Instance" \\
|
|
212
|
-
--instance-description "Main deployment" \\
|
|
213
|
-
--update-default-instance-yes[/dim]
|
|
214
|
-
"""
|
|
138
|
+
cloud_app = build_app(app_id=app_id, profile=profile)
|
|
215
139
|
|
|
216
|
-
|
|
217
|
-
|
|
140
|
+
# We cannot update an instance that does not exist.
|
|
141
|
+
if update_defined and not cloud_app.instance_exists(instance_id=update_instance_id):
|
|
142
|
+
error(
|
|
143
|
+
f"Used option --update-instance-id but the instance {update_instance_id} does not exist. "
|
|
144
|
+
"Use --create-instance-id instead."
|
|
145
|
+
)
|
|
218
146
|
|
|
219
|
-
|
|
220
|
-
|
|
147
|
+
# We cannot create an instance that already exists.
|
|
148
|
+
if create_defined and cloud_app.instance_exists(instance_id=create_instance_id):
|
|
149
|
+
error(
|
|
150
|
+
f"Used option --create-instance-id but the instance {create_instance_id} already exists. "
|
|
151
|
+
"Use --update-instance-id instead."
|
|
152
|
+
)
|
|
221
153
|
|
|
222
|
-
|
|
154
|
+
# Do the normal push first.
|
|
223
155
|
loaded_manifest = Manifest.from_yaml(dirpath=manifest) if manifest is not None and manifest != "" else None
|
|
224
156
|
cloud_app.push(
|
|
225
157
|
manifest=loaded_manifest,
|
|
@@ -228,134 +160,292 @@ def push(
|
|
|
228
160
|
rich_print=True,
|
|
229
161
|
)
|
|
230
162
|
|
|
231
|
-
|
|
163
|
+
now = datetime.now(timezone.utc)
|
|
164
|
+
version_id, should_continue = _handle_version_creation(
|
|
232
165
|
cloud_app=cloud_app,
|
|
233
166
|
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
167
|
version_id=version_id,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
instance_id=instance_id,
|
|
242
|
-
instance_name=instance_name,
|
|
243
|
-
instance_description=instance_description,
|
|
168
|
+
version_yes=version_yes,
|
|
169
|
+
now=now,
|
|
244
170
|
)
|
|
245
|
-
|
|
171
|
+
if not should_continue:
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
# If the override for updating an instance was used, we update the instance
|
|
175
|
+
# and we are done.
|
|
176
|
+
if update_defined:
|
|
177
|
+
info("Used option --update-instance-id to link version to existing instance.", emoji=":bulb:")
|
|
178
|
+
_update_instance(
|
|
179
|
+
cloud_app=cloud_app,
|
|
180
|
+
app_id=app_id,
|
|
181
|
+
version_id=version_id,
|
|
182
|
+
instance_id=update_instance_id,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
# If the override for creating a new instance was used, we create the
|
|
188
|
+
# instance and we are done.
|
|
189
|
+
if create_defined:
|
|
190
|
+
info("Used option --create-instance-id to link version to new instance.", emoji=":bulb:")
|
|
191
|
+
_create_instance(
|
|
192
|
+
cloud_app=cloud_app,
|
|
193
|
+
app_id=app_id,
|
|
194
|
+
version_id=version_id,
|
|
195
|
+
instance_id=create_instance_id,
|
|
196
|
+
now=now,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
# If no overrides are used, we handle instance prompting.
|
|
202
|
+
_handle_instance_prompting(
|
|
246
203
|
cloud_app=cloud_app,
|
|
247
204
|
app_id=app_id,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
update_default_instance_yes=update_default_instance_yes,
|
|
251
|
-
update_default_instance_no=update_default_instance_no,
|
|
205
|
+
version_id=version_id,
|
|
206
|
+
now=now,
|
|
252
207
|
)
|
|
253
208
|
|
|
254
209
|
|
|
255
|
-
def
|
|
210
|
+
def _handle_version_creation(
|
|
256
211
|
cloud_app: Application,
|
|
257
212
|
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
213
|
version_id: str | None,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
214
|
+
version_yes: bool,
|
|
215
|
+
now: datetime,
|
|
216
|
+
) -> tuple[str, bool]:
|
|
217
|
+
"""
|
|
218
|
+
Handle the logic for version creation after pushing an application.
|
|
219
|
+
|
|
220
|
+
If a version ID is provided and exists, it is used directly. If not, the user is prompted (unless auto-confirmed)
|
|
221
|
+
to create a new version. If confirmed, a new version is created with an automatic description.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
cloud_app : Application
|
|
226
|
+
The cloud application object to interact with Nextmv Cloud.
|
|
227
|
+
app_id : str
|
|
228
|
+
The application ID.
|
|
229
|
+
version_id : str or None
|
|
230
|
+
The version ID to use or check for existence. If None or empty, a new version may be created.
|
|
231
|
+
version_yes : bool
|
|
232
|
+
Whether to skip the prompt and auto-create a new version.
|
|
233
|
+
now : datetime
|
|
234
|
+
The current datetime, used for version description.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
tuple[str, bool]
|
|
239
|
+
A tuple containing the version ID (empty string if not created) and a boolean indicating
|
|
240
|
+
whether to continue with subsequent steps (True if a version is selected or created, False otherwise).
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
# If the user provides a version, and it exists, we use it directly and we
|
|
244
|
+
# are done.
|
|
245
|
+
if version_id is not None and version_id != "":
|
|
246
|
+
exists = cloud_app.version_exists(version_id=version_id)
|
|
247
|
+
if exists:
|
|
248
|
+
error(
|
|
249
|
+
f"Version [magenta]{version_id}[/magenta] already exists for application [magenta]{app_id}[/magenta]."
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
return "", False
|
|
253
|
+
|
|
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 [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
289
|
|
|
321
|
-
|
|
322
|
-
|
|
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,
|
|
357
370
|
)
|
|
358
|
-
|
|
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,
|
|
385
|
+
)
|
|
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
|
)
|
nextmv/cli/confirm.py
CHANGED
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
from rich.prompt import Confirm
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def get_confirmation(msg: str) -> bool:
|
|
6
|
+
def get_confirmation(msg: str, default: bool = False) -> bool:
|
|
7
7
|
"""
|
|
8
8
|
Method to get a yes/no confirmation from the user.
|
|
9
9
|
|
|
@@ -11,6 +11,8 @@ def get_confirmation(msg: str) -> bool:
|
|
|
11
11
|
----------
|
|
12
12
|
msg : str
|
|
13
13
|
The message to display to the user.
|
|
14
|
+
default : bool, optional
|
|
15
|
+
The default value if the user just presses Enter. Default is False.
|
|
14
16
|
|
|
15
17
|
Returns
|
|
16
18
|
-------
|
|
@@ -21,11 +23,11 @@ def get_confirmation(msg: str) -> bool:
|
|
|
21
23
|
# If this is not an interactive terminal, do not ask for confirmation, to
|
|
22
24
|
# avoid hanging indefinitely waiting for a user response.
|
|
23
25
|
if not sys.stdin.isatty():
|
|
24
|
-
return
|
|
26
|
+
return default
|
|
25
27
|
|
|
26
28
|
return Confirm.ask(
|
|
27
29
|
msg,
|
|
28
|
-
default=
|
|
30
|
+
default=default,
|
|
29
31
|
case_sensitive=False,
|
|
30
32
|
show_default=True,
|
|
31
33
|
show_choices=True,
|