Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove limitation on nested phases/steps #1843

Merged
merged 12 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 4 additions & 19 deletions src/snowflake/cli/api/console/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@
INDENTATION_LEVEL: int = 2


class CliConsoleNestingProhibitedError(RuntimeError):
"""CliConsole phase nesting not allowed."""


class CliConsole(AbstractConsole):
"""An utility for displaying intermediate output.

Expand Down Expand Up @@ -70,28 +66,21 @@ def _format_message(self, message: str, output: Output) -> Text:
@contextmanager
def phase(self, enter_message: str, exit_message: Optional[str] = None):
sfc-gh-bdufour marked this conversation as resolved.
Show resolved Hide resolved
"""A context manager for organising steps into logical group."""
if self.in_phase:
raise CliConsoleNestingProhibitedError("Only one phase allowed at a time.")
if self._extra_indent > 0:
raise CliConsoleNestingProhibitedError(
"Phase cannot be used in an indented block."
)

self._print(self._format_message(enter_message, Output.PHASE))
self._in_phase = True
self._extra_indent += 1

try:
yield self.step
finally:
self._in_phase = False
self._extra_indent -= 1
if exit_message:
self._print(self._format_message(exit_message, Output.PHASE))

@contextmanager
def indented(self):
"""
A context manager for temporarily indenting messages and warnings. Phases and steps cannot be used in indented blocks,
but multiple indented blocks can be nested (use sparingly).
A context manager for temporarily indenting messages and warnings.
Multiple indented blocks can be nested (use sparingly).
"""
self._extra_indent += 1
try:
Expand All @@ -104,10 +93,6 @@ def step(self, message: str):

If called within a phase, the output will be indented.
"""
if self._extra_indent > 0:
raise CliConsoleNestingProhibitedError(
"Step cannot be used in an indented block."
)
text = self._format_message(message, Output.STEP)
self._print(text)

Expand Down
53 changes: 41 additions & 12 deletions tests/api/console/test_cli_console_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import pytest
from snowflake.cli.api.console.console import (
CliConsole,
CliConsoleNestingProhibitedError,
)


Expand Down Expand Up @@ -74,12 +73,22 @@ def test_error_messages(cli_console, capsys):
assert_output_matches("42\n 73\n ops\nOPS\n", capsys)


def test_phase_nesting_not_allowed(cli_console):
def test_phase_nesting(cli_console, capsys):
sfc-gh-bdufour marked this conversation as resolved.
Show resolved Hide resolved
with cli_console.phase("Enter 1"):
with pytest.raises(CliConsoleNestingProhibitedError):
with cli_console.phase("Enter 2"):
with cli_console.phase("Enter 2"):
with cli_console.phase("Enter 3"):
pass

expected_output = dedent(
f"""\
Enter 1
Enter 2
sfc-gh-mchok marked this conversation as resolved.
Show resolved Hide resolved
Enter 3
"""
)

assert_output_matches(expected_output, capsys)


def test_phase_is_cleaned_up_on_exception(cli_console):
with pytest.raises(RuntimeError):
Expand All @@ -91,18 +100,38 @@ def test_phase_is_cleaned_up_on_exception(cli_console):
pass


def test_phase_cannot_be_indented(cli_console):
def test_phase_inside_indented(cli_console, capsys):
cli_console.step("Outside of Indent")
with cli_console.indented():
with pytest.raises(CliConsoleNestingProhibitedError):
with cli_console.phase("Enter"):
pass
cli_console.step("Step In Indent")
with cli_console.phase("Phase In Indent"):
cli_console.step("Step In Indent + Phase")

expected_output = dedent(
f"""\
Outside of Indent
Step In Indent
Phase In Indent
Step In Indent + Phase
"""
)

def test_step_cannot_be_indented(cli_console):
assert_output_matches(expected_output, capsys)


def test_step_inside_indented(cli_console, capsys):
cli_console.step("Outside of Indent")
with cli_console.indented():
with pytest.raises(CliConsoleNestingProhibitedError):
with cli_console.step("Operation"):
pass
cli_console.step("Operation")

expected_output = dedent(
f"""\
Outside of Indent
Operation
"""
)

assert_output_matches(expected_output, capsys)


def test_indented(cli_console, capsys):
Expand Down
34 changes: 34 additions & 0 deletions tests_integration/nativeapp/test_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,37 @@ def test_nativeapp_validate_with_post_deploy_hooks(
with nativeapp_teardown(project_dir=Path(temp_dir)):
result = runner.invoke_with_connection(["app", "validate"])
assert result.exit_code == 0, result.output


@pytest.mark.integration
def test_nativeapp_validate_with_artifacts_processor(
nativeapp_teardown, runner, temp_dir
):
ProjectV2Factory(
pdf__entities=dict(
pkg=ApplicationPackageEntityModelFactory(
identifier="myapp_pkg",
artifacts=[
"setup.sql",
"README.md",
"manifest.yml",
# just needs to have the templates processor to nest phases
{"src": "app/*", "dest": "./", "processors": ["templates"]},
],
),
app=ApplicationEntityModelFactory(
identifier="myapp",
fromm__target="pkg",
),
),
files={
"setup.sql": "CREATE OR ALTER VERSIONED SCHEMA core;",
"README.md": "\n",
"manifest.yml": "\n",
"app/dummy_file.md": "\n",
},
)

with nativeapp_teardown(project_dir=Path(temp_dir)):
result = runner.invoke_with_connection(["app", "validate"])
assert result.exit_code == 0, result.output