Skip to content

Commit 415c389

Browse files
committed
feat: merge generator config yaml
1 parent 4c4dce5 commit 415c389

File tree

2 files changed

+109
-11
lines changed

2 files changed

+109
-11
lines changed

monorepo-migration/migrate.sh

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ TRANSFORM_SCRIPT="$TRANSFORM_SCRIPT_DIR/transform_workflow.py"
5656
MODERNIZE_POM_SCRIPT="$TRANSFORM_SCRIPT_DIR/modernize_pom.py"
5757
UPDATE_ROOT_POM_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_root_pom.py"
5858
FIX_COPYRIGHT_SCRIPT="$TRANSFORM_SCRIPT_DIR/fix_copyright_headers.py"
59+
UPDATE_GENERATION_CONFIG_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_generation_config.py"
5960

6061
echo "Starting migration using git read-tree with isolated clones..."
6162

@@ -209,17 +210,7 @@ fi
209210
echo "Updating generation_config.yaml..."
210211
SOURCE_CONFIG="$SOURCE_REPO_NAME/generation_config.yaml"
211212
if [ -f "$SOURCE_CONFIG" ]; then
212-
# Extract the library entry (starts with - api_shortname)
213-
# This assumes the source config only has one library or we want the first one
214-
ENTRY=$(awk '/^ - api_shortname:/{flag=1; print $0; next} /^ - / && flag{flag=0} flag' "$SOURCE_CONFIG")
215-
216-
# Simple cleanup: remove repo and repo_short if they exist
217-
# Adjust indentation to match monorepo (0 spaces for -)
218-
CLEAN_ENTRY=$(echo "$ENTRY" | sed '/repo:/d' | sed '/repo_short:/d' | sed 's/^ //')
219-
220-
# Append to target generation_config.yaml
221-
echo "" >> generation_config.yaml
222-
echo "$CLEAN_ENTRY" >> generation_config.yaml
213+
python3 "$UPDATE_GENERATION_CONFIG_SCRIPT" "generation_config.yaml" "$SOURCE_CONFIG"
223214

224215
echo "Committing generation_config.yaml update..."
225216
git add generation_config.yaml
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2026 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import sys
17+
import yaml
18+
import re
19+
20+
def get_library_id(lib):
21+
"""
22+
Returns a unique identifier for a library.
23+
Prefer 'library_name', then 'api_shortname'.
24+
"""
25+
if 'library_name' in lib:
26+
return f"java-{lib['library_name']}"
27+
if 'api_shortname' in lib:
28+
return f"java-{lib['api_shortname']}"
29+
return "unknown"
30+
31+
def merge_libraries(target_libs, source_libs):
32+
"""
33+
Merges source_libs into target_libs.
34+
Libraries are matched by get_library_id.
35+
GAPICs are merged and deduplicated by proto_path.
36+
The final list is sorted by library_id.
37+
"""
38+
# Map from library_id to library dict
39+
target_map = {get_library_id(lib): lib for lib in target_libs}
40+
41+
for s_lib in source_libs:
42+
lib_id = get_library_id(s_lib)
43+
44+
# Clean up source library (remove repo fields)
45+
s_lib_cleaned = {k: v for k, v in s_lib.items() if k not in ('repo', 'repo_short')}
46+
47+
if lib_id in target_map:
48+
t_lib = target_map[lib_id]
49+
# Merge GAPICs
50+
t_gapics_list = t_lib.get('GAPICs', [])
51+
s_gapics_list = s_lib_cleaned.get('GAPICs', [])
52+
53+
# Map by proto_path for deduplication
54+
proto_map = {g['proto_path']: g for g in t_gapics_list}
55+
for g in s_gapics_list:
56+
proto_map[g['proto_path']] = g
57+
58+
# Sort GAPICs by proto_path
59+
sorted_protos = sorted(proto_map.keys())
60+
t_lib['GAPICs'] = [proto_map[p] for p in sorted_protos]
61+
62+
# Update other fields from source
63+
for k, v in s_lib_cleaned.items():
64+
if k != 'GAPICs':
65+
t_lib[k] = v
66+
else:
67+
target_map[lib_id] = s_lib_cleaned
68+
69+
# Return sorted list of libraries
70+
sorted_ids = sorted(target_map.keys())
71+
return [target_map[lib_id] for lib_id in sorted_ids]
72+
73+
def update_config(target_path, source_path):
74+
with open(target_path, 'r') as f:
75+
target_content = f.read()
76+
77+
with open(source_path, 'r') as f:
78+
source_data = yaml.safe_load(f) or {}
79+
80+
# Load target data
81+
target_data = yaml.safe_load(target_content) or {}
82+
83+
target_libs = target_data.get('libraries', [])
84+
source_libs = source_data.get('libraries', [])
85+
86+
merged_libs = merge_libraries(target_libs, source_libs)
87+
target_data['libraries'] = merged_libs
88+
89+
# Write back
90+
with open(target_path, 'w') as f:
91+
# Check if there was a license header in the original file
92+
header_match = re.search(r'^(#.*?\n\n)', target_content, re.DOTALL)
93+
if header_match:
94+
f.write(header_match.group(1))
95+
96+
# Use yaml.dump to write the data.
97+
# sort_keys=False to preserve order of fields within libraries if possible (YAML 1.2+ usually does, but pyyaml depends)
98+
yaml.dump(target_data, f, sort_keys=False, default_flow_style=False, indent=2)
99+
100+
if __name__ == "__main__":
101+
if len(sys.argv) != 3:
102+
print("Usage: python3 update_generation_config.py <target_config> <source_config>")
103+
sys.exit(1)
104+
105+
target_path = sys.argv[1]
106+
source_path = sys.argv[2]
107+
update_config(target_path, source_path)

0 commit comments

Comments
 (0)