Skip to content

Commit

Permalink
Add decorator to extract a single app and package from a PDFv2
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-fcampbell committed Oct 3, 2024
1 parent 8ab0a0f commit 48d3033
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 90 deletions.
134 changes: 59 additions & 75 deletions src/snowflake/cli/_plugins/nativeapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,20 @@
InteractiveOption,
ValidateOption,
)
from snowflake.cli._plugins.nativeapp.entities.application import ApplicationEntityModel
from snowflake.cli._plugins.nativeapp.entities.application import (
ApplicationEntityModel,
)
from snowflake.cli._plugins.nativeapp.entities.application_package import (
ApplicationPackageEntityModel,
)
from snowflake.cli._plugins.nativeapp.manager import NativeAppManager
from snowflake.cli._plugins.nativeapp.policy import (
AllowAlwaysPolicy,
AskAlwaysPolicy,
DenyAlwaysPolicy,
)
from snowflake.cli._plugins.nativeapp.run_processor import NativeAppRunProcessor
from snowflake.cli._plugins.nativeapp.teardown_processor import (
NativeAppTeardownProcessor,
)
from snowflake.cli._plugins.nativeapp.v2_conversions.compat import (
find_entity,
nativeapp_definition_v2_to_v1,
single_app_and_package,
)
from snowflake.cli._plugins.nativeapp.version.commands import app as versions_app
from snowflake.cli._plugins.stage.diff import (
Expand Down Expand Up @@ -93,44 +90,50 @@ def app_init(**options):

@app.command("bundle")
@with_project_definition()
@nativeapp_definition_v2_to_v1()
@single_app_and_package()
def app_bundle(
**options,
) -> CommandResult:
"""
Prepares a local folder with configured app artifacts.
"""

assert_project_type("native_app")

cli_context = get_cli_context()
manager = NativeAppManager(
project_definition=cli_context.project_definition.native_app,
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)
manager.build_bundle()
return MessageResult(f"Bundle generated at {manager.deploy_root}")
package_id = options["package_entity_id"]
package = cli_context.project_definition.entities[package_id]
ws.perform_action(
package_id,
EntityActions.BUNDLE,
)
return MessageResult(f"Bundle generated at {ws.project_root / package.deploy_root}")


@app.command("diff", requires_connection=True, hidden=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1()
@single_app_and_package()
def app_diff(
**options,
) -> CommandResult:
) -> CommandResult | None:
"""
Performs a diff between the app's source stage and the local deploy root.
"""
assert_project_type("native_app")

cli_context = get_cli_context()
manager = NativeAppManager(
project_definition=cli_context.project_definition.native_app,
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)
bundle_map = manager.build_bundle()
package_id = options["package_entity_id"]
package = cli_context.project_definition.entities[package_id]
bundle_map = ws.perform_action(
package_id,
EntityActions.BUNDLE,
)
stage_fqn = f"{package.identifier.name}.{package.stage}"
diff: DiffResult = compute_stage_diff(
local_root=Path(manager.deploy_root), stage_fqn=manager.stage_fqn
local_root=Path(package.deploy_root), stage_fqn=stage_fqn
)
if cli_context.output_format == OutputFormat.JSON:
return ObjectResult(diff.to_dict())
Expand All @@ -141,7 +144,7 @@ def app_diff(

@app.command("run", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1(app_required=True)
@single_app_and_package(app_required=True)
def app_run(
version: Optional[str] = typer.Option(
None,
Expand Down Expand Up @@ -170,59 +173,49 @@ def app_run(
Creates an application package in your Snowflake account, uploads code files to its stage,
then creates or upgrades an application object from the application package.
"""

assert_project_type("native_app")

is_interactive = False
if force:
policy = AllowAlwaysPolicy()
elif interactive:
is_interactive = True
policy = AskAlwaysPolicy()
else:
policy = DenyAlwaysPolicy()

cli_context = get_cli_context()
processor = NativeAppRunProcessor(
project_definition=cli_context.project_definition.native_app,
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)
bundle_map = processor.build_bundle()
processor.process(
bundle_map=bundle_map,
policy=policy,
version=version,
patch=patch,
from_release_directive=from_release_directive,
is_interactive=is_interactive,
app_id = options["app_entity_id"]
app_model = cli_context.project_definition.entities[app_id]
ws.perform_action(
app_id,
EntityActions.DEPLOY,
validate=validate,
from_release_directive=from_release_directive,
prune=True,
recursive=True,
paths=[],
interactive=interactive,
force=force,
)
app = ws.get_entity(app_id)
return MessageResult(
f"Your application object ({processor.app_name}) is now available:\n"
+ processor.get_snowsight_url()
f"Your application object ({app_model.fqn.name}) is now available:\n{app.get_snowsight_url()}"
)


@app.command("open", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1(app_required=True)
@single_app_and_package(app_required=True)
def app_open(
**options,
) -> CommandResult:
"""
Opens the Snowflake Native App inside of your browser,
once it has been installed in your account.
"""

assert_project_type("native_app")

cli_context = get_cli_context()
manager = NativeAppManager(
project_definition=cli_context.project_definition.native_app,
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)
if manager.get_existing_app_info():
typer.launch(manager.get_snowsight_url())
app_id = options["app_entity_id"]
app = ws.get_entity(app_id)
if app.get_existing_app_info():
typer.launch(app.get_snowsight_url())
return MessageResult(f"Snowflake Native App opened in browser.")
else:
return MessageResult(
Expand Down Expand Up @@ -306,7 +299,7 @@ def app_teardown(

@app.command("deploy", requires_connection=True)
@with_project_definition()
@nativeapp_definition_v2_to_v1()
@single_app_and_package()
def app_deploy(
prune: Optional[bool] = typer.Option(
default=None,
Expand Down Expand Up @@ -338,16 +331,6 @@ def app_deploy(
Creates an application package in your Snowflake account and syncs the local changes to the stage without creating or updating the application.
Running this command with no arguments at all, as in `snow app deploy`, is a shorthand for `snow app deploy --prune --recursive`.
"""

assert_project_type("native_app")

if force:
policy = AllowAlwaysPolicy()
elif interactive:
policy = AskAlwaysPolicy()
else:
policy = DenyAlwaysPolicy()

has_paths = paths is not None and len(paths) > 0
if prune is None and recursive is None and not has_paths:
prune = True
Expand All @@ -362,19 +345,20 @@ def app_deploy(
raise IncompatibleParametersError(["paths", "--prune"])

cli_context = get_cli_context()
manager = NativeAppManager(
project_definition=cli_context.project_definition.native_app,
ws = WorkspaceManager(
project_definition=cli_context.project_definition,
project_root=cli_context.project_root,
)

bundle_map = manager.build_bundle()
manager.deploy(
bundle_map=bundle_map,
package_id = options["package_entity_id"]
ws.perform_action(
package_id,
EntityActions.DEPLOY,
prune=prune,
recursive=recursive,
local_paths_to_sync=paths,
paths=paths,
validate=validate,
policy=policy,
interactive=interactive,
force=force,
)

return MessageResult(
Expand Down
29 changes: 21 additions & 8 deletions src/snowflake/cli/_plugins/nativeapp/entities/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
append_test_resource_suffix,
extract_schema,
identifier_for_url,
to_identifier,
unquote_identifier,
)
from snowflake.connector import DictCursor, ProgrammingError
Expand Down Expand Up @@ -245,7 +246,7 @@ def drop(
needs_confirm = True

# 1. If existing application is not found, exit gracefully
show_obj_row = cls.get_existing_app_info(
show_obj_row = cls.get_existing_app_info_static(
app_name=app_name,
app_role=app_role,
)
Expand Down Expand Up @@ -535,7 +536,7 @@ def create_or_upgrade_app(
with sql_executor.use_warehouse(app_warehouse):

# 2. Check for an existing application by the same name
show_app_row = cls.get_existing_app_info(
show_app_row = cls.get_existing_app_info_static(
app_name=app_name,
app_role=app_role,
)
Expand Down Expand Up @@ -678,11 +679,15 @@ def use_application_warehouse(
)
)

def get_existing_app_info(self) -> Optional[dict]:
model = self._entity_model
ctx = self._workspace_ctx
role = (model.meta and model.meta.role) or ctx.default_role
return self.get_existing_app_info_static(role, model.fqn.name)

# TODO merge this into get_existing_app_info once all static usages are removed
@staticmethod
def get_existing_app_info(
app_name: str,
app_role: str,
) -> Optional[dict]:
def get_existing_app_info_static(app_name: str, app_role: str) -> Optional[dict]:
"""
Check for an existing application object by the same name as in project definition, in account.
It executes a 'show applications like' query and returns the result as single row, if one exists.
Expand Down Expand Up @@ -850,9 +855,17 @@ def get_account_event_table():
results = sql_executor.execute_query(query, cursor_class=DictCursor)
return next((r["value"] for r in results if r["key"] == "EVENT_TABLE"), "")

@classmethod
def get_snowsight_url(cls, app_name: str, app_warehouse: str | None) -> str:
def get_snowsight_url(self) -> str:
"""Returns the URL that can be used to visit this app via Snowsight."""
model = self._entity_model
ctx = self._workspace_ctx
warehouse = (
model.meta and model.meta.warehouse and to_identifier(model.meta.warehouse)
) or to_identifier(ctx.default_warehouse)
return self.get_snowsight_url_static(model.fqn.name, warehouse)

@classmethod
def get_snowsight_url_static(cls, app_name: str, app_warehouse: str) -> str:
name = identifier_for_url(app_name)
with cls.use_application_warehouse(app_warehouse):
sql_executor = get_sql_executor()
Expand Down
4 changes: 2 additions & 2 deletions src/snowflake/cli/_plugins/nativeapp/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def sync_deploy_root_with_stage(
)

def get_existing_app_info(self) -> Optional[dict]:
return ApplicationEntity.get_existing_app_info(
return ApplicationEntity.get_existing_app_info_static(
app_name=self.app_name,
app_role=self.app_role,
)
Expand All @@ -244,7 +244,7 @@ def _application_object_to_str(self, obj: ApplicationOwnedObject):

def get_snowsight_url(self) -> str:
"""Returns the URL that can be used to visit this app via Snowsight."""
return ApplicationEntity.get_snowsight_url(
return ApplicationEntity.get_snowsight_url_static(
self.app_name, self.application_warehouse
)

Expand Down
Loading

0 comments on commit 48d3033

Please sign in to comment.