snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.0__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.
Files changed (251) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/{app → _app}/__main__.py +1 -1
  3. snowflake/cli/{app → _app}/cli_app.py +22 -13
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +15 -19
  5. snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
  6. snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
  7. snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
  8. snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
  9. snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
  10. snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
  11. snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
  12. snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
  13. snowflake/cli/{app → _app}/main_typer.py +2 -2
  14. snowflake/cli/{app → _app}/printing.py +2 -2
  15. snowflake/cli/_app/secret.py +9 -0
  16. snowflake/cli/{app → _app}/snow_connector.py +127 -61
  17. snowflake/cli/{app → _app}/telemetry.py +38 -7
  18. snowflake/cli/_app/version_check.py +74 -0
  19. snowflake/cli/{plugins → _plugins}/connection/commands.py +34 -11
  20. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  21. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  22. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  23. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  25. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  26. snowflake/cli/{plugins → _plugins}/git/commands.py +79 -26
  27. snowflake/cli/{plugins → _plugins}/git/manager.py +72 -17
  28. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  29. snowflake/cli/_plugins/helpers/commands.py +90 -0
  30. snowflake/cli/{plugins/notebook → _plugins/helpers}/plugin_spec.py +1 -1
  31. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  32. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  33. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +24 -9
  34. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +4 -4
  36. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +37 -18
  37. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
  38. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  39. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +5 -5
  40. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +1 -1
  41. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +29 -34
  42. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +114 -0
  43. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +252 -132
  44. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  45. snowflake/cli/_plugins/nativeapp/entities/application.py +878 -0
  46. snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
  47. snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -12
  48. snowflake/cli/_plugins/nativeapp/manager.py +415 -0
  49. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  50. snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +3 -0
  51. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +36 -20
  52. snowflake/cli/_plugins/nativeapp/run_processor.py +184 -0
  53. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
  54. snowflake/cli/_plugins/nativeapp/teardown_processor.py +70 -0
  55. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +262 -0
  56. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +20 -49
  57. snowflake/cli/_plugins/nativeapp/version/version_processor.py +98 -0
  58. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  59. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  60. snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
  61. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  62. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  63. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  64. snowflake/cli/{plugins → _plugins}/object/manager.py +43 -21
  65. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  66. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  67. snowflake/cli/_plugins/snowpark/common.py +268 -0
  68. snowflake/cli/{plugins → _plugins}/snowpark/models.py +2 -8
  69. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  71. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  72. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  73. snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
  74. snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
  75. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
  76. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  77. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  78. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  79. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  80. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  81. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  82. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  83. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  84. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  85. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  86. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  87. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  88. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  89. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  90. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  91. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  92. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  93. snowflake/cli/{plugins → _plugins}/stage/manager.py +62 -24
  94. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  95. snowflake/cli/_plugins/stage/utils.py +54 -0
  96. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +71 -62
  97. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +68 -70
  98. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  99. snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
  100. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
  101. snowflake/cli/_plugins/workspace/action_context.py +18 -0
  102. snowflake/cli/_plugins/workspace/commands.py +306 -0
  103. snowflake/cli/_plugins/workspace/manager.py +74 -0
  104. snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
  105. snowflake/cli/api/cli_global_context.py +152 -295
  106. snowflake/cli/api/commands/common.py +25 -0
  107. snowflake/cli/api/commands/decorators.py +19 -4
  108. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  109. snowflake/cli/api/commands/flags.py +143 -222
  110. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  111. snowflake/cli/api/commands/snow_typer.py +21 -11
  112. snowflake/cli/api/commands/utils.py +18 -0
  113. snowflake/cli/api/config.py +44 -12
  114. snowflake/cli/api/connections.py +216 -0
  115. snowflake/cli/api/console/abc.py +8 -3
  116. snowflake/cli/api/constants.py +11 -0
  117. snowflake/cli/api/entities/common.py +56 -0
  118. snowflake/cli/api/entities/utils.py +370 -0
  119. snowflake/cli/api/errno.py +1 -0
  120. snowflake/cli/api/exceptions.py +31 -5
  121. snowflake/cli/api/feature_flags.py +0 -1
  122. snowflake/cli/api/identifiers.py +45 -9
  123. snowflake/cli/api/metrics.py +92 -0
  124. snowflake/cli/api/project/definition.py +48 -6
  125. snowflake/cli/api/project/definition_conversion.py +400 -0
  126. snowflake/cli/api/project/definition_manager.py +16 -5
  127. snowflake/cli/api/project/project_verification.py +3 -3
  128. snowflake/cli/api/project/schemas/entities/common.py +91 -16
  129. snowflake/cli/api/project/schemas/entities/entities.py +37 -6
  130. snowflake/cli/api/project/schemas/project_definition.py +180 -49
  131. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  132. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  133. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
  134. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  135. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
  136. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  137. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
  138. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  139. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  140. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  141. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  142. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  143. snowflake/cli/api/project/util.py +23 -6
  144. snowflake/cli/api/rendering/jinja.py +14 -8
  145. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  146. snowflake/cli/api/rendering/sql_templates.py +56 -11
  147. snowflake/cli/api/rest_api.py +11 -5
  148. snowflake/cli/api/secure_path.py +16 -18
  149. snowflake/cli/api/secure_utils.py +90 -1
  150. snowflake/cli/api/sql_execution.py +47 -27
  151. snowflake/cli/api/utils/definition_rendering.py +45 -13
  152. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
  153. snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
  154. snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
  155. snowflake/cli/api/commands/project_initialisation.py +0 -65
  156. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  157. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  158. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  159. snowflake/cli/app/build_and_push.sh +0 -8
  160. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  161. snowflake/cli/plugins/nativeapp/init.py +0 -345
  162. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  163. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  164. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  165. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  166. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  167. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  168. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  169. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  170. snowflake/cli/plugins/snowpark/commands.py +0 -548
  171. snowflake/cli/plugins/snowpark/common.py +0 -307
  172. snowflake/cli/plugins/snowpark/manager.py +0 -109
  173. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  174. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  175. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  176. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  177. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  178. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  179. snowflake/cli/plugins/workspace/__init__.py +0 -13
  180. snowflake/cli/plugins/workspace/commands.py +0 -35
  181. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  182. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  183. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  184. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  185. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  186. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  187. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  188. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  189. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  190. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  191. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  192. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  193. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  194. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  195. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  196. /snowflake/cli/{app → _app}/__init__.py +0 -0
  197. /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
  198. /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
  199. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  200. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  201. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  202. /snowflake/cli/{app → _app}/constants.py +0 -0
  203. /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
  204. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  205. /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
  206. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  207. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  208. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  209. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  210. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  211. /snowflake/cli/{app → _app}/loggers.py +0 -0
  212. /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
  213. /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
  214. /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
  215. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  216. /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
  219. /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
  220. /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
  221. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  222. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  223. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  224. /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
  225. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  226. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  227. /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
  228. /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
  229. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  230. /snowflake/cli/{plugins/nativeapp/version → _plugins/object}/__init__.py +0 -0
  231. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  232. /snowflake/cli/{plugins/notebook → _plugins/snowpark}/__init__.py +0 -0
  233. /snowflake/cli/{plugins/object → _plugins/snowpark/package}/__init__.py +0 -0
  234. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  235. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  236. /snowflake/cli/{plugins/snowpark → _plugins/spcs/compute_pool}/__init__.py +0 -0
  237. /snowflake/cli/{plugins/snowpark/package → _plugins/spcs/image_registry}/__init__.py +0 -0
  238. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  239. /snowflake/cli/{plugins/spcs/compute_pool → _plugins/spcs/image_repository}/__init__.py +0 -0
  240. /snowflake/cli/{plugins/spcs/image_registry → _plugins/spcs/services}/__init__.py +0 -0
  241. /snowflake/cli/{plugins/spcs/image_repository → _plugins/sql}/__init__.py +0 -0
  242. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  243. /snowflake/cli/{plugins/spcs/jobs → _plugins/stage}/__init__.py +0 -0
  244. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  245. /snowflake/cli/{plugins/spcs/services → _plugins/streamlit}/__init__.py +0 -0
  246. /snowflake/cli/{plugins/sql → _plugins/workspace}/__init__.py +0 -0
  247. /snowflake/cli/{plugins/stage → api/project/schemas/entities}/__init__.py +0 -0
  248. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  249. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  250. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
  251. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -19,17 +19,17 @@ import logging
19
19
  from typing import Callable, Optional
20
20
 
21
21
  from click import ClickException
22
- from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
23
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
24
- from snowflake.cli.api.secure_path import SecurePath
25
- from snowflake.cli.api.sql_execution import SqlExecutionMixin
26
- from snowflake.cli.plugins.cortex.types import (
22
+ from snowflake.cli._plugins.cortex.types import (
27
23
  Language,
28
24
  Model,
29
25
  Question,
30
26
  SourceDocument,
31
27
  Text,
32
28
  )
29
+ from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
30
+ from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
31
+ from snowflake.cli.api.secure_path import SecurePath
32
+ from snowflake.cli.api.sql_execution import SqlExecutionMixin
33
33
  from snowflake.connector import ProgrammingError
34
34
  from snowflake.connector.cursor import DictCursor
35
35
 
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.cortex import commands
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.cortex import commands
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -18,10 +18,17 @@ import itertools
18
18
  import logging
19
19
  from os import path
20
20
  from pathlib import Path
21
- from typing import List, Optional
21
+ from typing import Dict, List, Optional
22
22
 
23
23
  import typer
24
24
  from click import ClickException
25
+ from snowflake.cli._plugins.git.manager import GitManager
26
+ from snowflake.cli._plugins.object.command_aliases import (
27
+ add_object_command_aliases,
28
+ scope_option,
29
+ )
30
+ from snowflake.cli._plugins.object.manager import ObjectManager
31
+ from snowflake.cli.api.commands.common import OnErrorType
25
32
  from snowflake.cli.api.commands.flags import (
26
33
  ExecuteVariablesOption,
27
34
  OnErrorOption,
@@ -34,13 +41,7 @@ from snowflake.cli.api.console.console import cli_console
34
41
  from snowflake.cli.api.constants import ObjectType
35
42
  from snowflake.cli.api.output.types import CollectionResult, CommandResult, QueryResult
36
43
  from snowflake.cli.api.utils.path_utils import is_stage_path
37
- from snowflake.cli.plugins.git.manager import GitManager
38
- from snowflake.cli.plugins.object.command_aliases import (
39
- add_object_command_aliases,
40
- scope_option,
41
- )
42
- from snowflake.cli.plugins.object.manager import ObjectManager
43
- from snowflake.cli.plugins.stage.manager import OnErrorType
44
+ from snowflake.connector import DictCursor
44
45
 
45
46
  app = SnowTyperFactory(
46
47
  name="git",
@@ -71,6 +72,7 @@ RepoPathArgument = typer.Argument(
71
72
  " For example: @my_repo/branches/main/"
72
73
  ),
73
74
  callback=_repo_path_argument_callback,
75
+ show_default=False,
74
76
  )
75
77
  add_object_command_aliases(
76
78
  app=app,
@@ -82,10 +84,12 @@ add_object_command_aliases(
82
84
  scope_option=scope_option(help_example="`list --in database my_db`"),
83
85
  )
84
86
 
87
+ from snowflake.cli.api.identifiers import FQN
88
+
85
89
 
86
- def _assure_repository_does_not_exist(om: ObjectManager, repository_name: str) -> None:
90
+ def _assure_repository_does_not_exist(om: ObjectManager, repository_name: FQN) -> None:
87
91
  if om.object_exists(
88
- object_type=ObjectType.GIT_REPOSITORY.value.cli_name, name=repository_name
92
+ object_type=ObjectType.GIT_REPOSITORY.value.cli_name, fqn=repository_name
89
93
  ):
90
94
  raise ClickException(f"Repository '{repository_name}' already exists")
91
95
 
@@ -95,14 +99,34 @@ def _validate_origin_url(url: str) -> None:
95
99
  raise ClickException("Url address should start with 'https'")
96
100
 
97
101
 
102
+ def _unique_new_object_name(
103
+ om: ObjectManager, object_type: ObjectType, proposed_fqn: FQN
104
+ ) -> str:
105
+ existing_objects: List[Dict] = om.show(
106
+ object_type=object_type.value.cli_name,
107
+ like=f"{proposed_fqn.name}%",
108
+ cursor_class=DictCursor,
109
+ ).fetchall()
110
+ existing_names = set(o["name"].upper() for o in existing_objects)
111
+
112
+ result = proposed_fqn.name
113
+ i = 1
114
+ while result.upper() in existing_names:
115
+ result = proposed_fqn.name + str(i)
116
+ i += 1
117
+ return result
118
+
119
+
98
120
  @app.command("setup", requires_connection=True)
99
121
  def setup(
100
- repository_name: str = RepoNameArgument,
122
+ repository_name: FQN = RepoNameArgument,
101
123
  **options,
102
124
  ) -> CommandResult:
103
125
  """
104
126
  Sets up a git repository object.
105
127
 
128
+ ## Usage notes
129
+
106
130
  You will be prompted for:
107
131
 
108
132
  * url - address of repository to be used for git clone operation
@@ -123,12 +147,29 @@ def setup(
123
147
  should_create_secret = False
124
148
  secret_name = None
125
149
  if secret_needed:
126
- secret_name = f"{repository_name}_secret"
127
- secret_name = typer.prompt(
128
- "Secret identifier (will be created if not exists)", default=secret_name
150
+ default_secret_name = (
151
+ FQN.from_string(f"{repository_name.name}_secret")
152
+ .set_schema(repository_name.schema)
153
+ .set_database(repository_name.database)
154
+ )
155
+ default_secret_name.set_name(
156
+ _unique_new_object_name(
157
+ om, object_type=ObjectType.SECRET, proposed_fqn=default_secret_name
158
+ ),
129
159
  )
160
+ secret_name = FQN.from_string(
161
+ typer.prompt(
162
+ "Secret identifier (will be created if not exists)",
163
+ default=default_secret_name.name,
164
+ )
165
+ )
166
+ if not secret_name.database:
167
+ secret_name.set_database(repository_name.database)
168
+ if not secret_name.schema:
169
+ secret_name.set_schema(repository_name.schema)
170
+
130
171
  if om.object_exists(
131
- object_type=ObjectType.SECRET.value.cli_name, name=secret_name
172
+ object_type=ObjectType.SECRET.value.cli_name, fqn=secret_name
132
173
  ):
133
174
  cli_console.step(f"Using existing secret '{secret_name}'")
134
175
  else:
@@ -137,10 +178,17 @@ def setup(
137
178
  secret_username = typer.prompt("username")
138
179
  secret_password = typer.prompt("password/token", hide_input=True)
139
180
 
140
- api_integration = f"{repository_name}_api_integration"
141
- api_integration = typer.prompt(
142
- "API integration identifier (will be created if not exists)",
143
- default=api_integration,
181
+ # API integration is an account-level object
182
+ api_integration = FQN.from_string(f"{repository_name.name}_api_integration")
183
+ api_integration.set_name(
184
+ typer.prompt(
185
+ "API integration identifier (will be created if not exists)",
186
+ default=_unique_new_object_name(
187
+ om,
188
+ object_type=ObjectType.INTEGRATION,
189
+ proposed_fqn=api_integration,
190
+ ),
191
+ )
144
192
  )
145
193
 
146
194
  if should_create_secret:
@@ -150,7 +198,7 @@ def setup(
150
198
  cli_console.step(f"Secret '{secret_name}' successfully created.")
151
199
 
152
200
  if not om.object_exists(
153
- object_type=ObjectType.INTEGRATION.value.cli_name, name=api_integration
201
+ object_type=ObjectType.INTEGRATION.value.cli_name, fqn=api_integration
154
202
  ):
155
203
  manager.create_api_integration(
156
204
  name=api_integration,
@@ -177,7 +225,7 @@ def setup(
177
225
  requires_connection=True,
178
226
  )
179
227
  def list_branches(
180
- repository_name: str = RepoNameArgument,
228
+ repository_name: FQN = RepoNameArgument,
181
229
  like=like_option(
182
230
  help_example='`list-branches --like "%_test"` lists all branches that end with "_test"'
183
231
  ),
@@ -186,7 +234,9 @@ def list_branches(
186
234
  """
187
235
  List all branches in the repository.
188
236
  """
189
- return QueryResult(GitManager().show_branches(repo_name=repository_name, like=like))
237
+ return QueryResult(
238
+ GitManager().show_branches(repo_name=repository_name.identifier, like=like)
239
+ )
190
240
 
191
241
 
192
242
  @app.command(
@@ -194,7 +244,7 @@ def list_branches(
194
244
  requires_connection=True,
195
245
  )
196
246
  def list_tags(
197
- repository_name: str = RepoNameArgument,
247
+ repository_name: FQN = RepoNameArgument,
198
248
  like=like_option(
199
249
  help_example='`list-tags --like "v2.0%"` lists all tags that start with "v2.0"'
200
250
  ),
@@ -203,7 +253,9 @@ def list_tags(
203
253
  """
204
254
  List all tags in the repository.
205
255
  """
206
- return QueryResult(GitManager().show_tags(repo_name=repository_name, like=like))
256
+ return QueryResult(
257
+ GitManager().show_tags(repo_name=repository_name.identifier, like=like)
258
+ )
207
259
 
208
260
 
209
261
  @app.command(
@@ -228,13 +280,13 @@ def list_files(
228
280
  requires_connection=True,
229
281
  )
230
282
  def fetch(
231
- repository_name: str = RepoNameArgument,
283
+ repository_name: FQN = RepoNameArgument,
232
284
  **options,
233
285
  ) -> CommandResult:
234
286
  """
235
287
  Fetch changes from origin to Snowflake repository.
236
288
  """
237
- return QueryResult(GitManager().fetch(repo_name=repository_name))
289
+ return QueryResult(GitManager().fetch(fqn=repository_name))
238
290
 
239
291
 
240
292
  @app.command(
@@ -245,6 +297,7 @@ def copy(
245
297
  repository_path: str = RepoPathArgument,
246
298
  destination_path: str = typer.Argument(
247
299
  help="Target path for copy operation. Should be a path to a directory on remote stage or local file system.",
300
+ show_default=False,
248
301
  ),
249
302
  parallel: int = typer.Option(
250
303
  4,
@@ -14,43 +14,64 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from pathlib import Path
17
+ from pathlib import Path, PurePosixPath
18
18
  from textwrap import dedent
19
19
  from typing import List
20
20
 
21
- from snowflake.cli.plugins.stage.manager import (
21
+ from click import UsageError
22
+ from snowflake.cli._plugins.stage.manager import (
22
23
  USER_STAGE_PREFIX,
23
24
  StageManager,
24
25
  StagePathParts,
25
26
  UserStagePathParts,
26
27
  )
28
+ from snowflake.cli.api.identifiers import FQN
27
29
  from snowflake.connector.cursor import SnowflakeCursor
28
30
 
31
+ # Replace magic numbers with constants
32
+ OMIT_FIRST = slice(1, None)
33
+ OMIT_STAGE = slice(3, None)
34
+ OMIT_STAGE_IN_NEW_LIST_FILES = slice(2, None)
35
+ ONLY_STAGE = slice(3)
36
+
29
37
 
30
38
  class GitStagePathParts(StagePathParts):
31
39
  def __init__(self, stage_path: str):
32
40
  self.stage = GitManager.get_stage_from_path(stage_path)
33
- stage_path_parts = Path(stage_path).parts
41
+ stage_path_parts = GitManager.split_git_path(stage_path)
34
42
  git_repo_name = stage_path_parts[0].split(".")[-1]
35
43
  if git_repo_name.startswith("@"):
36
- git_repo_name = git_repo_name[1:]
44
+ git_repo_name = git_repo_name[OMIT_FIRST]
37
45
  self.stage_name = "/".join([git_repo_name, *stage_path_parts[1:3], ""])
38
- self.directory = "/".join(stage_path_parts[3:])
46
+ self.directory = "/".join(stage_path_parts[OMIT_STAGE])
39
47
  self.is_directory = True if stage_path.endswith("/") else False
40
48
 
41
49
  @property
42
50
  def path(self) -> str:
43
- return (
44
- f"{self.stage_name}{self.directory}"
45
- if self.stage_name.endswith("/")
46
- else f"{self.stage_name}/{self.directory}"
47
- )
51
+ return f"{self.stage_name.rstrip('/')}/{self.directory}"
48
52
 
49
- def add_stage_prefix(self, file_path: str) -> str:
53
+ @classmethod
54
+ def get_directory(cls, stage_path: str) -> str:
55
+ git_path_parts = GitManager.split_git_path(stage_path)
56
+ # New file list does not have a stage name at the beginning
57
+ if stage_path.startswith("/"):
58
+ return "/".join(git_path_parts[OMIT_STAGE_IN_NEW_LIST_FILES])
59
+ else:
60
+ return "/".join(git_path_parts[OMIT_STAGE])
61
+
62
+ @property
63
+ def full_path(self) -> str:
64
+ return f"{self.stage.rstrip('/')}/{self.directory}"
65
+
66
+ def replace_stage_prefix(self, file_path: str) -> str:
50
67
  stage = Path(self.stage).parts[0]
51
- file_path_without_prefix = Path(file_path).parts[1:]
68
+ file_path_without_prefix = Path(file_path).parts[OMIT_FIRST]
52
69
  return f"{stage}/{'/'.join(file_path_without_prefix)}"
53
70
 
71
+ def add_stage_prefix(self, file_path: str) -> str:
72
+ stage = self.stage.rstrip("/")
73
+ return f"{stage}/{file_path.lstrip('/')}"
74
+
54
75
  def get_directory_from_file_path(self, file_path: str) -> List[str]:
55
76
  stage_path_length = len(Path(self.directory).parts)
56
77
  return list(Path(file_path).parts[3 + stage_path_length : -1])
@@ -63,15 +84,15 @@ class GitManager(StageManager):
63
84
  def show_tags(self, repo_name: str, like: str) -> SnowflakeCursor:
64
85
  return self._execute_query(f"show git tags like '{like}' in {repo_name}")
65
86
 
66
- def fetch(self, repo_name: str) -> SnowflakeCursor:
67
- return self._execute_query(f"alter git repository {repo_name} fetch")
87
+ def fetch(self, fqn: FQN) -> SnowflakeCursor:
88
+ return self._execute_query(f"alter git repository {fqn} fetch")
68
89
 
69
90
  def create(
70
- self, repo_name: str, api_integration: str, url: str, secret: str
91
+ self, repo_name: FQN, api_integration: str, url: str, secret: str
71
92
  ) -> SnowflakeCursor:
72
93
  query = dedent(
73
94
  f"""
74
- create git repository {repo_name}
95
+ create git repository {repo_name.sql_identifier}
75
96
  api_integration = {api_integration}
76
97
  origin = '{url}'
77
98
  """
@@ -86,7 +107,8 @@ class GitManager(StageManager):
86
107
  Returns stage name from potential path on stage. For example
87
108
  repo/branches/main/foo/bar -> repo/branches/main/
88
109
  """
89
- return f"{'/'.join(Path(path).parts[0:3])}/"
110
+ path_parts = GitManager.split_git_path(path)
111
+ return f"{'/'.join(path_parts[ONLY_STAGE])}/"
90
112
 
91
113
  @staticmethod
92
114
  def _stage_path_part_factory(stage_path: str) -> StagePathParts:
@@ -94,3 +116,36 @@ class GitManager(StageManager):
94
116
  if stage_path.startswith(USER_STAGE_PREFIX):
95
117
  return UserStagePathParts(stage_path)
96
118
  return GitStagePathParts(stage_path)
119
+
120
+ @staticmethod
121
+ def split_git_path(path: str):
122
+ # Check if path contains quotes and split it accordingly
123
+ if '/"' in path and '"/' in path:
124
+ if path.count('"') > 2:
125
+ raise UsageError(
126
+ f'Invalid string {path}, too much " in path, expected 2.'
127
+ )
128
+
129
+ path_parts = path.split('"')
130
+ before_quoted_part = GitManager._split_path_without_empty_parts(
131
+ path_parts[0]
132
+ )
133
+
134
+ if path_parts[2] == "/":
135
+ after_quoted_part = []
136
+ else:
137
+ after_quoted_part = GitManager._split_path_without_empty_parts(
138
+ path_parts[2]
139
+ )
140
+
141
+ return [
142
+ *before_quoted_part,
143
+ f'"{path_parts[1]}"',
144
+ *after_quoted_part,
145
+ ]
146
+ else:
147
+ return GitManager._split_path_without_empty_parts(path)
148
+
149
+ @staticmethod
150
+ def _split_path_without_empty_parts(path: str):
151
+ return [e for e in PurePosixPath(path).parts if e != "/"]
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.git import commands
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.git import commands
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -0,0 +1,90 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import typer
18
+ import yaml
19
+ from click import ClickException
20
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
21
+ from snowflake.cli.api.output.types import MessageResult
22
+ from snowflake.cli.api.project.definition_conversion import (
23
+ convert_project_definition_to_v2,
24
+ )
25
+ from snowflake.cli.api.project.definition_manager import DefinitionManager
26
+ from snowflake.cli.api.secure_path import SecurePath
27
+
28
+ app = SnowTyperFactory(
29
+ name="helpers",
30
+ help="Helper commands.",
31
+ )
32
+
33
+
34
+ @app.command()
35
+ def v1_to_v2(
36
+ accept_templates: bool = typer.Option(
37
+ False, "-t", "--accept-templates", help="Allows the migration of templates."
38
+ ),
39
+ migrate_local_yml: (bool | None) = typer.Option(
40
+ None,
41
+ "-l",
42
+ "--migrate-local-overrides/--no-migrate-local-overrides",
43
+ help=(
44
+ "Merge values in snowflake.local.yml into the main project definition. "
45
+ "The snowflake.local.yml file will not be migrated, "
46
+ "instead its values will be reflected in the output snowflake.yml file. "
47
+ "If unset and snowflake.local.yml is present, an error will be raised."
48
+ ),
49
+ show_default=False,
50
+ ),
51
+ **options,
52
+ ):
53
+ """Migrates the Snowpark, Streamlit, and Native App project definition files from V1 to V2."""
54
+ manager = DefinitionManager()
55
+ local_yml_path = manager.project_root / "snowflake.local.yml"
56
+ has_local_yml = local_yml_path in manager.project_config_paths
57
+ if has_local_yml:
58
+ if migrate_local_yml is None:
59
+ raise ClickException(
60
+ "snowflake.local.yml file detected, "
61
+ "please specify --migrate-local-overrides to include "
62
+ "or --no-migrate-local-overrides to exclude its values."
63
+ )
64
+ if not migrate_local_yml:
65
+ # If we don't want the local file,
66
+ # remove it from the list of paths to load
67
+ manager.project_config_paths.remove(local_yml_path)
68
+
69
+ pd = manager.unrendered_project_definition
70
+
71
+ if pd.meets_version_requirement("2"):
72
+ return MessageResult("Project definition is already at version 2.")
73
+
74
+ pd_v2 = convert_project_definition_to_v2(
75
+ manager.project_root, pd, accept_templates, manager.template_context
76
+ )
77
+
78
+ SecurePath("snowflake.yml").rename("snowflake_V1.yml")
79
+ if has_local_yml:
80
+ SecurePath("snowflake.local.yml").rename("snowflake_V1.local.yml")
81
+ with open("snowflake.yml", "w") as file:
82
+ yaml.dump(
83
+ pd_v2.model_dump(
84
+ exclude_unset=True, exclude_none=True, mode="json", by_alias=True
85
+ ),
86
+ file,
87
+ sort_keys=False,
88
+ width=float("inf"), # Don't break lines
89
+ )
90
+ return MessageResult("Project definition migrated to version 2.")
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.helpers import commands
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.notebook import commands
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -23,10 +23,10 @@ from click import ClickException
23
23
  from snowflake.cli.__about__ import VERSION
24
24
  from snowflake.cli.api.commands.flags import (
25
25
  NoInteractiveOption,
26
- parse_key_value_variables,
27
26
  variables_option,
28
27
  )
29
28
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
29
+ from snowflake.cli.api.commands.utils import parse_key_value_variables
30
30
  from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
31
31
  from snowflake.cli.api.exceptions import InvalidTemplate
32
32
  from snowflake.cli.api.output.types import (
@@ -68,7 +68,8 @@ TemplateOption = typer.Option(
68
68
  show_default=False,
69
69
  )
70
70
  SourceOption = typer.Option(
71
- default=DEFAULT_SOURCE,
71
+ DEFAULT_SOURCE,
72
+ "--template-source",
72
73
  help=f"local path to template directory or URL to git repository with templates.",
73
74
  )
74
75
  VariablesOption = variables_option(
@@ -106,7 +107,7 @@ def _fetch_remote_template(
106
107
  from git import rmtree as git_rmtree
107
108
 
108
109
  # TODO: during nativeapp refactor get rid of this dependency
109
- from snowflake.cli.plugins.nativeapp.utils import shallow_git_clone
110
+ from snowflake.cli._plugins.nativeapp.utils import shallow_git_clone
110
111
 
111
112
  log.info("Downloading remote template from %s", url)
112
113
  try:
@@ -132,13 +133,13 @@ def _fetch_remote_template(
132
133
  return template_root
133
134
 
134
135
 
135
- def _read_template_metadata(template_root: SecurePath) -> Template:
136
+ def _read_template_metadata(template_root: SecurePath, args_error_msg: str) -> Template:
136
137
  """Parse template.yml file."""
137
138
  template_metadata_path = template_root / TEMPLATE_METADATA_FILE_NAME
138
139
  log.debug("Reading template metadata from %s", template_metadata_path.path)
139
140
  if not template_metadata_path.exists():
140
141
  raise InvalidTemplate(
141
- f"Template does not have {TEMPLATE_METADATA_FILE_NAME} file."
142
+ f"File {TEMPLATE_METADATA_FILE_NAME} not found. {args_error_msg}"
142
143
  )
143
144
  with template_metadata_path.open(read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB) as fd:
144
145
  yaml_contents = yaml.safe_load(fd) or {}
@@ -203,6 +204,7 @@ def init(
203
204
  is_remote = any(
204
205
  template_source.startswith(prefix) for prefix in ["git@", "http://", "https://"] # type: ignore
205
206
  )
207
+ args_error_msg = f"Check whether {TemplateOption.param_decls[0]} and {SourceOption.param_decls[0]} arguments are correct."
206
208
 
207
209
  # copy/download template into tmpdir, so it is going to be removed in case command ends with an error
208
210
  with SecurePath.temporary_directory() as tmpdir:
@@ -217,7 +219,9 @@ def init(
217
219
  destination=tmpdir,
218
220
  )
219
221
 
220
- template_metadata = _read_template_metadata(template_root)
222
+ template_metadata = _read_template_metadata(
223
+ template_root, args_error_msg=args_error_msg
224
+ )
221
225
  if template_metadata.minimum_cli_version:
222
226
  _validate_cli_version(template_metadata.minimum_cli_version)
223
227
 
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.init import commands
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.init import commands
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -22,7 +22,8 @@ from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tupl
22
22
 
23
23
  from click.exceptions import ClickException
24
24
  from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
25
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
25
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
26
+ from snowflake.cli.api.project.util import to_identifier
26
27
  from snowflake.cli.api.secure_path import SecurePath
27
28
  from yaml import safe_load
28
29
 
@@ -199,6 +200,12 @@ class _ArtifactPathMap:
199
200
  """
200
201
  return self.__src_to_dest.keys()
201
202
 
203
+ def is_empty(self) -> bool:
204
+ """
205
+ Returns True if this map has no source-destination mappings.
206
+ """
207
+ return len(self.__src_dest_pairs) == 0
208
+
202
209
  def __iter__(self) -> Iterator[Tuple[Path, Path]]:
203
210
  """
204
211
  Returns all (source, destination) pairs known to this map, in insertion order.
@@ -240,6 +247,9 @@ class BundleMap:
240
247
  self._deploy_root: Path = resolve_without_follow(deploy_root)
241
248
  self._artifact_map = _ArtifactPathMap(project_root=self._project_root)
242
249
 
250
+ def is_empty(self) -> bool:
251
+ return self._artifact_map.is_empty()
252
+
243
253
  def deploy_root(self) -> Path:
244
254
  return self._deploy_root
245
255
 
@@ -658,6 +668,11 @@ def build_bundle(
658
668
  for artifact in artifacts:
659
669
  bundle_map.add(artifact)
660
670
 
671
+ if bundle_map.is_empty():
672
+ raise ArtifactError(
673
+ "No artifacts mapping found in project definition, nothing to do."
674
+ )
675
+
661
676
  for (absolute_src, absolute_dest) in bundle_map.all_mappings(
662
677
  absolute=True, expand_directories=False
663
678
  ):
@@ -720,23 +735,23 @@ def find_setup_script_file(deploy_root: Path) -> Path:
720
735
 
721
736
  def find_version_info_in_manifest_file(
722
737
  deploy_root: Path,
723
- ) -> Tuple[Optional[str], Optional[str]]:
738
+ ) -> Tuple[Optional[str], Optional[int]]:
724
739
  """
725
740
  Find version and patch, if available, in the manifest.yml file.
726
741
  """
727
- version_field = "version"
728
742
  name_field = "name"
729
743
  patch_field = "patch"
730
744
 
731
745
  manifest_content = find_and_read_manifest_file(deploy_root=deploy_root)
732
746
 
733
747
  version_name: Optional[str] = None
734
- patch_name: Optional[str] = None
748
+ patch_number: Optional[int] = None
735
749
 
736
- if version_field in manifest_content:
737
- version_info = manifest_content[version_field]
738
- version_name = version_info[name_field]
750
+ version_info = manifest_content.get("version", None)
751
+ if version_info:
752
+ if name_field in version_info:
753
+ version_name = to_identifier(str(version_info[name_field]))
739
754
  if patch_field in version_info:
740
- patch_name = version_info[patch_field]
755
+ patch_number = int(version_info[patch_field])
741
756
 
742
- return version_name, patch_name
757
+ return version_name, patch_number