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
@@ -16,28 +16,27 @@ from __future__ import annotations
16
16
 
17
17
  import time
18
18
  from abc import ABC, abstractmethod
19
- from contextlib import contextmanager
20
19
  from datetime import datetime
21
20
  from functools import cached_property
22
21
  from pathlib import Path
23
22
  from textwrap import dedent
24
- from typing import Generator, List, Optional, TypedDict
23
+ from typing import Generator, List, Optional
25
24
 
26
- from click import ClickException
27
25
  from snowflake.cli._plugins.connection.util import make_snowsight_url
28
- from snowflake.cli._plugins.nativeapp.artifacts import (
29
- BundleMap,
30
- build_bundle,
26
+ from snowflake.cli._plugins.nativeapp.application_entity import (
27
+ ApplicationEntity,
28
+ ApplicationOwnedObject,
31
29
  )
32
- from snowflake.cli._plugins.nativeapp.codegen.compiler import (
33
- NativeAppCompiler,
30
+ from snowflake.cli._plugins.nativeapp.application_package_entity import (
31
+ ApplicationPackageEntity,
34
32
  )
35
- from snowflake.cli._plugins.nativeapp.constants import (
36
- NAME_COL,
33
+ from snowflake.cli._plugins.nativeapp.artifacts import (
34
+ BundleMap,
37
35
  )
38
36
  from snowflake.cli._plugins.nativeapp.exceptions import (
39
37
  NoEventTableForAccount,
40
38
  )
39
+ from snowflake.cli._plugins.nativeapp.policy import AllowAlwaysPolicy, PolicyBase
41
40
  from snowflake.cli._plugins.nativeapp.project_model import (
42
41
  NativeAppProjectModel,
43
42
  )
@@ -45,17 +44,14 @@ from snowflake.cli._plugins.stage.diff import (
45
44
  DiffResult,
46
45
  )
47
46
  from snowflake.cli.api.console import cli_console as cc
48
- from snowflake.cli.api.entities.application_package_entity import (
49
- ApplicationPackageEntity,
50
- )
51
47
  from snowflake.cli.api.entities.utils import (
52
48
  execute_post_deploy_hooks,
53
49
  generic_sql_error_handler,
54
50
  sync_deploy_root_with_stage,
55
51
  )
56
52
  from snowflake.cli.api.project.schemas.entities.common import PostDeployHook
57
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
58
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
53
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
54
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
59
55
  from snowflake.cli.api.project.util import (
60
56
  identifier_for_url,
61
57
  unquote_identifier,
@@ -63,8 +59,6 @@ from snowflake.cli.api.project.util import (
63
59
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
64
60
  from snowflake.connector import DictCursor, ProgrammingError
65
61
 
66
- ApplicationOwnedObject = TypedDict("ApplicationOwnedObject", {"name": str, "type": str})
67
-
68
62
 
69
63
  class NativeAppCommandProcessor(ABC):
70
64
  @abstractmethod
@@ -141,20 +135,8 @@ class NativeAppManager(SqlExecutionMixin):
141
135
  def application_warehouse(self) -> Optional[str]:
142
136
  return self.na_project.application_warehouse
143
137
 
144
- @contextmanager
145
138
  def use_application_warehouse(self):
146
- if self.application_warehouse:
147
- with self.use_warehouse(self.application_warehouse):
148
- yield
149
- else:
150
- raise ClickException(
151
- dedent(
152
- f"""\
153
- Application warehouse cannot be empty.
154
- Please provide a value for it in your connection information or your project definition file.
155
- """
156
- )
157
- )
139
+ return ApplicationEntity.use_application_warehouse(self.application_warehouse)
158
140
 
159
141
  @property
160
142
  def project_identifier(self) -> str:
@@ -219,10 +201,14 @@ class NativeAppManager(SqlExecutionMixin):
219
201
  """
220
202
  Populates the local deploy root from artifact sources.
221
203
  """
222
- bundle_map = build_bundle(self.project_root, self.deploy_root, self.artifacts)
223
- compiler = NativeAppCompiler(self.na_project.get_bundle_context())
224
- compiler.compile_artifacts()
225
- return bundle_map
204
+ return ApplicationPackageEntity.bundle(
205
+ project_root=self.project_root,
206
+ deploy_root=self.deploy_root,
207
+ bundle_root=self.bundle_root,
208
+ generated_root=self.generated_root,
209
+ package_name=self.package_name,
210
+ artifacts=self.artifacts,
211
+ )
226
212
 
227
213
  def sync_deploy_root_with_stage(
228
214
  self,
@@ -249,14 +235,10 @@ class NativeAppManager(SqlExecutionMixin):
249
235
  )
250
236
 
251
237
  def get_existing_app_info(self) -> Optional[dict]:
252
- """
253
- Check for an existing application object by the same name as in project definition, in account.
254
- It executes a 'show applications like' query and returns the result as single row, if one exists.
255
- """
256
- with self.use_role(self.app_role):
257
- return self.show_specific_object(
258
- "applications", self.app_name, name_col=NAME_COL
259
- )
238
+ return ApplicationEntity.get_existing_app_info(
239
+ app_name=self.app_name,
240
+ app_role=self.app_role,
241
+ )
260
242
 
261
243
  def get_existing_app_pkg_info(self) -> Optional[dict]:
262
244
  return ApplicationPackageEntity.get_existing_app_pkg_info(
@@ -264,32 +246,19 @@ class NativeAppManager(SqlExecutionMixin):
264
246
  package_role=self.package_role,
265
247
  )
266
248
 
267
- def get_objects_owned_by_application(self) -> List[ApplicationOwnedObject]:
268
- """
269
- Returns all application objects owned by this application.
270
- """
271
- with self.use_role(self.app_role):
272
- results = self._execute_query(
273
- f"show objects owned by application {self.app_name}"
274
- ).fetchall()
275
- return [{"name": row[1], "type": row[2]} for row in results]
249
+ def get_objects_owned_by_application(self):
250
+ return ApplicationEntity.get_objects_owned_by_application(
251
+ app_name=self.app_name,
252
+ app_role=self.app_role,
253
+ )
276
254
 
277
255
  def _application_objects_to_str(
278
256
  self, application_objects: list[ApplicationOwnedObject]
279
257
  ) -> str:
280
- """
281
- Returns a list in an "(Object Type) Object Name" format. Database-level and schema-level object names are fully qualified:
282
- (COMPUTE_POOL) POOL_NAME
283
- (DATABASE) DB_NAME
284
- (SCHEMA) DB_NAME.PUBLIC
285
- ...
286
- """
287
- return "\n".join(
288
- [self._application_object_to_str(obj) for obj in application_objects]
289
- )
258
+ return ApplicationEntity.application_objects_to_str(application_objects)
290
259
 
291
- def _application_object_to_str(self, obj: ApplicationOwnedObject) -> str:
292
- return f"({obj['type']}) {obj['name']}"
260
+ def _application_object_to_str(self, obj: ApplicationOwnedObject):
261
+ return ApplicationEntity.application_object_to_str(obj)
293
262
 
294
263
  def get_snowsight_url(self) -> str:
295
264
  """Returns the URL that can be used to visit this app via Snowsight."""
@@ -338,40 +307,34 @@ class NativeAppManager(SqlExecutionMixin):
338
307
  bundle_map: BundleMap,
339
308
  prune: bool,
340
309
  recursive: bool,
310
+ policy: PolicyBase,
341
311
  stage_fqn: Optional[str] = None,
342
312
  local_paths_to_sync: List[Path] | None = None,
343
313
  validate: bool = True,
344
314
  print_diff: bool = True,
345
315
  ) -> DiffResult:
346
- """app deploy process"""
347
-
348
- # 1. Create an empty application package, if none exists
349
- self.create_app_package()
350
-
351
- with self.use_role(self.package_role):
352
- # 2. now that the application package exists, create shared data
353
- self._apply_package_scripts()
354
-
355
- # 3. Upload files from deploy root local folder to the above stage
356
- stage_fqn = stage_fqn or self.stage_fqn
357
- diff = self.sync_deploy_root_with_stage(
358
- bundle_map=bundle_map,
359
- role=self.package_role,
360
- prune=prune,
361
- recursive=recursive,
362
- stage_fqn=stage_fqn,
363
- local_paths_to_sync=local_paths_to_sync,
364
- print_diff=print_diff,
365
- )
366
-
367
- # 4. Execute post-deploy hooks
368
- with self.use_package_warehouse():
369
- self.execute_package_post_deploy_hooks()
370
-
371
- if validate:
372
- self.validate(use_scratch_stage=False)
373
-
374
- return diff
316
+ return ApplicationPackageEntity.deploy(
317
+ console=cc,
318
+ project_root=self.project_root,
319
+ deploy_root=self.deploy_root,
320
+ bundle_root=self.bundle_root,
321
+ generated_root=self.generated_root,
322
+ artifacts=self.artifacts,
323
+ bundle_map=bundle_map,
324
+ package_name=self.package_name,
325
+ package_role=self.package_role,
326
+ package_distribution=self.package_distribution,
327
+ prune=prune,
328
+ recursive=recursive,
329
+ paths=local_paths_to_sync,
330
+ print_diff=print_diff,
331
+ validate=validate,
332
+ stage_fqn=stage_fqn or self.stage_fqn,
333
+ package_warehouse=self.package_warehouse,
334
+ post_deploy_hooks=self.package_post_deploy_hooks,
335
+ package_scripts=self.package_scripts,
336
+ policy=policy,
337
+ )
375
338
 
376
339
  def deploy_to_scratch_stage_fn(self):
377
340
  bundle_map = self.build_bundle()
@@ -382,6 +345,7 @@ class NativeAppManager(SqlExecutionMixin):
382
345
  stage_fqn=self.scratch_stage_fqn,
383
346
  validate=False,
384
347
  print_diff=False,
348
+ policy=AllowAlwaysPolicy(),
385
349
  )
386
350
 
387
351
  def validate(self, use_scratch_stage: bool = False):
@@ -27,6 +27,9 @@ class PolicyBase(ABC):
27
27
  def should_proceed(self, user_prompt: Optional[str]) -> bool:
28
28
  pass
29
29
 
30
+ def __eq__(self, value: object) -> bool:
31
+ return self.__class__ == value.__class__
32
+
30
33
 
31
34
  class AllowAlwaysPolicy(PolicyBase):
32
35
  """Always allow a Snowflake CLI command to continue execution."""
@@ -28,8 +28,8 @@ from snowflake.cli.api.project.definition import (
28
28
  default_role,
29
29
  )
30
30
  from snowflake.cli.api.project.schemas.entities.common import PostDeployHook
31
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
32
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
31
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
32
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
33
33
  from snowflake.cli.api.project.util import (
34
34
  append_test_resource_suffix,
35
35
  extract_schema,
@@ -15,135 +15,35 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from textwrap import dedent
19
18
  from typing import Optional
20
19
 
21
20
  import typer
22
- from click import UsageError
23
- from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
24
- from snowflake.cli._plugins.nativeapp.constants import (
25
- ALLOWED_SPECIAL_COMMENTS,
26
- COMMENT_COL,
27
- PATCH_COL,
28
- SPECIAL_COMMENT,
29
- VERSION_COL,
21
+ from snowflake.cli._plugins.nativeapp.application_entity import (
22
+ ApplicationEntity,
30
23
  )
31
- from snowflake.cli._plugins.nativeapp.exceptions import (
32
- ApplicationCreatedExternallyError,
33
- ApplicationPackageDoesNotExistError,
24
+ from snowflake.cli._plugins.nativeapp.application_package_entity import (
25
+ ApplicationPackageEntity,
34
26
  )
27
+ from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
35
28
  from snowflake.cli._plugins.nativeapp.manager import (
36
29
  NativeAppCommandProcessor,
37
30
  NativeAppManager,
38
31
  )
39
32
  from snowflake.cli._plugins.nativeapp.policy import PolicyBase
40
- from snowflake.cli._plugins.nativeapp.project_model import (
41
- NativeAppProjectModel,
33
+ from snowflake.cli._plugins.nativeapp.same_account_install_method import (
34
+ SameAccountInstallMethod,
42
35
  )
43
- from snowflake.cli._plugins.stage.manager import StageManager
44
36
  from snowflake.cli.api.console import cli_console as cc
45
37
  from snowflake.cli.api.entities.utils import (
46
- ensure_correct_owner,
47
38
  generic_sql_error_handler,
48
39
  )
49
40
  from snowflake.cli.api.errno import (
50
41
  APPLICATION_NO_LONGER_AVAILABLE,
51
42
  APPLICATION_OWNS_EXTERNAL_OBJECTS,
52
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
53
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
54
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
55
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
56
- )
57
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
58
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
59
- from snowflake.cli.api.project.util import (
60
- identifier_to_show_like_pattern,
61
- unquote_identifier,
62
43
  )
63
- from snowflake.cli.api.utils.cursor import find_all_rows
44
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
64
45
  from snowflake.connector import ProgrammingError
65
- from snowflake.connector.cursor import DictCursor, SnowflakeCursor
66
-
67
- # Reasons why an `alter application ... upgrade` might fail
68
- UPGRADE_RESTRICTION_CODES = {
69
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
70
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
71
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
72
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
73
- APPLICATION_NO_LONGER_AVAILABLE,
74
- }
75
-
76
-
77
- def print_messages(create_or_upgrade_cursor: Optional[SnowflakeCursor]):
78
- """
79
- Shows messages in the console returned by the CREATE or UPGRADE
80
- APPLICATION command.
81
- """
82
- if not create_or_upgrade_cursor:
83
- return
84
-
85
- messages = [row[0] for row in create_or_upgrade_cursor.fetchall()]
86
- for message in messages:
87
- cc.warning(message)
88
- cc.message("")
89
-
90
-
91
- class SameAccountInstallMethod:
92
- _requires_created_by_cli: bool
93
- _from_release_directive: bool
94
- version: Optional[str]
95
- patch: Optional[int]
96
-
97
- def __init__(
98
- self,
99
- requires_created_by_cli: bool,
100
- version: Optional[str] = None,
101
- patch: Optional[int] = None,
102
- from_release_directive: bool = False,
103
- ):
104
- self._requires_created_by_cli = requires_created_by_cli
105
- self.version = version
106
- self.patch = patch
107
- self._from_release_directive = from_release_directive
108
-
109
- @classmethod
110
- def unversioned_dev(cls):
111
- """aka. stage dev aka loose files"""
112
- return cls(True)
113
-
114
- @classmethod
115
- def versioned_dev(cls, version: str, patch: Optional[int] = None):
116
- return cls(False, version, patch)
117
-
118
- @classmethod
119
- def release_directive(cls):
120
- return cls(False, from_release_directive=True)
121
-
122
- @property
123
- def is_dev_mode(self) -> bool:
124
- return not self._from_release_directive
125
-
126
- def using_clause(self, app: NativeAppProjectModel) -> str:
127
- if self._from_release_directive:
128
- return ""
129
-
130
- if self.version:
131
- patch_clause = f"patch {self.patch}" if self.patch else ""
132
- return f"using version {self.version} {patch_clause}"
133
-
134
- stage_name = StageManager.quote_stage_name(app.stage_fqn)
135
- return f"using {stage_name}"
136
-
137
- def ensure_app_usable(self, app: NativeAppProjectModel, show_app_row: dict):
138
- """Raise an exception if we cannot proceed with install given the pre-existing application object"""
139
-
140
- if self._requires_created_by_cli:
141
- if show_app_row[COMMENT_COL] not in ALLOWED_SPECIAL_COMMENTS:
142
- # this application object was not created by this tooling
143
- raise ApplicationCreatedExternallyError(app.app_name)
144
-
145
- # expected owner
146
- ensure_correct_owner(row=show_app_row, role=app.app_role, obj_name=app.app_name)
46
+ from snowflake.connector.cursor import SnowflakeCursor
147
47
 
148
48
 
149
49
  class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
@@ -151,49 +51,16 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
151
51
  super().__init__(project_definition, project_root)
152
52
 
153
53
  def get_all_existing_versions(self) -> SnowflakeCursor:
154
- """
155
- Get all existing versions, if defined, for an application package.
156
- It executes a 'show versions in application package' query and returns all the results.
157
- """
158
- with self.use_role(self.package_role):
159
- show_obj_query = f"show versions in application package {self.package_name}"
160
- show_obj_cursor = self._execute_query(show_obj_query)
161
-
162
- if show_obj_cursor.rowcount is None:
163
- raise SnowflakeSQLExecutionError(show_obj_query)
164
-
165
- return show_obj_cursor
54
+ return ApplicationPackageEntity.version_list(
55
+ self.package_name, self.package_role
56
+ )
166
57
 
167
58
  def get_existing_version_info(self, version: str) -> Optional[dict]:
168
- """
169
- Get the latest patch on an existing version by name in the application package.
170
- Executes 'show versions like ... in application package' query and returns
171
- the latest patch in the version as a single row, if one exists. Otherwise,
172
- returns None.
173
- """
174
- with self.use_role(self.package_role):
175
- try:
176
- query = f"show versions like {identifier_to_show_like_pattern(version)} in application package {self.package_name}"
177
- cursor = self._execute_query(query, cursor_class=DictCursor)
178
-
179
- if cursor.rowcount is None:
180
- raise SnowflakeSQLExecutionError(query)
181
-
182
- matching_rows = find_all_rows(
183
- cursor, lambda row: row[VERSION_COL] == unquote_identifier(version)
184
- )
185
-
186
- if not matching_rows:
187
- return None
188
-
189
- return max(matching_rows, key=lambda row: row[PATCH_COL])
190
-
191
- except ProgrammingError as err:
192
- if err.msg.__contains__("does not exist or not authorized"):
193
- raise ApplicationPackageDoesNotExistError(self.package_name)
194
- else:
195
- generic_sql_error_handler(err=err, role=self.package_role)
196
- return None
59
+ return ApplicationPackageEntity.get_existing_version_info(
60
+ version=version,
61
+ package_name=self.package_name,
62
+ package_role=self.package_role,
63
+ )
197
64
 
198
65
  def drop_application_before_upgrade(
199
66
  self, policy: PolicyBase, is_interactive: bool, cascade: bool = False
@@ -249,90 +116,26 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
249
116
  install_method: SameAccountInstallMethod,
250
117
  is_interactive: bool = False,
251
118
  ):
252
- with self.use_role(self.app_role):
253
-
254
- # 1. Need to use a warehouse to create an application object
255
- with self.use_warehouse(self.application_warehouse):
256
-
257
- # 2. Check for an existing application by the same name
258
- show_app_row = self.get_existing_app_info()
259
-
260
- # 3. If existing application is found, perform a few validations and upgrade the application object.
261
- if show_app_row:
262
-
263
- install_method.ensure_app_usable(self._na_project, show_app_row)
264
-
265
- # If all the above checks are in order, proceed to upgrade
266
- try:
267
- cc.step(
268
- f"Upgrading existing application object {self.app_name}."
269
- )
270
- using_clause = install_method.using_clause(self._na_project)
271
- upgrade_cursor = self._execute_query(
272
- f"alter application {self.app_name} upgrade {using_clause}",
273
- )
274
- print_messages(upgrade_cursor)
275
-
276
- if install_method.is_dev_mode:
277
- # if debug_mode is present (controlled), ensure it is up-to-date
278
- if self.debug_mode is not None:
279
- self._execute_query(
280
- f"alter application {self.app_name} set debug_mode = {self.debug_mode}"
281
- )
282
-
283
- # hooks always executed after a create or upgrade
284
- self.execute_app_post_deploy_hooks()
285
- return
286
-
287
- except ProgrammingError as err:
288
- if err.errno not in UPGRADE_RESTRICTION_CODES:
289
- generic_sql_error_handler(err=err)
290
- else: # The existing application object was created from a different process.
291
- cc.warning(err.msg)
292
- self.drop_application_before_upgrade(policy, is_interactive)
293
-
294
- # 4. With no (more) existing application objects, create an application object using the release directives
295
- cc.step(f"Creating new application object {self.app_name} in account.")
296
-
297
- if self.app_role != self.package_role:
298
- with self.use_role(self.package_role):
299
- self._execute_query(
300
- f"grant install, develop on application package {self.package_name} to role {self.app_role}"
301
- )
302
- self._execute_query(
303
- f"grant usage on schema {self.package_name}.{self.stage_schema} to role {self.app_role}"
304
- )
305
- self._execute_query(
306
- f"grant read on stage {self.stage_fqn} to role {self.app_role}"
307
- )
308
-
309
- try:
310
- # by default, applications are created in debug mode when possible;
311
- # this can be overridden in the project definition
312
- debug_mode_clause = ""
313
- if install_method.is_dev_mode:
314
- initial_debug_mode = (
315
- self.debug_mode if self.debug_mode is not None else True
316
- )
317
- debug_mode_clause = f"debug_mode = {initial_debug_mode}"
318
-
319
- using_clause = install_method.using_clause(self._na_project)
320
- create_cursor = self._execute_query(
321
- dedent(
322
- f"""\
323
- create application {self.app_name}
324
- from application package {self.package_name} {using_clause} {debug_mode_clause}
325
- comment = {SPECIAL_COMMENT}
326
- """
327
- ),
328
- )
329
- print_messages(create_cursor)
330
-
331
- # hooks always executed after a create or upgrade
332
- self.execute_app_post_deploy_hooks()
333
-
334
- except ProgrammingError as err:
335
- generic_sql_error_handler(err)
119
+ def drop_app():
120
+ self.drop_application_before_upgrade(policy, is_interactive)
121
+
122
+ return ApplicationEntity.create_or_upgrade_app(
123
+ console=cc,
124
+ project_root=self.project_root,
125
+ package_name=self.package_name,
126
+ package_role=self.package_role,
127
+ app_name=self.app_name,
128
+ app_role=self.app_role,
129
+ app_warehouse=self.application_warehouse,
130
+ stage_schema=self.stage_schema,
131
+ stage_fqn=self.stage_fqn,
132
+ debug_mode=self.debug_mode,
133
+ policy=policy,
134
+ install_method=install_method,
135
+ is_interactive=is_interactive,
136
+ post_deploy_hooks=self.app_post_deploy_hooks,
137
+ drop_application_before_upgrade=drop_app,
138
+ )
336
139
 
337
140
  def process(
338
141
  self,
@@ -346,46 +149,36 @@ class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
346
149
  *args,
347
150
  **kwargs,
348
151
  ):
349
- """
350
- Create or upgrade the application object using the given strategy
351
- (unversioned dev, versioned dev, or same-account release directive).
352
- """
353
-
354
- # same-account release directive
355
- if from_release_directive:
356
- self.create_or_upgrade_app(
357
- policy=policy,
358
- is_interactive=is_interactive,
359
- install_method=SameAccountInstallMethod.release_directive(),
360
- )
361
- return
362
-
363
- # versioned dev
364
- if version:
365
- try:
366
- version_exists = self.get_existing_version_info(version)
367
- if not version_exists:
368
- raise UsageError(
369
- f"Application package {self.package_name} does not have any version {version} defined. Use 'snow app version create' to define a version in the application package first."
370
- )
371
- except ApplicationPackageDoesNotExistError as app_err:
372
- raise UsageError(
373
- f"Application package {self.package_name} does not exist. Use 'snow app version create' to first create an application package and then define a version in it."
374
- )
375
-
376
- self.create_or_upgrade_app(
152
+ def deploy_package():
153
+ self.deploy(
154
+ bundle_map=bundle_map,
155
+ prune=True,
156
+ recursive=True,
157
+ validate=validate,
377
158
  policy=policy,
378
- install_method=SameAccountInstallMethod.versioned_dev(version, patch),
379
- is_interactive=is_interactive,
380
159
  )
381
- return
382
160
 
383
- # unversioned dev
384
- self.deploy(
385
- bundle_map=bundle_map, prune=True, recursive=True, validate=validate
386
- )
387
- self.create_or_upgrade_app(
388
- policy=policy,
161
+ def drop_app():
162
+ self.drop_application_before_upgrade(policy, is_interactive)
163
+
164
+ ApplicationEntity.deploy(
165
+ console=cc,
166
+ project_root=self.project_root,
167
+ app_name=self.app_name,
168
+ app_role=self.app_role,
169
+ app_warehouse=self.application_warehouse,
170
+ package_name=self.package_name,
171
+ package_role=self.package_role,
172
+ stage_schema=self.stage_schema,
173
+ stage_fqn=self.stage_fqn,
174
+ debug_mode=self.debug_mode,
175
+ validate=validate,
176
+ from_release_directive=from_release_directive,
389
177
  is_interactive=is_interactive,
390
- install_method=SameAccountInstallMethod.unversioned_dev(),
178
+ policy=policy,
179
+ version=version,
180
+ patch=patch,
181
+ post_deploy_hooks=self.app_post_deploy_hooks,
182
+ deploy_package=deploy_package,
183
+ drop_application_before_upgrade=drop_app,
391
184
  )