Skip to content

Commit 5244589

Browse files
authored
chore(librarian): add ability to update version files for proto-only libraries (#14674)
This PR add ability to update the version number in version files for proto-only libraries, specifically files `setup.py` and `pyproject.toml`. For proto-only libraries like `google-cloud-audit-log`, version information lives in `setup.py` rather than `gapic_version.py`. See the version string here: https://github.com/googleapis/google-cloud-python/blob/63eea55ac407e4978c43deaeb1c985b1c8a170dc/packages/google-cloud-audit-log/setup.py#L23 For `pyproject.toml`, see here: https://github.com/googleapis/google-cloud-python/blob/63eea55ac407e4978c43deaeb1c985b1c8a170dc/packages/googleapis-common-protos/pyproject.toml#L21 Compared with the version string which exists in `gapic_version.py` here: https://github.com/googleapis/google-cloud-python/blob/63eea55ac407e4978c43deaeb1c985b1c8a170dc/packages/google-cloud-access-approval/google/cloud/accessapproval_v1/gapic_version.py#L16 Note that in `setup.py` and `pyproject.toml`, the version string is `version = "a.b.c"` whereas in `gapic_version.py` the version string is `__version__ = "a.b.c"`
1 parent 63eea55 commit 5244589

File tree

2 files changed

+82
-10
lines changed

2 files changed

+82
-10
lines changed

.generator/cli.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,10 @@ def _process_version_file(content, version, version_path) -> str:
10581058
10591059
Returns: A string with the modified content.
10601060
"""
1061-
pattern = r"(__version__\s*=\s*[\"'])([^\"']+)([\"'].*)"
1061+
if version_path.name.endswith("gapic_version.py"):
1062+
pattern = r"(__version__\s*=\s*[\"'])([^\"']+)([\"'].*)"
1063+
else:
1064+
pattern = r"(version\s*=\s*[\"'])([^\"']+)([\"'].*)"
10621065
replacement_string = f"\\g<1>{version}\\g<3>"
10631066
new_content, num_replacements = re.subn(pattern, replacement_string, content)
10641067
if num_replacements == 0:
@@ -1071,8 +1074,9 @@ def _process_version_file(content, version, version_path) -> str:
10711074
def _update_version_for_library(
10721075
repo: str, output: str, path_to_library: str, version: str
10731076
):
1074-
"""Updates the version string in `**/gapic_version.py` and `samples/**/snippet_metadata.json`
1075-
for a given library.
1077+
"""Updates the version string in `**/gapic_version.py`, `setup.py`,
1078+
`pyproject.toml` and `samples/**/snippet_metadata.json` for a
1079+
given library, if applicable.
10761080
10771081
Args:
10781082
repo(str): This directory will contain all directories that make up a
@@ -1088,8 +1092,15 @@ def _update_version_for_library(
10881092
"""
10891093

10901094
# Find and update gapic_version.py files
1091-
gapic_version_files = Path(f"{repo}/{path_to_library}").rglob("**/gapic_version.py")
1092-
for version_file in gapic_version_files:
1095+
version_files = Path(f"{repo}/{path_to_library}").rglob("**/gapic_version.py")
1096+
if not version_files:
1097+
# Fallback to `pyproject.toml`` or `setup.py``. Proto-only libraries have
1098+
# version information in `setup.py` or `pyproject.toml` instead of `gapic_version.py`.
1099+
pyproject_toml = Path(f"{repo}/{path_to_library}/pyproject.toml")
1100+
setup_py = Path(f"{repo}/{path_to_library}/setup.py")
1101+
version_files = [pyproject_toml if pyproject_toml.exists() else setup_py]
1102+
1103+
for version_file in version_files:
10931104
updated_content = _process_version_file(
10941105
_read_text_file(version_file), version, version_file
10951106
)

.generator/test_cli.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ def test_update_global_changelog(mocker, mock_release_init_request_file):
965965
handle.write.assert_called_once_with("[google-cloud-language==1.2.3]")
966966

967967

968-
def test_update_version_for_library_success(mocker):
968+
def test_update_version_for_library_success_gapic(mocker):
969969
m = mock_open()
970970

971971
mock_rglob = mocker.patch(
@@ -984,7 +984,67 @@ def test_update_version_for_library_success(mocker):
984984

985985
handle = m()
986986
assert handle.write.call_args_list[0].args[0] == '__version__ = "1.2.3"'
987+
# Get all the arguments passed to the mock's write method
988+
# and join them into a single string.
989+
written_content = "".join(
990+
[call.args[0] for call in handle.write.call_args_list[1:]]
991+
)
992+
# Create the expected output string with the correct formatting.
993+
assert (
994+
written_content
995+
== '{\n "clientLibrary": {\n "version": "1.2.3"\n }\n}\n'
996+
)
997+
998+
999+
def test_update_version_for_library_success_proto_only_setup_py(mocker):
1000+
m = mock_open()
1001+
1002+
mock_rglob = mocker.patch("pathlib.Path.rglob")
1003+
mock_rglob.side_effect = [[], [pathlib.Path("repo/setup.py")]]
1004+
mock_shutil_copy = mocker.patch("shutil.copy")
1005+
mock_content = 'version = "1.2.2"'
1006+
mock_json_metadata = {"clientLibrary": {"version": "0.1.0"}}
1007+
1008+
with unittest.mock.patch("cli.open", m):
1009+
mocker.patch("cli._read_text_file", return_value=mock_content)
1010+
mocker.patch("cli._read_json_file", return_value=mock_json_metadata)
1011+
_update_version_for_library(
1012+
"repo", "output", "packages/google-cloud-language", "1.2.3"
1013+
)
1014+
1015+
handle = m()
1016+
assert handle.write.call_args_list[0].args[0] == 'version = "1.2.3"'
1017+
# Get all the arguments passed to the mock's write method
1018+
# and join them into a single string.
1019+
written_content = "".join(
1020+
[call.args[0] for call in handle.write.call_args_list[1:]]
1021+
)
1022+
# Create the expected output string with the correct formatting.
1023+
assert (
1024+
written_content
1025+
== '{\n "clientLibrary": {\n "version": "1.2.3"\n }\n}\n'
1026+
)
1027+
1028+
1029+
def test_update_version_for_library_success_proto_only_py_project_toml(mocker):
1030+
m = mock_open()
9871031

1032+
mock_path_exists = mocker.patch("pathlib.Path.exists")
1033+
mock_rglob = mocker.patch("pathlib.Path.rglob")
1034+
mock_rglob.side_effect = [[], [pathlib.Path("repo/pyproject.toml")]]
1035+
mock_shutil_copy = mocker.patch("shutil.copy")
1036+
mock_content = 'version = "1.2.2"'
1037+
mock_json_metadata = {"clientLibrary": {"version": "0.1.0"}}
1038+
1039+
with unittest.mock.patch("cli.open", m):
1040+
mocker.patch("cli._read_text_file", return_value=mock_content)
1041+
mocker.patch("cli._read_json_file", return_value=mock_json_metadata)
1042+
_update_version_for_library(
1043+
"repo", "output", "packages/google-cloud-language", "1.2.3"
1044+
)
1045+
1046+
handle = m()
1047+
assert handle.write.call_args_list[0].args[0] == 'version = "1.2.3"'
9881048
# Get all the arguments passed to the mock's write method
9891049
# and join them into a single string.
9901050
written_content = "".join(
@@ -1099,18 +1159,18 @@ def test_update_changelog_for_library_failure(mocker):
10991159

11001160

11011161
def test_process_version_file_success():
1102-
version_file_contents = '__version__ = "1.2.2"'
1162+
version_file_contents = 'version = "1.2.2"'
11031163
new_version = "1.2.3"
11041164
modified_content = _process_version_file(
1105-
version_file_contents, new_version, "file.txt"
1165+
version_file_contents, new_version, Path("file.txt")
11061166
)
1107-
assert modified_content == f'__version__ = "{new_version}"'
1167+
assert modified_content == f'version = "{new_version}"'
11081168

11091169

11101170
def test_process_version_file_failure():
11111171
"""Tests that value error is raised if the version string cannot be found"""
11121172
with pytest.raises(ValueError):
1113-
_process_version_file("", "", "")
1173+
_process_version_file("", "", Path(""))
11141174

11151175

11161176
def test_create_main_version_header():
@@ -1367,6 +1427,7 @@ def test_get_staging_child_directory_gapic_versioned():
13671427
expected = "v1"
13681428
assert _get_staging_child_directory(api_path, False) == expected
13691429

1430+
13701431
def test_get_staging_child_directory_gapic_non_versioned():
13711432
"""
13721433
Tests the behavior for GAPIC clients with no standard 'v' prefix versioning.

0 commit comments

Comments
 (0)