diff --git a/src/snowflake/cli/_plugins/project/commands.py b/src/snowflake/cli/_plugins/project/commands.py index a0be411c5b..a24ae2369b 100644 --- a/src/snowflake/cli/_plugins/project/commands.py +++ b/src/snowflake/cli/_plugins/project/commands.py @@ -15,6 +15,7 @@ import logging import typer +from snowflake.cli._plugins.project.feature_flags import FeatureFlag from snowflake.cli._plugins.project.manager import ProjectManager from snowflake.cli._plugins.project.project_entity_model import ( ProjectEntityModel, @@ -32,7 +33,9 @@ app = SnowTyperFactory( name="project", help="Manages projects in Snowflake.", + is_hidden=FeatureFlag.ENABLE_SNOWFLAKE_PROJECTS.is_disabled, ) + log = logging.getLogger(__name__) project_identifier = identifier_argument(sf_object="project", example="MY_PROJECT") @@ -93,7 +96,6 @@ def create_version( cli_console.step(f"Creating stage {stage_name}") sm.create(fqn=stage_name) - # TODO: improve this behavior for file in project.artifacts: cli_console.step(f"Uploading {file} to {stage_name}") if isinstance(file, str): diff --git a/src/snowflake/cli/_plugins/project/feature_flags.py b/src/snowflake/cli/_plugins/project/feature_flags.py new file mode 100644 index 0000000000..e363958f36 --- /dev/null +++ b/src/snowflake/cli/_plugins/project/feature_flags.py @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Snowflake Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from enum import unique + +from snowflake.cli.api.feature_flags import BooleanFlag, FeatureFlagMixin + + +@unique +class FeatureFlag(FeatureFlagMixin): + ENABLE_SNOWFLAKE_PROJECTS = BooleanFlag("ENABLE_NATIVE_APP_PYTHON_SETUP", False) diff --git a/src/snowflake/cli/_plugins/project/manager.py b/src/snowflake/cli/_plugins/project/manager.py index 7548b622ee..ed452bb4c9 100644 --- a/src/snowflake/cli/_plugins/project/manager.py +++ b/src/snowflake/cli/_plugins/project/manager.py @@ -23,6 +23,8 @@ def execute( self, project_name: FQN, version: str | None = None, dry_run: bool = False ): query = f"EXECUTE PROJECT {project_name.sql_identifier}" + if version: + query += f" WITH VERSION {version}" if dry_run: query += " DRY_RUN=TRUE" return self._execute_query(query=query) diff --git a/tests/dcm_project/test_dcm_project.py b/tests/dcm_project/test_dcm_project.py index 43c707f8d8..9b3bf4a3c7 100644 --- a/tests/dcm_project/test_dcm_project.py +++ b/tests/dcm_project/test_dcm_project.py @@ -6,12 +6,42 @@ @mock.patch(ProjectManager) -def test_create_version(mock_pm, runner, project_directory): +@mock.patch("snowflake.cli._plugins.stage.manager.StageManager.put") +def test_create_version(mock_put, mock_pm, runner, project_directory): + stage = FQN.from_stage("my_project_stage") + with project_directory("dcm_project") as fh: result = runner.invoke(["project", "create-version"]) assert result.exit_code == 0, result.output mock_pm().create_version.assert_called_once_with( project_name=FQN.from_string("my_project"), - stage_name=FQN.from_stage("my_project_stage"), + stage_name=stage, + ) + mock_put.assert_has_calls( + [ + mock.call(local_path="definitions/", stage_path=stage), + mock.call(local_path="manifest.yml", stage_path=stage), + ] + ) + + +@mock.patch(ProjectManager) +def test_execute_project(mock_pm, runner, project_directory): + result = runner.invoke(["project", "execute", "fooBar", "--version", "v1"]) + assert result.exit_code == 0, result.output + + mock_pm().execute.assert_called_once_with( + project_name=FQN.from_string("fooBar"), + version="v1", + ) + + +@mock.patch(ProjectManager) +def test_validate_project(mock_pm, runner, project_directory): + result = runner.invoke(["project", "validate", "fooBar", "--version", "v1"]) + assert result.exit_code == 0, result.output + + mock_pm().execute.assert_called_once_with( + project_name=FQN.from_string("fooBar"), version="v1", dry_run=True ) diff --git a/tests/dcm_project/test_dcm_project_manager.py b/tests/dcm_project/test_dcm_project_manager.py new file mode 100644 index 0000000000..68ce9e8730 --- /dev/null +++ b/tests/dcm_project/test_dcm_project_manager.py @@ -0,0 +1,40 @@ +from unittest import mock + +from snowflake.cli._plugins.project.manager import ProjectManager +from snowflake.cli.api.identifiers import FQN + +execute_queries = ( + "snowflake.cli._plugins.project.commands.ProjectManager._execute_query" +) +TEST_STAGE = FQN.from_stage("@test_stage") +TEST_PROJECT = FQN.from_string("my_project") + + +@mock.patch(execute_queries) +def test_create_version(mock_execute_query, runner, project_directory): + mgr = ProjectManager() + mgr.create_version(project_name=TEST_PROJECT, stage_name=TEST_STAGE) + + mock_execute_query.assert_called_once_with( + query="ALTER PROJECT IDENTIFIER('my_project') ADD VERSION FROM IDENTIFIER('test_stage')" + ) + + +@mock.patch(execute_queries) +def test_execute_project(mock_execute_query, runner, project_directory): + mgr = ProjectManager() + mgr.execute(project_name=TEST_PROJECT, version="v42") + + mock_execute_query.assert_called_once_with( + query="EXECUTE PROJECT IDENTIFIER('my_project') WITH VERSION v42" + ) + + +@mock.patch(execute_queries) +def test_validate_project(mock_execute_query, runner, project_directory): + mgr = ProjectManager() + mgr.execute(project_name=TEST_PROJECT, version="v42", dry_run=True) + + mock_execute_query.assert_called_once_with( + query="EXECUTE PROJECT IDENTIFIER('my_project') WITH VERSION v42 DRY_RUN=TRUE" + )