Skip to content

Commit

Permalink
Add support for --create-version in snow app publish (#1982)
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-melnacouzi authored Jan 10, 2025
1 parent 47bb325 commit 056af4e
Show file tree
Hide file tree
Showing 7 changed files with 527 additions and 101 deletions.
35 changes: 29 additions & 6 deletions src/snowflake/cli/_plugins/nativeapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from typing import Generator, Iterable, List, Optional, cast

import typer
from snowflake.cli._plugins.nativeapp.artifacts import VersionInfo
from snowflake.cli._plugins.nativeapp.common_flags import (
ForceOption,
InteractiveOption,
Expand Down Expand Up @@ -538,13 +539,15 @@ def result(self):
@with_project_definition()
@force_project_definition_v2()
def app_publish(
version: str = typer.Option(
version: Optional[str] = typer.Option(
default=None,
show_default=False,
help="The version to publish to the release channel. The version must be created fist using 'snow app version create'.",
help="The version to publish to the provided release channel and release directive. Version is required to exist unless `--create-version` flag is used.",
),
patch: int = typer.Option(
patch: Optional[int] = typer.Option(
default=None,
show_default=False,
help="The patch number under the given version. The patch number must be created first using 'snow app version create'.",
help="The patch number under the given version. This will be used when setting the release directive. Patch is required to exist unless `--create-version` flag is used.",
),
channel: Optional[str] = typer.Option(
"DEFAULT",
Expand All @@ -556,6 +559,23 @@ def app_publish(
),
interactive: bool = InteractiveOption,
force: Optional[bool] = ForceOption,
create_version: bool = typer.Option(
False,
"--create-version",
help="Create a new version or patch based on the provided `--version` and `--patch` values. Fallback to the manifest values if not provided.",
is_flag=True,
),
from_stage: bool = typer.Option(
False,
"--from-stage",
help="When enabled, the Snowflake CLI creates a version from the current application package stage without syncing to the stage first. Can only be used with `--create-version` flag.",
is_flag=True,
),
label: Optional[str] = typer.Option(
None,
"--label",
help="A label for the version that is displayed to consumers. Can only be used with `--create-version` flag.",
),
**options,
) -> CommandResult:
"""
Expand All @@ -567,7 +587,7 @@ def app_publish(
project_root=cli_context.project_root,
)
package_id = options["package_entity_id"]
ws.perform_action(
version_info: VersionInfo = ws.perform_action(
package_id,
EntityActions.PUBLISH,
version=version,
Expand All @@ -576,7 +596,10 @@ def app_publish(
release_directive=directive,
interactive=interactive,
force=force,
create_version=create_version,
from_stage=from_stage,
label=label,
)
return MessageResult(
f"Version {version} and patch {patch} published to release directive {directive} of release channel {channel}."
f"Version {version_info.version_name} and patch {version_info.patch_number} published to release directive {directive} of release channel {channel}."
)
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,6 @@ def action_version_create(
else:
policy = DenyAlwaysPolicy()

if skip_git_check:
git_policy = DenyAlwaysPolicy()
else:
git_policy = AllowAlwaysPolicy()

bundle_map = self._bundle(action_ctx)
resolved_version, resolved_patch, resolved_label = self.resolve_version_info(
version=version,
Expand All @@ -461,7 +456,7 @@ def action_version_create(
interactive=interactive,
)

if git_policy.should_proceed():
if not skip_git_check:
self.check_index_changes_in_git_repo(policy=policy, interactive=interactive)

# if user is asking to create the version from the current stage,
Expand Down Expand Up @@ -1005,15 +1000,18 @@ def _find_version_with_no_recent_update(
def action_publish(
self,
action_ctx: ActionContext,
version: str,
patch: int,
version: Optional[str],
patch: Optional[int],
release_channel: Optional[str],
release_directive: str,
interactive: bool,
force: bool,
*args,
create_version: bool = False,
from_stage: bool = False,
label: Optional[str] = None,
**kwargs,
) -> None:
) -> VersionInfo:
"""
Publishes a version and a patch to a release directive of a release channel.
Expand All @@ -1030,7 +1028,37 @@ def action_publish(
else:
policy = DenyAlwaysPolicy()

if from_stage and not create_version:
raise UsageError(
"--from-stage flag can only be used with --create-version flag."
)
if label is not None and not create_version:
raise UsageError("--label can only be used with --create-version flag.")

console = self._workspace_ctx.console
if create_version:
result = self.action_version_create(
action_ctx=action_ctx,
version=version,
patch=patch,
label=label,
skip_git_check=True,
interactive=interactive,
force=force,
from_stage=from_stage,
)
version = result.version_name
patch = result.patch_number

if version is None:
raise UsageError(
"Please provide a version using --version or use --create-version flag to create a version based on the manifest file."
)
if patch is None:
raise UsageError(
"Please provide a patch number using --patch or use --create-version flag to auto create a patch."
)

versions_info = get_snowflake_facade().show_versions(self.name, self.role)

available_patches = [
Expand Down Expand Up @@ -1123,6 +1151,7 @@ def action_publish(
patch=patch,
role=self.role,
)
return VersionInfo(version, patch, None)

def _bundle_children(self, action_ctx: ActionContext) -> List[str]:
# Create _children directory
Expand Down Expand Up @@ -1694,7 +1723,8 @@ def resolve_version_info(
resolved_label = label if label is not None else label_manifest

# Check if patch needs to throw a bad option error, either if application package does not exist or if version does not exist
if resolved_patch is not None:
# If patch is 0 and version does not exist, it is a valid case, because patch 0 is the first patch in a version.
if resolved_patch:
try:
if not self.get_existing_version_info(to_identifier(resolved_version)):
raise BadOptionUsage(
Expand Down
17 changes: 14 additions & 3 deletions src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
ACCOUNT_DOES_NOT_EXIST,
ACCOUNT_HAS_TOO_MANY_QUALIFIERS,
APPLICATION_PACKAGE_MAX_VERSIONS_HIT,
APPLICATION_PACKAGE_PATCH_ALREADY_EXISTS,
APPLICATION_REQUIRES_TELEMETRY_SHARING,
CANNOT_DEREGISTER_VERSION_ASSOCIATED_WITH_CHANNEL,
CANNOT_DISABLE_MANDATORY_TELEMETRY,
Expand Down Expand Up @@ -374,6 +375,10 @@ def drop_version_from_package(
raise UserInputError(
f"Cannot drop version {version} from application package {package_name} because it is associated with a release channel."
) from err
if err.errno == VERSION_DOES_NOT_EXIST:
raise UserInputError(
f"Version {version} does not exist in application package {package_name}."
) from err
handle_unclassified_error(
err,
f"Failed to {action} version {version} from application package {package_name}.",
Expand Down Expand Up @@ -407,11 +412,12 @@ def add_patch_to_package_version(
with_label_clause = (
f"\nlabel={to_string_literal(label)}" if label is not None else ""
)
patch_query = f"{patch}" if patch else ""

patch_query = f" {patch}" if patch is not None else ""
add_patch_query = dedent(
f"""\
alter application package {package_name}
add patch {patch_query} for version {version}
add patch{patch_query} for version {version}
using @{stage_fqn}{with_label_clause}
"""
)
Expand All @@ -421,9 +427,14 @@ def add_patch_to_package_version(
add_patch_query, cursor_class=DictCursor
).fetchall()
except Exception as err:
if isinstance(err, ProgrammingError):
if err.errno == APPLICATION_PACKAGE_PATCH_ALREADY_EXISTS:
raise UserInputError(
f"Patch {patch} already exists for version {version} in application package {package_name}."
) from err
handle_unclassified_error(
err,
f"Failed to create patch {patch_query} for version {version} in application package {package_name}.",
f"Failed to create patch{patch_query} for version {version} in application package {package_name}.",
)
try:
show_row = result_cursor[0]
Expand Down
Loading

0 comments on commit 056af4e

Please sign in to comment.