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

Snow 1348392 update replace checks #1049

Merged
merged 10 commits into from
May 9, 2024
2 changes: 2 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
* Added support for fully qualified stage names in stage and git execute commands.
* Fixed a bug where `snow app run` was not upgrading the application when the local state and remote stage are identical (for example immediately after `snow app deploy`).
* Fixed handling of stage path separators on Windows
* Change to `external_access_integrations` in `snowflake.yml` now also triggers function replace
* The `--info` callback returns info about configured feature flags.


# v2.2.0

## Backward incompatibility
Expand Down
2 changes: 2 additions & 0 deletions src/snowflake/cli/plugins/snowpark/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ def _deploy_single_object(
handler = object_definition.handler
returns = object_definition.returns
imports = object_definition.imports
external_access_integrations = object_definition.external_access_integrations
replace_object = False

object_exists = identifier in existing_objects
Expand All @@ -285,6 +286,7 @@ def _deploy_single_object(
handler=handler,
return_type=returns,
snowflake_dependencies=snowflake_dependencies,
external_access_integrations=external_access_integrations,
imports=imports,
stage_artifact_file=stage_artifact_path,
)
Expand Down
16 changes: 15 additions & 1 deletion src/snowflake/cli/plugins/snowpark/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def check_if_replace_is_required(
handler: str,
return_type: str,
snowflake_dependencies: List[str],
external_access_integrations: List[str],
imports: List[str],
stage_artifact_file: str,
) -> bool:
Expand All @@ -42,6 +43,15 @@ def check_if_replace_is_required(
)
return True

if set(external_access_integrations) != set(
resource_json.get("external_access_integrations", [])
):
log.info(
"Found difference of external access integrations. Replacing the %s.",
object_type,
)
return True

if (
resource_json["handler"].lower() != handler.lower()
or _sql_to_python_return_type_mapper(resource_json["returns"]).lower()
Expand Down Expand Up @@ -189,7 +199,11 @@ def format_arg(arg: Argument):
result += f" default {val}"
return result

arguments = ", ".join(format_arg(arg) for arg in udf_sproc.signature)
if udf_sproc.signature and udf_sproc.signature != "null":
arguments = ", ".join(format_arg(arg) for arg in udf_sproc.signature)
else:
arguments = ""

name = slq_exec_mixin.to_fully_qualified_name(
udf_sproc.name,
database=udf_sproc.database,
Expand Down
125 changes: 125 additions & 0 deletions tests_integration/test_snowpark_external_access.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest

from tests.testing_utils.fixtures import alter_snowflake_yml
from tests_integration.testing_utils import SnowparkTestSetup, SnowparkTestSteps

STAGE_NAME = "dev_deployment"
Expand Down Expand Up @@ -38,6 +39,130 @@ def test_snowpark_external_access(project_directory, _test_steps, test_database)
)


def test_snowpark_upgrades_with_external_access(
project_directory, _test_steps, test_database, alter_snowflake_yml
):

with project_directory("snowpark") as tmp_dir:
_test_steps.snowpark_build_should_zip_files()

_test_steps.snowpark_deploy_should_finish_successfully_and_return(
[
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_PROCEDURE(name string)",
"status": "created",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.TEST()",
"status": "created",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_FUNCTION(name string)",
"status": "created",
"type": "function",
},
]
)

alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.functions.0.external_access_integrations",
value=["snowflake_docs_access_integration"],
)
alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.procedures.0.external_access_integrations",
value=["snowflake_docs_access_integration"],
)

_test_steps.snowpark_deploy_should_finish_successfully_and_return(
[
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_PROCEDURE(name string)",
"status": "definition updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.TEST()",
"status": "packages updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_FUNCTION(name string)",
"status": "definition updated",
"type": "function",
},
],
additional_arguments=["--replace"],
)

alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.functions.0.external_access_integrations",
value=["CLI_TEST_INTEGRATION"],
)

alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.procedures.0.external_access_integrations",
value=["CLI_TEST_INTEGRATION"],
)

_test_steps.snowpark_deploy_should_finish_successfully_and_return(
[
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_PROCEDURE(name string)",
"status": "definition updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.TEST()",
"status": "packages updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_FUNCTION(name string)",
"status": "definition updated",
"type": "function",
},
],
additional_arguments=["--replace"],
)

alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.functions.0.external_access_integrations",
value=[],
)
alter_snowflake_yml(
tmp_dir / "snowflake.yml",
parameter_path="snowpark.procedures.0.external_access_integrations",
value=[],
)
_test_steps.snowpark_deploy_should_finish_successfully_and_return(
[
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_PROCEDURE(name string)",
"status": "definition updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.TEST()",
"status": "packages updated",
"type": "procedure",
},
{
"object": f"{test_database.upper()}.PUBLIC.HELLO_FUNCTION(name string)",
"status": "definition updated",
"type": "function",
},
],
additional_arguments=["--replace"],
)


@pytest.fixture
def _test_setup(
runner,
Expand Down
Loading