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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/{app → _app}/__main__.py +1 -1
- snowflake/cli/{app → _app}/cli_app.py +22 -13
- snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +15 -19
- snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
- snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
- snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
- snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
- snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
- snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
- snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
- snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
- snowflake/cli/{app → _app}/main_typer.py +2 -2
- snowflake/cli/{app → _app}/printing.py +2 -2
- snowflake/cli/_app/secret.py +9 -0
- snowflake/cli/{app → _app}/snow_connector.py +127 -61
- snowflake/cli/{app → _app}/telemetry.py +38 -7
- snowflake/cli/_app/version_check.py +74 -0
- snowflake/cli/{plugins → _plugins}/connection/commands.py +34 -11
- snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
- snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
- snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
- snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
- snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
- snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/git/commands.py +79 -26
- snowflake/cli/{plugins → _plugins}/git/manager.py +72 -17
- snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
- snowflake/cli/_plugins/helpers/commands.py +90 -0
- snowflake/cli/{plugins/notebook → _plugins/helpers}/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
- snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +24 -9
- snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +4 -4
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +37 -18
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +5 -5
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +29 -34
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +114 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +252 -132
- snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
- snowflake/cli/_plugins/nativeapp/entities/application.py +878 -0
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -12
- snowflake/cli/_plugins/nativeapp/manager.py +415 -0
- snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +3 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +36 -20
- snowflake/cli/_plugins/nativeapp/run_processor.py +184 -0
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +70 -0
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +262 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +20 -49
- snowflake/cli/_plugins/nativeapp/version/version_processor.py +98 -0
- snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
- snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
- snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
- snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
- snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
- snowflake/cli/{plugins → _plugins}/object/manager.py +43 -21
- snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
- snowflake/cli/_plugins/snowpark/commands.py +450 -0
- snowflake/cli/_plugins/snowpark/common.py +268 -0
- snowflake/cli/{plugins → _plugins}/snowpark/models.py +2 -8
- snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
- snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
- snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
- snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
- snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
- snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
- snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
- snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
- snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
- snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
- snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
- snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
- snowflake/cli/{plugins → _plugins}/stage/manager.py +62 -24
- snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
- snowflake/cli/_plugins/stage/utils.py +54 -0
- snowflake/cli/{plugins → _plugins}/streamlit/commands.py +71 -62
- snowflake/cli/{plugins → _plugins}/streamlit/manager.py +68 -70
- snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
- snowflake/cli/_plugins/workspace/action_context.py +18 -0
- snowflake/cli/_plugins/workspace/commands.py +306 -0
- snowflake/cli/_plugins/workspace/manager.py +74 -0
- snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
- snowflake/cli/api/cli_global_context.py +152 -295
- snowflake/cli/api/commands/common.py +25 -0
- snowflake/cli/api/commands/decorators.py +19 -4
- snowflake/cli/api/commands/experimental_behaviour.py +2 -3
- snowflake/cli/api/commands/flags.py +143 -222
- snowflake/cli/api/commands/overrideable_parameter.py +143 -0
- snowflake/cli/api/commands/snow_typer.py +21 -11
- snowflake/cli/api/commands/utils.py +18 -0
- snowflake/cli/api/config.py +44 -12
- snowflake/cli/api/connections.py +216 -0
- snowflake/cli/api/console/abc.py +8 -3
- snowflake/cli/api/constants.py +11 -0
- snowflake/cli/api/entities/common.py +56 -0
- snowflake/cli/api/entities/utils.py +370 -0
- snowflake/cli/api/errno.py +1 -0
- snowflake/cli/api/exceptions.py +31 -5
- snowflake/cli/api/feature_flags.py +0 -1
- snowflake/cli/api/identifiers.py +45 -9
- snowflake/cli/api/metrics.py +92 -0
- snowflake/cli/api/project/definition.py +48 -6
- snowflake/cli/api/project/definition_conversion.py +400 -0
- snowflake/cli/api/project/definition_manager.py +16 -5
- snowflake/cli/api/project/project_verification.py +3 -3
- snowflake/cli/api/project/schemas/entities/common.py +91 -16
- snowflake/cli/api/project/schemas/entities/entities.py +37 -6
- snowflake/cli/api/project/schemas/project_definition.py +180 -49
- snowflake/cli/api/project/schemas/updatable_model.py +11 -3
- snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
- snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
- snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
- snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
- snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
- 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/project/util.py +23 -6
- snowflake/cli/api/rendering/jinja.py +14 -8
- snowflake/cli/api/rendering/project_definition_templates.py +5 -1
- snowflake/cli/api/rendering/sql_templates.py +56 -11
- snowflake/cli/api/rest_api.py +11 -5
- snowflake/cli/api/secure_path.py +16 -18
- snowflake/cli/api/secure_utils.py +90 -1
- snowflake/cli/api/sql_execution.py +47 -27
- snowflake/cli/api/utils/definition_rendering.py +45 -13
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
- snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
- snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
- snowflake/cli/api/commands/project_initialisation.py +0 -65
- snowflake/cli/api/commands/typer_pre_execute.py +0 -26
- snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
- snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
- snowflake/cli/app/build_and_push.sh +0 -8
- snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
- snowflake/cli/plugins/nativeapp/init.py +0 -345
- snowflake/cli/plugins/nativeapp/manager.py +0 -823
- snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
- snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
- snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
- snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
- snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
- snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
- snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
- snowflake/cli/plugins/snowpark/commands.py +0 -548
- snowflake/cli/plugins/snowpark/common.py +0 -307
- snowflake/cli/plugins/snowpark/manager.py +0 -109
- snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
- snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
- snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
- snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
- snowflake/cli/plugins/streamlit/__init__.py +0 -13
- snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/plugins/workspace/__init__.py +0 -13
- snowflake/cli/plugins/workspace/commands.py +0 -35
- snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
- snowflake/cli/templates/default_snowpark/.gitignore +0 -4
- snowflake/cli/templates/default_snowpark/app/common.py +0 -2
- snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
- snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
- snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
- snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
- snowflake/cli/templates/default_streamlit/.gitignore +0 -4
- snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
- snowflake/cli/templates/default_streamlit/environment.yml +0 -6
- snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
- snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
- snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
- snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
- snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
- /snowflake/cli/{app → _app}/__init__.py +0 -0
- /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
- /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
- /snowflake/cli/{app → _app}/constants.py +0 -0
- /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
- /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
- /snowflake/cli/{app → _app}/loggers.py +0 -0
- /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
- /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
- /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
- /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
- /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
- /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
- /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
- /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
- /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
- /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
- /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
- /snowflake/cli/{plugins/nativeapp/version → _plugins/object}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
- /snowflake/cli/{plugins/notebook → _plugins/snowpark}/__init__.py +0 -0
- /snowflake/cli/{plugins/object → _plugins/snowpark/package}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
- /snowflake/cli/{plugins/snowpark → _plugins/spcs/compute_pool}/__init__.py +0 -0
- /snowflake/cli/{plugins/snowpark/package → _plugins/spcs/image_registry}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
- /snowflake/cli/{plugins/spcs/compute_pool → _plugins/spcs/image_repository}/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/image_registry → _plugins/spcs/services}/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/image_repository → _plugins/sql}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
- /snowflake/cli/{plugins/spcs/jobs → _plugins/stage}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
- /snowflake/cli/{plugins/spcs/services → _plugins/streamlit}/__init__.py +0 -0
- /snowflake/cli/{plugins/sql → _plugins/workspace}/__init__.py +0 -0
- /snowflake/cli/{plugins/stage → api/project/schemas/entities}/__init__.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-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,389 +0,0 @@
|
|
|
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
|
-
from pathlib import Path
|
|
18
|
-
from textwrap import dedent
|
|
19
|
-
from typing import Optional
|
|
20
|
-
|
|
21
|
-
import typer
|
|
22
|
-
from click import UsageError
|
|
23
|
-
from snowflake.cli.api.console import cli_console as cc
|
|
24
|
-
from snowflake.cli.api.errno import (
|
|
25
|
-
APPLICATION_NO_LONGER_AVAILABLE,
|
|
26
|
-
APPLICATION_OWNS_EXTERNAL_OBJECTS,
|
|
27
|
-
CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
|
|
28
|
-
CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
|
|
29
|
-
NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
30
|
-
ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
31
|
-
)
|
|
32
|
-
from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
|
|
33
|
-
from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
|
|
34
|
-
from snowflake.cli.api.project.util import (
|
|
35
|
-
identifier_to_show_like_pattern,
|
|
36
|
-
unquote_identifier,
|
|
37
|
-
)
|
|
38
|
-
from snowflake.cli.api.utils.cursor import find_all_rows
|
|
39
|
-
from snowflake.cli.plugins.nativeapp.artifacts import BundleMap
|
|
40
|
-
from snowflake.cli.plugins.nativeapp.constants import (
|
|
41
|
-
ALLOWED_SPECIAL_COMMENTS,
|
|
42
|
-
COMMENT_COL,
|
|
43
|
-
PATCH_COL,
|
|
44
|
-
SPECIAL_COMMENT,
|
|
45
|
-
VERSION_COL,
|
|
46
|
-
)
|
|
47
|
-
from snowflake.cli.plugins.nativeapp.exceptions import (
|
|
48
|
-
ApplicationCreatedExternallyError,
|
|
49
|
-
ApplicationPackageDoesNotExistError,
|
|
50
|
-
)
|
|
51
|
-
from snowflake.cli.plugins.nativeapp.manager import (
|
|
52
|
-
NativeAppCommandProcessor,
|
|
53
|
-
NativeAppManager,
|
|
54
|
-
ensure_correct_owner,
|
|
55
|
-
generic_sql_error_handler,
|
|
56
|
-
)
|
|
57
|
-
from snowflake.cli.plugins.nativeapp.policy import PolicyBase
|
|
58
|
-
from snowflake.cli.plugins.nativeapp.project_model import (
|
|
59
|
-
NativeAppProjectModel,
|
|
60
|
-
)
|
|
61
|
-
from snowflake.cli.plugins.stage.manager import StageManager
|
|
62
|
-
from snowflake.connector import ProgrammingError
|
|
63
|
-
from snowflake.connector.cursor import DictCursor, SnowflakeCursor
|
|
64
|
-
|
|
65
|
-
# Reasons why an `alter application ... upgrade` might fail
|
|
66
|
-
UPGRADE_RESTRICTION_CODES = {
|
|
67
|
-
CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
|
|
68
|
-
CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
|
|
69
|
-
ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
70
|
-
NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
|
|
71
|
-
APPLICATION_NO_LONGER_AVAILABLE,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def print_messages(create_or_upgrade_cursor: Optional[SnowflakeCursor]):
|
|
76
|
-
"""
|
|
77
|
-
Shows messages in the console returned by the CREATE or UPGRADE
|
|
78
|
-
APPLICATION command.
|
|
79
|
-
"""
|
|
80
|
-
if not create_or_upgrade_cursor:
|
|
81
|
-
return
|
|
82
|
-
|
|
83
|
-
messages = [row[0] for row in create_or_upgrade_cursor.fetchall()]
|
|
84
|
-
for message in messages:
|
|
85
|
-
cc.warning(message)
|
|
86
|
-
cc.message("")
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class SameAccountInstallMethod:
|
|
90
|
-
_requires_created_by_cli: bool
|
|
91
|
-
_from_release_directive: bool
|
|
92
|
-
version: Optional[str]
|
|
93
|
-
patch: Optional[int]
|
|
94
|
-
|
|
95
|
-
def __init__(
|
|
96
|
-
self,
|
|
97
|
-
requires_created_by_cli: bool,
|
|
98
|
-
version: Optional[str] = None,
|
|
99
|
-
patch: Optional[int] = None,
|
|
100
|
-
from_release_directive: bool = False,
|
|
101
|
-
):
|
|
102
|
-
self._requires_created_by_cli = requires_created_by_cli
|
|
103
|
-
self.version = version
|
|
104
|
-
self.patch = patch
|
|
105
|
-
self._from_release_directive = from_release_directive
|
|
106
|
-
|
|
107
|
-
@classmethod
|
|
108
|
-
def unversioned_dev(cls):
|
|
109
|
-
"""aka. stage dev aka loose files"""
|
|
110
|
-
return cls(True)
|
|
111
|
-
|
|
112
|
-
@classmethod
|
|
113
|
-
def versioned_dev(cls, version: str, patch: Optional[int] = None):
|
|
114
|
-
return cls(False, version, patch)
|
|
115
|
-
|
|
116
|
-
@classmethod
|
|
117
|
-
def release_directive(cls):
|
|
118
|
-
return cls(False, from_release_directive=True)
|
|
119
|
-
|
|
120
|
-
@property
|
|
121
|
-
def is_dev_mode(self) -> bool:
|
|
122
|
-
return not self._from_release_directive
|
|
123
|
-
|
|
124
|
-
def using_clause(self, app: NativeAppProjectModel) -> str:
|
|
125
|
-
if self._from_release_directive:
|
|
126
|
-
return ""
|
|
127
|
-
|
|
128
|
-
if self.version:
|
|
129
|
-
patch_clause = f"patch {self.patch}" if self.patch else ""
|
|
130
|
-
return f"using version {self.version} {patch_clause}"
|
|
131
|
-
|
|
132
|
-
stage_name = StageManager.quote_stage_name(app.stage_fqn)
|
|
133
|
-
return f"using {stage_name}"
|
|
134
|
-
|
|
135
|
-
def ensure_app_usable(self, app: NativeAppProjectModel, show_app_row: dict):
|
|
136
|
-
"""Raise an exception if we cannot proceed with install given the pre-existing application object"""
|
|
137
|
-
|
|
138
|
-
if self._requires_created_by_cli:
|
|
139
|
-
if show_app_row[COMMENT_COL] not in ALLOWED_SPECIAL_COMMENTS:
|
|
140
|
-
# this application object was not created by this tooling
|
|
141
|
-
raise ApplicationCreatedExternallyError(app.app_name)
|
|
142
|
-
|
|
143
|
-
# expected owner
|
|
144
|
-
ensure_correct_owner(row=show_app_row, role=app.app_role, obj_name=app.app_name)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
|
|
148
|
-
def __init__(self, project_definition: NativeApp, project_root: Path):
|
|
149
|
-
super().__init__(project_definition, project_root)
|
|
150
|
-
|
|
151
|
-
def get_all_existing_versions(self) -> SnowflakeCursor:
|
|
152
|
-
"""
|
|
153
|
-
Get all existing versions, if defined, for an application package.
|
|
154
|
-
It executes a 'show versions in application package' query and returns all the results.
|
|
155
|
-
"""
|
|
156
|
-
with self.use_role(self.package_role):
|
|
157
|
-
show_obj_query = f"show versions in application package {self.package_name}"
|
|
158
|
-
show_obj_cursor = self._execute_query(show_obj_query)
|
|
159
|
-
|
|
160
|
-
if show_obj_cursor.rowcount is None:
|
|
161
|
-
raise SnowflakeSQLExecutionError(show_obj_query)
|
|
162
|
-
|
|
163
|
-
return show_obj_cursor
|
|
164
|
-
|
|
165
|
-
def get_existing_version_info(self, version: str) -> Optional[dict]:
|
|
166
|
-
"""
|
|
167
|
-
Get the latest patch on an existing version by name in the application package.
|
|
168
|
-
Executes 'show versions like ... in application package' query and returns
|
|
169
|
-
the latest patch in the version as a single row, if one exists. Otherwise,
|
|
170
|
-
returns None.
|
|
171
|
-
"""
|
|
172
|
-
with self.use_role(self.package_role):
|
|
173
|
-
try:
|
|
174
|
-
query = f"show versions like {identifier_to_show_like_pattern(version)} in application package {self.package_name}"
|
|
175
|
-
cursor = self._execute_query(query, cursor_class=DictCursor)
|
|
176
|
-
|
|
177
|
-
if cursor.rowcount is None:
|
|
178
|
-
raise SnowflakeSQLExecutionError(query)
|
|
179
|
-
|
|
180
|
-
matching_rows = find_all_rows(
|
|
181
|
-
cursor, lambda row: row[VERSION_COL] == unquote_identifier(version)
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
if not matching_rows:
|
|
185
|
-
return None
|
|
186
|
-
|
|
187
|
-
return max(matching_rows, key=lambda row: row[PATCH_COL])
|
|
188
|
-
|
|
189
|
-
except ProgrammingError as err:
|
|
190
|
-
if err.msg.__contains__("does not exist or not authorized"):
|
|
191
|
-
raise ApplicationPackageDoesNotExistError(self.package_name)
|
|
192
|
-
else:
|
|
193
|
-
generic_sql_error_handler(err=err, role=self.package_role)
|
|
194
|
-
return None
|
|
195
|
-
|
|
196
|
-
def drop_application_before_upgrade(
|
|
197
|
-
self, policy: PolicyBase, is_interactive: bool, cascade: bool = False
|
|
198
|
-
):
|
|
199
|
-
"""
|
|
200
|
-
This method will attempt to drop an application object if a previous upgrade fails.
|
|
201
|
-
"""
|
|
202
|
-
if cascade:
|
|
203
|
-
try:
|
|
204
|
-
if application_objects := self.get_objects_owned_by_application():
|
|
205
|
-
application_objects_str = self._application_objects_to_str(
|
|
206
|
-
application_objects
|
|
207
|
-
)
|
|
208
|
-
cc.message(
|
|
209
|
-
f"The following objects are owned by application {self.app_name} and need to be dropped:\n{application_objects_str}"
|
|
210
|
-
)
|
|
211
|
-
except ProgrammingError as err:
|
|
212
|
-
if err.errno != APPLICATION_NO_LONGER_AVAILABLE:
|
|
213
|
-
generic_sql_error_handler(err)
|
|
214
|
-
cc.warning(
|
|
215
|
-
"The application owns other objects but they could not be determined."
|
|
216
|
-
)
|
|
217
|
-
user_prompt = "Do you want the Snowflake CLI to drop these objects, then drop the existing application object and recreate it?"
|
|
218
|
-
else:
|
|
219
|
-
user_prompt = "Do you want the Snowflake CLI to drop the existing application object and recreate it?"
|
|
220
|
-
|
|
221
|
-
if not policy.should_proceed(user_prompt):
|
|
222
|
-
if is_interactive:
|
|
223
|
-
cc.message("Not upgrading the application object.")
|
|
224
|
-
raise typer.Exit(0)
|
|
225
|
-
else:
|
|
226
|
-
cc.message(
|
|
227
|
-
"Cannot upgrade the application object non-interactively without --force."
|
|
228
|
-
)
|
|
229
|
-
raise typer.Exit(1)
|
|
230
|
-
try:
|
|
231
|
-
cascade_msg = " (cascade)" if cascade else ""
|
|
232
|
-
cc.step(f"Dropping application object {self.app_name}{cascade_msg}.")
|
|
233
|
-
cascade_sql = " cascade" if cascade else ""
|
|
234
|
-
self._execute_query(f"drop application {self.app_name}{cascade_sql}")
|
|
235
|
-
except ProgrammingError as err:
|
|
236
|
-
if err.errno == APPLICATION_OWNS_EXTERNAL_OBJECTS and not cascade:
|
|
237
|
-
# We need to cascade the deletion, let's try again (only if we didn't try with cascade already)
|
|
238
|
-
return self.drop_application_before_upgrade(
|
|
239
|
-
policy, is_interactive, cascade=True
|
|
240
|
-
)
|
|
241
|
-
else:
|
|
242
|
-
generic_sql_error_handler(err)
|
|
243
|
-
|
|
244
|
-
def create_or_upgrade_app(
|
|
245
|
-
self,
|
|
246
|
-
policy: PolicyBase,
|
|
247
|
-
install_method: SameAccountInstallMethod,
|
|
248
|
-
is_interactive: bool = False,
|
|
249
|
-
):
|
|
250
|
-
with self.use_role(self.app_role):
|
|
251
|
-
|
|
252
|
-
# 1. Need to use a warehouse to create an application object
|
|
253
|
-
with self.use_warehouse(self.application_warehouse):
|
|
254
|
-
|
|
255
|
-
# 2. Check for an existing application by the same name
|
|
256
|
-
show_app_row = self.get_existing_app_info()
|
|
257
|
-
|
|
258
|
-
# 3. If existing application is found, perform a few validations and upgrade the application object.
|
|
259
|
-
if show_app_row:
|
|
260
|
-
|
|
261
|
-
install_method.ensure_app_usable(self._na_project, show_app_row)
|
|
262
|
-
|
|
263
|
-
# If all the above checks are in order, proceed to upgrade
|
|
264
|
-
try:
|
|
265
|
-
cc.step(
|
|
266
|
-
f"Upgrading existing application object {self.app_name}."
|
|
267
|
-
)
|
|
268
|
-
using_clause = install_method.using_clause(self._na_project)
|
|
269
|
-
upgrade_cursor = self._execute_query(
|
|
270
|
-
f"alter application {self.app_name} upgrade {using_clause}",
|
|
271
|
-
)
|
|
272
|
-
print_messages(upgrade_cursor)
|
|
273
|
-
|
|
274
|
-
if install_method.is_dev_mode:
|
|
275
|
-
# if debug_mode is present (controlled), ensure it is up-to-date
|
|
276
|
-
if self.debug_mode is not None:
|
|
277
|
-
self._execute_query(
|
|
278
|
-
f"alter application {self.app_name} set debug_mode = {self.debug_mode}"
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
# hooks always executed after a create or upgrade
|
|
282
|
-
self.execute_app_post_deploy_hooks()
|
|
283
|
-
return
|
|
284
|
-
|
|
285
|
-
except ProgrammingError as err:
|
|
286
|
-
if err.errno not in UPGRADE_RESTRICTION_CODES:
|
|
287
|
-
generic_sql_error_handler(err=err)
|
|
288
|
-
else: # The existing application object was created from a different process.
|
|
289
|
-
cc.warning(err.msg)
|
|
290
|
-
self.drop_application_before_upgrade(policy, is_interactive)
|
|
291
|
-
|
|
292
|
-
# 4. With no (more) existing application objects, create an application object using the release directives
|
|
293
|
-
cc.step(f"Creating new application object {self.app_name} in account.")
|
|
294
|
-
|
|
295
|
-
if self.app_role != self.package_role:
|
|
296
|
-
with self.use_role(self.package_role):
|
|
297
|
-
self._execute_query(
|
|
298
|
-
f"grant install, develop on application package {self.package_name} to role {self.app_role}"
|
|
299
|
-
)
|
|
300
|
-
self._execute_query(
|
|
301
|
-
f"grant usage on schema {self.package_name}.{self.stage_schema} to role {self.app_role}"
|
|
302
|
-
)
|
|
303
|
-
self._execute_query(
|
|
304
|
-
f"grant read on stage {self.stage_fqn} to role {self.app_role}"
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
try:
|
|
308
|
-
# by default, applications are created in debug mode when possible;
|
|
309
|
-
# this can be overridden in the project definition
|
|
310
|
-
debug_mode_clause = ""
|
|
311
|
-
if install_method.is_dev_mode:
|
|
312
|
-
initial_debug_mode = (
|
|
313
|
-
self.debug_mode if self.debug_mode is not None else True
|
|
314
|
-
)
|
|
315
|
-
debug_mode_clause = f"debug_mode = {initial_debug_mode}"
|
|
316
|
-
|
|
317
|
-
using_clause = install_method.using_clause(self._na_project)
|
|
318
|
-
create_cursor = self._execute_query(
|
|
319
|
-
dedent(
|
|
320
|
-
f"""\
|
|
321
|
-
create application {self.app_name}
|
|
322
|
-
from application package {self.package_name} {using_clause} {debug_mode_clause}
|
|
323
|
-
comment = {SPECIAL_COMMENT}
|
|
324
|
-
"""
|
|
325
|
-
),
|
|
326
|
-
)
|
|
327
|
-
print_messages(create_cursor)
|
|
328
|
-
|
|
329
|
-
# hooks always executed after a create or upgrade
|
|
330
|
-
self.execute_app_post_deploy_hooks()
|
|
331
|
-
|
|
332
|
-
except ProgrammingError as err:
|
|
333
|
-
generic_sql_error_handler(err)
|
|
334
|
-
|
|
335
|
-
def process(
|
|
336
|
-
self,
|
|
337
|
-
bundle_map: BundleMap,
|
|
338
|
-
policy: PolicyBase,
|
|
339
|
-
version: Optional[str] = None,
|
|
340
|
-
patch: Optional[int] = None,
|
|
341
|
-
from_release_directive: bool = False,
|
|
342
|
-
is_interactive: bool = False,
|
|
343
|
-
validate: bool = True,
|
|
344
|
-
*args,
|
|
345
|
-
**kwargs,
|
|
346
|
-
):
|
|
347
|
-
"""
|
|
348
|
-
Create or upgrade the application object using the given strategy
|
|
349
|
-
(unversioned dev, versioned dev, or same-account release directive).
|
|
350
|
-
"""
|
|
351
|
-
|
|
352
|
-
# same-account release directive
|
|
353
|
-
if from_release_directive:
|
|
354
|
-
self.create_or_upgrade_app(
|
|
355
|
-
policy=policy,
|
|
356
|
-
is_interactive=is_interactive,
|
|
357
|
-
install_method=SameAccountInstallMethod.release_directive(),
|
|
358
|
-
)
|
|
359
|
-
return
|
|
360
|
-
|
|
361
|
-
# versioned dev
|
|
362
|
-
if version:
|
|
363
|
-
try:
|
|
364
|
-
version_exists = self.get_existing_version_info(version)
|
|
365
|
-
if not version_exists:
|
|
366
|
-
raise UsageError(
|
|
367
|
-
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."
|
|
368
|
-
)
|
|
369
|
-
except ApplicationPackageDoesNotExistError as app_err:
|
|
370
|
-
raise UsageError(
|
|
371
|
-
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."
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
self.create_or_upgrade_app(
|
|
375
|
-
policy=policy,
|
|
376
|
-
install_method=SameAccountInstallMethod.versioned_dev(version, patch),
|
|
377
|
-
is_interactive=is_interactive,
|
|
378
|
-
)
|
|
379
|
-
return
|
|
380
|
-
|
|
381
|
-
# unversioned dev
|
|
382
|
-
self.deploy(
|
|
383
|
-
bundle_map=bundle_map, prune=True, recursive=True, validate=validate
|
|
384
|
-
)
|
|
385
|
-
self.create_or_upgrade_app(
|
|
386
|
-
policy=policy,
|
|
387
|
-
is_interactive=is_interactive,
|
|
388
|
-
install_method=SameAccountInstallMethod.unversioned_dev(),
|
|
389
|
-
)
|
|
@@ -1,301 +0,0 @@
|
|
|
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
|
-
from pathlib import Path
|
|
18
|
-
from textwrap import dedent
|
|
19
|
-
from typing import Dict, Optional
|
|
20
|
-
|
|
21
|
-
import typer
|
|
22
|
-
from snowflake.cli.api.console import cli_console as cc
|
|
23
|
-
from snowflake.cli.api.errno import APPLICATION_NO_LONGER_AVAILABLE
|
|
24
|
-
from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
|
|
25
|
-
from snowflake.cli.plugins.nativeapp.constants import (
|
|
26
|
-
ALLOWED_SPECIAL_COMMENTS,
|
|
27
|
-
COMMENT_COL,
|
|
28
|
-
EXTERNAL_DISTRIBUTION,
|
|
29
|
-
INTERNAL_DISTRIBUTION,
|
|
30
|
-
OWNER_COL,
|
|
31
|
-
)
|
|
32
|
-
from snowflake.cli.plugins.nativeapp.exceptions import (
|
|
33
|
-
CouldNotDropApplicationPackageWithVersions,
|
|
34
|
-
)
|
|
35
|
-
from snowflake.cli.plugins.nativeapp.manager import (
|
|
36
|
-
NativeAppCommandProcessor,
|
|
37
|
-
NativeAppManager,
|
|
38
|
-
ensure_correct_owner,
|
|
39
|
-
)
|
|
40
|
-
from snowflake.cli.plugins.nativeapp.utils import (
|
|
41
|
-
needs_confirmation,
|
|
42
|
-
)
|
|
43
|
-
from snowflake.connector import ProgrammingError
|
|
44
|
-
from snowflake.connector.cursor import DictCursor
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class NativeAppTeardownProcessor(NativeAppManager, NativeAppCommandProcessor):
|
|
48
|
-
def __init__(self, project_definition: Dict, project_root: Path):
|
|
49
|
-
super().__init__(project_definition, project_root)
|
|
50
|
-
|
|
51
|
-
def drop_generic_object(
|
|
52
|
-
self, object_type: str, object_name: str, role: str, cascade: bool = False
|
|
53
|
-
):
|
|
54
|
-
"""
|
|
55
|
-
Drop object using the given role.
|
|
56
|
-
"""
|
|
57
|
-
with self.use_role(role):
|
|
58
|
-
cc.step(f"Dropping {object_type} {object_name} now.")
|
|
59
|
-
drop_query = f"drop {object_type} {object_name}"
|
|
60
|
-
if cascade:
|
|
61
|
-
drop_query += " cascade"
|
|
62
|
-
try:
|
|
63
|
-
self._execute_query(drop_query)
|
|
64
|
-
except:
|
|
65
|
-
raise SnowflakeSQLExecutionError(drop_query)
|
|
66
|
-
|
|
67
|
-
cc.message(f"Dropped {object_type} {object_name} successfully.")
|
|
68
|
-
|
|
69
|
-
def drop_application(
|
|
70
|
-
self, auto_yes: bool, interactive: bool = False, cascade: Optional[bool] = None
|
|
71
|
-
):
|
|
72
|
-
"""
|
|
73
|
-
Attempts to drop the application object if all validations and user prompts allow so.
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
|
-
needs_confirm = True
|
|
77
|
-
|
|
78
|
-
# 1. If existing application is not found, exit gracefully
|
|
79
|
-
show_obj_row = self.get_existing_app_info()
|
|
80
|
-
if show_obj_row is None:
|
|
81
|
-
cc.warning(
|
|
82
|
-
f"Role {self.app_role} does not own any application object with the name {self.app_name}, or the application object does not exist."
|
|
83
|
-
)
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
# 2. Check for the right owner
|
|
87
|
-
ensure_correct_owner(
|
|
88
|
-
row=show_obj_row, role=self.app_role, obj_name=self.app_name
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
# 3. Check if created by the Snowflake CLI
|
|
92
|
-
row_comment = show_obj_row[COMMENT_COL]
|
|
93
|
-
if row_comment not in ALLOWED_SPECIAL_COMMENTS and needs_confirmation(
|
|
94
|
-
needs_confirm, auto_yes
|
|
95
|
-
):
|
|
96
|
-
should_drop_object = typer.confirm(
|
|
97
|
-
dedent(
|
|
98
|
-
f"""\
|
|
99
|
-
Application object {self.app_name} was not created by Snowflake CLI.
|
|
100
|
-
Application object details:
|
|
101
|
-
Name: {self.app_name}
|
|
102
|
-
Created on: {show_obj_row["created_on"]}
|
|
103
|
-
Source: {show_obj_row["source"]}
|
|
104
|
-
Owner: {show_obj_row[OWNER_COL]}
|
|
105
|
-
Comment: {show_obj_row[COMMENT_COL]}
|
|
106
|
-
Version: {show_obj_row["version"]}
|
|
107
|
-
Patch: {show_obj_row["patch"]}
|
|
108
|
-
Are you sure you want to drop it?
|
|
109
|
-
"""
|
|
110
|
-
)
|
|
111
|
-
)
|
|
112
|
-
if not should_drop_object:
|
|
113
|
-
cc.message(f"Did not drop application object {self.app_name}.")
|
|
114
|
-
# The user desires to keep the app, therefore we can't proceed since it would
|
|
115
|
-
# leave behind an orphan app when we get to dropping the package
|
|
116
|
-
raise typer.Abort()
|
|
117
|
-
|
|
118
|
-
# 4. Check for application objects owned by the application
|
|
119
|
-
# This query will fail if the application package has already been dropped, so handle this case gracefully
|
|
120
|
-
has_objects_to_drop = False
|
|
121
|
-
message_prefix = ""
|
|
122
|
-
cascade_true_message = ""
|
|
123
|
-
cascade_false_message = ""
|
|
124
|
-
interactive_prompt = ""
|
|
125
|
-
non_interactive_abort = ""
|
|
126
|
-
try:
|
|
127
|
-
if application_objects := self.get_objects_owned_by_application():
|
|
128
|
-
has_objects_to_drop = True
|
|
129
|
-
message_prefix = (
|
|
130
|
-
f"The following objects are owned by application {self.app_name}"
|
|
131
|
-
)
|
|
132
|
-
cascade_true_message = f"{message_prefix} and will be dropped:"
|
|
133
|
-
cascade_false_message = f"{message_prefix} and will NOT be dropped:"
|
|
134
|
-
interactive_prompt = "Would you like to drop these objects in addition to the application? [y/n/ABORT]"
|
|
135
|
-
non_interactive_abort = "Re-run teardown again with --cascade or --no-cascade to specify whether these objects should be dropped along with the application"
|
|
136
|
-
except ProgrammingError as e:
|
|
137
|
-
if e.errno != APPLICATION_NO_LONGER_AVAILABLE:
|
|
138
|
-
raise
|
|
139
|
-
application_objects = []
|
|
140
|
-
message_prefix = f"Could not determine which objects are owned by application {self.app_name}"
|
|
141
|
-
has_objects_to_drop = True # potentially, but we don't know what they are
|
|
142
|
-
cascade_true_message = (
|
|
143
|
-
f"{message_prefix}, an unknown number of objects will be dropped."
|
|
144
|
-
)
|
|
145
|
-
cascade_false_message = f"{message_prefix}, they will NOT be dropped."
|
|
146
|
-
interactive_prompt = f"Would you like to drop an unknown set of objects in addition to the application? [y/n/ABORT]"
|
|
147
|
-
non_interactive_abort = f"Re-run teardown again with --cascade or --no-cascade to specify whether any objects should be dropped along with the application."
|
|
148
|
-
|
|
149
|
-
if has_objects_to_drop:
|
|
150
|
-
if cascade is True:
|
|
151
|
-
# If the user explicitly passed the --cascade flag
|
|
152
|
-
cc.message(cascade_true_message)
|
|
153
|
-
with cc.indented():
|
|
154
|
-
for obj in application_objects:
|
|
155
|
-
cc.message(self._application_object_to_str(obj))
|
|
156
|
-
elif cascade is False:
|
|
157
|
-
# If the user explicitly passed the --no-cascade flag
|
|
158
|
-
cc.message(cascade_false_message)
|
|
159
|
-
with cc.indented():
|
|
160
|
-
for obj in application_objects:
|
|
161
|
-
cc.message(self._application_object_to_str(obj))
|
|
162
|
-
elif interactive:
|
|
163
|
-
# If the user didn't pass any cascade flag and the session is interactive
|
|
164
|
-
cc.message(message_prefix)
|
|
165
|
-
with cc.indented():
|
|
166
|
-
for obj in application_objects:
|
|
167
|
-
cc.message(self._application_object_to_str(obj))
|
|
168
|
-
user_response = typer.prompt(
|
|
169
|
-
interactive_prompt,
|
|
170
|
-
show_default=False,
|
|
171
|
-
default="ABORT",
|
|
172
|
-
).lower()
|
|
173
|
-
if user_response in ["y", "yes"]:
|
|
174
|
-
cascade = True
|
|
175
|
-
elif user_response in ["n", "no"]:
|
|
176
|
-
cascade = False
|
|
177
|
-
else:
|
|
178
|
-
raise typer.Abort()
|
|
179
|
-
else:
|
|
180
|
-
# Else abort since we don't know what to do and can't ask the user
|
|
181
|
-
cc.message(message_prefix)
|
|
182
|
-
with cc.indented():
|
|
183
|
-
for obj in application_objects:
|
|
184
|
-
cc.message(self._application_object_to_str(obj))
|
|
185
|
-
cc.message(non_interactive_abort)
|
|
186
|
-
raise typer.Abort()
|
|
187
|
-
elif cascade is None:
|
|
188
|
-
# If there's nothing to drop, set cascade to an explicit False value
|
|
189
|
-
cascade = False
|
|
190
|
-
|
|
191
|
-
# 5. All validations have passed, drop object
|
|
192
|
-
self.drop_generic_object(
|
|
193
|
-
object_type="application",
|
|
194
|
-
object_name=self.app_name,
|
|
195
|
-
role=self.app_role,
|
|
196
|
-
cascade=cascade,
|
|
197
|
-
)
|
|
198
|
-
return # The application object was successfully dropped, therefore exit gracefully
|
|
199
|
-
|
|
200
|
-
def drop_package(self, auto_yes: bool):
|
|
201
|
-
"""
|
|
202
|
-
Attempts to drop application package unless user specifies otherwise.
|
|
203
|
-
"""
|
|
204
|
-
needs_confirm = True
|
|
205
|
-
|
|
206
|
-
# 1. If existing application package is not found, exit gracefully
|
|
207
|
-
show_obj_row = self.get_existing_app_pkg_info()
|
|
208
|
-
if show_obj_row is None:
|
|
209
|
-
cc.warning(
|
|
210
|
-
f"Role {self.package_role} does not own any application package with the name {self.package_name}, or the application package does not exist."
|
|
211
|
-
)
|
|
212
|
-
return
|
|
213
|
-
|
|
214
|
-
# 2. Check for the right owner
|
|
215
|
-
ensure_correct_owner(
|
|
216
|
-
row=show_obj_row, role=self.package_role, obj_name=self.package_name
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
with self.use_role(self.package_role):
|
|
220
|
-
# 3. Check for versions in the application package
|
|
221
|
-
show_versions_query = (
|
|
222
|
-
f"show versions in application package {self.package_name}"
|
|
223
|
-
)
|
|
224
|
-
show_versions_cursor = self._execute_query(
|
|
225
|
-
show_versions_query, cursor_class=DictCursor
|
|
226
|
-
)
|
|
227
|
-
if show_versions_cursor.rowcount is None:
|
|
228
|
-
raise SnowflakeSQLExecutionError(show_versions_query)
|
|
229
|
-
|
|
230
|
-
if show_versions_cursor.rowcount > 0:
|
|
231
|
-
# allow dropping a package with versions when --force is set
|
|
232
|
-
if not auto_yes:
|
|
233
|
-
raise CouldNotDropApplicationPackageWithVersions(
|
|
234
|
-
"Drop versions first, or use --force to override."
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
# 4. Check distribution of the existing application package
|
|
238
|
-
actual_distribution = self.get_app_pkg_distribution_in_snowflake
|
|
239
|
-
if not self.verify_project_distribution(actual_distribution):
|
|
240
|
-
cc.warning(
|
|
241
|
-
f"Continuing to execute `snow app teardown` on application package {self.package_name} with distribution '{actual_distribution}'."
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
# 5. If distribution is internal, check if created by the Snowflake CLI
|
|
245
|
-
row_comment = show_obj_row[COMMENT_COL]
|
|
246
|
-
if actual_distribution == INTERNAL_DISTRIBUTION:
|
|
247
|
-
if row_comment in ALLOWED_SPECIAL_COMMENTS:
|
|
248
|
-
needs_confirm = False
|
|
249
|
-
else:
|
|
250
|
-
if needs_confirmation(needs_confirm, auto_yes):
|
|
251
|
-
cc.warning(
|
|
252
|
-
f"Application package {self.package_name} was not created by Snowflake CLI."
|
|
253
|
-
)
|
|
254
|
-
else:
|
|
255
|
-
if needs_confirmation(needs_confirm, auto_yes):
|
|
256
|
-
cc.warning(
|
|
257
|
-
f"Application package {self.package_name} in your Snowflake account has distribution property '{EXTERNAL_DISTRIBUTION}' and could be associated with one or more of your listings on Snowflake Marketplace."
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
if needs_confirmation(needs_confirm, auto_yes):
|
|
261
|
-
should_drop_object = typer.confirm(
|
|
262
|
-
dedent(
|
|
263
|
-
f"""\
|
|
264
|
-
Application package details:
|
|
265
|
-
Name: {self.app_name}
|
|
266
|
-
Created on: {show_obj_row["created_on"]}
|
|
267
|
-
Distribution: {actual_distribution}
|
|
268
|
-
Owner: {show_obj_row[OWNER_COL]}
|
|
269
|
-
Comment: {show_obj_row[COMMENT_COL]}
|
|
270
|
-
Are you sure you want to drop it?
|
|
271
|
-
"""
|
|
272
|
-
)
|
|
273
|
-
)
|
|
274
|
-
if not should_drop_object:
|
|
275
|
-
cc.message(f"Did not drop application package {self.package_name}.")
|
|
276
|
-
return # The user desires to keep the application package, therefore exit gracefully
|
|
277
|
-
|
|
278
|
-
# All validations have passed, drop object
|
|
279
|
-
self.drop_generic_object(
|
|
280
|
-
object_type="application package",
|
|
281
|
-
object_name=self.package_name,
|
|
282
|
-
role=self.package_role,
|
|
283
|
-
)
|
|
284
|
-
return # The application package was successfully dropped, therefore exit gracefully
|
|
285
|
-
|
|
286
|
-
def process(
|
|
287
|
-
self,
|
|
288
|
-
interactive: bool,
|
|
289
|
-
force_drop: bool = False,
|
|
290
|
-
cascade: Optional[bool] = None,
|
|
291
|
-
*args,
|
|
292
|
-
**kwargs,
|
|
293
|
-
):
|
|
294
|
-
|
|
295
|
-
# Drop the application object
|
|
296
|
-
self.drop_application(
|
|
297
|
-
auto_yes=force_drop, interactive=interactive, cascade=cascade
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
# Drop the application package
|
|
301
|
-
self.drop_package(auto_yes=force_drop)
|