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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/_app/cli_app.py +10 -1
- snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
- snowflake/cli/_app/secret.py +9 -0
- snowflake/cli/_app/snow_connector.py +110 -51
- snowflake/cli/_app/telemetry.py +8 -4
- snowflake/cli/_app/version_check.py +74 -0
- snowflake/cli/_plugins/git/commands.py +55 -14
- snowflake/cli/_plugins/git/manager.py +53 -7
- snowflake/cli/_plugins/helpers/commands.py +57 -0
- snowflake/cli/{api/commands/typer_pre_execute.py → _plugins/helpers/plugin_spec.py} +14 -10
- snowflake/cli/_plugins/nativeapp/application_entity.py +651 -0
- snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_entity_model.py +2 -2
- snowflake/cli/_plugins/nativeapp/application_package_entity.py +1107 -0
- snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_package_entity_model.py +3 -3
- snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
- snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +3 -6
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +50 -32
- snowflake/cli/_plugins/nativeapp/commands.py +84 -16
- snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
- snowflake/cli/_plugins/nativeapp/manager.py +56 -92
- snowflake/cli/_plugins/nativeapp/policy.py +3 -0
- snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
- snowflake/cli/_plugins/nativeapp/run_processor.py +65 -272
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +11 -154
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +150 -40
- snowflake/cli/_plugins/nativeapp/version/commands.py +6 -24
- snowflake/cli/_plugins/nativeapp/version/version_processor.py +35 -235
- snowflake/cli/_plugins/snowpark/commands.py +5 -5
- snowflake/cli/_plugins/snowpark/common.py +4 -4
- snowflake/cli/_plugins/snowpark/models.py +2 -1
- snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
- snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
- snowflake/cli/_plugins/stage/manager.py +9 -4
- snowflake/cli/_plugins/streamlit/commands.py +4 -4
- snowflake/cli/_plugins/streamlit/manager.py +17 -4
- snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
- snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
- snowflake/cli/_plugins/workspace/action_context.py +2 -1
- snowflake/cli/_plugins/workspace/commands.py +127 -48
- snowflake/cli/_plugins/workspace/manager.py +1 -0
- snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
- snowflake/cli/api/cli_global_context.py +136 -313
- snowflake/cli/api/commands/flags.py +76 -91
- snowflake/cli/api/commands/snow_typer.py +7 -5
- snowflake/cli/api/config.py +1 -1
- snowflake/cli/api/connections.py +214 -0
- snowflake/cli/api/console/abc.py +4 -2
- snowflake/cli/api/entities/common.py +4 -0
- snowflake/cli/api/entities/utils.py +41 -31
- snowflake/cli/api/errno.py +1 -0
- snowflake/cli/api/identifiers.py +7 -3
- snowflake/cli/api/project/definition.py +11 -0
- snowflake/cli/api/project/definition_conversion.py +175 -16
- snowflake/cli/api/project/schemas/entities/common.py +15 -14
- snowflake/cli/api/project/schemas/entities/entities.py +13 -10
- snowflake/cli/api/project/schemas/project_definition.py +107 -45
- snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
- snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
- snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
- snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
- snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
- snowflake/cli/api/rendering/project_definition_templates.py +4 -0
- snowflake/cli/api/rendering/sql_templates.py +7 -0
- snowflake/cli/api/sql_execution.py +6 -15
- snowflake/cli/api/utils/definition_rendering.py +3 -1
- {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/METADATA +9 -9
- {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/RECORD +88 -81
- snowflake/cli/api/entities/application_entity.py +0 -12
- snowflake/cli/api/entities/application_package_entity.py +0 -553
- snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
- snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
- /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
- /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
- /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
- {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-3.0.0rc1.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/entry_points.txt +0 -0
- {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
|
|
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.
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
from snowflake.cli._plugins.nativeapp.application_entity import (
|
|
27
|
+
ApplicationEntity,
|
|
28
|
+
ApplicationOwnedObject,
|
|
31
29
|
)
|
|
32
|
-
from snowflake.cli._plugins.nativeapp.
|
|
33
|
-
|
|
30
|
+
from snowflake.cli._plugins.nativeapp.application_package_entity import (
|
|
31
|
+
ApplicationPackageEntity,
|
|
34
32
|
)
|
|
35
|
-
from snowflake.cli._plugins.nativeapp.
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
254
|
-
|
|
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)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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)
|
|
292
|
-
return
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
|
23
|
-
|
|
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.
|
|
32
|
-
|
|
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.
|
|
41
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
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
|
)
|