nextmv 1.0.0.dev4__tar.gz → 1.0.0.dev6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/PKG-INFO +3 -1
  2. nextmv-1.0.0.dev6/nextmv/__about__.py +1 -0
  3. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/__entrypoint__.py +1 -2
  4. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/__init__.py +0 -4
  5. nextmv-1.0.0.dev6/nextmv/cli/cloud/app/push.py +451 -0
  6. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/input_set/__init__.py +2 -0
  7. nextmv-1.0.0.dev6/nextmv/cli/cloud/input_set/delete.py +67 -0
  8. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/create.py +4 -9
  9. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/stop.py +14 -2
  10. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/stop.py +14 -2
  11. nextmv-1.0.0.dev6/nextmv/cli/community/clone.py +86 -0
  12. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/community/list.py +46 -116
  13. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/confirm.py +5 -3
  14. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/__init__.py +4 -38
  15. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/acceptance_test.py +1 -65
  16. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/account.py +1 -6
  17. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/__init__.py +1 -198
  18. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_batch_scenario.py +2 -17
  19. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_input_set.py +42 -6
  20. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_instance.py +1 -1
  21. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_managed_input.py +1 -1
  22. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_shadow.py +10 -4
  23. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_switchback.py +11 -2
  24. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_version.py +1 -1
  25. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/batch_experiment.py +3 -1
  26. nextmv-1.0.0.dev6/nextmv/cloud/community.py +441 -0
  27. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/shadow.py +25 -0
  28. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/deprecated.py +5 -3
  29. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/input.py +0 -52
  30. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/runner.py +1 -1
  31. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/options.py +11 -256
  32. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/output.py +0 -62
  33. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/run.py +1 -10
  34. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/status.py +1 -51
  35. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/pyproject.toml +2 -0
  36. nextmv-1.0.0.dev6/tests/README.md +31 -0
  37. nextmv-1.0.0.dev6/tests/integration/cloud/test_integration_cloud.py +575 -0
  38. nextmv-1.0.0.dev6/tests/scripts/__init__.py +0 -0
  39. nextmv-1.0.0.dev6/tests/test_entrypoint/__init__.py +0 -0
  40. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_entrypoint/test_entrypoint.py +4 -4
  41. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_options.py +1 -252
  42. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_run.py +2 -13
  43. nextmv-1.0.0.dev4/nextmv/__about__.py +0 -1
  44. nextmv-1.0.0.dev4/nextmv/cli/cloud/app/push.py +0 -361
  45. nextmv-1.0.0.dev4/nextmv/cli/community/clone.py +0 -272
  46. nextmv-1.0.0.dev4/tests/cli/test_community.py +0 -666
  47. nextmv-1.0.0.dev4/tests/scripts/options_deprecated.py +0 -8
  48. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/.gitignore +0 -0
  49. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/LICENSE +0 -0
  50. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/README.md +0 -0
  51. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/_serialization.py +0 -0
  52. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/base_model.py +0 -0
  53. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/CONTRIBUTING.md +0 -0
  54. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/__init__.py +0 -0
  55. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/__init__.py +0 -0
  56. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/__init__.py +0 -0
  57. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/create.py +0 -0
  58. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/delete.py +0 -0
  59. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/get.py +0 -0
  60. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/list.py +0 -0
  61. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/acceptance/update.py +0 -0
  62. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/account/__init__.py +0 -0
  63. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/account/create.py +0 -0
  64. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/account/delete.py +0 -0
  65. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/account/get.py +0 -0
  66. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/account/update.py +0 -0
  67. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/__init__.py +0 -0
  68. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/create.py +0 -0
  69. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/delete.py +0 -0
  70. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/exists.py +0 -0
  71. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/get.py +0 -0
  72. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/list.py +0 -0
  73. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/app/update.py +0 -0
  74. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/__init__.py +0 -0
  75. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/create.py +0 -0
  76. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/delete.py +0 -0
  77. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/get.py +0 -0
  78. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/list.py +0 -0
  79. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/metadata.py +0 -0
  80. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/batch/update.py +0 -0
  81. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/data/__init__.py +0 -0
  82. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/data/upload.py +0 -0
  83. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/__init__.py +0 -0
  84. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/create.py +0 -0
  85. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/delete.py +0 -0
  86. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/get.py +0 -0
  87. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/list.py +0 -0
  88. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/ensemble/update.py +0 -0
  89. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/input_set/create.py +0 -0
  90. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/input_set/get.py +0 -0
  91. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/input_set/list.py +0 -0
  92. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/input_set/update.py +0 -0
  93. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/__init__.py +0 -0
  94. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/create.py +0 -0
  95. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/delete.py +0 -0
  96. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/exists.py +0 -0
  97. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/get.py +0 -0
  98. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/list.py +0 -0
  99. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/instance/update.py +0 -0
  100. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/__init__.py +0 -0
  101. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/create.py +0 -0
  102. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/delete.py +0 -0
  103. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/get.py +0 -0
  104. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/list.py +0 -0
  105. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/managed_input/update.py +0 -0
  106. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/__init__.py +0 -0
  107. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/cancel.py +0 -0
  108. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/get.py +0 -0
  109. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/input.py +0 -0
  110. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/list.py +0 -0
  111. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/logs.py +0 -0
  112. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/metadata.py +0 -0
  113. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/run/track.py +0 -0
  114. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/__init__.py +0 -0
  115. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/create.py +0 -0
  116. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/delete.py +0 -0
  117. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/get.py +0 -0
  118. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/list.py +0 -0
  119. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/metadata.py +0 -0
  120. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/scenario/update.py +0 -0
  121. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/__init__.py +0 -0
  122. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/create.py +0 -0
  123. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/delete.py +0 -0
  124. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/get.py +0 -0
  125. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/list.py +0 -0
  126. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/secrets/update.py +0 -0
  127. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/__init__.py +0 -0
  128. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/create.py +0 -0
  129. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/delete.py +0 -0
  130. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/get.py +0 -0
  131. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/list.py +0 -0
  132. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/metadata.py +0 -0
  133. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/start.py +0 -0
  134. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/shadow/update.py +0 -0
  135. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/__init__.py +0 -0
  136. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/create.py +0 -0
  137. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/delete.py +0 -0
  138. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/get.py +0 -0
  139. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/list.py +0 -0
  140. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/metadata.py +0 -0
  141. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/start.py +0 -0
  142. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/switchback/update.py +0 -0
  143. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/upload/__init__.py +0 -0
  144. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/upload/create.py +0 -0
  145. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/__init__.py +0 -0
  146. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/create.py +0 -0
  147. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/delete.py +0 -0
  148. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/exists.py +0 -0
  149. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/get.py +0 -0
  150. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/list.py +0 -0
  151. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/cloud/version/update.py +0 -0
  152. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/community/__init__.py +0 -0
  153. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/configuration/__init__.py +0 -0
  154. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/configuration/config.py +0 -0
  155. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/configuration/create.py +0 -0
  156. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/configuration/delete.py +0 -0
  157. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/configuration/list.py +0 -0
  158. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/main.py +0 -0
  159. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/message.py +0 -0
  160. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/options.py +0 -0
  161. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cli/version.py +0 -0
  162. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_acceptance.py +0 -0
  163. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_ensemble.py +0 -0
  164. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_run.py +0 -0
  165. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_secrets.py +0 -0
  166. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/application/_utils.py +0 -0
  167. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/assets.py +0 -0
  168. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/client.py +0 -0
  169. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/ensemble.py +0 -0
  170. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/input_set.py +0 -0
  171. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/instance.py +0 -0
  172. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/integration.py +0 -0
  173. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/package.py +0 -0
  174. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/scenario.py +0 -0
  175. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/secrets.py +0 -0
  176. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/switchback.py +0 -0
  177. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/url.py +0 -0
  178. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/cloud/version.py +0 -0
  179. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/.gitignore +0 -0
  180. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/README.md +0 -0
  181. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/app.yaml +0 -0
  182. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/input.json +0 -0
  183. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/main.py +0 -0
  184. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/requirements.txt +0 -0
  185. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/src/__init__.py +0 -0
  186. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/default_app/src/visuals.py +0 -0
  187. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/__init__.py +0 -0
  188. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/application.py +0 -0
  189. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/executor.py +0 -0
  190. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/geojson_handler.py +0 -0
  191. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/local.py +0 -0
  192. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/local/plotly_handler.py +0 -0
  193. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/logger.py +0 -0
  194. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/manifest.py +0 -0
  195. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/model.py +0 -0
  196. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/polling.py +0 -0
  197. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/nextmv/safe.py +0 -0
  198. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/__init__.py +0 -0
  199. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cli/__init__.py +0 -0
  200. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cli/test_configuration.py +0 -0
  201. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cli/test_main.py +0 -0
  202. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cli/test_version.py +0 -0
  203. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/__init__.py +0 -0
  204. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/app.yaml +0 -0
  205. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/test_client.py +0 -0
  206. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/test_instance.py +0 -0
  207. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/test_package.py +0 -0
  208. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/cloud/test_scenario.py +0 -0
  209. {nextmv-1.0.0.dev4/tests/local → nextmv-1.0.0.dev6/tests/integration}/__init__.py +0 -0
  210. {nextmv-1.0.0.dev4/tests/scripts → nextmv-1.0.0.dev6/tests/integration/cloud}/__init__.py +0 -0
  211. {nextmv-1.0.0.dev4/tests/test_entrypoint → nextmv-1.0.0.dev6/tests/local}/__init__.py +0 -0
  212. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/local/test_application.py +0 -0
  213. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/local/test_executor.py +0 -0
  214. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/local/test_runner.py +0 -0
  215. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options1.py +0 -0
  216. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options2.py +0 -0
  217. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options3.py +0 -0
  218. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options4.py +0 -0
  219. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options5.py +0 -0
  220. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options6.py +0 -0
  221. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/scripts/options7.py +0 -0
  222. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_base_model.py +0 -0
  223. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_input.py +0 -0
  224. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_inputs/test_data.csv +0 -0
  225. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_inputs/test_data.json +0 -0
  226. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_inputs/test_data.txt +0 -0
  227. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_logger.py +0 -0
  228. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_manifest.py +0 -0
  229. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_model.py +0 -0
  230. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_output.py +0 -0
  231. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_polling.py +0 -0
  232. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_safe.py +0 -0
  233. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_serialization.py +0 -0
  234. {nextmv-1.0.0.dev4 → nextmv-1.0.0.dev6}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextmv
3
- Version: 1.0.0.dev4
3
+ Version: 1.0.0.dev6
4
4
  Summary: The all-purpose Python SDK for Nextmv
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
6
  Project-URL: Documentation, https://nextmv-py.docs.nextmv.io/en/latest/nextmv/
@@ -230,11 +230,13 @@ Provides-Extra: dev
230
230
  Requires-Dist: build>=1.0.3; extra == 'dev'
231
231
  Requires-Dist: folium>=0.20.0; extra == 'dev'
232
232
  Requires-Dist: mlflow>=2.19.0; extra == 'dev'
233
+ Requires-Dist: nextpipe>=0.6.0.dev0; extra == 'dev'
233
234
  Requires-Dist: nextroute>=1.11.1; extra == 'dev'
234
235
  Requires-Dist: openpyxl>=3.1.5; extra == 'dev'
235
236
  Requires-Dist: pandas>=2.2.3; extra == 'dev'
236
237
  Requires-Dist: plotly>=6.0.1; extra == 'dev'
237
238
  Requires-Dist: pydantic>=2.5.2; extra == 'dev'
239
+ Requires-Dist: pytest>=9.0.2; extra == 'dev'
238
240
  Requires-Dist: pyyaml>=6.0.1; extra == 'dev'
239
241
  Requires-Dist: requests>=2.31.0; extra == 'dev'
240
242
  Requires-Dist: ruff>=0.1.7; extra == 'dev'
@@ -0,0 +1 @@
1
+ __version__ = "v1.0.0.dev6"
@@ -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 = cloud.Manifest.from_yaml(".")
18
+ manifest = nextmv.Manifest.from_yaml(".")
20
19
 
21
20
  # Load the options from the manifest.
22
21
  options = manifest.extract_options()
@@ -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__
@@ -0,0 +1,451 @@
1
+ """
2
+ This module defines the cloud app push command for the Nextmv CLI.
3
+ """
4
+
5
+ import sys
6
+ from datetime import datetime, timezone
7
+ from typing import Annotated
8
+
9
+ import typer
10
+ from rich.prompt import Prompt
11
+
12
+ from nextmv.cli.configuration.config import build_app
13
+ from nextmv.cli.confirm import get_confirmation
14
+ from nextmv.cli.message import error, in_progress, info, success
15
+ from nextmv.cli.options import AppIDOption, ProfileOption
16
+ from nextmv.cloud.application import Application
17
+ from nextmv.manifest import Manifest
18
+
19
+ # Set up subcommand application.
20
+ app = typer.Typer()
21
+
22
+
23
+ @app.command()
24
+ def push(
25
+ app_id: AppIDOption,
26
+ app_dir: Annotated[
27
+ str | None,
28
+ typer.Option(
29
+ "--app-dir",
30
+ "-d",
31
+ help="The path to the application's root directory.",
32
+ metavar="APP_DIR",
33
+ ),
34
+ ] = ".",
35
+ manifest: Annotated[
36
+ str | None,
37
+ typer.Option(
38
+ "--manifest",
39
+ "-m",
40
+ help="Path to the application manifest file ([magenta]app.yaml[/magenta]).",
41
+ metavar="MANIFEST_PATH",
42
+ ),
43
+ ] = None,
44
+ # Options for version control.
45
+ version_id: Annotated[
46
+ str | None,
47
+ typer.Option(
48
+ "--version-id",
49
+ "-v",
50
+ help="Custom ID for version creation after app push. Automatically generated if not provided. "
51
+ "Activates --version-yes.",
52
+ metavar="VERSION_ID",
53
+ rich_help_panel="Version control",
54
+ ),
55
+ ] = None,
56
+ version_yes: Annotated[
57
+ bool,
58
+ typer.Option(
59
+ "--version-yes",
60
+ "-y",
61
+ help="Create a new version after push. Skips confirmation prompt. Useful for non-interactive sessions.",
62
+ rich_help_panel="Version control",
63
+ ),
64
+ ] = False,
65
+ # Options for instance control.
66
+ create_instance_id: Annotated[
67
+ str | None,
68
+ typer.Option(
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",
74
+ rich_help_panel="Instance control",
75
+ ),
76
+ ] = None,
77
+ update_instance_id: Annotated[
78
+ str | None,
79
+ typer.Option(
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",
85
+ rich_help_panel="Instance control",
86
+ ),
87
+ ] = None,
88
+ profile: ProfileOption = None,
89
+ ) -> None:
90
+ """
91
+ Push (deploy) a Nextmv application to Nextmv Cloud.
92
+
93
+ Use the --app-dir option to specify the path to your application's root
94
+ directory. By default, the current working directory is used.
95
+
96
+ You can also provide a custom manifest file using the --manifest option. If
97
+ not provided, the CLI will look for a file named
98
+ [magenta]app.yaml[/magenta] in the application's root.
99
+
100
+ By default, this command only pushes the app. After the push, you will be
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.
107
+
108
+ [bold][underline]Examples[/underline][/bold]
109
+
110
+ - Push an application, with ID [magenta]hare-app[/magenta], from the current directory.
111
+ $ [dim]nextmv cloud app push --app-id hare-app[/dim]
112
+
113
+ - Push an application, with ID [magenta]hare-app[/magenta], from the [magenta]./my-app[/magenta] directory.
114
+ $ [dim]nextmv cloud app push --app-id hare-app --app-dir ./my-app[/dim]
115
+
116
+ - Push an application, with ID [magenta]hare-app[/magenta], using a custom manifest file.
117
+ $ [dim]nextmv cloud app push --app-id hare-app --manifest ./custom-manifest.yaml[/dim]
118
+
119
+ - Push and automatically create a new version (no prompt).
120
+ $ [dim]nextmv cloud app push --app-id hare-app --version-yes[/dim]
121
+
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]
124
+
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]
127
+
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
+ """
131
+
132
+ cloud_app = build_app(app_id=app_id, profile=profile)
133
+
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
+ )
141
+
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
+ )
154
+
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
+ )
161
+
162
+ # Do the normal push first.
163
+ loaded_manifest = Manifest.from_yaml(dirpath=manifest) if manifest is not None and manifest != "" else None
164
+ cloud_app.push(
165
+ manifest=loaded_manifest,
166
+ app_dir=app_dir,
167
+ verbose=True,
168
+ rich_print=True,
169
+ )
170
+
171
+ now = datetime.now(timezone.utc)
172
+ version_id, should_continue = _handle_version_creation(
173
+ cloud_app=cloud_app,
174
+ app_id=app_id,
175
+ version_id=version_id,
176
+ version_yes=version_yes,
177
+ now=now,
178
+ )
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(
211
+ cloud_app=cloud_app,
212
+ app_id=app_id,
213
+ version_id=version_id,
214
+ now=now,
215
+ )
216
+
217
+
218
+ def _handle_version_creation(
219
+ cloud_app: Application,
220
+ app_id: str,
221
+ version_id: str | None,
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 != "":
254
+ info(
255
+ msg=f"Version [magenta]{version_id}[/magenta] does not exist. A new version will be created.",
256
+ emoji=":bulb:",
257
+ )
258
+
259
+ version_yes = True # Activate auto-confirm since user provided a version ID.
260
+
261
+ # If we are not auto-confirming version creation, ask the user.
262
+ if not version_yes:
263
+ should_create = get_confirmation(
264
+ msg=f"Do you want to create a new version for application [magenta]{app_id}[/magenta] now?",
265
+ default=True,
266
+ )
267
+
268
+ # If the user does not want to create a new version, we are done.
269
+ if not should_create:
270
+ info(
271
+ msg="Will not create a new version.",
272
+ emoji=":bulb:",
273
+ )
274
+ return "", False
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')}"
280
+ version = cloud_app.new_version(
281
+ id=version_id,
282
+ description=version_description,
283
+ )
284
+ version_id = version.id
285
+ success(f"New version [magenta]{version_id}[/magenta] created for application [magenta]{app_id}[/magenta].")
286
+
287
+ return version_id, True
288
+
289
+
290
+ def _handle_instance_prompting(
291
+ cloud_app: Application,
292
+ app_id: str,
293
+ version_id: str,
294
+ now: datetime,
295
+ ) -> None:
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
+
322
+ return
323
+
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 == "":
331
+ info(
332
+ msg="No instance ID provided. Skipping instance linking.",
333
+ emoji=":bulb:",
334
+ )
335
+ return
336
+
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
+ should_update = get_confirmation(
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,
347
+ )
348
+
349
+ if not should_update:
350
+ info(
351
+ msg=f"Will not update instance [magenta]{instance_id}[/magenta].",
352
+ emoji=":bulb:",
353
+ )
354
+ return
355
+
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,
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)
411
+ success(
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]."
451
+ )
@@ -5,6 +5,7 @@ This module defines the cloud input-set command tree for the Nextmv CLI.
5
5
  import typer
6
6
 
7
7
  from nextmv.cli.cloud.input_set.create import app as create_app
8
+ from nextmv.cli.cloud.input_set.delete import app as delete_app
8
9
  from nextmv.cli.cloud.input_set.get import app as get_app
9
10
  from nextmv.cli.cloud.input_set.list import app as list_app
10
11
  from nextmv.cli.cloud.input_set.update import app as update_app
@@ -12,6 +13,7 @@ from nextmv.cli.cloud.input_set.update import app as update_app
12
13
  # Set up subcommand application.
13
14
  app = typer.Typer()
14
15
  app.add_typer(create_app)
16
+ app.add_typer(delete_app)
15
17
  app.add_typer(get_app)
16
18
  app.add_typer(list_app)
17
19
  app.add_typer(update_app)
@@ -0,0 +1,67 @@
1
+ """
2
+ This module defines the cloud input-set delete command for the Nextmv CLI.
3
+ """
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from nextmv.cli.configuration.config import build_app
10
+ from nextmv.cli.confirm import get_confirmation
11
+ from nextmv.cli.message import info, success
12
+ from nextmv.cli.options import AppIDOption, InputSetIDOption, ProfileOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def delete(
20
+ app_id: AppIDOption,
21
+ input_set_id: InputSetIDOption,
22
+ yes: Annotated[
23
+ bool,
24
+ typer.Option(
25
+ "--yes",
26
+ "-y",
27
+ help="Agree to deletion confirmation prompt. Useful for non-interactive sessions.",
28
+ ),
29
+ ] = False,
30
+ profile: ProfileOption = None,
31
+ ) -> None:
32
+ """
33
+ Deletes a Nextmv Cloud input set.
34
+
35
+ This action is permanent and cannot be undone. The input set and all
36
+ associated data will be deleted. Use the --yes flag to skip the
37
+ confirmation prompt.
38
+
39
+ [bold][underline]Examples[/underline][/bold]
40
+
41
+ - Delete the input set with the ID [magenta]hop-analysis[/magenta] from application
42
+ [magenta]hare-app[/magenta].
43
+ $ [dim]nextmv cloud input-set delete --app-id hare-app --input-set-id hop-analysis[/dim]
44
+
45
+ - Delete the input set without confirmation prompt.
46
+ $ [dim]nextmv cloud input-set delete --app-id hare-app --input-set-id carrot-routes --yes[/dim]
47
+ """
48
+
49
+ if not yes:
50
+ confirm = get_confirmation(
51
+ f"Are you sure you want to delete input set [magenta]{input_set_id}[/magenta] "
52
+ f"from application [magenta]{app_id}[/magenta]? This action cannot be undone.",
53
+ )
54
+
55
+ if not confirm:
56
+ info(
57
+ msg=f"Input set [magenta]{input_set_id}[/magenta] will not be deleted.",
58
+ emoji=":bulb:",
59
+ )
60
+ return
61
+
62
+ cloud_app = build_app(app_id=app_id, profile=profile)
63
+ cloud_app.delete_input_set(input_set_id=input_set_id)
64
+ success(
65
+ f"Input set [magenta]{input_set_id}[/magenta] deleted successfully "
66
+ f"from application [magenta]{app_id}[/magenta]."
67
+ )
@@ -129,7 +129,7 @@ def create(
129
129
  metavar="INSTANCE_ID",
130
130
  rich_help_panel="Run configuration",
131
131
  ),
132
- ] = "latest",
132
+ ] = None,
133
133
  integration_id: Annotated[
134
134
  str | None,
135
135
  typer.Option(
@@ -240,12 +240,11 @@ def create(
240
240
  specify the instance with the --instance-id flag. These are the possible
241
241
  values for this flag:
242
242
 
243
+ - [yellow]unspecified[/yellow]: Run against the default instance of the
244
+ application. When an application is created, the default instance is [magenta]latest[/magenta].
243
245
  - [yellow]latest[/yellow]: uses the special [magenta]latest[/magenta]
244
246
  instance of the application. This corresponds to the latest pushed
245
- executable. This is the default behavior.
246
- - [yellow]default[/yellow]: if the application has a [italic]default[/italic]
247
- instance configured, then it uses that instance. Setting the flag's value
248
- to [magenta]''[/magenta] (empty string) has the same effect.
247
+ executable.
249
248
  - [yellow]<INSTANCE_ID>[/yellow]: uses the instance with the given ID.
250
249
 
251
250
  [bold][underline]Examples[/underline][/bold]
@@ -319,10 +318,6 @@ def create(
319
318
  )
320
319
  run_options = build_run_options(options)
321
320
 
322
- # Handles the default instance.
323
- if instance_id == "default":
324
- instance_id = ""
325
-
326
321
  # Start the run before deciding if we should poll or not.
327
322
  input_kwarg = resolve_input_kwarg(
328
323
  stdin=stdin,
@@ -2,11 +2,14 @@
2
2
  This module defines the cloud shadow stop command for the Nextmv CLI.
3
3
  """
4
4
 
5
+ from typing import Annotated
6
+
5
7
  import typer
6
8
 
7
9
  from nextmv.cli.configuration.config import build_app
8
- from nextmv.cli.message import in_progress, success
10
+ from nextmv.cli.message import enum_values, in_progress, success
9
11
  from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
12
+ from nextmv.cloud.shadow import StopIntent
10
13
 
11
14
  # Set up subcommand application.
12
15
  app = typer.Typer()
@@ -15,6 +18,15 @@ app = typer.Typer()
15
18
  @app.command()
16
19
  def stop(
17
20
  app_id: AppIDOption,
21
+ intent: Annotated[
22
+ StopIntent,
23
+ typer.Option(
24
+ "--intent",
25
+ "-i",
26
+ help=f"Intent for stopping the shadow test. Allowed values are: {enum_values(StopIntent)}.",
27
+ metavar="INTENT",
28
+ ),
29
+ ],
18
30
  shadow_test_id: ShadowTestIDOption,
19
31
  profile: ProfileOption = None,
20
32
  ) -> None:
@@ -34,7 +46,7 @@ def stop(
34
46
 
35
47
  in_progress(msg="Stopping shadow test...")
36
48
  cloud_app = build_app(app_id=app_id, profile=profile)
37
- cloud_app.stop_shadow_test(shadow_test_id=shadow_test_id)
49
+ cloud_app.stop_shadow_test(shadow_test_id=shadow_test_id, intent=StopIntent(intent))
38
50
  success(
39
51
  f"Shadow test [magenta]{shadow_test_id}[/magenta] stopped successfully "
40
52
  f"in application [magenta]{app_id}[/magenta]."