Skip to content

Commit a94c2f0

Browse files
authored
feat: add generation config comparator (#2587)
In this PR: - Add a generation config comparator to compare the change type and which libraries are affected by the change. - Refactor `LibraryConfig`. - Add unit tests (no integration tests because the comparator has not been used). The comparator makes assumptions that the following library level parameters will not change: - googleapis commit (no use case) This is the first step to [improve](https://docs.google.com/document/d/1JiCcG3X7lnxaJErKe0ES_JkyU7ECb40nf2Xez3gWvuo/edit?tab=t.g3vua2kd06gx#heading=h.pygigzqg78jp) performance of hermetic code generation.
1 parent 4c7fd88 commit a94c2f0

8 files changed

+868
-24
lines changed

library_generation/model/library_config.py

+68
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15+
from hashlib import sha1
1516

1617
from typing import List, Optional
1718
from library_generation.model.gapic_config import GapicConfig
@@ -71,3 +72,70 @@ def __init__(
7172
self.cloud_api = cloud_api
7273
self.requires_billing = requires_billing
7374
self.extra_versioned_modules = extra_versioned_modules
75+
76+
def get_library_name(self) -> str:
77+
"""
78+
Return the library name of a given LibraryConfig object
79+
:return: the library name
80+
"""
81+
return self.library_name if self.library_name else self.api_shortname
82+
83+
def __eq__(self, other):
84+
return (
85+
self.api_shortname == other.api_shortname
86+
and self.api_description == other.api_description
87+
and self.name_pretty == other.name_pretty
88+
and self.product_documentation == other.product_documentation
89+
and self.gapic_configs == other.gapic_configs
90+
and self.library_type == other.library_type
91+
and self.release_level == other.release_level
92+
and self.api_id == other.api_id
93+
and self.api_reference == other.api_reference
94+
and self.codeowner_team == other.codeowner_team
95+
and self.excluded_dependencies == other.excluded_dependencies
96+
and self.excluded_poms == other.excluded_poms
97+
and self.client_documentation == other.client_documentation
98+
and self.distribution_name == other.distribution_name
99+
and self.googleapis_commitish == other.googleapis_commitish
100+
and self.group_id == other.group_id
101+
and self.issue_tracker == other.issue_tracker
102+
and self.library_name == other.library_name
103+
and self.rest_documentation == other.rest_documentation
104+
and self.rpc_documentation == other.rpc_documentation
105+
and self.cloud_api == other.cloud_api
106+
and self.requires_billing == other.requires_billing
107+
and self.extra_versioned_modules == other.extra_versioned_modules
108+
)
109+
110+
def __hash__(self):
111+
m = sha1()
112+
m.update(
113+
str(
114+
[
115+
self.api_shortname,
116+
self.api_description,
117+
self.name_pretty,
118+
self.product_documentation,
119+
self.library_type,
120+
self.release_level,
121+
self.api_id,
122+
self.api_reference,
123+
self.codeowner_team,
124+
self.excluded_dependencies,
125+
self.excluded_poms,
126+
self.client_documentation,
127+
self.distribution_name,
128+
self.googleapis_commitish,
129+
self.group_id,
130+
self.issue_tracker,
131+
self.library_name,
132+
self.rest_documentation,
133+
self.rpc_documentation,
134+
self.cloud_api,
135+
self.requires_billing,
136+
self.extra_versioned_modules,
137+
]
138+
+ [config.proto_path for config in self.gapic_configs]
139+
).encode("utf-8")
140+
)
141+
return int(m.hexdigest(), 16)

library_generation/test/integration_tests.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
from library_generation.model.generation_config import from_yaml, GenerationConfig
3030
from library_generation.test.compare_poms import compare_xml
3131
from library_generation.utilities import (
32-
get_library_name,
3332
sh_util as shell_call,
3433
run_process_and_print_output,
3534
)
@@ -214,7 +213,7 @@ def __pull_repo_to(cls, default_dest: Path, repo: str, committish: str) -> str:
214213
def __get_library_names_from_config(cls, config: GenerationConfig) -> List[str]:
215214
library_names = []
216215
for library in config.libraries:
217-
library_names.append(f"java-{get_library_name(library)}")
216+
library_names.append(f"java-{library.get_library_name()}")
218217

219218
return library_names
220219

@@ -248,21 +247,22 @@ def __load_json_to_sorted_list(cls, path: str) -> List[tuple]:
248247

249248
@classmethod
250249
def __recursive_diff_files(
251-
self,
250+
cls,
252251
dcmp: dircmp,
253252
diff_files: List[str],
254253
left_only: List[str],
255254
right_only: List[str],
256255
dirname: str = "",
257256
):
258257
"""
259-
recursively compares two subdirectories. The found differences are passed to three expected list references
258+
Recursively compares two subdirectories. The found differences are
259+
passed to three expected list references.
260260
"""
261261
append_dirname = lambda d: dirname + d
262262
diff_files.extend(map(append_dirname, dcmp.diff_files))
263263
left_only.extend(map(append_dirname, dcmp.left_only))
264264
right_only.extend(map(append_dirname, dcmp.right_only))
265265
for sub_dirname, sub_dcmp in dcmp.subdirs.items():
266-
self.__recursive_diff_files(
266+
cls.__recursive_diff_files(
267267
sub_dcmp, diff_files, left_only, right_only, dirname + sub_dirname + "/"
268268
)

library_generation/test/model/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import unittest
15+
16+
from library_generation.model.library_config import LibraryConfig
17+
18+
19+
class LibraryConfigTest(unittest.TestCase):
20+
def test_get_library_returns_library_name(self):
21+
library = LibraryConfig(
22+
api_shortname="secret",
23+
name_pretty="",
24+
product_documentation="",
25+
api_description="",
26+
gapic_configs=list(),
27+
library_name="secretmanager",
28+
)
29+
self.assertEqual("secretmanager", library.get_library_name())
30+
31+
def test_get_library_returns_api_shortname(self):
32+
library = LibraryConfig(
33+
api_shortname="secret",
34+
name_pretty="",
35+
product_documentation="",
36+
api_description="",
37+
gapic_configs=list(),
38+
)
39+
self.assertEqual("secret", library.get_library_name())

library_generation/test/utilities_unit_tests.py

-6
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,6 @@ def test_remove_version_from_returns_self(self):
391391
"google/cloud/aiplatform", util.remove_version_from(proto_path)
392392
)
393393

394-
def test_get_library_returns_library_name(self):
395-
self.assertEqual("bare-metal-solution", util.get_library_name(library_1))
396-
397-
def test_get_library_returns_api_shortname(self):
398-
self.assertEqual("secretmanager", util.get_library_name(library_2))
399-
400394
def test_generate_prerequisite_files_non_monorepo_success(self):
401395
library_path = self.__setup_prerequisite_files(
402396
num_libraries=1, library_type="GAPIC_COMBO"

0 commit comments

Comments
 (0)