Skip to content

Commit

Permalink
Fix not able to add patch to quoted versions
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-melnacouzi committed Dec 10, 2024
1 parent ca0879b commit a9c3cec
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 1 deletion.
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

## Fixes and improvements
* Fixed crashes with older x86_64 Intel CPUs.
* Fixed inability to add patches to lowercase quoted versions

# v3.2.0

Expand Down
4 changes: 4 additions & 0 deletions src/snowflake/cli/api/project/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ def unquote_identifier(identifier: str) -> str:
string for a LIKE clause, or to match an identifier passed back as
a value from a SQL statement.
"""
# ensure input is a valid identifier - otherwise, it could accidentally uppercase
# a quoted identifier
identifier = to_identifier(identifier)

if match := re.fullmatch(QUOTED_IDENTIFIER_REGEX, identifier):
return match.group(1).replace('""', '"')
# unquoted identifiers are internally represented as uppercase
Expand Down
22 changes: 22 additions & 0 deletions tests/project/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
to_identifier,
to_quoted_identifier,
to_string_literal,
unquote_identifier,
)

VALID_UNQUOTED_IDENTIFIERS = (
Expand Down Expand Up @@ -335,3 +336,24 @@ def test_identifier_to_str(identifier, expected_value):
)
def test_sanitize_identifier(identifier, expected_value):
assert sanitize_identifier(identifier) == expected_value


@pytest.mark.parametrize(
"identifier, expected",
[
# valid unquoted id -> return upper case version
("Id_1", "ID_1"),
# valid quoted id -> remove quotes and keep case
('"Id""1"', 'Id"1'),
# unquoted id with special characters -> treat it as quoted ID and reserve case
("Id.aBc", "Id.aBc"),
# unquoted id with double quotes inside -> treat is quoted ID
('Id"1', 'Id"1'),
# quoted id with escaped double quotes -> unescape and keep case
('"Id""1"', 'Id"1'),
# empty string -> return the same
("", ""),
],
)
def test_unquote_identifier(identifier, expected):
assert unquote_identifier(identifier) == expected
2 changes: 1 addition & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_path_resolver(mock_system, argument, expected):
("my_app", "MY_APP"),
('"My App"', "My%20App"),
("SYSTEM$GET", "SYSTEM%24GET"),
("mailorder_!@#$%^&*()/_app", "MAILORDER_!%40%23%24%25%5E%26*()%2F_APP"),
("mailorder_!@#$%^&*()/_app", "mailorder_!%40%23%24%25%5E%26*()%2F_app"),
('"Mailorder *App* is /cool/"', "Mailorder%20*App*%20is%20%2Fcool%2F"),
],
)
Expand Down
50 changes: 50 additions & 0 deletions tests_integration/nativeapp/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,53 @@ def test_version_create_with_manage_versions_only(
]
)
assert result.exit_code == 0, result.output


@pytest.mark.integration
def test_nativeapp_version_create_quoted_identifiers(
runner,
snowflake_session,
default_username,
resource_suffix,
nativeapp_project_directory,
):
project_name = "myapp"
with nativeapp_project_directory("napp_init_v2"):
package_name = f"{project_name}_pkg_{default_username}{resource_suffix}".upper()

# create version
result = runner.invoke_with_connection_json(
["app", "version", "create", "v1.0"]
)
assert result.exit_code == 0

# create another patch
result = runner.invoke_with_connection_json(
["app", "version", "create", "v1.0"]
)
assert result.exit_code == 0

# create custom patch
result = runner.invoke_with_connection_json(
["app", "version", "create", "v1.0", "--patch", "4"]
)
assert result.exit_code == 0

# app package contains 3 patches for version v1.0
expect = row_from_snowflake_session(
snowflake_session.execute_string(
f"show versions in application package {package_name}"
)
)
assert contains_row_with(expect, {"version": "v1.0", "patch": 0})
assert contains_row_with(expect, {"version": "v1.0", "patch": 1})
assert contains_row_with(expect, {"version": "v1.0", "patch": 4})

# drop the version
result_drop = runner.invoke_with_connection_json(
["app", "version", "drop", "v1.0", "--force"]
)
assert result_drop.exit_code == 0

actual = runner.invoke_with_connection_json(["app", "version", "list"])
assert len(actual.json) == 0

0 comments on commit a9c3cec

Please sign in to comment.