nextmv 1.0.0.dev1__tar.gz → 1.0.0.dev2__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 (213) hide show
  1. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/PKG-INFO +1 -1
  2. nextmv-1.0.0.dev2/nextmv/__about__.py +1 -0
  3. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/__init__.py +2 -0
  4. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/get.py +1 -1
  5. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/input_set/create.py +5 -3
  6. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/input_set/update.py +1 -1
  7. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/get.py +1 -1
  8. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/update.py +1 -1
  9. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/__init__.py +33 -0
  10. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/create.py +184 -0
  11. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/delete.py +68 -0
  12. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/get.py +61 -0
  13. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/list.py +63 -0
  14. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/metadata.py +66 -0
  15. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/start.py +43 -0
  16. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/stop.py +43 -0
  17. nextmv-1.0.0.dev2/nextmv/cli/cloud/shadow/update.py +95 -0
  18. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/options.py +14 -0
  19. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/__init__.py +5 -0
  20. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/__init__.py +2 -0
  21. nextmv-1.0.0.dev2/nextmv/cloud/application/_shadow.py +314 -0
  22. nextmv-1.0.0.dev2/nextmv/cloud/shadow.py +190 -0
  23. nextmv-1.0.0.dev1/nextmv/__about__.py +0 -1
  24. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/.gitignore +0 -0
  25. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/LICENSE +0 -0
  26. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/README.md +0 -0
  27. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/__entrypoint__.py +0 -0
  28. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/__init__.py +0 -0
  29. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/_serialization.py +0 -0
  30. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/base_model.py +0 -0
  31. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/CONTRIBUTING.md +0 -0
  32. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/__init__.py +0 -0
  33. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/__init__.py +0 -0
  34. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/create.py +0 -0
  35. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/delete.py +0 -0
  36. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/get.py +0 -0
  37. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/list.py +0 -0
  38. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/acceptance/update.py +0 -0
  39. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/account/__init__.py +0 -0
  40. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/account/create.py +0 -0
  41. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/account/delete.py +0 -0
  42. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/account/get.py +0 -0
  43. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/account/update.py +0 -0
  44. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/__init__.py +0 -0
  45. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/create.py +0 -0
  46. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/delete.py +0 -0
  47. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/exists.py +0 -0
  48. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/get.py +0 -0
  49. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/list.py +0 -0
  50. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/push.py +0 -0
  51. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/app/update.py +0 -0
  52. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/__init__.py +0 -0
  53. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/create.py +0 -0
  54. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/delete.py +0 -0
  55. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/list.py +0 -0
  56. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/metadata.py +0 -0
  57. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/batch/update.py +0 -0
  58. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/data/__init__.py +0 -0
  59. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/data/upload.py +0 -0
  60. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/ensemble/__init__.py +0 -0
  61. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/ensemble/create.py +0 -0
  62. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/ensemble/delete.py +0 -0
  63. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/ensemble/get.py +0 -0
  64. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/ensemble/update.py +0 -0
  65. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/input_set/__init__.py +0 -0
  66. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/input_set/get.py +0 -0
  67. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/input_set/list.py +0 -0
  68. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/__init__.py +0 -0
  69. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/create.py +0 -0
  70. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/delete.py +0 -0
  71. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/exists.py +0 -0
  72. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/get.py +0 -0
  73. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/list.py +0 -0
  74. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/instance/update.py +0 -0
  75. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/__init__.py +0 -0
  76. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/create.py +0 -0
  77. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/delete.py +0 -0
  78. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/get.py +0 -0
  79. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/list.py +0 -0
  80. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/managed_input/update.py +0 -0
  81. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/__init__.py +0 -0
  82. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/cancel.py +0 -0
  83. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/create.py +0 -0
  84. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/get.py +0 -0
  85. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/input.py +0 -0
  86. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/list.py +0 -0
  87. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/logs.py +0 -0
  88. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/metadata.py +0 -0
  89. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/run/track.py +0 -0
  90. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/__init__.py +0 -0
  91. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/create.py +0 -0
  92. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/delete.py +0 -0
  93. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/list.py +0 -0
  94. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/metadata.py +0 -0
  95. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/scenario/update.py +0 -0
  96. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/__init__.py +0 -0
  97. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/create.py +0 -0
  98. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/delete.py +0 -0
  99. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/get.py +0 -0
  100. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/secrets/list.py +0 -0
  101. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/upload/__init__.py +0 -0
  102. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/upload/create.py +0 -0
  103. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/__init__.py +0 -0
  104. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/create.py +0 -0
  105. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/delete.py +0 -0
  106. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/exists.py +0 -0
  107. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/get.py +0 -0
  108. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/list.py +0 -0
  109. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/cloud/version/update.py +0 -0
  110. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/community/__init__.py +0 -0
  111. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/community/clone.py +0 -0
  112. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/community/list.py +0 -0
  113. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/configuration/__init__.py +0 -0
  114. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/configuration/config.py +0 -0
  115. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/configuration/create.py +0 -0
  116. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/configuration/delete.py +0 -0
  117. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/configuration/list.py +0 -0
  118. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/main.py +0 -0
  119. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/message.py +0 -0
  120. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cli/version.py +0 -0
  121. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/acceptance_test.py +0 -0
  122. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/account.py +0 -0
  123. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_acceptance.py +0 -0
  124. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_batch_scenario.py +0 -0
  125. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_ensemble.py +0 -0
  126. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_input_set.py +0 -0
  127. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_instance.py +0 -0
  128. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_managed_input.py +0 -0
  129. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_run.py +0 -0
  130. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_secrets.py +0 -0
  131. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_utils.py +0 -0
  132. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/application/_version.py +0 -0
  133. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/assets.py +0 -0
  134. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/batch_experiment.py +0 -0
  135. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/client.py +0 -0
  136. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/ensemble.py +0 -0
  137. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/input_set.py +0 -0
  138. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/instance.py +0 -0
  139. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/integration.py +0 -0
  140. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/package.py +0 -0
  141. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/scenario.py +0 -0
  142. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/secrets.py +0 -0
  143. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/url.py +0 -0
  144. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/cloud/version.py +0 -0
  145. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/.gitignore +0 -0
  146. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/README.md +0 -0
  147. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/app.yaml +0 -0
  148. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/input.json +0 -0
  149. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/main.py +0 -0
  150. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/requirements.txt +0 -0
  151. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/src/__init__.py +0 -0
  152. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/default_app/src/visuals.py +0 -0
  153. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/deprecated.py +0 -0
  154. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/input.py +0 -0
  155. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/__init__.py +0 -0
  156. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/application.py +0 -0
  157. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/executor.py +0 -0
  158. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/geojson_handler.py +0 -0
  159. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/local.py +0 -0
  160. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/plotly_handler.py +0 -0
  161. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/local/runner.py +0 -0
  162. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/logger.py +0 -0
  163. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/manifest.py +0 -0
  164. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/model.py +0 -0
  165. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/options.py +0 -0
  166. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/output.py +0 -0
  167. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/polling.py +0 -0
  168. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/run.py +0 -0
  169. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/safe.py +0 -0
  170. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/nextmv/status.py +0 -0
  171. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/pyproject.toml +0 -0
  172. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/__init__.py +0 -0
  173. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cli/__init__.py +0 -0
  174. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cli/test_community.py +0 -0
  175. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cli/test_configuration.py +0 -0
  176. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cli/test_main.py +0 -0
  177. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cli/test_version.py +0 -0
  178. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/__init__.py +0 -0
  179. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/app.yaml +0 -0
  180. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/test_client.py +0 -0
  181. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/test_instance.py +0 -0
  182. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/test_package.py +0 -0
  183. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/cloud/test_scenario.py +0 -0
  184. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/local/__init__.py +0 -0
  185. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/local/test_application.py +0 -0
  186. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/local/test_executor.py +0 -0
  187. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/local/test_runner.py +0 -0
  188. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/__init__.py +0 -0
  189. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options1.py +0 -0
  190. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options2.py +0 -0
  191. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options3.py +0 -0
  192. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options4.py +0 -0
  193. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options5.py +0 -0
  194. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options6.py +0 -0
  195. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options7.py +0 -0
  196. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/scripts/options_deprecated.py +0 -0
  197. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_base_model.py +0 -0
  198. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_entrypoint/__init__.py +0 -0
  199. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_entrypoint/test_entrypoint.py +0 -0
  200. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_input.py +0 -0
  201. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_inputs/test_data.csv +0 -0
  202. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_inputs/test_data.json +0 -0
  203. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_inputs/test_data.txt +0 -0
  204. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_logger.py +0 -0
  205. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_manifest.py +0 -0
  206. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_model.py +0 -0
  207. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_options.py +0 -0
  208. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_output.py +0 -0
  209. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_polling.py +0 -0
  210. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_run.py +0 -0
  211. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_safe.py +0 -0
  212. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/tests/test_serialization.py +0 -0
  213. {nextmv-1.0.0.dev1 → nextmv-1.0.0.dev2}/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.dev1
3
+ Version: 1.0.0.dev2
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/
@@ -0,0 +1 @@
1
+ __version__ = "v1.0.0.dev2"
@@ -16,6 +16,7 @@ from nextmv.cli.cloud.managed_input import app as managed_input_app
16
16
  from nextmv.cli.cloud.run import app as run_app
17
17
  from nextmv.cli.cloud.scenario import app as scenario_app
18
18
  from nextmv.cli.cloud.secrets import app as secrets_app
19
+ from nextmv.cli.cloud.shadow import app as shadow_app
19
20
  from nextmv.cli.cloud.upload import app as upload_app
20
21
  from nextmv.cli.cloud.version import app as version_app
21
22
 
@@ -33,6 +34,7 @@ app.add_typer(managed_input_app, name="managed-input")
33
34
  app.add_typer(run_app, name="run")
34
35
  app.add_typer(scenario_app, name="scenario")
35
36
  app.add_typer(secrets_app, name="secrets")
37
+ app.add_typer(shadow_app, name="shadow")
36
38
  app.add_typer(upload_app, name="upload")
37
39
  app.add_typer(version_app, name="version")
38
40
 
@@ -48,7 +48,7 @@ def get(
48
48
  profile: ProfileOption = None,
49
49
  ) -> None:
50
50
  """
51
- Get a Nextmv Cloud batch experiment.
51
+ Get a Nextmv Cloud batch experiment, including its runs.
52
52
 
53
53
  Use the [code]--wait[/code] flag to wait for the batch experiment to
54
54
  complete, polling for results. Using the [code]--output[/code] flag will
@@ -72,7 +72,8 @@ def create(
72
72
  typer.Option(
73
73
  "--start-time",
74
74
  formats=["%Y-%m-%dT%H:%M:%S%z"],
75
- help="Start time for filtering runs. (example: [magenta]'2024-01-01T00:00:00Z'[/magenta])",
75
+ help="Start time for filtering runs in [magenta]RFC 3339[/magenta] format. "
76
+ "Example: [magenta]'2024-01-01T00:00:00Z'[/magenta]",
76
77
  metavar="START_TIME",
77
78
  ),
78
79
  ] = None,
@@ -81,7 +82,8 @@ def create(
81
82
  typer.Option(
82
83
  "--end-time",
83
84
  formats=["%Y-%m-%dT%H:%M:%S%z"],
84
- help="End time for filtering runs. (example: [magenta]'2024-01-01T00:00:00Z'[/magenta])",
85
+ help="End time for filtering runs in [magenta]RFC 3339[/magenta] format. "
86
+ "Example: [magenta]'2024-01-01T00:00:00Z'[/magenta]",
85
87
  metavar="END_TIME",
86
88
  ),
87
89
  ] = None,
@@ -99,7 +101,7 @@ def create(
99
101
  typer.Option(
100
102
  "--inputs",
101
103
  help="Inputs for the input set. Data should be valid [magenta]json[/magenta]. Object "
102
- "format: [magenta][{'id': 'id', 'name': 'name', 'description': 'description'}][/magenta].",
104
+ "format: [green][{'id': 'id', 'name': 'name', 'description': 'description'}][/green].",
103
105
  metavar="INPUTS",
104
106
  ),
105
107
  ] = None,
@@ -43,7 +43,7 @@ def update(
43
43
  typer.Option(
44
44
  "--inputs",
45
45
  help="Inputs for the input set. Data should be valid [magenta]json[/magenta]. Object "
46
- "format: [magenta][{'id': 'id', 'name': 'name', 'description': 'description'}][/magenta].",
46
+ "format: [green][{'id': 'id', 'name': 'name', 'description': 'description'}][/green].",
47
47
  metavar="INPUTS",
48
48
  ),
49
49
  ] = None,
@@ -48,7 +48,7 @@ def get(
48
48
  profile: ProfileOption = None,
49
49
  ) -> None:
50
50
  """
51
- Get a Nextmv Cloud scenario test.
51
+ Get a Nextmv Cloud scenario test, including its runs.
52
52
 
53
53
  Use the [code]--wait[/code] flag to wait for the scenario test to
54
54
  complete, polling for results. Using the [code]--output[/code] flag will
@@ -57,7 +57,7 @@ def update(
57
57
  "Pass multiple secrets by repeating the flag, or providing a list of objects. "
58
58
  "Allowed values for [magenta]type[/magenta] are: "
59
59
  f"{enum_values(SecretType)}. "
60
- "Object format: [magenta]{'type': type, 'location': location, 'value': value}[/magenta]. "
60
+ "Object format: [green]{'type': type, 'location': location, 'value': value}[/green]. "
61
61
  "This will replace all existing secrets in the collection.",
62
62
  metavar="SECRETS",
63
63
  ),
@@ -0,0 +1,33 @@
1
+ """
2
+ This module defines the cloud batch command tree for the Nextmv CLI.
3
+ """
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.cloud.shadow.create import app as create_app
8
+ from nextmv.cli.cloud.shadow.delete import app as delete_app
9
+ from nextmv.cli.cloud.shadow.get import app as get_app
10
+ from nextmv.cli.cloud.shadow.list import app as list_app
11
+ from nextmv.cli.cloud.shadow.metadata import app as metadata_app
12
+ from nextmv.cli.cloud.shadow.start import app as start_app
13
+ from nextmv.cli.cloud.shadow.stop import app as stop_app
14
+ from nextmv.cli.cloud.shadow.update import app as update_app
15
+
16
+ # Set up subcommand application.
17
+ app = typer.Typer()
18
+ app.add_typer(create_app)
19
+ app.add_typer(delete_app)
20
+ app.add_typer(get_app)
21
+ app.add_typer(list_app)
22
+ app.add_typer(metadata_app)
23
+ app.add_typer(start_app)
24
+ app.add_typer(stop_app)
25
+ app.add_typer(update_app)
26
+
27
+
28
+ @app.callback()
29
+ def callback() -> None:
30
+ """
31
+ Create and manage Nextmv Cloud shadow tests.
32
+ """
33
+ pass
@@ -0,0 +1,184 @@
1
+ """
2
+ This module defines the cloud shadow create command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from datetime import datetime
7
+ from typing import Annotated
8
+
9
+ import typer
10
+
11
+ from nextmv.cli.configuration.config import build_app
12
+ from nextmv.cli.message import error, in_progress, print_json
13
+ from nextmv.cli.options import AppIDOption, ProfileOption
14
+ from nextmv.cloud.shadow import StartEvents, TerminationEvents
15
+
16
+ # Set up subcommand application.
17
+ app = typer.Typer()
18
+
19
+
20
+ @app.command()
21
+ def create(
22
+ app_id: AppIDOption,
23
+ comparisons: Annotated[
24
+ str,
25
+ typer.Option(
26
+ "--comparisons",
27
+ "-c",
28
+ help="Object mapping baseline instance IDs to a list of comparison instance IDs. "
29
+ "Data should be valid [magenta]json[/magenta]. "
30
+ "Object format: [green]{'baseline_id1': ['comparison_id1', 'comparison_id2'], 'baseline_id2': ...}[/green]",
31
+ metavar="COMPARISONS",
32
+ ),
33
+ ],
34
+ termination_maximum_runs: Annotated[
35
+ int,
36
+ typer.Option(
37
+ "--termination-maximum-runs",
38
+ "-m",
39
+ help="Maximum number of runs for the shadow test termination condition. Must be at least 1.",
40
+ metavar="TERMINATION_MAXIMUM_RUNS",
41
+ ),
42
+ ],
43
+ description: Annotated[
44
+ str | None,
45
+ typer.Option(
46
+ "--description",
47
+ "-d",
48
+ help="Description of the shadow test.",
49
+ metavar="DESCRIPTION",
50
+ ),
51
+ ] = None,
52
+ name: Annotated[
53
+ str | None,
54
+ typer.Option(
55
+ "--name",
56
+ "-n",
57
+ help="Name of the shadow test. If not provided, the ID will be used as the name.",
58
+ metavar="NAME",
59
+ ),
60
+ ] = None,
61
+ shadow_test_id: Annotated[
62
+ str | None,
63
+ typer.Option(
64
+ "--shadow-test-id",
65
+ "-s",
66
+ help="ID for the shadow test. Will be generated if not provided.",
67
+ envvar="NEXTMV_SHADOW_TEST_ID",
68
+ metavar="SHADOW_TEST_ID",
69
+ ),
70
+ ] = None,
71
+ start_time: Annotated[
72
+ datetime | None,
73
+ typer.Option(
74
+ "--start-time",
75
+ "-r",
76
+ formats=["%Y-%m-%dT%H:%M:%S%z"],
77
+ help="Scheduled time for shadow test start in [magenta]RFC 3339[/magenta] format. "
78
+ "Example: [magenta]'2024-01-01T00:00:00Z'[/magenta]",
79
+ metavar="START_TIME",
80
+ ),
81
+ ] = None,
82
+ termination_time: Annotated[
83
+ datetime | None,
84
+ typer.Option(
85
+ "--termination-time",
86
+ "-t",
87
+ help="Scheduled time for shadow test end in [magenta]RFC 3339[/magenta] format. "
88
+ "Example: [magenta]'2024-01-01T00:00:00Z'[/magenta]",
89
+ formats=["%Y-%m-%dT%H:%M:%S%z"],
90
+ metavar="TERMINATION_TIME",
91
+ ),
92
+ ] = None,
93
+ profile: ProfileOption = None,
94
+ ) -> None:
95
+ """
96
+ Create a new Nextmv Cloud shadow test in draft mode.
97
+
98
+ Use the [code]--comparisons[/code] option to define how to set up instance
99
+ comparisons. The value should be valid [magenta]json[/magenta]. The keys of
100
+ the comparisons object are the baseline instance IDs, and the values
101
+ are the candidate lists of instance IDs to compare against the respective
102
+ baseline.
103
+
104
+ Here is an example comparisons object:
105
+ [green]{
106
+ "baseline-instance-1": ["candidate-instance-1", "candidate-instance-2"],
107
+ "baseline-instance-2": ["candidate-instance-3"]
108
+ }[/green]
109
+
110
+ You may specify the [code]--start-time[/code] option to make the shadow
111
+ test start at a specific time. Alternatively, you may use the
112
+ [code]nextmv cloud shadow start[/code] command to start the test.
113
+
114
+ The [code]--termination-maximum-runs[/code] option is required and provides
115
+ control over when the shadow test should terminate, after said number of
116
+ runs. Alternatively, you may specify the [code]--termination-time[/code]
117
+ option or use the [code]nextmv cloud shadow stop[/code] command to stop the
118
+ test
119
+
120
+ [bold][underline]Examples[/underline][/bold]
121
+
122
+ - Create a shadow test with a baseline and two candidate instances:
123
+ $ [green]COMPARISONS='{
124
+ "fluffy-bunny-baseline": [
125
+ "hopping-candidate-ears",
126
+ "speedy-cottontail"
127
+ ]
128
+ }'
129
+ nextmv cloud shadow create --app-id hare-app --shadow-test-id bunny-hop-shadow --name "Bunny Hop Showdown" \\
130
+ --comparisons "$COMPARISONS" --termination-maximum-runs 100[/green]
131
+
132
+ - Create a shadow test with multiple baselines and candidates:
133
+ $ [green]COMPARISONS='{
134
+ "fluffy-bunny-baseline": [
135
+ "hopping-candidate-ears"
136
+ ],
137
+ "wise-old-rabbit": [
138
+ "burrow-master"
139
+ ]
140
+ }'
141
+ nextmv cloud shadow create --app-id hare-app --shadow-test-id warren-race --name "Warren Race Test" \\
142
+ --comparisons "$COMPARISONS" --termination-maximum-runs 50[/green]
143
+
144
+ - Create a shadow test with a scheduled start and termination time:
145
+ $ [green]COMPARISONS='{
146
+ "fluffy-bunny-baseline": [
147
+ "hopping-candidate-ears"
148
+ ]
149
+ }'
150
+ nextmv cloud shadow create --app-id hare-app --shadow-test-id sunrise-hop --name "Sunrise Hop Test" \\
151
+ --comparisons "$COMPARISONS" --start-time '2026-01-23T10:00:00Z' \\
152
+ --termination-time '2026-01-23T18:00:00Z' --termination-maximum-runs 20[/green]
153
+
154
+ - Create a shadow test with a description:
155
+ $ [green]COMPARISONS='{
156
+ "fluffy-bunny-baseline": [
157
+ "hopping-candidate-ears"
158
+ ]
159
+ }'
160
+ nextmv cloud shadow create --app-id hare-app --shadow-test-id carrot-compare --name "Carrot Comparison" \\
161
+ --description "Testing cool bunnies" --comparisons "$COMPARISONS" --termination-maximum-runs 10[/green]
162
+ """
163
+
164
+ cloud_app = build_app(app_id=app_id, profile=profile)
165
+
166
+ try:
167
+ comparisons_dict = json.loads(comparisons)
168
+ except json.JSONDecodeError as e:
169
+ error(f"Invalid comparisons format: [magenta]{comparisons}[/magenta]. Error: {e}")
170
+
171
+ in_progress(msg="Creating shadow test...")
172
+ shadow_test = cloud_app.new_shadow_test(
173
+ comparisons=comparisons_dict,
174
+ termination_events=TerminationEvents(
175
+ maximum_runs=termination_maximum_runs,
176
+ time=termination_time,
177
+ ),
178
+ shadow_test_id=shadow_test_id,
179
+ name=name,
180
+ description=description,
181
+ start_events=StartEvents(time=start_time) if start_time is not None else None,
182
+ )
183
+
184
+ print_json(shadow_test.to_dict())
@@ -0,0 +1,68 @@
1
+ """
2
+ This module defines the cloud shadow delete command for the Nextmv CLI.
3
+ """
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+ from rich.prompt import Confirm
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import info, success
12
+ from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def delete(
20
+ app_id: AppIDOption,
21
+ shadow_test_id: ShadowTestIDOption,
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 shadow test.
34
+
35
+ This action is permanent and cannot be undone. The shadow test and all
36
+ associated data, including runs, will be deleted. Use the [code]--yes[/code]
37
+ flag to skip the confirmation prompt.
38
+
39
+ [bold][underline]Examples[/underline][/bold]
40
+
41
+ - Delete the shadow test with the ID [magenta]hop-analysis[/magenta] from application
42
+ [magenta]hare-app[/magenta].
43
+ $ [green]nextmv cloud shadow delete --app-id hare-app --shadow-test-id hop-analysis[/green]
44
+
45
+ - Delete the shadow test without confirmation prompt.
46
+ $ [green]nextmv cloud shadow delete --app-id hare-app --shadow-test-id carrot-routes --yes[/green]
47
+ """
48
+
49
+ if not yes:
50
+ confirm = Confirm.ask(
51
+ f"Are you sure you want to delete shadow test [magenta]{shadow_test_id}[/magenta] "
52
+ f"from application [magenta]{app_id}[/magenta]? This action cannot be undone.",
53
+ default=False,
54
+ )
55
+
56
+ if not confirm:
57
+ info(
58
+ msg=f"Shadow test [magenta]{shadow_test_id}[/magenta] will not be deleted.",
59
+ emoji=":bulb:",
60
+ )
61
+ return
62
+
63
+ cloud_app = build_app(app_id=app_id, profile=profile)
64
+ cloud_app.delete_shadow_test(shadow_test_id=shadow_test_id)
65
+ success(
66
+ f"Shadow test [magenta]{shadow_test_id}[/magenta] deleted successfully "
67
+ f"from application [magenta]{app_id}[/magenta]."
68
+ )
@@ -0,0 +1,61 @@
1
+ """
2
+ This module defines the cloud shadow get command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from typing import Annotated
7
+
8
+ import typer
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import in_progress, print_json, success
12
+ from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def get(
20
+ app_id: AppIDOption,
21
+ shadow_test_id: ShadowTestIDOption,
22
+ output: Annotated[
23
+ str | None,
24
+ typer.Option(
25
+ "--output",
26
+ "-o",
27
+ help="Saves the results to this location.",
28
+ metavar="OUTPUT_PATH",
29
+ ),
30
+ ] = None,
31
+ profile: ProfileOption = None,
32
+ ) -> None:
33
+ """
34
+ Get a Nextmv Cloud shadow test, including its runs.
35
+
36
+ [bold][underline]Examples[/underline][/bold]
37
+
38
+ - Get the shadow test with ID [magenta]carrot-optimization[/magenta] from application
39
+ [magenta]hare-app[/magenta].
40
+ $ [green]nextmv cloud shadow get --app-id hare-app --shadow-test-id carrot-optimization[/green]
41
+
42
+ - Get the shadow test using a specific profile.
43
+ $ [green]nextmv cloud shadow get --app-id hare-app --shadow-test-id lettuce-routes --profile prod[/green]
44
+ """
45
+
46
+ cloud_app = build_app(app_id=app_id, profile=profile)
47
+ in_progress(msg="Getting shadow test...")
48
+ shadow_test = cloud_app.shadow_test(shadow_test_id=shadow_test_id)
49
+
50
+ shadow_test_dict = shadow_test.to_dict()
51
+
52
+ # Handle output
53
+ if output is not None and output != "":
54
+ with open(output, "w") as f:
55
+ json.dump(shadow_test_dict, f, indent=2)
56
+
57
+ success(msg=f"Shadow test output saved to [magenta]{output}[/magenta].")
58
+
59
+ return
60
+
61
+ print_json(shadow_test_dict)
@@ -0,0 +1,63 @@
1
+ """
2
+ This module defines the cloud shadow list command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from typing import Annotated
7
+
8
+ import typer
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import in_progress, print_json, success
12
+ from nextmv.cli.options import AppIDOption, ProfileOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def list(
20
+ app_id: AppIDOption,
21
+ output: Annotated[
22
+ str | None,
23
+ typer.Option(
24
+ "--output",
25
+ "-o",
26
+ help="Saves the list of shadow tests to this location.",
27
+ metavar="OUTPUT_PATH",
28
+ ),
29
+ ] = None,
30
+ profile: ProfileOption = None,
31
+ ) -> None:
32
+ """
33
+ List all Nextmv Cloud shadow tests for an application.
34
+
35
+ This command retrieves all shadow tests associated with the specified
36
+ application.
37
+
38
+ [bold][underline]Examples[/underline][/bold]
39
+
40
+ - List all shadow tests for application [magenta]hare-app[/magenta].
41
+ $ [green]nextmv cloud shadow list --app-id hare-app[/green]
42
+
43
+ - List all shadow tests and save to a file.
44
+ $ [green]nextmv cloud shadow list --app-id hare-app --output tests.json[/green]
45
+
46
+ - List all shadow tests using a specific profile.
47
+ $ [green]nextmv cloud shadow list --app-id hare-app --profile prod[/green]
48
+ """
49
+
50
+ cloud_app = build_app(app_id=app_id, profile=profile)
51
+ in_progress(msg="Listing shadow tests...")
52
+ shadow_tests = cloud_app.list_shadow_tests()
53
+ shadow_tests_dict = [test.to_dict() for test in shadow_tests]
54
+
55
+ if output is not None and output != "":
56
+ with open(output, "w") as f:
57
+ json.dump(shadow_tests_dict, f, indent=2)
58
+
59
+ success(msg=f"Shadow tests list saved to [magenta]{output}[/magenta].")
60
+
61
+ return
62
+
63
+ print_json(shadow_tests_dict)
@@ -0,0 +1,66 @@
1
+ """
2
+ This module defines the cloud shadow metadata command for the Nextmv CLI.
3
+ """
4
+
5
+ import json
6
+ from typing import Annotated
7
+
8
+ import typer
9
+
10
+ from nextmv.cli.configuration.config import build_app
11
+ from nextmv.cli.message import in_progress, print_json, success
12
+ from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
13
+
14
+ # Set up subcommand application.
15
+ app = typer.Typer()
16
+
17
+
18
+ @app.command()
19
+ def metadata(
20
+ app_id: AppIDOption,
21
+ shadow_test_id: ShadowTestIDOption,
22
+ output: Annotated[
23
+ str | None,
24
+ typer.Option(
25
+ "--output",
26
+ "-o",
27
+ help="Saves the shadow test metadata to this location.",
28
+ metavar="OUTPUT_PATH",
29
+ ),
30
+ ] = None,
31
+ profile: ProfileOption = None,
32
+ ) -> None:
33
+ """
34
+ Get metadata for a Nextmv Cloud shadow test.
35
+
36
+ This command retrieves metadata for a specific shadow test, including
37
+ status, creation date, and other high-level information without the full
38
+ run details.
39
+
40
+ [bold][underline]Examples[/underline][/bold]
41
+
42
+ - Get metadata for shadow test [magenta]bunny-warren-optimization[/magenta] from application
43
+ [magenta]hare-app[/magenta].
44
+ $ [green]nextmv cloud shadow metadata --app-id hare-app --shadow-test-id bunny-warren-optimization[/green]
45
+
46
+ - Get metadata and save to a file.
47
+ $ [green]nextmv cloud shadow metadata --app-id hare-app --shadow-test-id lettuce-delivery \\
48
+ --output metadata.json[/green]
49
+
50
+ - Get metadata using a specific profile.
51
+ $ [green]nextmv cloud shadow metadata --app-id hare-app --shadow-test-id hop-schedule --profile prod[/green]
52
+ """
53
+
54
+ cloud_app = build_app(app_id=app_id, profile=profile)
55
+ in_progress(msg="Getting shadow test metadata...")
56
+ shadow_metadata = cloud_app.shadow_test_metadata(shadow_test_id=shadow_test_id)
57
+ shadow_metadata_dict = shadow_metadata.to_dict()
58
+
59
+ if output is not None and output != "":
60
+ with open(output, "w") as f:
61
+ json.dump(shadow_metadata_dict, f, indent=2)
62
+
63
+ success(msg=f"Shadow test metadata saved to [magenta]{output}[/magenta].")
64
+ return
65
+
66
+ print_json(shadow_metadata_dict)
@@ -0,0 +1,43 @@
1
+ """
2
+ This module defines the cloud shadow start command for the Nextmv CLI.
3
+ """
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.configuration.config import build_app
8
+ from nextmv.cli.message import in_progress, success
9
+ from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
10
+
11
+ # Set up subcommand application.
12
+ app = typer.Typer()
13
+
14
+
15
+ @app.command()
16
+ def start(
17
+ app_id: AppIDOption,
18
+ shadow_test_id: ShadowTestIDOption,
19
+ profile: ProfileOption = None,
20
+ ) -> None:
21
+ """
22
+ Starts a Nextmv Cloud shadow test.
23
+
24
+ Before starting a shadow test, it must be created in draft state. You may
25
+ use the [code]nextmv cloud shadow create[/code] command to create a new
26
+ shadow test. Alternatively, define a [code]--start-time[/code] when using
27
+ the [code]nextmv cloud shadow create[/code] command to have the shadow test
28
+ start automatically at a specific time.
29
+
30
+ [bold][underline]Examples[/underline][/bold]
31
+
32
+ - Start the shadow test with the ID [magenta]hop-analysis[/magenta] from application
33
+ [magenta]hare-app[/magenta].
34
+ $ [green]nextmv cloud shadow start --app-id hare-app --shadow-test-id hop-analysis[/green]
35
+ """
36
+
37
+ in_progress(msg="Starting shadow test...")
38
+ cloud_app = build_app(app_id=app_id, profile=profile)
39
+ cloud_app.start_shadow_test(shadow_test_id=shadow_test_id)
40
+ success(
41
+ f"Shadow test [magenta]{shadow_test_id}[/magenta] started successfully "
42
+ f"in application [magenta]{app_id}[/magenta]."
43
+ )
@@ -0,0 +1,43 @@
1
+ """
2
+ This module defines the cloud shadow stop command for the Nextmv CLI.
3
+ """
4
+
5
+ import typer
6
+
7
+ from nextmv.cli.configuration.config import build_app
8
+ from nextmv.cli.message import in_progress, success
9
+ from nextmv.cli.options import AppIDOption, ProfileOption, ShadowTestIDOption
10
+
11
+ # Set up subcommand application.
12
+ app = typer.Typer()
13
+
14
+
15
+ @app.command()
16
+ def stop(
17
+ app_id: AppIDOption,
18
+ shadow_test_id: ShadowTestIDOption,
19
+ profile: ProfileOption = None,
20
+ ) -> None:
21
+ """
22
+ Stops a Nextmv Cloud shadow test.
23
+
24
+ Before stopping a shadow test, it must be in a started state. You may
25
+ use the [code]nextmv cloud shadow start[/code] command to start
26
+ a shadow test. Alternatively, define a [code]--start-time[/code] when using
27
+ the [code]nextmv cloud shadow create[/code] command to have the shadow test
28
+ start automatically at a specific time.
29
+
30
+ [bold][underline]Examples[/underline][/bold]
31
+
32
+ - Start the shadow test with the ID [magenta]hop-analysis[/magenta] from application
33
+ [magenta]hare-app[/magenta].
34
+ $ [green]nextmv cloud shadow start --app-id hare-app --shadow-test-id hop-analysis[/green]
35
+ """
36
+
37
+ in_progress(msg="Starting shadow test...")
38
+ cloud_app = build_app(app_id=app_id, profile=profile)
39
+ cloud_app.start_shadow_test(shadow_test_id=shadow_test_id)
40
+ success(
41
+ f"Shadow test [magenta]{shadow_test_id}[/magenta] started successfully "
42
+ f"in application [magenta]{app_id}[/magenta]."
43
+ )