snowflake-cli-labs 3.0.0rc1__py3-none-any.whl → 3.0.0rc3__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 (92) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/cli_app.py +10 -1
  3. snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
  4. snowflake/cli/_app/secret.py +9 -0
  5. snowflake/cli/_app/snow_connector.py +110 -51
  6. snowflake/cli/_app/telemetry.py +8 -4
  7. snowflake/cli/_app/version_check.py +74 -0
  8. snowflake/cli/_plugins/git/commands.py +55 -14
  9. snowflake/cli/_plugins/git/manager.py +53 -7
  10. snowflake/cli/_plugins/helpers/commands.py +57 -0
  11. snowflake/cli/{api/commands/typer_pre_execute.py → _plugins/helpers/plugin_spec.py} +14 -10
  12. snowflake/cli/_plugins/nativeapp/application_entity.py +651 -0
  13. snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_entity_model.py +2 -2
  14. snowflake/cli/_plugins/nativeapp/application_package_entity.py +1107 -0
  15. snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_package_entity_model.py +3 -3
  16. snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
  17. snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
  18. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
  19. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +1 -1
  20. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
  21. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
  22. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
  23. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +3 -6
  24. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +50 -32
  25. snowflake/cli/_plugins/nativeapp/commands.py +84 -16
  26. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
  27. snowflake/cli/_plugins/nativeapp/manager.py +56 -92
  28. snowflake/cli/_plugins/nativeapp/policy.py +3 -0
  29. snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
  30. snowflake/cli/_plugins/nativeapp/run_processor.py +65 -272
  31. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
  32. snowflake/cli/_plugins/nativeapp/teardown_processor.py +11 -154
  33. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +150 -40
  34. snowflake/cli/_plugins/nativeapp/version/commands.py +6 -24
  35. snowflake/cli/_plugins/nativeapp/version/version_processor.py +35 -235
  36. snowflake/cli/_plugins/snowpark/commands.py +5 -5
  37. snowflake/cli/_plugins/snowpark/common.py +4 -4
  38. snowflake/cli/_plugins/snowpark/models.py +2 -1
  39. snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
  40. snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
  41. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
  42. snowflake/cli/_plugins/stage/manager.py +9 -4
  43. snowflake/cli/_plugins/streamlit/commands.py +4 -4
  44. snowflake/cli/_plugins/streamlit/manager.py +17 -4
  45. snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
  46. snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
  47. snowflake/cli/_plugins/workspace/action_context.py +2 -1
  48. snowflake/cli/_plugins/workspace/commands.py +127 -48
  49. snowflake/cli/_plugins/workspace/manager.py +1 -0
  50. snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
  51. snowflake/cli/api/cli_global_context.py +136 -313
  52. snowflake/cli/api/commands/flags.py +76 -91
  53. snowflake/cli/api/commands/snow_typer.py +7 -5
  54. snowflake/cli/api/config.py +1 -1
  55. snowflake/cli/api/connections.py +214 -0
  56. snowflake/cli/api/console/abc.py +4 -2
  57. snowflake/cli/api/entities/common.py +4 -0
  58. snowflake/cli/api/entities/utils.py +41 -31
  59. snowflake/cli/api/errno.py +1 -0
  60. snowflake/cli/api/identifiers.py +7 -3
  61. snowflake/cli/api/project/definition.py +11 -0
  62. snowflake/cli/api/project/definition_conversion.py +175 -16
  63. snowflake/cli/api/project/schemas/entities/common.py +15 -14
  64. snowflake/cli/api/project/schemas/entities/entities.py +13 -10
  65. snowflake/cli/api/project/schemas/project_definition.py +107 -45
  66. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  67. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
  68. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  69. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  70. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  71. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  72. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  73. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  74. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  75. snowflake/cli/api/rendering/project_definition_templates.py +4 -0
  76. snowflake/cli/api/rendering/sql_templates.py +7 -0
  77. snowflake/cli/api/sql_execution.py +6 -15
  78. snowflake/cli/api/utils/definition_rendering.py +3 -1
  79. {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/METADATA +9 -9
  80. {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/RECORD +88 -81
  81. snowflake/cli/api/entities/application_entity.py +0 -12
  82. snowflake/cli/api/entities/application_package_entity.py +0 -553
  83. snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
  84. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  85. /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
  86. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
  87. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
  88. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  89. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  90. {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/WHEEL +0 -0
  91. {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/entry_points.txt +0 -0
  92. {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/licenses/LICENSE +0 -0
@@ -19,14 +19,14 @@ from typing import List, Literal, Optional, Union
19
19
  from pydantic import Field, field_validator
20
20
  from snowflake.cli.api.project.schemas.entities.common import (
21
21
  EntityModelBase,
22
+ Identifier,
22
23
  )
23
- from snowflake.cli.api.project.schemas.identifier_model import Identifier
24
- from snowflake.cli.api.project.schemas.native_app.package import DistributionOptions
25
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
26
24
  from snowflake.cli.api.project.schemas.updatable_model import (
27
25
  DiscriminatorField,
28
26
  IdentifierField,
29
27
  )
28
+ from snowflake.cli.api.project.schemas.v1.native_app.package import DistributionOptions
29
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
30
30
  from snowflake.cli.api.project.util import append_test_resource_suffix
31
31
 
32
32
 
@@ -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
 
@@ -734,23 +735,23 @@ def find_setup_script_file(deploy_root: Path) -> Path:
734
735
 
735
736
  def find_version_info_in_manifest_file(
736
737
  deploy_root: Path,
737
- ) -> Tuple[Optional[str], Optional[str]]:
738
+ ) -> Tuple[Optional[str], Optional[int]]:
738
739
  """
739
740
  Find version and patch, if available, in the manifest.yml file.
740
741
  """
741
- version_field = "version"
742
742
  name_field = "name"
743
743
  patch_field = "patch"
744
744
 
745
745
  manifest_content = find_and_read_manifest_file(deploy_root=deploy_root)
746
746
 
747
747
  version_name: Optional[str] = None
748
- patch_name: Optional[str] = None
748
+ patch_number: Optional[int] = None
749
749
 
750
- if version_field in manifest_content:
751
- version_info = manifest_content[version_field]
752
- 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]))
753
754
  if patch_field in version_info:
754
- patch_name = version_info[patch_field]
755
+ patch_number = int(version_info[patch_field])
755
756
 
756
- return version_name, patch_name
757
+ return version_name, patch_number
@@ -18,7 +18,7 @@ from typing import (
18
18
  List,
19
19
  )
20
20
 
21
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
21
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
22
22
 
23
23
 
24
24
  @dataclass
@@ -20,7 +20,7 @@ from typing import Optional
20
20
 
21
21
  from click import ClickException
22
22
  from snowflake.cli._plugins.nativeapp.bundle_context import BundleContext
23
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
23
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
24
24
  PathMapping,
25
25
  ProcessorMapping,
26
26
  )
@@ -35,7 +35,7 @@ from snowflake.cli._plugins.nativeapp.codegen.templates.templates_processor impo
35
35
  )
36
36
  from snowflake.cli._plugins.nativeapp.feature_flags import FeatureFlag
37
37
  from snowflake.cli.api.console import cli_console as cc
38
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
38
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
39
39
  ProcessorMapping,
40
40
  )
41
41
 
@@ -38,7 +38,7 @@ from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
38
38
  )
39
39
  from snowflake.cli._plugins.stage.diff import to_stage_path
40
40
  from snowflake.cli.api.console import cli_console as cc
41
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
41
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
42
42
  PathMapping,
43
43
  ProcessorMapping,
44
44
  )
@@ -27,7 +27,7 @@ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
27
27
  ExtensionFunctionTypeEnum,
28
28
  NativeAppExtensionFunction,
29
29
  )
30
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
30
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
31
31
  from snowflake.cli.api.project.util import (
32
32
  is_valid_identifier,
33
33
  is_valid_string_literal,
@@ -18,8 +18,8 @@ from enum import Enum
18
18
  from typing import List, Optional
19
19
 
20
20
  from pydantic import Field
21
- from snowflake.cli.api.project.schemas.snowpark.callable import _CallableBase
22
21
  from snowflake.cli.api.project.schemas.updatable_model import IdentifierField
22
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import _CallableBase
23
23
 
24
24
 
25
25
  class ExtensionFunctionTypeEnum(str, Enum):
@@ -49,7 +49,7 @@ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
49
49
  )
50
50
  from snowflake.cli._plugins.stage.diff import to_stage_path
51
51
  from snowflake.cli.api.console import cli_console as cc
52
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
52
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
53
53
  PathMapping,
54
54
  ProcessorMapping,
55
55
  )
@@ -323,11 +323,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
323
323
  predicate=is_python_file_artifact,
324
324
  )
325
325
  ):
326
- cc.step(
327
- "Processing Snowpark annotations from {}".format(
328
- dest_file.relative_to(bundle_map.deploy_root())
329
- )
330
- )
326
+ src_file_name = src_file.relative_to(self._bundle_ctx.project_root)
327
+ cc.step(f"Processing Snowpark annotations from {src_file_name}")
331
328
  collected_extension_function_json = _execute_in_sandbox(
332
329
  py_file=str(dest_file.resolve()),
333
330
  deploy_root=self._bundle_ctx.deploy_root,
@@ -14,6 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from pathlib import Path
17
18
  from typing import Optional
18
19
 
19
20
  import jinja2
@@ -24,33 +25,78 @@ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
24
25
  from snowflake.cli._plugins.nativeapp.exceptions import InvalidTemplateInFileError
25
26
  from snowflake.cli.api.cli_global_context import get_cli_context
26
27
  from snowflake.cli.api.console import cli_console as cc
27
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
28
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
28
29
  PathMapping,
29
30
  ProcessorMapping,
30
31
  )
31
32
  from snowflake.cli.api.rendering.project_definition_templates import (
32
33
  get_client_side_jinja_env,
34
+ has_client_side_templates,
33
35
  )
34
36
  from snowflake.cli.api.rendering.sql_templates import (
35
37
  choose_sql_jinja_env_based_on_template_syntax,
38
+ has_sql_templates,
36
39
  )
37
40
 
38
41
 
42
+ def _is_sql_file(file: Path) -> bool:
43
+ return file.name.lower().endswith(".sql")
44
+
45
+
39
46
  class TemplatesProcessor(ArtifactProcessor):
40
47
  """
41
48
  Processor class to perform template expansion on all relevant artifacts (specified in the project definition file).
42
49
  """
43
50
 
51
+ def expand_templates_in_file(self, src: Path, dest: Path) -> None:
52
+ """
53
+ Expand templates in the file.
54
+ """
55
+ if src.is_dir():
56
+ return
57
+
58
+ with self.edit_file(dest) as file:
59
+ if not has_client_side_templates(file.contents) and not (
60
+ _is_sql_file(dest) and has_sql_templates(file.contents)
61
+ ):
62
+ return
63
+
64
+ src_file_name = src.relative_to(self._bundle_ctx.project_root)
65
+ cc.step(f"Expanding templates in {src_file_name}")
66
+ with cc.indented():
67
+ try:
68
+ jinja_env = (
69
+ choose_sql_jinja_env_based_on_template_syntax(
70
+ file.contents, reference_name=src_file_name
71
+ )
72
+ if _is_sql_file(dest)
73
+ else get_client_side_jinja_env()
74
+ )
75
+ expanded_template = jinja_env.from_string(file.contents).render(
76
+ get_cli_context().template_context
77
+ )
78
+
79
+ # For now, we are printing the source file path in the error message
80
+ # instead of the destination file path to make it easier for the user
81
+ # to identify the file that has the error, and edit the correct file.
82
+ except jinja2.TemplateSyntaxError as e:
83
+ raise InvalidTemplateInFileError(src_file_name, e, e.lineno) from e
84
+
85
+ except jinja2.UndefinedError as e:
86
+ raise InvalidTemplateInFileError(src_file_name, e) from e
87
+
88
+ if expanded_template != file.contents:
89
+ file.edited_contents = expanded_template
90
+
44
91
  def process(
45
92
  self,
46
93
  artifact_to_process: PathMapping,
47
94
  processor_mapping: Optional[ProcessorMapping],
48
95
  **kwargs,
49
- ):
96
+ ) -> None:
50
97
  """
51
98
  Process the artifact by executing the template expansion logic on it.
52
99
  """
53
- cc.step(f"Processing artifact {artifact_to_process} with templates processor")
54
100
 
55
101
  bundle_map = BundleMap(
56
102
  project_root=self._bundle_ctx.project_root,
@@ -62,32 +108,4 @@ class TemplatesProcessor(ArtifactProcessor):
62
108
  absolute=True,
63
109
  expand_directories=True,
64
110
  ):
65
- if src.is_dir():
66
- continue
67
- with self.edit_file(dest) as f:
68
- file_name = src.relative_to(self._bundle_ctx.project_root)
69
-
70
- jinja_env = (
71
- choose_sql_jinja_env_based_on_template_syntax(
72
- f.contents, reference_name=file_name
73
- )
74
- if dest.name.lower().endswith(".sql")
75
- else get_client_side_jinja_env()
76
- )
77
-
78
- try:
79
- expanded_template = jinja_env.from_string(f.contents).render(
80
- get_cli_context().template_context
81
- )
82
-
83
- # For now, we are printing the source file path in the error message
84
- # instead of the destination file path to make it easier for the user
85
- # to identify the file that has the error, and edit the correct file.
86
- except jinja2.TemplateSyntaxError as e:
87
- raise InvalidTemplateInFileError(file_name, e, e.lineno) from e
88
-
89
- except jinja2.UndefinedError as e:
90
- raise InvalidTemplateInFileError(file_name, e) from e
91
-
92
- if expanded_template != f.contents:
93
- f.edited_contents = expanded_template
111
+ self.expand_templates_in_file(src, dest)
@@ -22,6 +22,12 @@ from textwrap import dedent
22
22
  from typing import Generator, Iterable, List, Optional, cast
23
23
 
24
24
  import typer
25
+ from snowflake.cli._plugins.nativeapp.application_entity_model import (
26
+ ApplicationEntityModel,
27
+ )
28
+ from snowflake.cli._plugins.nativeapp.application_package_entity_model import (
29
+ ApplicationPackageEntityModel,
30
+ )
25
31
  from snowflake.cli._plugins.nativeapp.common_flags import (
26
32
  ForceOption,
27
33
  InteractiveOption,
@@ -46,6 +52,7 @@ from snowflake.cli._plugins.nativeapp.utils import (
46
52
  shallow_git_clone,
47
53
  )
48
54
  from snowflake.cli._plugins.nativeapp.v2_conversions.v2_to_v1_decorator import (
55
+ find_entity,
49
56
  nativeapp_definition_v2_to_v1,
50
57
  )
51
58
  from snowflake.cli._plugins.nativeapp.version.commands import app as versions_app
@@ -54,11 +61,13 @@ from snowflake.cli._plugins.stage.diff import (
54
61
  compute_stage_diff,
55
62
  )
56
63
  from snowflake.cli._plugins.stage.utils import print_diff_to_console
64
+ from snowflake.cli._plugins.workspace.manager import WorkspaceManager
57
65
  from snowflake.cli.api.cli_global_context import get_cli_context
58
66
  from snowflake.cli.api.commands.decorators import (
59
67
  with_project_definition,
60
68
  )
61
69
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
70
+ from snowflake.cli.api.entities.common import EntityActions
62
71
  from snowflake.cli.api.exceptions import IncompatibleParametersError
63
72
  from snowflake.cli.api.output.formats import OutputFormat
64
73
  from snowflake.cli.api.output.types import (
@@ -69,6 +78,7 @@ from snowflake.cli.api.output.types import (
69
78
  StreamResult,
70
79
  )
71
80
  from snowflake.cli.api.project.project_verification import assert_project_type
81
+ from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
72
82
  from snowflake.cli.api.secure_path import SecurePath
73
83
  from typing_extensions import Annotated
74
84
 
@@ -160,7 +170,7 @@ def app_list_templates(**options) -> CommandResult:
160
170
 
161
171
  @app.command("bundle")
162
172
  @with_project_definition()
163
- @nativeapp_definition_v2_to_v1
173
+ @nativeapp_definition_v2_to_v1()
164
174
  def app_bundle(
165
175
  **options,
166
176
  ) -> CommandResult:
@@ -181,7 +191,7 @@ def app_bundle(
181
191
 
182
192
  @app.command("diff", requires_connection=True, hidden=True)
183
193
  @with_project_definition()
184
- @nativeapp_definition_v2_to_v1
194
+ @nativeapp_definition_v2_to_v1()
185
195
  def app_diff(
186
196
  **options,
187
197
  ) -> CommandResult:
@@ -208,7 +218,7 @@ def app_diff(
208
218
 
209
219
  @app.command("run", requires_connection=True)
210
220
  @with_project_definition()
211
- @nativeapp_definition_v2_to_v1
221
+ @nativeapp_definition_v2_to_v1(app_required=True)
212
222
  def app_run(
213
223
  version: Optional[str] = typer.Option(
214
224
  None,
@@ -272,7 +282,7 @@ def app_run(
272
282
 
273
283
  @app.command("open", requires_connection=True)
274
284
  @with_project_definition()
275
- @nativeapp_definition_v2_to_v1
285
+ @nativeapp_definition_v2_to_v1(app_required=True)
276
286
  def app_open(
277
287
  **options,
278
288
  ) -> CommandResult:
@@ -299,7 +309,9 @@ def app_open(
299
309
 
300
310
  @app.command("teardown", requires_connection=True)
301
311
  @with_project_definition()
302
- @nativeapp_definition_v2_to_v1
312
+ # This command doesn't use @nativeapp_definition_v2_to_v1 because it needs to
313
+ # be aware of PDFv2 definitions that have multiple apps created from the same package,
314
+ # which all need to be torn down.
303
315
  def app_teardown(
304
316
  force: Optional[bool] = ForceOption,
305
317
  cascade: Optional[bool] = typer.Option(
@@ -308,26 +320,70 @@ def app_teardown(
308
320
  show_default=False,
309
321
  ),
310
322
  interactive: bool = InteractiveOption,
323
+ # Same as the param auto-added by @nativeapp_definition_v2_to_v1
324
+ package_entity_id: Optional[str] = typer.Option(
325
+ default="",
326
+ help="The ID of the package entity on which to operate when definition_version is 2 or higher.",
327
+ ),
311
328
  **options,
312
329
  ) -> CommandResult:
313
330
  """
314
331
  Attempts to drop both the application object and application package as defined in the project definition file.
315
332
  """
333
+ cli_context = get_cli_context()
334
+ project = cli_context.project_definition
335
+ if isinstance(project, ProjectDefinitionV1):
336
+ # Old behaviour, not multi-app aware so we can use the old processor
337
+ processor = NativeAppTeardownProcessor(
338
+ project_definition=cli_context.project_definition.native_app,
339
+ project_root=cli_context.project_root,
340
+ )
341
+ processor.process(interactive, force, cascade)
342
+ else:
343
+ # New behaviour, multi-app aware so teardown all the apps created from the package
344
+
345
+ # Determine the package entity to drop, there must be one
346
+ app_package_entity = find_entity(
347
+ project,
348
+ ApplicationPackageEntityModel,
349
+ package_entity_id,
350
+ disambiguation_option="--package-entity-id",
351
+ required=True,
352
+ )
353
+ assert app_package_entity is not None # satisfy mypy
316
354
 
317
- assert_project_type("native_app")
355
+ # Same implementation as `snow ws drop`
356
+ ws = WorkspaceManager(
357
+ project_definition=cli_context.project_definition,
358
+ project_root=cli_context.project_root,
359
+ )
360
+ for app_entity in project.get_entities_by_type(
361
+ ApplicationEntityModel.get_type()
362
+ ).values():
363
+ # Drop each app
364
+ if app_entity.from_.target == app_package_entity.entity_id:
365
+ ws.perform_action(
366
+ app_entity.entity_id,
367
+ EntityActions.DROP,
368
+ force_drop=force,
369
+ interactive=interactive,
370
+ cascade=cascade,
371
+ )
372
+ # Then drop the package
373
+ ws.perform_action(
374
+ app_package_entity.entity_id,
375
+ EntityActions.DROP,
376
+ force_drop=force,
377
+ interactive=interactive,
378
+ cascade=cascade,
379
+ )
318
380
 
319
- cli_context = get_cli_context()
320
- processor = NativeAppTeardownProcessor(
321
- project_definition=cli_context.project_definition.native_app,
322
- project_root=cli_context.project_root,
323
- )
324
- processor.process(interactive, force, cascade)
325
381
  return MessageResult(f"Teardown is now complete.")
326
382
 
327
383
 
328
384
  @app.command("deploy", requires_connection=True)
329
385
  @with_project_definition()
330
- @nativeapp_definition_v2_to_v1
386
+ @nativeapp_definition_v2_to_v1()
331
387
  def app_deploy(
332
388
  prune: Optional[bool] = typer.Option(
333
389
  default=None,
@@ -350,6 +406,8 @@ def app_deploy(
350
406
  unspecified, the command syncs all local changes to the stage."""
351
407
  ).strip(),
352
408
  ),
409
+ interactive: bool = InteractiveOption,
410
+ force: Optional[bool] = ForceOption,
353
411
  validate: bool = ValidateOption,
354
412
  **options,
355
413
  ) -> CommandResult:
@@ -360,6 +418,13 @@ def app_deploy(
360
418
 
361
419
  assert_project_type("native_app")
362
420
 
421
+ if force:
422
+ policy = AllowAlwaysPolicy()
423
+ elif interactive:
424
+ policy = AskAlwaysPolicy()
425
+ else:
426
+ policy = DenyAlwaysPolicy()
427
+
363
428
  has_paths = paths is not None and len(paths) > 0
364
429
  if prune is None and recursive is None and not has_paths:
365
430
  prune = True
@@ -386,6 +451,7 @@ def app_deploy(
386
451
  recursive=recursive,
387
452
  local_paths_to_sync=paths,
388
453
  validate=validate,
454
+ policy=policy,
389
455
  )
390
456
 
391
457
  return MessageResult(
@@ -395,8 +461,10 @@ def app_deploy(
395
461
 
396
462
  @app.command("validate", requires_connection=True)
397
463
  @with_project_definition()
398
- @nativeapp_definition_v2_to_v1
399
- def app_validate(**options):
464
+ @nativeapp_definition_v2_to_v1()
465
+ def app_validate(
466
+ **options,
467
+ ):
400
468
  """
401
469
  Validates a deployed Snowflake Native App's setup script.
402
470
  """
@@ -428,7 +496,7 @@ DEFAULT_EVENT_FOLLOW_LAST = 20
428
496
 
429
497
  @app.command("events", requires_connection=True)
430
498
  @with_project_definition()
431
- @nativeapp_definition_v2_to_v1
499
+ @nativeapp_definition_v2_to_v1(app_required=True)
432
500
  def app_events(
433
501
  since: str = typer.Option(
434
502
  default="",
@@ -48,15 +48,6 @@ class ApplicationCreatedExternallyError(ClickException):
48
48
  )
49
49
 
50
50
 
51
- class UnexpectedOwnerError(ClickException):
52
- """An operation is blocked because an object is owned by an unexpected role."""
53
-
54
- def __init__(self, item: str, expected_owner: str, actual_owner: str):
55
- super().__init__(
56
- f"Cannot operate on {item}: owned by {actual_owner} (expected {expected_owner})"
57
- )
58
-
59
-
60
51
  class MissingScriptError(ClickException):
61
52
  """A referenced script was not found."""
62
53