Skip to content

chore: migrate config change functions to common module #3311

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

Merged
merged 25 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b038532
chore: mirgrate config change to common
JoeWang1127 Oct 24, 2024
fbbfc5f
update deps in modules
JoeWang1127 Oct 24, 2024
a301b02
use tempfile
JoeWang1127 Oct 24, 2024
3940b7f
change import in library_generation module
JoeWang1127 Oct 24, 2024
412d82e
change import in release_note_generation module
JoeWang1127 Oct 24, 2024
4c50486
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 24, 2024
1470a05
add config change cli
JoeWang1127 Oct 24, 2024
5d7a4d7
change entry_point.py
JoeWang1127 Oct 24, 2024
bebe941
do not compare config in it
JoeWang1127 Oct 25, 2024
8e26e1c
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 25, 2024
67c14ac
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 28, 2024
7f128fc
suppress download progress in IT
JoeWang1127 Oct 28, 2024
67742a0
remove unused deps in action
JoeWang1127 Oct 28, 2024
49e3821
pass changed libraries to docker run
JoeWang1127 Oct 28, 2024
94a3068
add default value
JoeWang1127 Oct 28, 2024
c542fbb
add default value
JoeWang1127 Oct 28, 2024
4a9340c
change docs
JoeWang1127 Oct 28, 2024
fc47bd9
fix unit tests
JoeWang1127 Oct 28, 2024
2a3d172
change doc according to code review
JoeWang1127 Oct 28, 2024
f90803d
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 28, 2024
11936ce
change cli name
JoeWang1127 Oct 29, 2024
0486b3c
change cli name
JoeWang1127 Oct 29, 2024
fae5ae7
change sign
JoeWang1127 Oct 29, 2024
9d2ede8
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 30, 2024
ef8f4fd
Merge branch 'main' into chore/separte-config-change
JoeWang1127 Oct 30, 2024
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
2 changes: 0 additions & 2 deletions .github/scripts/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ runs:
cd "${GITHUB_WORKSPACE}"
pip install --require-hashes -r hermetic_build/common/requirements.txt
pip install hermetic_build/common
pip install --require-hashes -r hermetic_build/library_generation/requirements.txt
pip install hermetic_build/library_generation
pip install --require-hashes -r hermetic_build/release_note_generation/requirements.txt
pip install hermetic_build/release_note_generation
- name: Generate changed libraries
Expand Down
10 changes: 8 additions & 2 deletions .github/scripts/hermetic_library_generation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ pushd "${api_def_dir}"
git checkout "${googleapis_commitish}"
popd

# get changed library list.
changed_libraries=$(python hermetic_build/common/cli/get_changed_libraries.py create \
--baseline-generation-config-path="${baseline_generation_config}" \
--current-generation-config-path="${generation_config}")
echo "Changed libraries are: ${changed_libraries:-"No changed library"}."

# run hermetic code generation docker image.
docker run \
--rm \
Expand All @@ -101,8 +107,8 @@ docker run \
-v "${api_def_dir}:${workspace_name}/googleapis" \
-e GENERATOR_VERSION="${image_tag}" \
gcr.io/cloud-devrel-public-resources/java-library-generation:"${image_tag}" \
--baseline-generation-config-path="${workspace_name}/${baseline_generation_config}" \
--current-generation-config-path="${workspace_name}/${generation_config}" \
--generation-config-path="${workspace_name}/${generation_config}" \
--library-names="${changed_libraries}" \
--api-definitions-path="${workspace_name}/googleapis"

python hermetic_build/release_note_generation/cli/generate_release_note.py generate \
Expand Down
83 changes: 83 additions & 0 deletions hermetic_build/common/cli/get_changed_libraries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os

import click as click

from common.model.generation_config import from_yaml
from common.utils.generation_config_comparator import compare_config


@click.group(invoke_without_command=False)
@click.pass_context
@click.version_option(message="%(version)s")
def main(ctx):
pass


@main.command()
@click.option(
"--baseline-generation-config-path",
required=True,
type=str,
help="""
Absolute or relative path to a generation_config.yaml.
This config file is used for computing changed library list.
""",
)
@click.option(
"--current-generation-config-path",
required=True,
type=str,
help="""
Absolute or relative path to a generation_config.yaml that contains the
metadata about library generation.
""",
)
def create(
baseline_generation_config_path: str,
current_generation_config_path: str,
) -> None:
"""
Compares baseline generation config with current generation config and
generates changed library names (a comma separated string) based on current
generation config.
"""
baseline_generation_config_path = os.path.abspath(baseline_generation_config_path)
if not os.path.isfile(baseline_generation_config_path):
raise FileNotFoundError(
f"{baseline_generation_config_path} does not exist. "
"A valid generation config has to be passed in as "
"baseline-generation-config-path."
)
current_generation_config_path = os.path.abspath(current_generation_config_path)
if not os.path.isfile(current_generation_config_path):
raise FileNotFoundError(
f"{current_generation_config_path} does not exist. "
"A valid generation config has to be passed in as "
"current-generation-config-path."
)
config_change = compare_config(
baseline_config=from_yaml(baseline_generation_config_path),
current_config=from_yaml(current_generation_config_path),
)
changed_libraries = config_change.get_changed_libraries()
if changed_libraries is None:
print("No changed library.")
return
click.echo(",".join(config_change.get_changed_libraries()))


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import shutil
import tempfile
from enum import Enum
from typing import Optional
from git import Commit, Repo

from common.model.gapic_inputs import parse_build_str
from common.model.generation_config import GenerationConfig
from common.model.library_config import LibraryConfig
from library_generation.utils.utilities import sh_util
from library_generation.utils.proto_path_utils import find_versioned_proto_path
from common.utils.proto_path_utils import find_versioned_proto_path

INSERTIONS = "insertions"
LINES = "lines"
Expand Down Expand Up @@ -109,25 +106,22 @@ def get_qualified_commits(
:param repo_url: the repository contains the commit history.
:return: QualifiedCommit objects.
"""
tmp_dir = sh_util("get_output_folder")
shutil.rmtree(tmp_dir, ignore_errors=True)
os.mkdir(tmp_dir)
# we only need commit history, thus shadow clone is enough.
repo = Repo.clone_from(url=repo_url, to_path=tmp_dir, filter=["blob:none"])
commit = repo.commit(self.current_config.googleapis_commitish)
proto_paths = self.current_config.get_proto_path_to_library_name()
qualified_commits = []
while str(commit.hexsha) != self.baseline_config.googleapis_commitish:
qualified_commit = ConfigChange.__create_qualified_commit(
proto_paths=proto_paths, commit=commit
)
if qualified_commit is not None:
qualified_commits.append(qualified_commit)
commit_parents = commit.parents
if len(commit_parents) == 0:
break
commit = commit_parents[0]
shutil.rmtree(tmp_dir, ignore_errors=True)
with tempfile.TemporaryDirectory() as tmp_dir:
# we only need commit history, thus a shadow clone is enough.
repo = Repo.clone_from(url=repo_url, to_path=tmp_dir, filter=["blob:none"])
commit = repo.commit(self.current_config.googleapis_commitish)
proto_paths = self.current_config.get_proto_path_to_library_name()
qualified_commits = []
while str(commit.hexsha) != self.baseline_config.googleapis_commitish:
qualified_commit = ConfigChange.__create_qualified_commit(
proto_paths=proto_paths, commit=commit
)
if qualified_commit is not None:
qualified_commits.append(qualified_commit)
commit_parents = commit.parents
if len(commit_parents) == 0:
break
commit = commit_parents[0]
return qualified_commits

def __get_library_names_from_qualified_commits(self) -> list[str]:
Expand Down
1 change: 1 addition & 0 deletions hermetic_build/common/requirements.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
black==24.8.0
GitPython==3.1.43
parameterized==0.9.0
PyYAML==6.0.2
12 changes: 12 additions & 0 deletions hermetic_build/common/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
# via black
gitdb==4.0.11 \
--hash=sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 \
--hash=sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b
# via gitpython
gitpython==3.1.43 \
--hash=sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c \
--hash=sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff
# via -r hermetic_build/common/requirements.in
mypy-extensions==1.0.0 \
--hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \
--hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782
Expand Down Expand Up @@ -107,3 +115,7 @@ pyyaml==6.0.2 \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via -r hermetic_build/common/requirements.in
smmap==5.0.1 \
--hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \
--hash=sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da
# via gitdb
Empty file.
71 changes: 71 additions & 0 deletions hermetic_build/common/tests/cli/config_change_unit_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from click.testing import CliRunner
import unittest

from common.cli.get_changed_libraries import create

script_dir = os.path.dirname(os.path.realpath(__file__))
test_resource_dir = os.path.join(script_dir, "..", "resources", "cli")


class GetChangedLibrariesTest(unittest.TestCase):
def test_entry_point_without_baseline_config_raise_system_exception(self):
os.chdir(script_dir)
runner = CliRunner()
# noinspection PyTypeChecker
result = runner.invoke(create)
self.assertEqual(2, result.exit_code)
self.assertEqual(SystemExit, result.exc_info[0])

def test_entry_point_without_current_config_raise_system_exception(self):
os.chdir(script_dir)
runner = CliRunner()
# noinspection PyTypeChecker
result = runner.invoke(
create, ["--baseline-generation-config-path=/invalid/path/file"]
)
self.assertEqual(2, result.exit_code)
self.assertEqual(SystemExit, result.exc_info[0])

def test_entry_point_with_invalid_baseline_config_raise_file_exception(self):
os.chdir(script_dir)
runner = CliRunner()
# noinspection PyTypeChecker
result = runner.invoke(
create,
[
"--baseline-generation-config-path=/invalid/path/file",
"--current-generation-config-path=/invalid/path/file",
],
)
self.assertEqual(1, result.exit_code)
self.assertEqual(FileNotFoundError, result.exc_info[0])
self.assertRegex(result.exception.args[0], "baseline-generation-config-path")

def test_entry_point_with_invalid_current_config_raise_file_exception(self):
os.chdir(script_dir)
runner = CliRunner()
# noinspection PyTypeChecker
result = runner.invoke(
create,
[
f"--baseline-generation-config-path={test_resource_dir}/empty_config.yaml",
"--current-generation-config-path=/invalid/path/file",
],
)
self.assertEqual(1, result.exit_code)
self.assertEqual(FileNotFoundError, result.exc_info[0])
self.assertRegex(result.exception.args[0], "current-generation-config-path")
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
# limitations under the License.
import unittest

from library_generation.model.config_change import ChangeType
from library_generation.model.config_change import ConfigChange
from library_generation.model.config_change import LibraryChange
from common.model.config_change import ChangeType
from common.model.config_change import ConfigChange
from common.model.config_change import LibraryChange
from common.model.gapic_config import GapicConfig
from common.model.generation_config import GenerationConfig
from common.model.library_config import LibraryConfig
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from common.model.gapic_config import GapicConfig
from common.model.generation_config import GenerationConfig
from common.model.library_config import LibraryConfig
from library_generation.utils.generation_config_comparator import ChangeType
from library_generation.utils.generation_config_comparator import compare_config
from common.utils.generation_config_comparator import ChangeType
from common.utils.generation_config_comparator import compare_config


class GenerationConfigComparatorTest(unittest.TestCase):
Expand Down
39 changes: 39 additions & 0 deletions hermetic_build/common/tests/utils/proto_path_utils_unit_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import unittest
from pathlib import Path
from common.utils.proto_path_utils import find_versioned_proto_path

script_dir = os.path.dirname(os.path.realpath(__file__))
resources_dir = os.path.join(script_dir, "..", "resources")
test_config_dir = Path(os.path.join(resources_dir, "test-config")).resolve()


class ProtoPathsUtilsTest(unittest.TestCase):
def test_find_versioned_proto_path_nested_version_success(self):
proto_path = "google/cloud/aiplatform/v1/schema/predict/params/image_classification.proto"
expected = "google/cloud/aiplatform/v1"
self.assertEqual(expected, find_versioned_proto_path(proto_path))

def test_find_versioned_proto_path_success(self):
proto_path = "google/cloud/asset/v1p2beta1/assets.proto"
expected = "google/cloud/asset/v1p2beta1"
self.assertEqual(expected, find_versioned_proto_path(proto_path))

def test_find_versioned_proto_without_version_return_itself(self):
proto_path = "google/type/color.proto"
expected = "google/type/color.proto"
self.assertEqual(expected, find_versioned_proto_path(proto_path))
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
from typing import Any
from typing import Dict
from typing import List
from library_generation.model.config_change import ChangeType
from library_generation.model.config_change import ConfigChange
from library_generation.model.config_change import LibraryChange
from library_generation.model.config_change import HashLibrary
from common.model.config_change import ChangeType
from common.model.config_change import ConfigChange
from common.model.config_change import LibraryChange
from common.model.config_change import HashLibrary
from common.model.gapic_config import GapicConfig
from common.model.generation_config import GenerationConfig
from common.model.library_config import LibraryConfig
Expand Down
33 changes: 33 additions & 0 deletions hermetic_build/common/utils/proto_path_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re


def find_versioned_proto_path(proto_path: str) -> str:
"""
Returns a versioned proto_path from a given proto_path; or proto_path itself
if it doesn't contain a versioned proto_path.
:param proto_path: a proto file path
:return: the versioned proto_path
"""
version_regex = re.compile(r"^v[1-9].*")
directories = proto_path.split("/")
for directory in directories:
result = version_regex.search(directory)
if result:
version = result[0]
idx = proto_path.find(version)
return proto_path[:idx] + version
return proto_path
Loading
Loading