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.
Files changed (73) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
  3. snowflake/cli/_app/secret.py +9 -0
  4. snowflake/cli/_app/snow_connector.py +39 -27
  5. snowflake/cli/_plugins/git/manager.py +53 -7
  6. snowflake/cli/_plugins/helpers/commands.py +57 -0
  7. snowflake/cli/{api/project/schemas/snowpark/__init__.py → _plugins/helpers/plugin_spec.py} +17 -0
  8. snowflake/cli/{api/entities → _plugins/nativeapp}/application_entity.py +18 -64
  9. snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_entity_model.py +2 -2
  10. snowflake/cli/{api/entities → _plugins/nativeapp}/application_package_entity.py +482 -33
  11. snowflake/cli/{api/project/schemas/entities → _plugins/nativeapp}/application_package_entity_model.py +3 -3
  12. snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
  13. snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
  14. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
  15. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +1 -1
  16. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
  17. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
  18. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
  19. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +1 -1
  20. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +1 -1
  21. snowflake/cli/_plugins/nativeapp/commands.py +84 -16
  22. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
  23. snowflake/cli/_plugins/nativeapp/manager.py +14 -9
  24. snowflake/cli/_plugins/nativeapp/policy.py +3 -0
  25. snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
  26. snowflake/cli/_plugins/nativeapp/run_processor.py +16 -19
  27. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -4
  28. snowflake/cli/_plugins/nativeapp/teardown_processor.py +6 -6
  29. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +124 -88
  30. snowflake/cli/_plugins/nativeapp/version/commands.py +6 -24
  31. snowflake/cli/_plugins/nativeapp/version/version_processor.py +35 -235
  32. snowflake/cli/_plugins/snowpark/commands.py +4 -4
  33. snowflake/cli/_plugins/snowpark/common.py +4 -4
  34. snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
  35. snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
  36. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
  37. snowflake/cli/_plugins/stage/manager.py +9 -4
  38. snowflake/cli/_plugins/streamlit/commands.py +3 -3
  39. snowflake/cli/_plugins/streamlit/manager.py +8 -4
  40. snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
  41. snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
  42. snowflake/cli/_plugins/workspace/commands.py +83 -36
  43. snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
  44. snowflake/cli/api/commands/snow_typer.py +1 -1
  45. snowflake/cli/api/entities/common.py +3 -0
  46. snowflake/cli/api/entities/utils.py +0 -14
  47. snowflake/cli/api/errno.py +1 -0
  48. snowflake/cli/api/identifiers.py +4 -3
  49. snowflake/cli/api/project/definition_conversion.py +10 -9
  50. snowflake/cli/api/project/schemas/entities/common.py +17 -4
  51. snowflake/cli/api/project/schemas/entities/entities.py +13 -10
  52. snowflake/cli/api/project/schemas/project_definition.py +6 -6
  53. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  54. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
  55. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  56. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  57. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  58. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  59. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  60. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  61. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  62. snowflake/cli/api/sql_execution.py +6 -15
  63. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/METADATA +6 -6
  64. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/RECORD +72 -67
  65. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  66. /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
  67. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
  68. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
  69. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  70. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  71. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/WHEEL +0 -0
  72. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc3.dist-info}/entry_points.txt +0 -0
  73. {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.application_entity_model import (
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
- if app_entity_id:
74
- # If the user specified an app entity ID, use that one directly
75
- app_definition = apps.get(app_entity_id)
76
- elif len(apps) == 1:
77
- # Otherwise, if there is only one app entity, fall back to that one
78
- app_definition = next(iter(apps.values()))
79
- elif len(apps) > 1:
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 target_package != package_entity_id:
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 packages:
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
- if package_entity_id:
106
- # If the user specified a package entity ID (or we inferred one from the app entity), use that one directly
107
- app_package_definition = packages.get(package_entity_id)
108
- elif len(packages) == 1:
109
- # Otherwise, if there is only one package entity, fall back to that one
110
- app_package_definition = next(iter(packages.values()))
111
- elif len(packages) > 1:
112
- # If there are multiple package entities, the user must specify which one to use
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
- def nativeapp_definition_v2_to_v1(func):
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
- @wraps(func)
193
- def wrapper(*args, **kwargs):
194
- original_pdf: Optional[DefinitionV20] = get_cli_context().project_definition
195
- if not original_pdf:
196
- raise ValueError(
197
- "Project definition could not be found. The nativeapp_definition_v2_to_v1 command decorator assumes with_project_definition() was called before it."
198
- )
199
- if original_pdf.definition_version == "2":
200
- package_entity_id = kwargs.get("package_entity_id", "")
201
- app_entity_id = kwargs.get("app_entity_id", "")
202
- pdfv1 = _pdf_v2_to_v1(original_pdf, package_entity_id, app_entity_id)
203
- get_cli_context_manager().override_project_definition = pdfv1
204
- return func(*args, **kwargs)
205
-
206
- return _options_decorator_factory(
207
- wrapper,
208
- additional_options=[
209
- inspect.Parameter(
210
- "package_entity_id",
211
- inspect.Parameter.KEYWORD_ONLY,
212
- annotation=Optional[str],
213
- default=typer.Option(
214
- default="",
215
- help="The ID of the package entity on which to operate when definition_version is 2 or higher.",
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
- inspect.Parameter(
219
- "app_entity_id",
220
- inspect.Parameter.KEYWORD_ONLY,
221
- annotation=Optional[str],
222
- default=typer.Option(
223
- default="",
224
- help="The ID of the application entity on which to operate when definition_version is 2 or higher.",
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
- policy=policy,
112
- git_policy=git_policy,
113
- is_interactive=is_interactive,
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, List, Optional
19
+ from typing import Dict, Optional
20
20
 
21
21
  import typer
22
- from click import BadOptionUsage, ClickException
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.entities.utils import ensure_correct_owner
40
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
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
- policy: PolicyBase,
174
- git_policy: PolicyBase,
175
- is_interactive: bool,
52
+ force: bool,
53
+ interactive: bool,
54
+ skip_git_check: bool,
176
55
  *args,
177
56
  **kwargs,
178
57
  ):
179
- """
180
- Perform bundle, application package creation, stage upload, version and/or patch to an application package.
181
- """
182
-
183
- # Make sure version is not None before proceeding any further.
184
- # This will raise an exception if version information is not found. Patch can be None.
185
- if not version:
186
- cc.message(
187
- "Version was not provided through the Snowflake CLI. Checking version in the manifest.yml instead."
188
- )
189
-
190
- version, patch = find_version_info_in_manifest_file(self.deploy_root)
191
- if not version:
192
- raise ClickException(
193
- "Manifest.yml file does not contain a value for the version field."
194
- )
195
-
196
- # Check if --patch needs to throw a bad option error, either if application package does not exist or if version does not exist
197
- if patch:
198
- try:
199
- if not self.get_existing_version_info(version):
200
- raise BadOptionUsage(
201
- option_name="patch",
202
- message=f"Cannot create a custom patch when version {version} is not defined in the application package {self.package_name}. Try again without using --patch.",
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,