Skip to content

Commit e508ae6

Browse files
authoredJun 10, 2024
feat: generate pr description from configuration comparison result (#2841)
In this PR: - Generate pull request description from configuration comparison result. - The pull request description contains repo-level changes, if applicable, and googleapis commit from baseline config (exclusive) to current config (inclusive). An example of pr description with repo-level change: ``` This pull request is generated with proto changes between [googleapis/googleapis@3b6f144](googleapis/googleapis@3b6f144) (exclusive) and [googleapis/googleapis@0cea717](googleapis/googleapis@0cea717) (inclusive). BEGIN_COMMIT_OVERRIDE BEGIN_NESTED_COMMIT fix(deps): update the Java code generator (gapic-generator-java) to 1.2.3 END_NESTED_COMMIT BEGIN_NESTED_COMMIT chore: update the libraries_bom version to 2.3.4 END_NESTED_COMMIT BEGIN_NESTED_COMMIT feat: Make Layout Parser generally available in V1 PiperOrigin-RevId: 638924855 Source Link: [googleapis/googleapis@0cea717](googleapis/googleapis@0cea717) END_NESTED_COMMIT END_COMMIT_OVERRIDE ```
1 parent 6c5d6ce commit e508ae6

8 files changed

+262
-85
lines changed
 

‎.github/workflows/hermetic_library_generation.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
-f .cloudbuild/library_generation/library_generation.Dockerfile \
3535
-t gcr.io/cloud-devrel-public-resources/java-library-generation:latest \
3636
.
37-
- name: Install gapic-generator-java-pom-parent
37+
- name: Install all modules
3838
shell: bash
3939
run: |
4040
mvn -V -B -ntp clean install -DskipTests

‎library_generation/cli/entry_point.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ def generate(
135135
target_library_names=config_change.get_changed_libraries(),
136136
)
137137
generate_pr_descriptions(
138-
config=config_change.current_config,
139-
baseline_commit=config_change.baseline_config.googleapis_commitish,
138+
config_change=config_change,
140139
description_path=repository_path,
141140
)
142141

‎library_generation/generate_pr_description.py

+35-33
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import shutil
1818
from typing import Dict
1919
from git import Commit, Repo
20-
from library_generation.model.generation_config import GenerationConfig
20+
21+
from library_generation.model.config_change import ConfigChange
2122
from library_generation.utils.proto_path_utils import find_versioned_proto_path
2223
from library_generation.utils.commit_message_formatter import (
2324
format_commit_message,
25+
format_repo_level_change,
2426
commit_link,
2527
)
2628
from library_generation.utils.commit_message_formatter import wrap_override_commit
@@ -29,42 +31,38 @@
2931

3032

3133
def generate_pr_descriptions(
32-
config: GenerationConfig,
33-
baseline_commit: str,
34+
config_change: ConfigChange,
3435
description_path: str,
3536
repo_url: str = "https://github.com/googleapis/googleapis.git",
3637
) -> None:
3738
"""
38-
Generate pull request description from baseline_commit (exclusive) to the
39-
googleapis commit (inclusive) in the given generation config.
39+
Generate pull request description from configuration comparison result.
40+
41+
The pull request description contains repo-level changes, if applicable,
42+
and googleapis commit from baseline config (exclusive) to current config
43+
(inclusive).
4044
4145
The pull request description will be generated into
4246
description_path/pr_description.txt.
4347
44-
If baseline_commit is the same as googleapis commit in the given generation
45-
config, no pr_description.txt will be generated.
48+
No pr_description.txt will be generated if no changes in the configurations.
4649
47-
:param config: a GenerationConfig object. The googleapis commit in this
48-
configuration is the latest commit, inclusively, from which the commit
49-
message is considered.
50-
:param baseline_commit: The baseline (oldest) commit, exclusively, from
51-
which the commit message is considered. This commit should be an ancestor
52-
of googleapis commit in configuration.
50+
:param config_change: a ConfigChange object, containing changes in baseline
51+
and current generation configurations.
5352
:param description_path: the path to which the pull request description
5453
file goes.
5554
:param repo_url: the GitHub repository from which retrieves the commit
5655
history.
5756
"""
58-
if baseline_commit == config.googleapis_commitish:
59-
return
60-
61-
paths = config.get_proto_path_to_library_name()
62-
description = get_commit_messages(
57+
repo_level_message = format_repo_level_change(config_change)
58+
paths = config_change.current_config.get_proto_path_to_library_name()
59+
description = get_repo_level_commit_messages(
6360
repo_url=repo_url,
64-
current_commit_sha=config.googleapis_commitish,
65-
baseline_commit_sha=baseline_commit,
61+
current_commit_sha=config_change.current_config.googleapis_commitish,
62+
baseline_commit_sha=config_change.baseline_config.googleapis_commitish,
6663
paths=paths,
67-
is_monorepo=config.is_monorepo(),
64+
is_monorepo=config_change.current_config.is_monorepo(),
65+
repo_level_message=repo_level_message,
6866
)
6967

7068
if description == EMPTY_MESSAGE:
@@ -77,12 +75,13 @@ def generate_pr_descriptions(
7775
f.write(description)
7876

7977

80-
def get_commit_messages(
78+
def get_repo_level_commit_messages(
8179
repo_url: str,
8280
current_commit_sha: str,
8381
baseline_commit_sha: str,
8482
paths: Dict[str, str],
8583
is_monorepo: bool,
84+
repo_level_message: list[str] = None,
8685
) -> str:
8786
"""
8887
Combine commit messages of a repository from latest_commit to
@@ -97,10 +96,13 @@ def get_commit_messages(
9796
selecting commit message. This commit should be an ancestor of
9897
:param paths: a mapping from file paths to library_name.
9998
:param is_monorepo: whether to generate commit messages in a monorepo.
99+
:param repo_level_message: commit messages regarding repo-level changes.
100100
:return: commit messages.
101101
:raise ValueError: if current_commit is older than or equal to
102102
baseline_commit.
103103
"""
104+
if current_commit_sha == baseline_commit_sha:
105+
return EMPTY_MESSAGE
104106
tmp_dir = "/tmp/repo"
105107
shutil.rmtree(tmp_dir, ignore_errors=True)
106108
os.mkdir(tmp_dir)
@@ -134,6 +136,7 @@ def get_commit_messages(
134136
baseline_commit=baseline_commit,
135137
commits=qualified_commits,
136138
is_monorepo=is_monorepo,
139+
repo_level_message=repo_level_message,
137140
)
138141

139142

@@ -160,20 +163,19 @@ def __combine_commit_messages(
160163
baseline_commit: Commit,
161164
commits: Dict[Commit, str],
162165
is_monorepo: bool,
166+
repo_level_message: list[str],
163167
) -> str:
164-
messages = [
165-
f"This pull request is generated with proto changes between {commit_link(baseline_commit)} (exclusive) "
166-
f"and {commit_link(current_commit)} (inclusive).",
167-
"",
168+
description = [
169+
f"This pull request is generated with proto changes between "
170+
f"{commit_link(baseline_commit)} (exclusive) "
171+
f"and {commit_link(current_commit)} (inclusive).\n",
168172
]
169-
170-
messages.extend(
171-
wrap_override_commit(
172-
format_commit_message(commits=commits, is_monorepo=is_monorepo)
173-
)
173+
commit_message = repo_level_message
174+
commit_message.extend(
175+
format_commit_message(commits=commits, is_monorepo=is_monorepo)
174176
)
175-
176-
return "\n".join(messages)
177+
description.extend(wrap_override_commit(commit_message))
178+
return "\n".join(description)
177179

178180

179181
def __get_commit_timestamp(commit: Commit) -> int:

‎library_generation/model/generation_config.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
LIBRARY_LEVEL_PARAMETER = "Library level parameter"
2222
GAPIC_LEVEL_PARAMETER = "GAPIC level parameter"
2323
COMMON_PROTOS_LIBRARY_NAME = "common-protos"
24+
GAPIC_GENERATOR_VERSION = "gapic_generator_version"
25+
LIBRARIES_BOM_VERSION = "libraries_bom_version"
2426

2527

2628
class GenerationConfig:
@@ -144,14 +146,14 @@ def from_yaml(path_to_yaml: str) -> GenerationConfig:
144146

145147
parsed_config = GenerationConfig(
146148
gapic_generator_version=__required(
147-
config, "gapic_generator_version", REPO_LEVEL_PARAMETER
149+
config, GAPIC_GENERATOR_VERSION, REPO_LEVEL_PARAMETER
148150
),
149151
googleapis_commitish=__required(
150152
config, "googleapis_commitish", REPO_LEVEL_PARAMETER
151153
),
152154
grpc_version=__optional(config, "grpc_version", None),
153155
protoc_version=__optional(config, "protoc_version", None),
154-
libraries_bom_version=__optional(config, "libraries_bom_version", None),
156+
libraries_bom_version=__optional(config, LIBRARIES_BOM_VERSION, None),
155157
libraries=parsed_libraries,
156158
)
157159

‎library_generation/test/generate_pr_description_unit_tests.py

+110-34
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,23 @@
1313
# limitations under the License.
1414
import os
1515
import unittest
16+
from filecmp import cmp
1617

1718
from library_generation.generate_pr_description import (
18-
get_commit_messages,
19+
get_repo_level_commit_messages,
1920
generate_pr_descriptions,
2021
)
22+
from library_generation.model.config_change import (
23+
ConfigChange,
24+
ChangeType,
25+
LibraryChange,
26+
)
27+
from library_generation.model.gapic_config import GapicConfig
2128
from library_generation.model.generation_config import GenerationConfig
29+
from library_generation.model.library_config import LibraryConfig
30+
31+
script_dir = os.path.dirname(os.path.realpath(__file__))
32+
resources_dir = os.path.join(script_dir, "resources", "goldens")
2233

2334

2435
class GeneratePrDescriptionTest(unittest.TestCase):
@@ -30,44 +41,51 @@ def test_get_commit_messages_current_is_older_raise_exception(self):
3041
self.assertRaisesRegex(
3142
ValueError,
3243
"newer than",
33-
get_commit_messages,
44+
get_repo_level_commit_messages,
3445
"https://github.com/googleapis/googleapis.git",
3546
current_commit,
3647
baseline_commit,
3748
{},
3849
True,
3950
)
4051

41-
def test_get_commit_messages_current_and_baseline_are_same_raise_exception(self):
52+
def test_get_commit_messages_with_same_current_and_baseline_returns_empty_message(
53+
self,
54+
):
4255
# committed on April 1st, 2024
4356
current_commit = "36441693dddaf0ed73951ad3a15c215a332756aa"
4457
baseline_commit = "36441693dddaf0ed73951ad3a15c215a332756aa"
45-
self.assertRaisesRegex(
46-
ValueError,
47-
"newer than",
48-
get_commit_messages,
49-
"https://github.com/googleapis/googleapis.git",
50-
current_commit,
51-
baseline_commit,
52-
{},
53-
True,
58+
self.assertEqual(
59+
"",
60+
get_repo_level_commit_messages(
61+
"https://github.com/googleapis/googleapis.git",
62+
current_commit,
63+
baseline_commit,
64+
{},
65+
True,
66+
),
5467
)
5568

56-
def test_generate_pr_description_with_same_googleapis_commits(self):
69+
def test_generate_pr_description_with_no_change_in_config(self):
5770
commit_sha = "36441693dddaf0ed73951ad3a15c215a332756aa"
58-
cwd = os.getcwd()
71+
config = GenerationConfig(
72+
gapic_generator_version="",
73+
googleapis_commitish=commit_sha,
74+
libraries_bom_version="",
75+
# use empty libraries to make sure no qualified commit between
76+
# two commit sha.
77+
libraries=[],
78+
)
79+
pr_description_path = os.path.join(os.getcwd(), "no_config_change")
5980
generate_pr_descriptions(
60-
config=GenerationConfig(
61-
gapic_generator_version="",
62-
googleapis_commitish=commit_sha,
63-
grpc_version="",
64-
protoc_version="",
65-
libraries=[],
81+
config_change=ConfigChange(
82+
change_to_libraries={},
83+
baseline_config=config,
84+
current_config=config,
6685
),
67-
baseline_commit=commit_sha,
68-
description_path=cwd,
86+
description_path=pr_description_path,
6987
)
70-
self.assertFalse(os.path.isfile(f"{cwd}/pr_description.txt"))
88+
self.assertFalse(os.path.isfile(f"{pr_description_path}/pr_description.txt"))
7189

7290
def test_generate_pr_description_does_not_create_pr_description_without_qualified_commit(
7391
self,
@@ -76,19 +94,77 @@ def test_generate_pr_description_does_not_create_pr_description_without_qualifie
7694
old_commit_sha = "30717c0b0c9966906880703208a4c820411565c4"
7795
# committed on May 23rd, 2024
7896
new_commit_sha = "eeed69d446a90eb4a4a2d1762c49d637075390c1"
97+
pr_description_path = os.path.join(os.getcwd(), "no_qualified_commit")
98+
generate_pr_descriptions(
99+
config_change=ConfigChange(
100+
change_to_libraries={},
101+
baseline_config=GenerationConfig(
102+
gapic_generator_version="",
103+
googleapis_commitish=old_commit_sha,
104+
# use empty libraries to make sure no qualified commit between
105+
# two commit sha.
106+
libraries=[],
107+
),
108+
current_config=GenerationConfig(
109+
gapic_generator_version="",
110+
googleapis_commitish=new_commit_sha,
111+
# use empty libraries to make sure no qualified commit between
112+
# two commit sha.
113+
libraries=[],
114+
),
115+
),
116+
description_path=pr_description_path,
117+
)
118+
self.assertFalse(os.path.isfile(f"{pr_description_path}/pr_description.txt"))
119+
120+
def test_generate_pr_description_with_combined_message(
121+
self,
122+
):
123+
# no other commits between these two commits.
124+
baseline_commit_sha = "3b6f144d47b0a1d2115ab2445ec06e80cc324a44"
125+
documentai_commit_sha = "0cea7170404bec3d994f43db4fa292f5034cbe9a"
79126
cwd = os.getcwd()
127+
library = LibraryConfig(
128+
api_shortname="documentai",
129+
api_description="",
130+
name_pretty="",
131+
product_documentation="",
132+
gapic_configs=[GapicConfig(proto_path="google/cloud/documentai/v1")],
133+
)
80134
generate_pr_descriptions(
81-
config=GenerationConfig(
82-
gapic_generator_version="",
83-
googleapis_commitish=new_commit_sha,
84-
libraries_bom_version="",
85-
grpc_version="",
86-
protoc_version="",
87-
# use empty libraries to make sure no qualified commit between
88-
# two commit sha.
89-
libraries=[],
135+
config_change=ConfigChange(
136+
change_to_libraries={
137+
ChangeType.REPO_LEVEL_CHANGE: [
138+
LibraryChange(
139+
changed_param="gapic_generator_version",
140+
current_value="1.2.3",
141+
),
142+
LibraryChange(
143+
changed_param="libraries_bom_version", current_value="2.3.4"
144+
),
145+
],
146+
ChangeType.GOOGLEAPIS_COMMIT: [],
147+
},
148+
baseline_config=GenerationConfig(
149+
gapic_generator_version="",
150+
googleapis_commitish=baseline_commit_sha,
151+
libraries=[library],
152+
),
153+
current_config=GenerationConfig(
154+
gapic_generator_version="1.2.3",
155+
googleapis_commitish=documentai_commit_sha,
156+
libraries_bom_version="2.3.4",
157+
libraries=[library],
158+
),
90159
),
91-
baseline_commit=old_commit_sha,
92160
description_path=cwd,
93161
)
94-
self.assertFalse(os.path.isfile(f"{cwd}/pr_description.txt"))
162+
self.assertTrue(os.path.isfile(f"{cwd}/pr_description.txt"))
163+
self.assertTrue(
164+
cmp(
165+
f"{resources_dir}/pr_description-golden.txt",
166+
f"{cwd}/pr_description.txt",
167+
),
168+
"The generated PR description does not match the expected golden file",
169+
)
170+
os.remove(f"{cwd}/pr_description.txt")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This pull request is generated with proto changes between [googleapis/googleapis@3b6f144](https://github.com/googleapis/googleapis/commit/3b6f144d47b0a1d2115ab2445ec06e80cc324a44) (exclusive) and [googleapis/googleapis@0cea717](https://github.com/googleapis/googleapis/commit/0cea7170404bec3d994f43db4fa292f5034cbe9a) (inclusive).
2+
3+
BEGIN_COMMIT_OVERRIDE
4+
BEGIN_NESTED_COMMIT
5+
fix(deps): update the Java code generator (gapic-generator-java) to 1.2.3
6+
END_NESTED_COMMIT
7+
BEGIN_NESTED_COMMIT
8+
chore: update the libraries_bom version to 2.3.4
9+
END_NESTED_COMMIT
10+
BEGIN_NESTED_COMMIT
11+
feat: Make Layout Parser generally available in V1
12+
13+
PiperOrigin-RevId: 638924855
14+
15+
Source Link: [googleapis/googleapis@0cea717](https://github.com/googleapis/googleapis/commit/0cea7170404bec3d994f43db4fa292f5034cbe9a)
16+
END_NESTED_COMMIT
17+
END_COMMIT_OVERRIDE

0 commit comments

Comments
 (0)
Please sign in to comment.