Skip to content

Commit

Permalink
SNOW-1653909 If we can't find an app entity to convert, only fail if …
Browse files Browse the repository at this point in the history
…it's required, update `snow app teardown` to tear down multiple apps (#1557)

Followup to #1546 to fix a bug where it would complain if we had a PDv2 with multiple app entities for commands that didn't care about the app at all.

Also updates `snow app teardown` to me PDFv2-aware so we can teardown all the apps created from one package.
  • Loading branch information
sfc-gh-fcampbell committed Sep 19, 2024
1 parent cb7bc80 commit 96509d0
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 129 deletions.
86 changes: 71 additions & 15 deletions src/snowflake/cli/_plugins/nativeapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
from typing import Generator, Iterable, List, Optional, cast

import typer
from snowflake.cli._plugins.nativeapp.application_entity_model import (
ApplicationEntityModel,
)
from snowflake.cli._plugins.nativeapp.application_package_entity_model import (
ApplicationPackageEntityModel,
)
from snowflake.cli._plugins.nativeapp.common_flags import (
ForceOption,
InteractiveOption,
Expand All @@ -46,6 +52,7 @@
shallow_git_clone,
)
from snowflake.cli._plugins.nativeapp.v2_conversions.v2_to_v1_decorator import (
find_entity,
nativeapp_definition_v2_to_v1,
)
from snowflake.cli._plugins.nativeapp.version.commands import app as versions_app
Expand All @@ -54,11 +61,13 @@
compute_stage_diff,
)
from snowflake.cli._plugins.stage.utils import print_diff_to_console
from snowflake.cli._plugins.workspace.manager import WorkspaceManager
from snowflake.cli.api.cli_global_context import get_cli_context
from snowflake.cli.api.commands.decorators import (
with_project_definition,
)
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
from snowflake.cli.api.entities.common import EntityActions
from snowflake.cli.api.exceptions import IncompatibleParametersError
from snowflake.cli.api.output.formats import OutputFormat
from snowflake.cli.api.output.types import (
Expand All @@ -69,6 +78,7 @@
StreamResult,
)
from snowflake.cli.api.project.project_verification import assert_project_type
from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
from snowflake.cli.api.secure_path import SecurePath
from typing_extensions import Annotated

Expand Down Expand Up @@ -160,7 +170,7 @@ def app_list_templates(**options) -> CommandResult:

@app.command("bundle")
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1()
def app_bundle(
**options,
) -> CommandResult:
Expand All @@ -181,7 +191,7 @@ def app_bundle(

@app.command("diff", requires_connection=True, hidden=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1()
def app_diff(
**options,
) -> CommandResult:
Expand All @@ -208,7 +218,7 @@ def app_diff(

@app.command("run", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1(app_required=True)
def app_run(
version: Optional[str] = typer.Option(
None,
Expand Down Expand Up @@ -272,7 +282,7 @@ def app_run(

@app.command("open", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1(app_required=True)
def app_open(
**options,
) -> CommandResult:
Expand All @@ -299,7 +309,9 @@ def app_open(

@app.command("teardown", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
# This command doesn't use @nativeapp_definition_v2_to_v1 because it needs to
# be aware of PDFv2 definitions that have multiple apps created from the same package,
# which all need to be torn down.
def app_teardown(
force: Optional[bool] = ForceOption,
cascade: Optional[bool] = typer.Option(
Expand All @@ -308,26 +320,70 @@ def app_teardown(
show_default=False,
),
interactive: bool = InteractiveOption,
# Same as the param auto-added by @nativeapp_definition_v2_to_v1
package_entity_id: Optional[str] = typer.Option(
default="",
help="The ID of the package entity on which to operate when definition_version is 2 or higher.",
),
**options,
) -> CommandResult:
"""
Attempts to drop both the application object and application package as defined in the project definition file.
"""
cli_context = get_cli_context()
project = cli_context.project_definition
if isinstance(project, ProjectDefinitionV1):
# Old behaviour, not multi-app aware so we can use the old processor
processor = NativeAppTeardownProcessor(
project_definition=cli_context.project_definition.native_app,
project_root=cli_context.project_root,
)
processor.process(interactive, force, cascade)
else:
# New behaviour, multi-app aware so teardown all the apps created from the package

# Determine the package entity to drop, there must be one
app_package_entity = find_entity(
project,
ApplicationPackageEntityModel,
package_entity_id,
disambiguation_option="--package-entity-id",
required=True,
)
assert app_package_entity is not None # satisfy mypy

assert_project_type("native_app")
# Same implementation as `snow ws drop`
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)
for app_entity in project.get_entities_by_type(
ApplicationEntityModel.get_type()
).values():
# Drop each app
if app_entity.from_.target == app_package_entity.entity_id:
ws.perform_action(
app_entity.entity_id,
EntityActions.DROP,
force_drop=force,
interactive=interactive,
cascade=cascade,
)
# Then drop the package
ws.perform_action(
app_package_entity.entity_id,
EntityActions.DROP,
force_drop=force,
interactive=interactive,
cascade=cascade,
)

cli_context = get_cli_context()
processor = NativeAppTeardownProcessor(
project_definition=cli_context.project_definition.native_app,
project_root=cli_context.project_root,
)
processor.process(interactive, force, cascade)
return MessageResult(f"Teardown is now complete.")


@app.command("deploy", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1()
def app_deploy(
prune: Optional[bool] = typer.Option(
default=None,
Expand Down Expand Up @@ -395,7 +451,7 @@ def app_deploy(

@app.command("validate", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1()
def app_validate(**options):
"""
Validates a deployed Snowflake Native App's setup script.
Expand Down Expand Up @@ -428,7 +484,7 @@ class RecordType(Enum):

@app.command("events", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1
@nativeapp_definition_v2_to_v1(app_required=True)
def app_events(
since: str = typer.Option(
default="",
Expand Down
Loading

0 comments on commit 96509d0

Please sign in to comment.