Skip to content

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-melnacouzi committed Dec 16, 2024
1 parent a2e711b commit d4a458e
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 244 deletions.
144 changes: 40 additions & 104 deletions src/snowflake/cli/_plugins/nativeapp/entities/application_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import json
import os
import re
from datetime import datetime
from pathlib import Path
from textwrap import dedent
from typing import Any, List, Literal, Optional, Set, Union
Expand Down Expand Up @@ -54,6 +53,7 @@
from snowflake.cli._plugins.nativeapp.sf_facade_exceptions import (
InsufficientPrivilegesError,
)
from snowflake.cli._plugins.nativeapp.sf_sql_facade import ReleaseChannel
from snowflake.cli._plugins.nativeapp.utils import needs_confirmation, sanitize_dir_name
from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
FunctionEntityModel,
Expand All @@ -66,7 +66,6 @@
)
from snowflake.cli._plugins.workspace.context import ActionContext
from snowflake.cli.api.cli_global_context import span
from snowflake.cli.api.console.abc import AbstractConsole
from snowflake.cli.api.entities.common import (
EntityBase,
attach_spans_to_entity_actions,
Expand Down Expand Up @@ -136,99 +135,6 @@ def ensure_app_roles_is_a_set(
return application_roles


class ReleaseChannel(dict[str, Any]):
"""
Represents a release channel.
This class is a dictionary with the following keys:
- name: The name of the release channel.
- description: The description of the release channel.
- created_on: The timestamp when the release channel was created.
- updated_on: The timestamp when the release channel was last updated.
- targets: The target accounts for the release channel.
- versions: The versions added to the release channel.
"""

def __init__(self, data: dict[str, Any]):
targets = json.loads(str(data.get("targets"))) if data.get("targets") else {}
versions = json.loads(str(data.get("versions"))) if data.get("versions") else []

super().__init__(
{
"name": data.get("name") or "",
"description": data.get("description") or "",
"created_on": data.get("created_on"),
"updated_on": data.get("updated_on"),
"targets": targets,
"versions": versions,
}
)

@property
def name(self) -> str:
return self.get("name") # type: ignore

@property
def description(self) -> str:
return self.get("description") # type: ignore

@property
def created_on(self) -> Optional[datetime]:
return self.get("created_on") # type: ignore

@property
def updated_on(self) -> Optional[datetime]:
return self.get("updated_on") # type: ignore

@property
def targets(self) -> dict[str, Any]:
return self.get("targets") # type: ignore

@property
def versions(self) -> list[str]:
return self.get("versions") # type: ignore

def print_to_console(self, console: AbstractConsole) -> None:
"""
Prints the release channel details to the console.
"""
console.message(f"""[bold]{self.name}[/bold]""")
accounts_list: Optional[list[str]] = self.targets.get("accounts")
target_accounts = (
f"({', '.join(accounts_list)})"
if accounts_list is not None
else "ALL ACCOUNTS"
)

formatted_created_on = (
self.created_on.astimezone().strftime("%Y-%m-%d %H:%M:%S.%f %Z")
if self.created_on
else ""
)

formatted_updated_on = (
self.updated_on.astimezone().strftime("%Y-%m-%d %H:%M:%S.%f %Z")
if self.updated_on
else ""
)
with console.indented():
console.message(f"Description: {self.description}")
console.message(f"Versions: ({', '.join(self.versions)})")
console.message(f"Created on: {formatted_created_on}")
console.message(f"Updated on: {formatted_updated_on}")
console.message(f"Target accounts: {target_accounts}")

def matches_identifier(self, identifier: Optional[str]) -> bool:
"""
Checks if the release channel matches the provided identifier.
If the identifier is None, it matches everything.
"""
if identifier is None:
return True

return same_identifiers(self.name, identifier)


class ApplicationPackageChildField(UpdatableModel):
target: str = Field(title="The key of the entity to include in this package")
ensure_usable_by: Optional[EnsureUsableByField] = Field(
Expand Down Expand Up @@ -861,10 +767,42 @@ def action_release_directive_unset(
role=self.role,
)

def _print_channel_to_console(self, channel: ReleaseChannel) -> None:
"""
Prints the release channel details to the console.
"""
console = self._workspace_ctx.console

console.message(f"""[bold]{channel["name"]}[/bold]""")
accounts_list: Optional[list[str]] = channel["targets"].get("accounts")
target_accounts = (
f"({', '.join(accounts_list)})"
if accounts_list is not None
else "ALL ACCOUNTS"
)

formatted_created_on = (
channel["created_on"].astimezone().strftime("%Y-%m-%d %H:%M:%S.%f %Z")
if channel["created_on"]
else ""
)

formatted_updated_on = (
channel["updated_on"].astimezone().strftime("%Y-%m-%d %H:%M:%S.%f %Z")
if channel["updated_on"]
else ""
)
with console.indented():
console.message(f"Description: {channel['description']}")
console.message(f"Versions: ({', '.join(channel['versions'])})")
console.message(f"Created on: {formatted_created_on}")
console.message(f"Updated on: {formatted_updated_on}")
console.message(f"Target accounts: {target_accounts}")

def action_release_channel_list(
self,
action_ctx: ActionContext,
release_channel: Optional[str] = None,
release_channel: Optional[str],
*args,
**kwargs,
) -> list[ReleaseChannel]:
Expand All @@ -873,24 +811,22 @@ def action_release_channel_list(
If `release_channel` is provided, only the specified release channel is listed.
"""
console = self._workspace_ctx.console
available_channels = [
ReleaseChannel(channel)
for channel in get_snowflake_facade().show_release_channels(
self.name, self.role
)
]
available_channels = get_snowflake_facade().show_release_channels(
self.name, self.role
)

filtered_channels = [
channel
for channel in available_channels
if channel.matches_identifier(release_channel)
if release_channel is None
or same_identifiers(channel["name"], release_channel)
]

if not filtered_channels:
console.message("No release channels found.")
else:
for channel in filtered_channels:
channel.print_to_console(console)
self._print_channel_to_console(channel)

return filtered_channels

Expand Down
42 changes: 39 additions & 3 deletions src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
# limitations under the License.
from __future__ import annotations

import json
import logging
from contextlib import contextmanager
from datetime import datetime
from functools import cache
from textwrap import dedent
from typing import Any, Dict, List
from typing import Any, Dict, List, TypedDict

from snowflake.cli._plugins.connection.util import UIParameter, get_ui_parameter
from snowflake.cli._plugins.nativeapp.constants import (
Expand Down Expand Up @@ -52,6 +54,7 @@
CANNOT_DISABLE_MANDATORY_TELEMETRY,
CANNOT_DISABLE_RELEASE_CHANNELS,
DOES_NOT_EXIST_OR_CANNOT_BE_PERFORMED,
DOES_NOT_EXIST_OR_NOT_AUTHORIZED,
INSUFFICIENT_PRIVILEGES,
NO_WAREHOUSE_SELECTED_IN_SESSION,
RELEASE_DIRECTIVE_DOES_NOT_EXIST,
Expand All @@ -73,6 +76,18 @@
from snowflake.cli.api.utils.cursor import find_first_row
from snowflake.connector import DictCursor, ProgrammingError

ReleaseChannel = TypedDict(
"ReleaseChannel",
{
"name": str,
"description": str,
"created_on": datetime,
"updated_on": datetime,
"targets": dict[str, Any],
"versions": list[str],
},
)


class SnowflakeSQLFacade:
def __init__(self, sql_executor: BaseSqlExecutor | None = None):
Expand Down Expand Up @@ -1141,7 +1156,7 @@ def unset_release_directive(

def show_release_channels(
self, package_name: str, role: str | None = None
) -> list[dict[str, Any]]:
) -> list[ReleaseChannel]:
"""
Show release channels in a package.
@param package_name: Name of the package
Expand All @@ -1155,6 +1170,7 @@ def show_release_channels(
return []

package_identifier = to_identifier(package_name)
results = []
with self._use_role_optional(role):
try:
cursor = self._sql_executor.execute_query(
Expand All @@ -1166,11 +1182,31 @@ def show_release_channels(
if err.errno == SQL_COMPILATION_ERROR:
# Release not out yet and param not out yet
return []
if err.errno == DOES_NOT_EXIST_OR_NOT_AUTHORIZED:
raise UserInputError(
f"Application package {package_name} does not exist or you are not authorized to access it."
) from err
handle_unclassified_error(
err,
f"Failed to show release channels for application package {package_name}.",
)
return cursor.fetchall()
rows = cursor.fetchall()

for row in rows:
targets = json.loads(row["targets"]) if row.get("targets") else {}
versions = json.loads(row["versions"]) if row.get("versions") else []
results.append(
ReleaseChannel(
name=row["name"],
description=row["description"],
created_on=row["created_on"],
updated_on=row["updated_on"],
targets=targets,
versions=versions,
)
)

return results


def _strip_empty_lines(text: str) -> str:
Expand Down
33 changes: 11 additions & 22 deletions tests/nativeapp/__snapshots__/test_application_package_entity.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,24 @@

'''
# ---
# name: test_given_release_channel_with_missing_info_when_list_release_channels_then_success
'''
channel1
Description:
Versions: ()
Created on:
Updated on:
Target accounts: ALL ACCOUNTS

'''
# ---
# name: test_given_release_channel_with_no_target_account_then_show_all_accounts_in_snapshot
# name: test_given_release_channel_with_no_target_account_or_version_then_show_all_accounts_in_snapshot
'''
channel1
Description: desc
Versions: (v1, v2)
Created on: 2024-12-03 00:00:00.000000
Updated on: 2024-12-05 00:00:00.000000
Versions: ()
Created on: 2024-12-03 00:00:00.000000 UTC
Updated on: 2024-12-05 00:00:00.000000 UTC
Target accounts: ALL ACCOUNTS

'''
# ---
# name: test_given_release_channels_with_a_selected_channel_to_filter_when_list_release_channels_then_returned_selected_channel
'''
chAnnEl1
channel1
Description: desc
Versions: (v1, v2)
Created on: 2024-12-03 00:00:00.000000
Updated on: 2024-12-05 00:00:00.000000
Created on: 2024-12-03 00:00:00.000000 UTC
Updated on: 2024-12-05 00:00:00.000000 UTC
Target accounts: (org1.acc1, org2.acc2)

'''
Expand All @@ -43,14 +32,14 @@
channel1
Description: desc
Versions: (v1, v2)
Created on: 2024-12-03 00:00:00.000000
Updated on: 2024-12-05 00:00:00.000000
Created on: 2024-12-03 00:00:00.000000 UTC
Updated on: 2024-12-05 00:00:00.000000 UTC
Target accounts: (org1.acc1, org2.acc2)
channel2
Description: desc2
Versions: (v3)
Created on: 2024-12-03 00:00:00.000000
Updated on: 2024-12-05 00:00:00.000000
Created on: 2024-12-03 00:00:00.000000 UTC
Updated on: 2024-12-05 00:00:00.000000 UTC
Target accounts: (org3.acc3)

'''
Expand Down
Loading

0 comments on commit d4a458e

Please sign in to comment.