snowflake-cli 3.9.1__py3-none-any.whl → 3.10.1__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 -2
- snowflake/cli/_app/printing.py +53 -13
- snowflake/cli/_app/snow_connector.py +1 -0
- snowflake/cli/_app/telemetry.py +2 -0
- snowflake/cli/_app/version_check.py +73 -6
- snowflake/cli/_plugins/cortex/commands.py +8 -3
- snowflake/cli/_plugins/cortex/manager.py +24 -20
- snowflake/cli/_plugins/dbt/commands.py +5 -2
- snowflake/cli/_plugins/dbt/manager.py +9 -7
- snowflake/cli/_plugins/{project → dcm}/commands.py +95 -48
- snowflake/cli/_plugins/{project/project_entity_model.py → dcm/dcm_project_entity_model.py} +5 -5
- snowflake/cli/_plugins/{project → dcm}/manager.py +35 -14
- snowflake/cli/_plugins/{project → dcm}/plugin_spec.py +1 -1
- snowflake/cli/_plugins/git/manager.py +1 -11
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +4 -0
- snowflake/cli/_plugins/nativeapp/commands.py +3 -4
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +1 -1
- snowflake/cli/_plugins/nativeapp/release_channel/commands.py +1 -2
- snowflake/cli/_plugins/nativeapp/version/commands.py +1 -2
- snowflake/cli/_plugins/snowpark/common.py +23 -11
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +13 -5
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +10 -2
- snowflake/cli/_plugins/sql/commands.py +49 -1
- snowflake/cli/_plugins/sql/manager.py +14 -4
- snowflake/cli/_plugins/sql/repl.py +4 -0
- snowflake/cli/_plugins/stage/commands.py +30 -11
- snowflake/cli/_plugins/stage/diff.py +2 -0
- snowflake/cli/_plugins/stage/manager.py +79 -55
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +17 -30
- snowflake/cli/api/artifacts/upload.py +1 -1
- snowflake/cli/api/cli_global_context.py +5 -14
- snowflake/cli/api/commands/decorators.py +7 -0
- snowflake/cli/api/commands/flags.py +12 -0
- snowflake/cli/api/commands/snow_typer.py +23 -2
- snowflake/cli/api/config.py +9 -5
- snowflake/cli/api/connections.py +1 -0
- snowflake/cli/api/constants.py +2 -2
- snowflake/cli/api/entities/common.py +16 -13
- snowflake/cli/api/entities/utils.py +15 -9
- snowflake/cli/api/feature_flags.py +2 -5
- snowflake/cli/api/output/formats.py +6 -0
- snowflake/cli/api/output/types.py +48 -2
- snowflake/cli/api/project/schemas/entities/entities.py +6 -6
- snowflake/cli/api/rendering/sql_templates.py +67 -11
- snowflake/cli/api/rest_api.py +1 -0
- snowflake/cli/api/stage_path.py +41 -5
- {snowflake_cli-3.9.1.dist-info → snowflake_cli-3.10.1.dist-info}/METADATA +46 -13
- {snowflake_cli-3.9.1.dist-info → snowflake_cli-3.10.1.dist-info}/RECORD +53 -54
- snowflake/cli/_plugins/project/feature_flags.py +0 -22
- /snowflake/cli/_plugins/{project → dcm}/__init__.py +0 -0
- {snowflake_cli-3.9.1.dist-info → snowflake_cli-3.10.1.dist-info}/WHEEL +0 -0
- {snowflake_cli-3.9.1.dist-info → snowflake_cli-3.10.1.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.9.1.dist-info → snowflake_cli-3.10.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,17 +15,17 @@
|
|
|
15
15
|
from typing import List, Optional
|
|
16
16
|
|
|
17
17
|
import typer
|
|
18
|
+
from snowflake.cli._plugins.dcm.dcm_project_entity_model import (
|
|
19
|
+
DCMProjectEntityModel,
|
|
20
|
+
)
|
|
21
|
+
from snowflake.cli._plugins.dcm.manager import DCMProjectManager
|
|
18
22
|
from snowflake.cli._plugins.object.command_aliases import add_object_command_aliases
|
|
19
23
|
from snowflake.cli._plugins.object.commands import scope_option
|
|
20
24
|
from snowflake.cli._plugins.object.manager import ObjectManager
|
|
21
|
-
from snowflake.cli._plugins.project.feature_flags import FeatureFlag
|
|
22
|
-
from snowflake.cli._plugins.project.manager import ProjectManager
|
|
23
|
-
from snowflake.cli._plugins.project.project_entity_model import (
|
|
24
|
-
ProjectEntityModel,
|
|
25
|
-
)
|
|
26
25
|
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
27
26
|
from snowflake.cli.api.commands.decorators import with_project_definition
|
|
28
27
|
from snowflake.cli.api.commands.flags import (
|
|
28
|
+
IfExistsOption,
|
|
29
29
|
IfNotExistsOption,
|
|
30
30
|
OverrideableOption,
|
|
31
31
|
PruneOption,
|
|
@@ -39,6 +39,7 @@ from snowflake.cli.api.commands.utils import get_entity_for_operation
|
|
|
39
39
|
from snowflake.cli.api.console.console import cli_console
|
|
40
40
|
from snowflake.cli.api.constants import ObjectType
|
|
41
41
|
from snowflake.cli.api.exceptions import CliError
|
|
42
|
+
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
42
43
|
from snowflake.cli.api.identifiers import FQN
|
|
43
44
|
from snowflake.cli.api.output.types import (
|
|
44
45
|
MessageResult,
|
|
@@ -47,16 +48,16 @@ from snowflake.cli.api.output.types import (
|
|
|
47
48
|
)
|
|
48
49
|
|
|
49
50
|
app = SnowTyperFactory(
|
|
50
|
-
name="
|
|
51
|
-
help="Manages
|
|
51
|
+
name="dcm",
|
|
52
|
+
help="Manages DCM Projects in Snowflake.",
|
|
52
53
|
is_hidden=FeatureFlag.ENABLE_SNOWFLAKE_PROJECTS.is_disabled,
|
|
53
54
|
)
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
dcm_identifier = identifier_argument(sf_object="DCM Project", example="MY_PROJECT")
|
|
56
57
|
version_flag = typer.Option(
|
|
57
58
|
None,
|
|
58
59
|
"--version",
|
|
59
|
-
help="Version of the
|
|
60
|
+
help="Version of the DCM Project to use. If not specified default version is used. For names containing '$', use single quotes to prevent shell expansion (e.g., 'VERSION$1').",
|
|
60
61
|
show_default=False,
|
|
61
62
|
)
|
|
62
63
|
variables_flag = variables_option(
|
|
@@ -65,64 +66,77 @@ variables_flag = variables_option(
|
|
|
65
66
|
configuration_flag = typer.Option(
|
|
66
67
|
None,
|
|
67
68
|
"--configuration",
|
|
68
|
-
help="Configuration of the
|
|
69
|
+
help="Configuration of the DCM Project to use. If not specified default configuration is used.",
|
|
69
70
|
show_default=False,
|
|
70
71
|
)
|
|
71
72
|
from_option = OverrideableOption(
|
|
72
73
|
None,
|
|
73
74
|
"--from",
|
|
74
|
-
help="Create a new version using given stage instead of uploading local files.",
|
|
75
75
|
show_default=False,
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
add_object_command_aliases(
|
|
80
80
|
app=app,
|
|
81
|
-
object_type=ObjectType.
|
|
82
|
-
name_argument=
|
|
81
|
+
object_type=ObjectType.DCM_PROJECT,
|
|
82
|
+
name_argument=dcm_identifier,
|
|
83
83
|
like_option=like_option(
|
|
84
|
-
help_example='`list --like "my%"` lists all
|
|
84
|
+
help_example='`list --like "my%"` lists all DCM Projects that begin with "my"'
|
|
85
85
|
),
|
|
86
86
|
scope_option=scope_option(help_example="`list --in database my_db`"),
|
|
87
|
-
ommit_commands=["create"
|
|
87
|
+
ommit_commands=["create"],
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
@app.command(requires_connection=True)
|
|
92
|
-
def
|
|
93
|
-
identifier: FQN =
|
|
92
|
+
def deploy(
|
|
93
|
+
identifier: FQN = dcm_identifier,
|
|
94
94
|
version: Optional[str] = version_flag,
|
|
95
|
+
from_stage: Optional[str] = from_option(
|
|
96
|
+
help="Apply changes defined in given stage instead of using a specific project version."
|
|
97
|
+
),
|
|
95
98
|
variables: Optional[List[str]] = variables_flag,
|
|
96
99
|
configuration: Optional[str] = configuration_flag,
|
|
97
100
|
**options,
|
|
98
101
|
):
|
|
99
102
|
"""
|
|
100
|
-
|
|
103
|
+
Applies changes defined in DCM Project to Snowflake.
|
|
101
104
|
"""
|
|
102
|
-
|
|
105
|
+
if version and from_stage:
|
|
106
|
+
raise CliError("--version and --from are mutually exclusive.")
|
|
107
|
+
|
|
108
|
+
result = DCMProjectManager().execute(
|
|
103
109
|
project_name=identifier,
|
|
104
110
|
configuration=configuration,
|
|
105
111
|
version=version,
|
|
112
|
+
from_stage=from_stage,
|
|
106
113
|
variables=variables,
|
|
107
114
|
)
|
|
108
115
|
return QueryJsonValueResult(result)
|
|
109
116
|
|
|
110
117
|
|
|
111
118
|
@app.command(requires_connection=True)
|
|
112
|
-
def
|
|
113
|
-
identifier: FQN =
|
|
119
|
+
def plan(
|
|
120
|
+
identifier: FQN = dcm_identifier,
|
|
114
121
|
version: Optional[str] = version_flag,
|
|
122
|
+
from_stage: Optional[str] = from_option(
|
|
123
|
+
help="Plan DCM Project deployment from given stage instead of using a specific version."
|
|
124
|
+
),
|
|
115
125
|
variables: Optional[List[str]] = variables_flag,
|
|
116
126
|
configuration: Optional[str] = configuration_flag,
|
|
117
127
|
**options,
|
|
118
128
|
):
|
|
119
129
|
"""
|
|
120
|
-
|
|
130
|
+
Plans a DCM Project deployment (validates without executing).
|
|
121
131
|
"""
|
|
122
|
-
|
|
132
|
+
if version and from_stage:
|
|
133
|
+
raise CliError("--version and --from are mutually exclusive.")
|
|
134
|
+
|
|
135
|
+
result = DCMProjectManager().execute(
|
|
123
136
|
project_name=identifier,
|
|
124
137
|
configuration=configuration,
|
|
125
138
|
version=version,
|
|
139
|
+
from_stage=from_stage,
|
|
126
140
|
dry_run=True,
|
|
127
141
|
variables=variables,
|
|
128
142
|
)
|
|
@@ -132,11 +146,11 @@ def dry_run(
|
|
|
132
146
|
@app.command(requires_connection=True)
|
|
133
147
|
@with_project_definition()
|
|
134
148
|
def create(
|
|
135
|
-
entity_id: str = entity_argument("
|
|
149
|
+
entity_id: str = entity_argument("dcm"),
|
|
136
150
|
no_version: bool = typer.Option(
|
|
137
151
|
False,
|
|
138
152
|
"--no-version",
|
|
139
|
-
help="Do not initialize
|
|
153
|
+
help="Do not initialize DCM Project with a new version, only create the snowflake object.",
|
|
140
154
|
),
|
|
141
155
|
if_not_exists: bool = IfNotExistsOption(
|
|
142
156
|
help="Do nothing if the project already exists."
|
|
@@ -144,19 +158,19 @@ def create(
|
|
|
144
158
|
**options,
|
|
145
159
|
):
|
|
146
160
|
"""
|
|
147
|
-
Creates a
|
|
148
|
-
By default, the
|
|
161
|
+
Creates a DCM Project in Snowflake.
|
|
162
|
+
By default, the DCM Project is initialized with a new version created from local files.
|
|
149
163
|
"""
|
|
150
164
|
cli_context = get_cli_context()
|
|
151
|
-
project:
|
|
165
|
+
project: DCMProjectEntityModel = get_entity_for_operation(
|
|
152
166
|
cli_context=cli_context,
|
|
153
167
|
entity_id=entity_id,
|
|
154
168
|
project_definition=cli_context.project_definition,
|
|
155
|
-
entity_type="
|
|
169
|
+
entity_type="dcm",
|
|
156
170
|
)
|
|
157
171
|
om = ObjectManager()
|
|
158
|
-
if om.object_exists(object_type="
|
|
159
|
-
message = f"Project '{project.fqn}' already exists."
|
|
172
|
+
if om.object_exists(object_type="dcm", fqn=project.fqn):
|
|
173
|
+
message = f"DCM Project '{project.fqn}' already exists."
|
|
160
174
|
if if_not_exists:
|
|
161
175
|
return MessageResult(message)
|
|
162
176
|
raise CliError(message)
|
|
@@ -166,22 +180,24 @@ def create(
|
|
|
166
180
|
):
|
|
167
181
|
raise CliError(f"Stage '{project.stage}' already exists.")
|
|
168
182
|
|
|
169
|
-
|
|
170
|
-
with cli_console.phase(f"Creating
|
|
171
|
-
|
|
183
|
+
dpm = DCMProjectManager()
|
|
184
|
+
with cli_console.phase(f"Creating DCM Project '{project.fqn}'"):
|
|
185
|
+
dpm.create(project=project, initialize_version_from_local_files=not no_version)
|
|
172
186
|
|
|
173
187
|
if no_version:
|
|
174
|
-
return MessageResult(f"Project '{project.fqn}' successfully created.")
|
|
188
|
+
return MessageResult(f"DCM Project '{project.fqn}' successfully created.")
|
|
175
189
|
return MessageResult(
|
|
176
|
-
f"Project '{project.fqn}' successfully created and initial version is added."
|
|
190
|
+
f"DCM Project '{project.fqn}' successfully created and initial version is added."
|
|
177
191
|
)
|
|
178
192
|
|
|
179
193
|
|
|
180
194
|
@app.command(requires_connection=True)
|
|
181
195
|
@with_project_definition()
|
|
182
196
|
def add_version(
|
|
183
|
-
entity_id: str = entity_argument("
|
|
184
|
-
_from: Optional[str] = from_option(
|
|
197
|
+
entity_id: str = entity_argument("dcm"),
|
|
198
|
+
_from: Optional[str] = from_option(
|
|
199
|
+
help="Create a new version using given stage instead of uploading local files."
|
|
200
|
+
),
|
|
185
201
|
_alias: Optional[str] = typer.Option(
|
|
186
202
|
None, "--alias", help="Alias for the version.", show_default=False
|
|
187
203
|
),
|
|
@@ -191,25 +207,25 @@ def add_version(
|
|
|
191
207
|
prune: bool = PruneOption(default=True),
|
|
192
208
|
**options,
|
|
193
209
|
):
|
|
194
|
-
"""Uploads local files to Snowflake and cerates a new
|
|
210
|
+
"""Uploads local files to Snowflake and cerates a new DCM Project version."""
|
|
195
211
|
if _from is not None and prune:
|
|
196
212
|
cli_console.warning(
|
|
197
213
|
"When `--from` option is used, `--prune` option will be ignored and files from stage will be used as they are."
|
|
198
214
|
)
|
|
199
215
|
prune = False
|
|
200
216
|
cli_context = get_cli_context()
|
|
201
|
-
project:
|
|
217
|
+
project: DCMProjectEntityModel = get_entity_for_operation(
|
|
202
218
|
cli_context=cli_context,
|
|
203
219
|
entity_id=entity_id,
|
|
204
220
|
project_definition=cli_context.project_definition,
|
|
205
|
-
entity_type="
|
|
221
|
+
entity_type="dcm",
|
|
206
222
|
)
|
|
207
223
|
om = ObjectManager()
|
|
208
|
-
if not om.object_exists(object_type="
|
|
224
|
+
if not om.object_exists(object_type="dcm", fqn=project.fqn):
|
|
209
225
|
raise CliError(
|
|
210
|
-
f"Project '{project.fqn}' does not exist. Use `
|
|
226
|
+
f"DCM Project '{project.fqn}' does not exist. Use `dcm create` command first."
|
|
211
227
|
)
|
|
212
|
-
|
|
228
|
+
DCMProjectManager().add_version(
|
|
213
229
|
project=project,
|
|
214
230
|
prune=prune,
|
|
215
231
|
from_stage=_from,
|
|
@@ -218,18 +234,49 @@ def add_version(
|
|
|
218
234
|
)
|
|
219
235
|
alias_str = "" if _alias is None else f"'{_alias}' "
|
|
220
236
|
return MessageResult(
|
|
221
|
-
f"New
|
|
237
|
+
f"New version {alias_str}added to DCM Project '{project.fqn}'."
|
|
222
238
|
)
|
|
223
239
|
|
|
224
240
|
|
|
225
241
|
@app.command(requires_connection=True)
|
|
226
242
|
def list_versions(
|
|
227
|
-
identifier: FQN =
|
|
243
|
+
identifier: FQN = dcm_identifier,
|
|
228
244
|
**options,
|
|
229
245
|
):
|
|
230
246
|
"""
|
|
231
|
-
Lists versions of given
|
|
247
|
+
Lists versions of given DCM Project.
|
|
232
248
|
"""
|
|
233
|
-
pm =
|
|
249
|
+
pm = DCMProjectManager()
|
|
234
250
|
results = pm.list_versions(project_name=identifier)
|
|
235
251
|
return QueryResult(results)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@app.command(requires_connection=True)
|
|
255
|
+
def drop_version(
|
|
256
|
+
identifier: FQN = dcm_identifier,
|
|
257
|
+
version_name: str = typer.Argument(
|
|
258
|
+
help="Name or alias of the version to drop. For names containing '$', use single quotes to prevent shell expansion (e.g., 'VERSION$1').",
|
|
259
|
+
show_default=False,
|
|
260
|
+
),
|
|
261
|
+
if_exists: bool = IfExistsOption(help="Do nothing if the version does not exist."),
|
|
262
|
+
**options,
|
|
263
|
+
):
|
|
264
|
+
"""
|
|
265
|
+
Drops a version from the DCM Project.
|
|
266
|
+
"""
|
|
267
|
+
# Detect potential shell expansion issues
|
|
268
|
+
if version_name and version_name.upper() == "VERSION":
|
|
269
|
+
cli_console.warning(
|
|
270
|
+
f"Version name '{version_name}' might be truncated due to shell expansion. "
|
|
271
|
+
f"If you meant to use a version like 'VERSION$1', try using single quotes: 'VERSION$1'."
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
dpm = DCMProjectManager()
|
|
275
|
+
dpm.drop_version(
|
|
276
|
+
project_name=identifier,
|
|
277
|
+
version_name=version_name,
|
|
278
|
+
if_exists=if_exists,
|
|
279
|
+
)
|
|
280
|
+
return MessageResult(
|
|
281
|
+
f"Version '{version_name}' dropped from DCM Project '{identifier}'."
|
|
282
|
+
)
|
|
@@ -35,10 +35,10 @@ T = TypeVar("T")
|
|
|
35
35
|
MANIFEST_FILE_NAME = "manifest.yml"
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
class
|
|
39
|
-
type: Literal["
|
|
38
|
+
class DCMProjectEntityModel(EntityModelBaseWithArtifacts):
|
|
39
|
+
type: Literal["dcm"] = DiscriminatorField() # noqa: A003
|
|
40
40
|
stage: Optional[str] = Field(
|
|
41
|
-
title="Stage in which the
|
|
41
|
+
title="Stage in which the DCM Project artifacts will be stored", default=None
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
@field_validator("artifacts")
|
|
@@ -54,6 +54,6 @@ class ProjectEntityModel(EntityModelBaseWithArtifacts):
|
|
|
54
54
|
return super().transform_artifacts(orig_artifacts)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
@attach_spans_to_entity_actions(entity_name="
|
|
58
|
-
class
|
|
57
|
+
@attach_spans_to_entity_actions(entity_name="dcm")
|
|
58
|
+
class DCMProjectEntity(EntityBase[DCMProjectEntityModel]):
|
|
59
59
|
"""Placeholder for project entity"""
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
from textwrap import dedent
|
|
15
15
|
from typing import List, Optional
|
|
16
16
|
|
|
17
|
-
from snowflake.cli._plugins.
|
|
17
|
+
from snowflake.cli._plugins.dcm.dcm_project_entity_model import DCMProjectEntityModel
|
|
18
18
|
from snowflake.cli._plugins.stage.manager import StageManager
|
|
19
19
|
from snowflake.cli.api.artifacts.upload import sync_artifacts_with_stage
|
|
20
20
|
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
@@ -27,16 +27,21 @@ from snowflake.cli.api.stage_path import StagePath
|
|
|
27
27
|
from snowflake.connector.cursor import SnowflakeCursor
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class
|
|
30
|
+
class DCMProjectManager(SqlExecutionMixin):
|
|
31
31
|
def execute(
|
|
32
32
|
self,
|
|
33
33
|
project_name: FQN,
|
|
34
34
|
configuration: str | None = None,
|
|
35
35
|
version: str | None = None,
|
|
36
|
+
from_stage: str | None = None,
|
|
36
37
|
variables: List[str] | None = None,
|
|
37
38
|
dry_run: bool = False,
|
|
38
39
|
):
|
|
39
|
-
query = f"EXECUTE PROJECT {project_name.sql_identifier}"
|
|
40
|
+
query = f"EXECUTE DCM PROJECT {project_name.sql_identifier}"
|
|
41
|
+
if dry_run:
|
|
42
|
+
query += " PLAN"
|
|
43
|
+
else:
|
|
44
|
+
query += " DEPLOY"
|
|
40
45
|
if configuration or variables:
|
|
41
46
|
query += f" USING"
|
|
42
47
|
if configuration:
|
|
@@ -47,16 +52,17 @@ class ProjectManager(SqlExecutionMixin):
|
|
|
47
52
|
).removeprefix(" using")
|
|
48
53
|
if version:
|
|
49
54
|
query += f" WITH VERSION {version}"
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
elif from_stage:
|
|
56
|
+
stage_path = StagePath.from_stage_str(from_stage)
|
|
57
|
+
query += f" FROM {stage_path.absolute_path()}"
|
|
52
58
|
return self.execute_query(query=query)
|
|
53
59
|
|
|
54
60
|
def _create_object(self, project_name: FQN) -> SnowflakeCursor:
|
|
55
|
-
query = dedent(f"CREATE PROJECT {project_name.sql_identifier}")
|
|
61
|
+
query = dedent(f"CREATE DCM PROJECT {project_name.sql_identifier}")
|
|
56
62
|
return self.execute_query(query)
|
|
57
63
|
|
|
58
64
|
def create(
|
|
59
|
-
self, project:
|
|
65
|
+
self, project: DCMProjectEntityModel, initialize_version_from_local_files: bool
|
|
60
66
|
) -> None:
|
|
61
67
|
self._create_object(project.fqn)
|
|
62
68
|
if initialize_version_from_local_files:
|
|
@@ -70,9 +76,9 @@ class ProjectManager(SqlExecutionMixin):
|
|
|
70
76
|
comment: str | None = None,
|
|
71
77
|
):
|
|
72
78
|
stage_path = StagePath.from_stage_str(from_stage)
|
|
73
|
-
query = f"ALTER PROJECT {project_name.identifier} ADD VERSION"
|
|
79
|
+
query = f"ALTER DCM PROJECT {project_name.identifier} ADD VERSION"
|
|
74
80
|
if alias:
|
|
75
|
-
query += f
|
|
81
|
+
query += f" IF NOT EXISTS {alias}"
|
|
76
82
|
query += f" FROM {stage_path.absolute_path(at_prefix=True)}"
|
|
77
83
|
if comment:
|
|
78
84
|
query += f" COMMENT = '{comment}'"
|
|
@@ -80,15 +86,15 @@ class ProjectManager(SqlExecutionMixin):
|
|
|
80
86
|
|
|
81
87
|
def add_version(
|
|
82
88
|
self,
|
|
83
|
-
project:
|
|
89
|
+
project: DCMProjectEntityModel,
|
|
84
90
|
prune: bool = False,
|
|
85
91
|
from_stage: Optional[str] = None,
|
|
86
92
|
alias: Optional[str] = None,
|
|
87
93
|
comment: Optional[str] = None,
|
|
88
94
|
):
|
|
89
95
|
"""
|
|
90
|
-
Adds a version to
|
|
91
|
-
uploads local files to the stage defined in
|
|
96
|
+
Adds a version to DCM Project. If [from_stage] is not defined,
|
|
97
|
+
uploads local files to the stage defined in DCM Project definition.
|
|
92
98
|
"""
|
|
93
99
|
|
|
94
100
|
if not from_stage:
|
|
@@ -102,7 +108,7 @@ class ProjectManager(SqlExecutionMixin):
|
|
|
102
108
|
prune=prune,
|
|
103
109
|
)
|
|
104
110
|
|
|
105
|
-
with cli_console.phase(f"Creating
|
|
111
|
+
with cli_console.phase(f"Creating DCM Project version from stage {from_stage}"):
|
|
106
112
|
return self._create_version(
|
|
107
113
|
project_name=project.fqn,
|
|
108
114
|
from_stage=from_stage, # type:ignore
|
|
@@ -111,5 +117,20 @@ class ProjectManager(SqlExecutionMixin):
|
|
|
111
117
|
)
|
|
112
118
|
|
|
113
119
|
def list_versions(self, project_name: FQN):
|
|
114
|
-
query = f"SHOW VERSIONS IN PROJECT {project_name.identifier}"
|
|
120
|
+
query = f"SHOW VERSIONS IN DCM PROJECT {project_name.identifier}"
|
|
121
|
+
return self.execute_query(query=query)
|
|
122
|
+
|
|
123
|
+
def drop_version(
|
|
124
|
+
self,
|
|
125
|
+
project_name: FQN,
|
|
126
|
+
version_name: str,
|
|
127
|
+
if_exists: bool = False,
|
|
128
|
+
):
|
|
129
|
+
"""
|
|
130
|
+
Drops a version from the DCM Project.
|
|
131
|
+
"""
|
|
132
|
+
query = f"ALTER DCM PROJECT {project_name.identifier} DROP VERSION"
|
|
133
|
+
if if_exists:
|
|
134
|
+
query += " IF EXISTS"
|
|
135
|
+
query += f" {version_name}"
|
|
115
136
|
return self.execute_query(query=query)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from snowflake.cli._plugins.
|
|
15
|
+
from snowflake.cli._plugins.dcm import commands
|
|
16
16
|
from snowflake.cli.api.plugins.command import (
|
|
17
17
|
SNOWCLI_ROOT_COMMAND_PATH,
|
|
18
18
|
CommandSpec,
|
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
-
from pathlib import
|
|
17
|
+
from pathlib import PurePosixPath
|
|
18
18
|
from textwrap import dedent
|
|
19
|
-
from typing import List
|
|
20
19
|
|
|
21
20
|
from click import UsageError
|
|
22
21
|
from snowflake.cli._plugins.stage.manager import (
|
|
@@ -64,19 +63,10 @@ class GitStagePathParts(StagePathParts):
|
|
|
64
63
|
def full_path(self) -> str:
|
|
65
64
|
return f"{self.stage.rstrip('/')}/{self.directory}"
|
|
66
65
|
|
|
67
|
-
def replace_stage_prefix(self, file_path: str) -> str:
|
|
68
|
-
stage = Path(self.stage).parts[0]
|
|
69
|
-
file_path_without_prefix = Path(file_path).parts[OMIT_FIRST]
|
|
70
|
-
return f"{stage}/{'/'.join(file_path_without_prefix)}"
|
|
71
|
-
|
|
72
66
|
def add_stage_prefix(self, file_path: str) -> str:
|
|
73
67
|
stage = self.stage.rstrip("/")
|
|
74
68
|
return f"{stage}/{file_path.lstrip('/')}"
|
|
75
69
|
|
|
76
|
-
def get_directory_from_file_path(self, file_path: str) -> List[str]:
|
|
77
|
-
stage_path_length = len(Path(self.directory).parts)
|
|
78
|
-
return list(Path(file_path).parts[3 + stage_path_length : -1])
|
|
79
|
-
|
|
80
70
|
|
|
81
71
|
class GitManager(StageManager):
|
|
82
72
|
@staticmethod
|
|
@@ -49,6 +49,7 @@ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
|
|
|
49
49
|
from snowflake.cli._plugins.stage.diff import to_stage_path
|
|
50
50
|
from snowflake.cli.api.artifacts.bundle_map import BundleMap
|
|
51
51
|
from snowflake.cli.api.cli_global_context import get_cli_context, span
|
|
52
|
+
from snowflake.cli.api.console import cli_console
|
|
52
53
|
from snowflake.cli.api.console import cli_console as cc
|
|
53
54
|
from snowflake.cli.api.metrics import CLICounterField
|
|
54
55
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
@@ -181,6 +182,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
|
|
|
181
182
|
setup script with generated SQL that registers these functions.
|
|
182
183
|
"""
|
|
183
184
|
|
|
185
|
+
cli_console.warning(
|
|
186
|
+
"Snowpark processor is not supported and will be removed soon."
|
|
187
|
+
)
|
|
184
188
|
get_cli_context().metrics.set_counter(CLICounterField.SNOWPARK_PROCESSOR, 1)
|
|
185
189
|
|
|
186
190
|
bundle_map = BundleMap(
|
|
@@ -55,7 +55,6 @@ from snowflake.cli.api.exceptions import (
|
|
|
55
55
|
IncompatibleParametersError,
|
|
56
56
|
UnmetParametersError,
|
|
57
57
|
)
|
|
58
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
59
58
|
from snowflake.cli.api.output.types import (
|
|
60
59
|
CommandResult,
|
|
61
60
|
MessageResult,
|
|
@@ -117,9 +116,9 @@ def app_diff(
|
|
|
117
116
|
diff = ws.perform_action(
|
|
118
117
|
package_id,
|
|
119
118
|
EntityActions.DIFF,
|
|
120
|
-
print_to_console=cli_context.output_format
|
|
119
|
+
print_to_console=not cli_context.output_format.is_json,
|
|
121
120
|
)
|
|
122
|
-
if cli_context.output_format
|
|
121
|
+
if cli_context.output_format.is_json:
|
|
123
122
|
return ObjectResult(diff.to_dict())
|
|
124
123
|
|
|
125
124
|
return None
|
|
@@ -373,7 +372,7 @@ def app_validate(
|
|
|
373
372
|
)
|
|
374
373
|
package_id = options["package_entity_id"]
|
|
375
374
|
package = ws.get_entity(package_id)
|
|
376
|
-
if cli_context.output_format
|
|
375
|
+
if cli_context.output_format.is_json:
|
|
377
376
|
return ObjectResult(
|
|
378
377
|
package.get_validation_result(
|
|
379
378
|
action_ctx=ws.action_ctx,
|
|
@@ -1330,7 +1330,7 @@ class ApplicationPackageEntity(EntityBase[ApplicationPackageEntityModel]):
|
|
|
1330
1330
|
role=self.role,
|
|
1331
1331
|
prune=prune,
|
|
1332
1332
|
recursive=recursive,
|
|
1333
|
-
|
|
1333
|
+
stage_path_parts=stage_path,
|
|
1334
1334
|
local_paths_to_sync=paths,
|
|
1335
1335
|
print_diff=print_diff,
|
|
1336
1336
|
)
|
|
@@ -26,7 +26,6 @@ from snowflake.cli.api.cli_global_context import get_cli_context
|
|
|
26
26
|
from snowflake.cli.api.commands.decorators import with_project_definition
|
|
27
27
|
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
28
28
|
from snowflake.cli.api.entities.utils import EntityActions
|
|
29
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
30
29
|
from snowflake.cli.api.output.types import (
|
|
31
30
|
CollectionResult,
|
|
32
31
|
CommandResult,
|
|
@@ -68,7 +67,7 @@ def release_channel_list(
|
|
|
68
67
|
release_channel=channel,
|
|
69
68
|
)
|
|
70
69
|
|
|
71
|
-
if cli_context.output_format
|
|
70
|
+
if cli_context.output_format.is_json:
|
|
72
71
|
return CollectionResult(channels)
|
|
73
72
|
|
|
74
73
|
|
|
@@ -30,7 +30,6 @@ from snowflake.cli.api.commands.decorators import (
|
|
|
30
30
|
)
|
|
31
31
|
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
32
32
|
from snowflake.cli.api.entities.utils import EntityActions
|
|
33
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
34
33
|
from snowflake.cli.api.output.types import (
|
|
35
34
|
CollectionResult,
|
|
36
35
|
CommandResult,
|
|
@@ -105,7 +104,7 @@ def create(
|
|
|
105
104
|
)
|
|
106
105
|
|
|
107
106
|
message = "Version create is now complete."
|
|
108
|
-
if cli_context.output_format
|
|
107
|
+
if cli_context.output_format.is_json:
|
|
109
108
|
return ObjectResult(
|
|
110
109
|
{
|
|
111
110
|
"message": message,
|
|
@@ -79,7 +79,6 @@ class SnowparkObjectManager(SqlExecutionMixin):
|
|
|
79
79
|
) -> str:
|
|
80
80
|
entity.imports.extend(artifact_files)
|
|
81
81
|
imports = [f"'{x}'" for x in entity.imports]
|
|
82
|
-
packages_list = ",".join(f"'{p}'" for p in snowflake_dependencies)
|
|
83
82
|
|
|
84
83
|
object_type = entity.get_type()
|
|
85
84
|
|
|
@@ -91,7 +90,6 @@ class SnowparkObjectManager(SqlExecutionMixin):
|
|
|
91
90
|
f"runtime_version={entity.runtime or DEFAULT_RUNTIME}",
|
|
92
91
|
f"imports=({', '.join(imports)})",
|
|
93
92
|
f"handler='{entity.handler}'",
|
|
94
|
-
f"packages=({packages_list})",
|
|
95
93
|
]
|
|
96
94
|
|
|
97
95
|
if entity.external_access_integrations:
|
|
@@ -100,17 +98,24 @@ class SnowparkObjectManager(SqlExecutionMixin):
|
|
|
100
98
|
if entity.secrets:
|
|
101
99
|
query.append(entity.get_secrets_sql())
|
|
102
100
|
|
|
103
|
-
if
|
|
104
|
-
|
|
101
|
+
if entity.artifact_repository_packages and entity.packages:
|
|
102
|
+
raise UsageError(
|
|
103
|
+
"You cannot specify both artifact_repository_packages and packages.",
|
|
104
|
+
)
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
packages_list = snowflake_dependencies.copy()
|
|
107
|
+
if entity.artifact_repository and (
|
|
108
|
+
entity.artifact_repository_packages or entity.packages
|
|
109
|
+
):
|
|
110
|
+
if entity.artifact_repository_packages:
|
|
111
|
+
packages_list.extend(entity.artifact_repository_packages)
|
|
112
|
+
else:
|
|
113
|
+
packages_list.extend(entity.packages)
|
|
114
|
+
query.append(
|
|
115
|
+
f"ARTIFACT_REPOSITORY= {entity.artifact_repository}",
|
|
113
116
|
)
|
|
117
|
+
packages = [f"'{item}'" for item in packages_list]
|
|
118
|
+
query.append(f"packages=({','.join(packages)})")
|
|
114
119
|
|
|
115
120
|
if entity.resource_constraint:
|
|
116
121
|
constraints = ",".join(
|
|
@@ -118,6 +123,9 @@ class SnowparkObjectManager(SqlExecutionMixin):
|
|
|
118
123
|
)
|
|
119
124
|
query.append(f"RESOURCE_CONSTRAINT=({constraints})")
|
|
120
125
|
|
|
126
|
+
if isinstance(entity, ProcedureEntityModel) and entity.execute_as_caller:
|
|
127
|
+
query.append("execute as caller")
|
|
128
|
+
|
|
121
129
|
return self.execute_query("\n".join(query))
|
|
122
130
|
|
|
123
131
|
def deploy_entity(
|
|
@@ -215,6 +223,10 @@ def _check_if_replace_is_required(
|
|
|
215
223
|
)
|
|
216
224
|
return True
|
|
217
225
|
|
|
226
|
+
if entity.packages != resource_json.get("artifact_repository_packages", None):
|
|
227
|
+
log.info("Packages do not match. Replacing the %s", object_type)
|
|
228
|
+
return True
|
|
229
|
+
|
|
218
230
|
if isinstance(entity, ProcedureEntityModel):
|
|
219
231
|
if resource_json.get("execute as", "OWNER") != (
|
|
220
232
|
"CALLER" if entity.execute_as_caller else "OWNER"
|