Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-picks to 3.1.0rc1 #1752

Merged
merged 7 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
## Fixes and improvements
* Fixed a bug that would cause the `deploy_root`, `bundle_root`, and `generated_root` directories to be created in the current working directory instead of the project root when invoking commands with the `--project` flag from a different directory.
* Align variables for `snow stage|git execute`. For Python files variables are stripped of leading and trailing quotes.
* `snow spcs service list-images` now displays image tag and digest.
* `snow spcs image-repository list-images` now displays image tag and digest.
* Fix `snow stage list-files` for paths with directories.
* `snow --info` callback returns information about `SNOWFLAKE_HOME` variable.

# v3.0.2

Expand Down
2 changes: 2 additions & 0 deletions src/snowflake/cli/_app/cli_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from __future__ import annotations

import logging
import os
import platform
import sys
from dataclasses import dataclass
Expand Down Expand Up @@ -141,6 +142,7 @@ def _info_callback(value: bool):
{"key": "python_version", "value": sys.version},
{"key": "system_info", "value": platform.platform()},
{"key": "feature_flags", "value": get_feature_flags_section()},
{"key": "SNOWFLAKE_HOME", "value": os.getenv("SNOWFLAKE_HOME")},
],
)
print_result(result, output_format=OutputFormat.JSON)
Expand Down
47 changes: 18 additions & 29 deletions src/snowflake/cli/_plugins/connection/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@

import logging
import os.path
from pathlib import Path

import typer
from click import ClickException, Context, Parameter # type: ignore
from click import ClickException, Context, Parameter, UsageError # type: ignore
from click.core import ParameterSource # type: ignore
from click.types import StringParamType
from snowflake import connector
Expand Down Expand Up @@ -355,36 +354,22 @@ def set_default(
return MessageResult(f"Default connection set to: {name}")


@app.command(requires_connection=False)
@app.command(requires_connection=True)
def generate_jwt(
account: str = typer.Option(
None,
"--account",
"-a",
"--accountname",
help="Account name to use when authenticating with Snowflake.",
show_default=False,
),
user: str = typer.Option(
None,
"--user",
"-u",
"--username",
show_default=False,
help="Username to connect to Snowflake.",
),
private_key_file: Path = typer.Option(
None,
"--private-key",
"--private-key-path",
"-k",
help="Path to file containing private key",
dir_okay=False,
exists=True,
),
**options,
) -> CommandResult:
"""Generate and display a JWT token."""
connection_details = get_cli_context().connection_context.update_from_config()

msq_template = (
"{} is not set in the connection context, but required for JWT generation."
)
if not connection_details.user:
raise UsageError(msq_template.format("User"))
if not connection_details.account:
raise UsageError(msq_template.format("Account"))
if not connection_details.private_key_file:
raise UsageError(msq_template.format("Private key file"))
passphrase = os.getenv("PRIVATE_KEY_PASSPHRASE", None)
if not passphrase:
passphrase = typer.prompt(
Expand All @@ -393,9 +378,13 @@ def generate_jwt(
type=str,
default="",
)

try:
token = connector.auth.get_token_from_private_key(
user, account, private_key_file, passphrase
user=connection_details.user,
account=connection_details.account,
privatekey_path=connection_details.private_key_file,
key_password=passphrase,
)
return MessageResult(token)
except ValueError as err:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,6 @@ def action_validate(
package_warehouse=(
(model.meta and model.meta.warehouse) or workspace_ctx.default_warehouse
),
post_deploy_hooks=model.meta and model.meta.post_deploy,
package_scripts=[], # Package scripts are not supported in PDFv2
policy=policy,
use_scratch_stage=use_scratch_stage,
scratch_stage_fqn=f"{package_name}.{model.scratch_stage}",
Expand Down Expand Up @@ -479,8 +477,6 @@ def deploy(
paths=paths,
stage_fqn=stage_fqn,
package_warehouse=package_warehouse,
post_deploy_hooks=post_deploy_hooks,
package_scripts=package_scripts,
policy=policy,
use_scratch_stage=False,
scratch_stage_fqn="",
Expand Down Expand Up @@ -1201,8 +1197,6 @@ def validate_setup_script(
recursive: bool,
paths: List[Path] | None,
stage_fqn: str,
post_deploy_hooks: list[PostDeployHook] | None,
package_scripts: List[str],
policy: PolicyBase,
use_scratch_stage: bool,
scratch_stage_fqn: str,
Expand All @@ -1224,8 +1218,6 @@ def validate_setup_script(
paths=paths,
stage_fqn=stage_fqn,
package_warehouse=package_warehouse,
post_deploy_hooks=post_deploy_hooks,
package_scripts=package_scripts,
policy=policy,
use_scratch_stage=use_scratch_stage,
scratch_stage_fqn=scratch_stage_fqn,
Expand Down Expand Up @@ -1268,8 +1260,6 @@ def get_validation_result(self, use_scratch_stage: bool = True):
package_warehouse=(
(model.meta and model.meta.warehouse) or workspace_ctx.default_warehouse
),
post_deploy_hooks=model.meta and model.meta.post_deploy,
package_scripts=[], # Package scripts are not supported in PDFv2
policy=AllowAlwaysPolicy(),
use_scratch_stage=use_scratch_stage,
scratch_stage_fqn=f"{package_name}.{model.scratch_stage}",
Expand All @@ -1292,8 +1282,6 @@ def get_validation_result_static(
recursive: bool,
paths: List[Path] | None,
stage_fqn: str,
post_deploy_hooks: list[PostDeployHook] | None,
package_scripts: List[str],
policy: PolicyBase,
use_scratch_stage: bool,
scratch_stage_fqn: str,
Expand All @@ -1319,8 +1307,8 @@ def get_validation_result_static(
validate=False,
stage_fqn=stage_fqn,
package_warehouse=package_warehouse,
post_deploy_hooks=post_deploy_hooks,
package_scripts=package_scripts,
post_deploy_hooks=[],
package_scripts=[],
policy=policy,
)
prefixed_stage_fqn = StageManager.get_standard_stage_prefix(stage_fqn)
Expand Down
4 changes: 0 additions & 4 deletions src/snowflake/cli/_plugins/nativeapp/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,6 @@ def validate(self, use_scratch_stage: bool = False):
paths=[],
stage_fqn=self.stage_fqn,
package_warehouse=self.package_warehouse,
post_deploy_hooks=self.package_post_deploy_hooks,
package_scripts=self.package_scripts,
policy=AllowAlwaysPolicy(),
use_scratch_stage=use_scratch_stage,
scratch_stage_fqn=self.scratch_stage_fqn,
Expand All @@ -348,8 +346,6 @@ def get_validation_result(self, use_scratch_stage: bool = False):
paths=[],
stage_fqn=self.stage_fqn,
package_warehouse=self.package_warehouse,
post_deploy_hooks=self.package_post_deploy_hooks,
package_scripts=self.package_scripts,
policy=AllowAlwaysPolicy(),
use_scratch_stage=use_scratch_stage,
scratch_stage_fqn=self.scratch_stage_fqn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,6 @@ def wrapper(*args, **kwargs):

# Override the project definition so that the command operates on the new entities
cm.override_project_definition = pdfv2

# Override the template context so that templates refer to the new entities
# Reuse the old ctx.env and other top-level keys in the template context
# since they don't change between v1 and v2
pdfv2_dump = pdfv2.model_dump(
exclude_none=True, warnings=False, by_alias=True
)
new_ctx = pdfv2_dump | dict(env=cm.template_context["ctx"]["env"])
cm.override_template_context = cm.template_context | dict(ctx=new_ctx)
elif single_app_and_package:
package_entity_id = kwargs.get("package_entity_id", "")
app_entity_id = kwargs.get("app_entity_id", "")
Expand Down
3 changes: 0 additions & 3 deletions src/snowflake/cli/api/cli_global_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class _CliGlobalContextManager:
# Consider changing the way this calculation is provided to commands
# in order to remove this logic (then make project_definition a non-cloned @property)
override_project_definition: ProjectDefinition | None = None
override_template_context: dict | None = None

_definition_manager: DefinitionManager | None = None

Expand Down Expand Up @@ -98,8 +97,6 @@ def project_root(self) -> Path:

@property
def template_context(self) -> dict:
if self.override_template_context:
return self.override_template_context
return self._definition_manager_or_raise().template_context

@property
Expand Down
13 changes: 12 additions & 1 deletion src/snowflake/cli/api/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from pathlib import Path
from typing import Optional

from snowflake.cli.api.config import get_default_connection_name
from snowflake.cli.api.config import get_connection_dict, get_default_connection_name
from snowflake.cli.api.exceptions import InvalidSchemaError
from snowflake.connector import SnowflakeConnection
from snowflake.connector.compat import IS_WINDOWS
Expand Down Expand Up @@ -79,6 +79,17 @@ def update(self, **updates):
raise KeyError(f"{key} is not a field of {self.__class__.__name__}")
setattr(self, key, value)

def update_from_config(self) -> ConnectionContext:
connection_config = get_connection_dict(connection_name=self.connection_name)
if "private_key_path" in connection_config:
connection_config["private_key_file"] = connection_config[
"private_key_path"
]
del connection_config["private_key_path"]

self.update(**connection_config)
return self

def __repr__(self) -> str:
"""Minimal repr where None values have their keys omitted."""
items = [f"{k}={repr(v)}" for (k, v) in self.present_values_as_dict().items()]
Expand Down
4 changes: 3 additions & 1 deletion src/snowflake/cli/api/entities/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,11 @@ def execute_post_deploy_hooks(

with console.phase(f"Executing {deployed_object_type} post-deploy actions"):
sql_scripts_paths = []
display_paths = []
for hook in post_deploy_hooks:
if hook.sql_script:
sql_scripts_paths.append(hook.sql_script)
display_paths.append(hook.display_path)
else:
raise ValueError(
f"Unsupported {deployed_object_type} post-deploy hook type: {hook}"
Expand All @@ -246,7 +248,7 @@ def execute_post_deploy_hooks(
sql_scripts_paths,
)

for index, sql_script_path in enumerate(sql_scripts_paths):
for index, sql_script_path in enumerate(display_paths):
console.step(f"Executing SQL script: {sql_script_path}")
_execute_sql_script(
script_content=scripts_content_list[index],
Expand Down
Loading
Loading