snowflake-cli-labs 3.0.0rc2__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/commands_registration/builtin_plugins.py +2 -0
- snowflake/cli/_app/secret.py +9 -0
- snowflake/cli/_app/snow_connector.py +39 -27
- snowflake/cli/_plugins/git/manager.py +53 -7
- snowflake/cli/_plugins/helpers/commands.py +57 -0
- snowflake/cli/{api/project/schemas/snowpark/__init__.py → _plugins/helpers/plugin_spec.py} +17 -0
- snowflake/cli/{api/entities → _plugins/nativeapp}/application_entity.py +18 -64
- snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_entity_model.py +2 -2
- snowflake/cli/{api/entities → _plugins/nativeapp}/application_package_entity.py +482 -33
- 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 +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/commands.py +84 -16
- snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
- snowflake/cli/_plugins/nativeapp/manager.py +14 -9
- snowflake/cli/_plugins/nativeapp/policy.py +3 -0
- snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
- snowflake/cli/_plugins/nativeapp/run_processor.py +16 -19
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -4
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +6 -6
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +124 -88
- 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 +4 -4
- snowflake/cli/_plugins/snowpark/common.py +4 -4
- 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 +3 -3
- snowflake/cli/_plugins/streamlit/manager.py +8 -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/commands.py +83 -36
- snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
- snowflake/cli/api/commands/snow_typer.py +1 -1
- snowflake/cli/api/entities/common.py +3 -0
- snowflake/cli/api/entities/utils.py +0 -14
- snowflake/cli/api/errno.py +1 -0
- snowflake/cli/api/identifiers.py +4 -3
- snowflake/cli/api/project/definition_conversion.py +10 -9
- snowflake/cli/api/project/schemas/entities/common.py +17 -4
- snowflake/cli/api/project/schemas/entities/entities.py +13 -10
- snowflake/cli/api/project/schemas/project_definition.py +6 -6
- 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/sql_execution.py +6 -15
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/METADATA +6 -6
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/RECORD +72 -67
- 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.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/entry_points.txt +0 -0
- {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/licenses/LICENSE +0 -0
|
@@ -16,26 +16,27 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import inspect
|
|
18
18
|
from functools import wraps
|
|
19
|
-
from typing import Any, Dict, Optional, Union
|
|
19
|
+
from typing import Any, Dict, Optional, Type, TypeVar, Union
|
|
20
20
|
|
|
21
21
|
import typer
|
|
22
22
|
from click import ClickException
|
|
23
|
+
from snowflake.cli._plugins.nativeapp.application_entity_model import (
|
|
24
|
+
ApplicationEntityModel,
|
|
25
|
+
)
|
|
26
|
+
from snowflake.cli._plugins.nativeapp.application_package_entity_model import (
|
|
27
|
+
ApplicationPackageEntityModel,
|
|
28
|
+
)
|
|
23
29
|
from snowflake.cli.api.cli_global_context import (
|
|
24
30
|
get_cli_context,
|
|
25
31
|
get_cli_context_manager,
|
|
26
32
|
)
|
|
27
33
|
from snowflake.cli.api.commands.decorators import _options_decorator_factory
|
|
28
|
-
from snowflake.cli.api.project.schemas.entities.
|
|
29
|
-
ApplicationEntityModel,
|
|
30
|
-
)
|
|
31
|
-
from snowflake.cli.api.project.schemas.entities.application_package_entity_model import (
|
|
32
|
-
ApplicationPackageEntityModel,
|
|
33
|
-
)
|
|
34
|
-
from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
|
|
34
|
+
from snowflake.cli.api.project.schemas.entities.common import EntityModelBase
|
|
35
35
|
from snowflake.cli.api.project.schemas.project_definition import (
|
|
36
36
|
DefinitionV11,
|
|
37
37
|
DefinitionV20,
|
|
38
38
|
)
|
|
39
|
+
from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
|
|
39
40
|
from snowflake.cli.api.utils.definition_rendering import render_definition_template
|
|
40
41
|
|
|
41
42
|
|
|
@@ -55,33 +56,18 @@ def _pdf_v2_to_v1(
|
|
|
55
56
|
v2_definition: DefinitionV20,
|
|
56
57
|
package_entity_id: str = "",
|
|
57
58
|
app_entity_id: str = "",
|
|
59
|
+
app_required: bool = False,
|
|
58
60
|
) -> DefinitionV11:
|
|
59
61
|
pdfv1: Dict[str, Any] = {"definition_version": "1.1", "native_app": {}}
|
|
60
62
|
|
|
61
|
-
app_package_definition: Optional[ApplicationPackageEntityModel] = None
|
|
62
|
-
app_definition: Optional[ApplicationEntityModel] = None
|
|
63
|
-
|
|
64
|
-
# Enumerate all application package and application entities in the project definition
|
|
65
|
-
packages: dict[
|
|
66
|
-
str, ApplicationPackageEntityModel
|
|
67
|
-
] = v2_definition.get_entities_by_type(ApplicationPackageEntityModel.get_type())
|
|
68
|
-
apps: dict[str, ApplicationEntityModel] = v2_definition.get_entities_by_type(
|
|
69
|
-
ApplicationEntityModel.get_type()
|
|
70
|
-
)
|
|
71
|
-
|
|
72
63
|
# Determine the application entity to convert, there can be zero or one
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# If there are multiple app entities, the user must specify which one to use
|
|
81
|
-
raise ClickException(
|
|
82
|
-
"More than one application entity exists in the project definition file, "
|
|
83
|
-
"specify --app-entity-id to choose which one to operate on."
|
|
84
|
-
)
|
|
64
|
+
app_definition = find_entity(
|
|
65
|
+
v2_definition,
|
|
66
|
+
ApplicationEntityModel,
|
|
67
|
+
app_entity_id,
|
|
68
|
+
disambiguation_option="--app-entity-id",
|
|
69
|
+
required=app_required,
|
|
70
|
+
)
|
|
85
71
|
|
|
86
72
|
# Infer or verify the package if we have an app entity to convert
|
|
87
73
|
if app_definition:
|
|
@@ -89,7 +75,8 @@ def _pdf_v2_to_v1(
|
|
|
89
75
|
if package_entity_id:
|
|
90
76
|
# If the user specified a package entity ID,
|
|
91
77
|
# check that the app entity targets the user-specified package entity
|
|
92
|
-
if
|
|
78
|
+
# if the app entity is used by the command being run
|
|
79
|
+
if target_package != package_entity_id and app_required:
|
|
93
80
|
raise ClickException(
|
|
94
81
|
f"The application entity {app_definition.entity_id} does not "
|
|
95
82
|
f"target the application package entity {package_entity_id}. Either"
|
|
@@ -97,30 +84,21 @@ def _pdf_v2_to_v1(
|
|
|
97
84
|
f"or omit the --package-entity-id flag to automatically use the package entity "
|
|
98
85
|
f"that the application entity targets."
|
|
99
86
|
)
|
|
100
|
-
elif target_package in
|
|
87
|
+
elif target_package in v2_definition.get_entities_by_type(
|
|
88
|
+
ApplicationPackageEntityModel.get_type()
|
|
89
|
+
):
|
|
101
90
|
# If the user didn't target a specific package entity, use the one the app entity targets
|
|
102
91
|
package_entity_id = target_package
|
|
103
92
|
|
|
104
93
|
# Determine the package entity to convert, there must be one
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
raise ClickException(
|
|
114
|
-
"More than one application package entity exists in the project definition file, "
|
|
115
|
-
"specify --package-entity-id to choose which one to operate on."
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
# If we don't have a package entity to convert, error out since it's not optional
|
|
119
|
-
if not app_package_definition:
|
|
120
|
-
with_id = f'with ID "{package_entity_id}" ' if package_entity_id else ""
|
|
121
|
-
raise ClickException(
|
|
122
|
-
f"Could not find an application package entity {with_id}in the project definition file."
|
|
123
|
-
)
|
|
94
|
+
app_package_definition = find_entity(
|
|
95
|
+
v2_definition,
|
|
96
|
+
ApplicationPackageEntityModel,
|
|
97
|
+
package_entity_id,
|
|
98
|
+
disambiguation_option="--package-entity-id",
|
|
99
|
+
required=True,
|
|
100
|
+
)
|
|
101
|
+
assert app_package_definition is not None # satisfy mypy
|
|
124
102
|
|
|
125
103
|
# NativeApp
|
|
126
104
|
if app_definition and app_definition.fqn.identifier:
|
|
@@ -180,7 +158,60 @@ def _pdf_v2_to_v1(
|
|
|
180
158
|
return result.project_definition
|
|
181
159
|
|
|
182
160
|
|
|
183
|
-
|
|
161
|
+
T = TypeVar("T", bound=EntityModelBase)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def find_entity(
|
|
165
|
+
project_definition: DefinitionV20,
|
|
166
|
+
entity_class: Type[T],
|
|
167
|
+
entity_id: str,
|
|
168
|
+
disambiguation_option: str,
|
|
169
|
+
required: bool,
|
|
170
|
+
) -> T | None:
|
|
171
|
+
"""
|
|
172
|
+
Find an entity of the specified type in the project definition file.
|
|
173
|
+
|
|
174
|
+
If an ID is passed, only that entity will be considered,
|
|
175
|
+
otherwise look for a single entity of the specified type.
|
|
176
|
+
|
|
177
|
+
If there are multiple entities of the specified type,
|
|
178
|
+
the user must specify which one to use using the CLI option
|
|
179
|
+
named in the disambiguation_option parameter.
|
|
180
|
+
|
|
181
|
+
If no entity is found, an error is raised if required is True,
|
|
182
|
+
otherwise None is returned.
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
entity_type = entity_class.get_type()
|
|
186
|
+
entities = project_definition.get_entities_by_type(entity_type)
|
|
187
|
+
|
|
188
|
+
entity: Optional[T] = None
|
|
189
|
+
|
|
190
|
+
if entity_id:
|
|
191
|
+
# If we're looking for a specific entity, use that one directly
|
|
192
|
+
entity = entities.get(entity_id)
|
|
193
|
+
elif len(entities) == 1:
|
|
194
|
+
# Otherwise, if there is only one entity, fall back to that one
|
|
195
|
+
entity = next(iter(entities.values()))
|
|
196
|
+
elif len(entities) > 1 and required:
|
|
197
|
+
# If there are multiple entities and it's required,
|
|
198
|
+
# the user must specify which one to use
|
|
199
|
+
raise ClickException(
|
|
200
|
+
f"More than one {entity_type} entity exists in the project definition file, "
|
|
201
|
+
f"specify {disambiguation_option} to choose which one to operate on."
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# If we don't have a package entity to convert, error out if it's required
|
|
205
|
+
if not entity and required:
|
|
206
|
+
with_id = f'with ID "{entity_id}" ' if entity_id else ""
|
|
207
|
+
raise ClickException(
|
|
208
|
+
f"Could not find an {entity_type} entity {with_id}in the project definition file."
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return entity
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def nativeapp_definition_v2_to_v1(*, app_required: bool = False):
|
|
184
215
|
"""
|
|
185
216
|
A command decorator that attempts to automatically convert a native app project from
|
|
186
217
|
definition v2 to v1.1. Assumes with_project_definition() has already been called.
|
|
@@ -189,40 +220,45 @@ def nativeapp_definition_v2_to_v1(func):
|
|
|
189
220
|
entity type is expected.
|
|
190
221
|
"""
|
|
191
222
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
223
|
+
def decorator(func):
|
|
224
|
+
@wraps(func)
|
|
225
|
+
def wrapper(*args, **kwargs):
|
|
226
|
+
original_pdf: Optional[DefinitionV20] = get_cli_context().project_definition
|
|
227
|
+
if not original_pdf:
|
|
228
|
+
raise ValueError(
|
|
229
|
+
"Project definition could not be found. The nativeapp_definition_v2_to_v1 command decorator assumes with_project_definition() was called before it."
|
|
230
|
+
)
|
|
231
|
+
if original_pdf.definition_version == "2":
|
|
232
|
+
package_entity_id = kwargs.get("package_entity_id", "")
|
|
233
|
+
app_entity_id = kwargs.get("app_entity_id", "")
|
|
234
|
+
pdfv1 = _pdf_v2_to_v1(
|
|
235
|
+
original_pdf, package_entity_id, app_entity_id, app_required
|
|
236
|
+
)
|
|
237
|
+
get_cli_context_manager().override_project_definition = pdfv1
|
|
238
|
+
return func(*args, **kwargs)
|
|
239
|
+
|
|
240
|
+
return _options_decorator_factory(
|
|
241
|
+
wrapper,
|
|
242
|
+
additional_options=[
|
|
243
|
+
inspect.Parameter(
|
|
244
|
+
"package_entity_id",
|
|
245
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
246
|
+
annotation=Optional[str],
|
|
247
|
+
default=typer.Option(
|
|
248
|
+
default="",
|
|
249
|
+
help="The ID of the package entity on which to operate when definition_version is 2 or higher.",
|
|
250
|
+
),
|
|
216
251
|
),
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
252
|
+
inspect.Parameter(
|
|
253
|
+
"app_entity_id",
|
|
254
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
255
|
+
annotation=Optional[str],
|
|
256
|
+
default=typer.Option(
|
|
257
|
+
default="",
|
|
258
|
+
help="The ID of the application entity on which to operate when definition_version is 2 or higher.",
|
|
259
|
+
),
|
|
225
260
|
),
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
261
|
+
],
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return decorator
|
|
@@ -51,7 +51,7 @@ log = logging.getLogger(__name__)
|
|
|
51
51
|
|
|
52
52
|
@app.command(requires_connection=True)
|
|
53
53
|
@with_project_definition()
|
|
54
|
-
@nativeapp_definition_v2_to_v1
|
|
54
|
+
@nativeapp_definition_v2_to_v1()
|
|
55
55
|
def create(
|
|
56
56
|
version: Optional[str] = typer.Argument(
|
|
57
57
|
None,
|
|
@@ -82,42 +82,24 @@ def create(
|
|
|
82
82
|
if version is None and patch is not None:
|
|
83
83
|
raise MissingParameter("Cannot provide a patch without version!")
|
|
84
84
|
|
|
85
|
-
is_interactive = False
|
|
86
|
-
if force:
|
|
87
|
-
policy = AllowAlwaysPolicy()
|
|
88
|
-
elif interactive:
|
|
89
|
-
is_interactive = True
|
|
90
|
-
policy = AskAlwaysPolicy()
|
|
91
|
-
else:
|
|
92
|
-
policy = DenyAlwaysPolicy()
|
|
93
|
-
|
|
94
|
-
if skip_git_check:
|
|
95
|
-
git_policy = DenyAlwaysPolicy()
|
|
96
|
-
else:
|
|
97
|
-
git_policy = AllowAlwaysPolicy()
|
|
98
|
-
|
|
99
85
|
cli_context = get_cli_context()
|
|
100
86
|
processor = NativeAppVersionCreateProcessor(
|
|
101
87
|
project_definition=cli_context.project_definition.native_app,
|
|
102
88
|
project_root=cli_context.project_root,
|
|
103
89
|
)
|
|
104
|
-
|
|
105
|
-
# We need build_bundle() to (optionally) find version in manifest.yml and create an application package
|
|
106
|
-
bundle_map = processor.build_bundle()
|
|
107
90
|
processor.process(
|
|
108
|
-
bundle_map=bundle_map,
|
|
109
91
|
version=version,
|
|
110
92
|
patch=patch,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
93
|
+
force=force,
|
|
94
|
+
interactive=interactive,
|
|
95
|
+
skip_git_check=skip_git_check,
|
|
114
96
|
)
|
|
115
97
|
return MessageResult(f"Version create is now complete.")
|
|
116
98
|
|
|
117
99
|
|
|
118
100
|
@app.command("list", requires_connection=True)
|
|
119
101
|
@with_project_definition()
|
|
120
|
-
@nativeapp_definition_v2_to_v1
|
|
102
|
+
@nativeapp_definition_v2_to_v1()
|
|
121
103
|
def version_list(
|
|
122
104
|
**options,
|
|
123
105
|
) -> CommandResult:
|
|
@@ -138,7 +120,7 @@ def version_list(
|
|
|
138
120
|
|
|
139
121
|
@app.command(requires_connection=True)
|
|
140
122
|
@with_project_definition()
|
|
141
|
-
@nativeapp_definition_v2_to_v1
|
|
123
|
+
@nativeapp_definition_v2_to_v1()
|
|
142
124
|
def drop(
|
|
143
125
|
version: Optional[str] = typer.Argument(
|
|
144
126
|
None,
|
|
@@ -16,17 +16,17 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from textwrap import dedent
|
|
19
|
-
from typing import Dict,
|
|
19
|
+
from typing import Dict, Optional
|
|
20
20
|
|
|
21
21
|
import typer
|
|
22
|
-
from click import
|
|
22
|
+
from click import ClickException
|
|
23
|
+
from snowflake.cli._plugins.nativeapp.application_package_entity import (
|
|
24
|
+
ApplicationPackageEntity,
|
|
25
|
+
)
|
|
23
26
|
from snowflake.cli._plugins.nativeapp.artifacts import (
|
|
24
|
-
BundleMap,
|
|
25
27
|
find_version_info_in_manifest_file,
|
|
26
28
|
)
|
|
27
|
-
from snowflake.cli._plugins.nativeapp.constants import VERSION_COL
|
|
28
29
|
from snowflake.cli._plugins.nativeapp.exceptions import (
|
|
29
|
-
ApplicationPackageAlreadyExistsError,
|
|
30
30
|
ApplicationPackageDoesNotExistError,
|
|
31
31
|
)
|
|
32
32
|
from snowflake.cli._plugins.nativeapp.manager import (
|
|
@@ -36,245 +36,50 @@ from snowflake.cli._plugins.nativeapp.manager import (
|
|
|
36
36
|
from snowflake.cli._plugins.nativeapp.policy import PolicyBase
|
|
37
37
|
from snowflake.cli._plugins.nativeapp.run_processor import NativeAppRunProcessor
|
|
38
38
|
from snowflake.cli.api.console import cli_console as cc
|
|
39
|
-
from snowflake.cli.api.
|
|
40
|
-
from snowflake.cli.api.
|
|
41
|
-
from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
|
|
42
|
-
from snowflake.cli.api.project.util import to_identifier, unquote_identifier
|
|
43
|
-
from snowflake.cli.api.utils.cursor import (
|
|
44
|
-
find_all_rows,
|
|
45
|
-
)
|
|
39
|
+
from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
|
|
40
|
+
from snowflake.cli.api.project.util import to_identifier
|
|
46
41
|
from snowflake.connector import ProgrammingError
|
|
47
|
-
from snowflake.connector.cursor import DictCursor
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def check_index_changes_in_git_repo(
|
|
51
|
-
project_root: Path, policy: PolicyBase, is_interactive: bool
|
|
52
|
-
) -> None:
|
|
53
|
-
"""
|
|
54
|
-
Checks if the project root, i.e. the native apps project is a git repository. If it is a git repository,
|
|
55
|
-
it also checks if there any local changes to the directory that may not be on the application package stage.
|
|
56
|
-
"""
|
|
57
|
-
from git import Repo
|
|
58
|
-
from git.exc import InvalidGitRepositoryError
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
repo = Repo(project_root, search_parent_directories=True)
|
|
62
|
-
assert repo.git_dir is not None
|
|
63
|
-
|
|
64
|
-
# Check if the repo has any changes, including untracked files
|
|
65
|
-
if repo.is_dirty(untracked_files=True):
|
|
66
|
-
cc.warning(
|
|
67
|
-
"Changes detected in the git repository. "
|
|
68
|
-
"(Rerun your command with --skip-git-check flag to ignore this check)"
|
|
69
|
-
)
|
|
70
|
-
repo.git.execute(["git", "status"])
|
|
71
|
-
|
|
72
|
-
user_prompt = (
|
|
73
|
-
"You have local changes in this repository that are not part of a previous commit. "
|
|
74
|
-
"Do you still want to continue?"
|
|
75
|
-
)
|
|
76
|
-
if not policy.should_proceed(user_prompt):
|
|
77
|
-
if is_interactive:
|
|
78
|
-
cc.message("Not creating a new version.")
|
|
79
|
-
raise typer.Exit(0)
|
|
80
|
-
else:
|
|
81
|
-
cc.message(
|
|
82
|
-
"Cannot create a new version non-interactively without --force."
|
|
83
|
-
)
|
|
84
|
-
raise typer.Exit(1)
|
|
85
|
-
|
|
86
|
-
except InvalidGitRepositoryError:
|
|
87
|
-
pass # not a git repository, which is acceptable
|
|
88
42
|
|
|
89
43
|
|
|
90
44
|
class NativeAppVersionCreateProcessor(NativeAppRunProcessor):
|
|
91
45
|
def __init__(self, project_definition: Dict, project_root: Path):
|
|
92
46
|
super().__init__(project_definition, project_root)
|
|
93
47
|
|
|
94
|
-
def get_existing_release_directive_info_for_version(
|
|
95
|
-
self, version: str
|
|
96
|
-
) -> List[dict]:
|
|
97
|
-
"""
|
|
98
|
-
Get all existing release directives, if present, set on the version defined in an application package.
|
|
99
|
-
It executes a 'show release directives in application package' query and returns the filtered results, if they exist.
|
|
100
|
-
"""
|
|
101
|
-
with self.use_role(self.package_role):
|
|
102
|
-
show_obj_query = (
|
|
103
|
-
f"show release directives in application package {self.package_name}"
|
|
104
|
-
)
|
|
105
|
-
show_obj_cursor = self._execute_query(
|
|
106
|
-
show_obj_query, cursor_class=DictCursor
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
if show_obj_cursor.rowcount is None:
|
|
110
|
-
raise SnowflakeSQLExecutionError(show_obj_query)
|
|
111
|
-
|
|
112
|
-
show_obj_rows = find_all_rows(
|
|
113
|
-
show_obj_cursor,
|
|
114
|
-
lambda row: row[VERSION_COL] == unquote_identifier(version),
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
return show_obj_rows
|
|
118
|
-
|
|
119
|
-
def add_new_version(self, version: str) -> None:
|
|
120
|
-
"""
|
|
121
|
-
Defines a new version in an existing application package.
|
|
122
|
-
"""
|
|
123
|
-
# Make the version a valid identifier, adding quotes if necessary
|
|
124
|
-
version = to_identifier(version)
|
|
125
|
-
with self.use_role(self.package_role):
|
|
126
|
-
cc.step(
|
|
127
|
-
f"Defining a new version {version} in application package {self.package_name}"
|
|
128
|
-
)
|
|
129
|
-
add_version_query = dedent(
|
|
130
|
-
f"""\
|
|
131
|
-
alter application package {self.package_name}
|
|
132
|
-
add version {version}
|
|
133
|
-
using @{self.stage_fqn}
|
|
134
|
-
"""
|
|
135
|
-
)
|
|
136
|
-
self._execute_query(add_version_query, cursor_class=DictCursor)
|
|
137
|
-
cc.message(
|
|
138
|
-
f"Version {version} created for application package {self.package_name}."
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
def add_new_patch_to_version(self, version: str, patch: Optional[int] = None):
|
|
142
|
-
"""
|
|
143
|
-
Add a new patch, optionally a custom one, to an existing version in an application package.
|
|
144
|
-
"""
|
|
145
|
-
# Make the version a valid identifier, adding quotes if necessary
|
|
146
|
-
version = to_identifier(version)
|
|
147
|
-
with self.use_role(self.package_role):
|
|
148
|
-
cc.step(
|
|
149
|
-
f"Adding new patch to version {version} defined in application package {self.package_name}"
|
|
150
|
-
)
|
|
151
|
-
add_version_query = dedent(
|
|
152
|
-
f"""\
|
|
153
|
-
alter application package {self.package_name}
|
|
154
|
-
add patch {patch if patch else ""} for version {version}
|
|
155
|
-
using @{self.stage_fqn}
|
|
156
|
-
"""
|
|
157
|
-
)
|
|
158
|
-
result_cursor = self._execute_query(
|
|
159
|
-
add_version_query, cursor_class=DictCursor
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
show_row = result_cursor.fetchall()[0]
|
|
163
|
-
new_patch = show_row["patch"]
|
|
164
|
-
cc.message(
|
|
165
|
-
f"Patch {new_patch} created for version {version} defined in application package {self.package_name}."
|
|
166
|
-
)
|
|
167
|
-
|
|
168
48
|
def process(
|
|
169
49
|
self,
|
|
170
|
-
bundle_map: BundleMap,
|
|
171
50
|
version: Optional[str],
|
|
172
51
|
patch: Optional[int],
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
52
|
+
force: bool,
|
|
53
|
+
interactive: bool,
|
|
54
|
+
skip_git_check: bool,
|
|
176
55
|
*args,
|
|
177
56
|
**kwargs,
|
|
178
57
|
):
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
)
|
|
204
|
-
except ApplicationPackageDoesNotExistError as app_err:
|
|
205
|
-
raise BadOptionUsage(
|
|
206
|
-
option_name="patch",
|
|
207
|
-
message=f"Cannot create a custom patch when application package {self.package_name} does not exist. Try again without using --patch.",
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
if git_policy.should_proceed():
|
|
211
|
-
check_index_changes_in_git_repo(
|
|
212
|
-
project_root=self.project_root,
|
|
213
|
-
policy=policy,
|
|
214
|
-
is_interactive=is_interactive,
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
# TODO: consider using self.deploy() instead
|
|
218
|
-
|
|
219
|
-
try:
|
|
220
|
-
self.create_app_package()
|
|
221
|
-
except ApplicationPackageAlreadyExistsError as e:
|
|
222
|
-
cc.warning(e.message)
|
|
223
|
-
if not policy.should_proceed("Proceed with using this package?"):
|
|
224
|
-
raise typer.Abort() from e
|
|
225
|
-
|
|
226
|
-
with self.use_role(self.package_role):
|
|
227
|
-
# Now that the application package exists, create shared data
|
|
228
|
-
self._apply_package_scripts()
|
|
229
|
-
|
|
230
|
-
# Upload files from deploy root local folder to the above stage
|
|
231
|
-
self.sync_deploy_root_with_stage(
|
|
232
|
-
bundle_map=bundle_map,
|
|
233
|
-
role=self.package_role,
|
|
234
|
-
prune=True,
|
|
235
|
-
recursive=True,
|
|
236
|
-
stage_fqn=self.stage_fqn,
|
|
237
|
-
)
|
|
238
|
-
with self.use_package_warehouse():
|
|
239
|
-
self.execute_package_post_deploy_hooks()
|
|
240
|
-
|
|
241
|
-
# Warn if the version exists in a release directive(s)
|
|
242
|
-
existing_release_directives = (
|
|
243
|
-
self.get_existing_release_directive_info_for_version(version)
|
|
58
|
+
return ApplicationPackageEntity.version_create(
|
|
59
|
+
console=cc,
|
|
60
|
+
project_root=self.project_root,
|
|
61
|
+
deploy_root=self.deploy_root,
|
|
62
|
+
bundle_root=self.bundle_root,
|
|
63
|
+
generated_root=self.generated_root,
|
|
64
|
+
artifacts=self.artifacts,
|
|
65
|
+
package_name=self.package_name,
|
|
66
|
+
package_role=self.package_role,
|
|
67
|
+
package_distribution=self.package_distribution,
|
|
68
|
+
prune=True,
|
|
69
|
+
recursive=True,
|
|
70
|
+
paths=None,
|
|
71
|
+
print_diff=True,
|
|
72
|
+
validate=True,
|
|
73
|
+
stage_fqn=self.stage_fqn,
|
|
74
|
+
package_warehouse=self.package_warehouse,
|
|
75
|
+
post_deploy_hooks=self.package_post_deploy_hooks,
|
|
76
|
+
package_scripts=self.package_scripts,
|
|
77
|
+
version=version,
|
|
78
|
+
patch=patch,
|
|
79
|
+
force=force,
|
|
80
|
+
interactive=interactive,
|
|
81
|
+
skip_git_check=skip_git_check,
|
|
244
82
|
)
|
|
245
|
-
if existing_release_directives:
|
|
246
|
-
release_directive_names = ", ".join(
|
|
247
|
-
row["name"] for row in existing_release_directives
|
|
248
|
-
)
|
|
249
|
-
cc.warning(
|
|
250
|
-
dedent(
|
|
251
|
-
f"""\
|
|
252
|
-
Version {version} already defined in application package {self.package_name} and in release directive(s): {release_directive_names}.
|
|
253
|
-
"""
|
|
254
|
-
)
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
user_prompt = (
|
|
258
|
-
f"Are you sure you want to create a new patch for version {version} in application "
|
|
259
|
-
f"package {self.package_name}? Once added, this operation cannot be undone."
|
|
260
|
-
)
|
|
261
|
-
if not policy.should_proceed(user_prompt):
|
|
262
|
-
if is_interactive:
|
|
263
|
-
cc.message("Not creating a new patch.")
|
|
264
|
-
raise typer.Exit(0)
|
|
265
|
-
else:
|
|
266
|
-
cc.message(
|
|
267
|
-
"Cannot create a new patch non-interactively without --force."
|
|
268
|
-
)
|
|
269
|
-
raise typer.Exit(1)
|
|
270
|
-
|
|
271
|
-
# Define a new version in the application package
|
|
272
|
-
if not self.get_existing_version_info(version):
|
|
273
|
-
self.add_new_version(version=version)
|
|
274
|
-
return # A new version created automatically has patch 0, we do not need to further increment the patch.
|
|
275
|
-
|
|
276
|
-
# Add a new patch to an existing (old) version
|
|
277
|
-
self.add_new_patch_to_version(version=version, patch=patch)
|
|
278
83
|
|
|
279
84
|
|
|
280
85
|
class NativeAppVersionDropProcessor(NativeAppManager, NativeAppCommandProcessor):
|
|
@@ -295,12 +100,7 @@ class NativeAppVersionDropProcessor(NativeAppManager, NativeAppCommandProcessor)
|
|
|
295
100
|
|
|
296
101
|
# 1. Check for existing an existing application package
|
|
297
102
|
show_obj_row = self.get_existing_app_pkg_info()
|
|
298
|
-
if show_obj_row:
|
|
299
|
-
# Check for the right owner role
|
|
300
|
-
ensure_correct_owner(
|
|
301
|
-
row=show_obj_row, role=self.package_role, obj_name=self.package_name
|
|
302
|
-
)
|
|
303
|
-
else:
|
|
103
|
+
if not show_obj_row:
|
|
304
104
|
raise ApplicationPackageDoesNotExistError(self.package_name)
|
|
305
105
|
|
|
306
106
|
# 2. Check distribution of the existing application package
|
|
@@ -46,6 +46,10 @@ from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
|
|
|
46
46
|
AnacondaPackagesManager,
|
|
47
47
|
)
|
|
48
48
|
from snowflake.cli._plugins.snowpark.package.commands import app as package_app
|
|
49
|
+
from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
|
|
50
|
+
FunctionEntityModel,
|
|
51
|
+
ProcedureEntityModel,
|
|
52
|
+
)
|
|
49
53
|
from snowflake.cli._plugins.snowpark.snowpark_project_paths import (
|
|
50
54
|
SnowparkProjectPaths,
|
|
51
55
|
)
|
|
@@ -87,10 +91,6 @@ from snowflake.cli.api.output.types import (
|
|
|
87
91
|
from snowflake.cli.api.project.definition_conversion import (
|
|
88
92
|
convert_project_definition_to_v2,
|
|
89
93
|
)
|
|
90
|
-
from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
|
|
91
|
-
FunctionEntityModel,
|
|
92
|
-
ProcedureEntityModel,
|
|
93
|
-
)
|
|
94
94
|
from snowflake.cli.api.project.schemas.project_definition import (
|
|
95
95
|
ProjectDefinition,
|
|
96
96
|
ProjectDefinitionV2,
|