Skip to content

Commit c07bf8a

Browse files
committed
move google-api-services dependency management
1 parent f5a0f6d commit c07bf8a

File tree

3 files changed

+183
-6
lines changed

3 files changed

+183
-6
lines changed

monorepo-migration/migrate.sh

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ FIX_COPYRIGHT_SCRIPT="$TRANSFORM_SCRIPT_DIR/fix_copyright_headers.py"
5757
UPDATE_GENERATION_CONFIG_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_generation_config.py"
5858
UPDATE_OWLBOT_HERMETIC_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_owlbot_hermetic.py"
5959
TRANSFORM_OWLBOT_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_owlbot.py"
60+
UPDATE_DEP_MGMT_SCRIPT="$TRANSFORM_SCRIPT_DIR/update_dependency_management.py"
6061

6162
# Track number of commits made by this script
6263
COMMIT_COUNT=0
@@ -472,10 +473,34 @@ fi
472473
# git commit -n --no-gpg-sign -m "chore($SOURCE_REPO_NAME): update copyright headers to 2026 Google LLC"
473474
# COMMIT_COUNT=$((COMMIT_COUNT + 1))
474475

476+
# 7.10 Modernize pom.xml files and extract google-api-services dependencies
477+
modernize_and_extract() {
478+
local pom_file="$1"
479+
shift
480+
local cmd_output
481+
cmd_output=$(python3 "$MODERNIZE_POM_SCRIPT" "$pom_file" "$@" 2>&1)
482+
echo "$cmd_output" | grep -v "EXTRACT_DEP:" || true
483+
484+
# Process extracted dependencies
485+
echo "$cmd_output" | grep "EXTRACT_DEP:" | while read -r line; do
486+
dep_info="${line#EXTRACT_DEP:}"
487+
IFS=':' read -r gid aid ver <<< "$dep_info"
488+
echo "Extracting $gid:$aid:$ver to parent POM..."
489+
python3 "$UPDATE_DEP_MGMT_SCRIPT" "google-cloud-jar-parent/pom.xml" "$gid" "$aid" "$ver"
490+
491+
# Commit parent POM change if anything changed
492+
if git diff --name-only | grep -q "google-cloud-jar-parent/pom.xml"; then
493+
git add "google-cloud-jar-parent/pom.xml"
494+
git commit -n --no-gpg-sign -m "chore($SOURCE_REPO_NAME): manage $aid in parent POM"
495+
COMMIT_COUNT=$((COMMIT_COUNT + 1))
496+
fi
497+
done
498+
}
499+
475500
# 7.11 Modernize root pom.xml
476501
echo "Modernizing root pom.xml..."
477502
PARENT_VERSION=$(grep -m 1 "<version>.*{x-version-update:google-cloud-java:current}" google-cloud-jar-parent/pom.xml | sed -E 's/.*<version>(.*)<\/version>.*/\1/')
478-
python3 "$MODERNIZE_POM_SCRIPT" "$SOURCE_REPO_NAME/pom.xml" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME"
503+
modernize_and_extract "$SOURCE_REPO_NAME/pom.xml" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME"
479504

480505
echo "Committing root pom.xml modernization..."
481506
git add "$SOURCE_REPO_NAME/pom.xml"
@@ -489,7 +514,7 @@ echo "Modernizing BOM pom.xml..."
489514
while read -r bom_pom; do
490515
echo "Modernizing BOM: $bom_pom"
491516
# BOMs should inherit from google-cloud-pom-parent
492-
python3 "$MODERNIZE_POM_SCRIPT" "$bom_pom" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME" --parent-artifactId "google-cloud-pom-parent" --relative-path "../../google-cloud-pom-parent/pom.xml"
517+
modernize_and_extract "$bom_pom" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME" --parent-artifactId "google-cloud-pom-parent" --relative-path "../../google-cloud-pom-parent/pom.xml"
493518

494519
echo "Committing BOM pom.xml modernization for $bom_pom..."
495520
git add "$bom_pom"
@@ -502,7 +527,7 @@ echo "Modernizing other pom.xml files..."
502527
while read -r other_pom; do
503528
echo "Modernizing submodule POM: $other_pom"
504529
# Preserve the existing parent, but update everything else
505-
python3 "$MODERNIZE_POM_SCRIPT" "$other_pom" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME" --keep-parent
530+
modernize_and_extract "$other_pom" "$PARENT_VERSION" --source-repo "$SOURCE_REPO_NAME" --keep-parent
506531

507532
echo "Committing submodule pom.xml modernization for $other_pom..."
508533
git add "$other_pom" && git commit -n --no-gpg-sign -m "chore($SOURCE_REPO_NAME): modernize submodule pom.xml" && COMMIT_COUNT=$((COMMIT_COUNT + 1)) || true

monorepo-migration/modernize_pom.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@ def get_managed_dependencies(pom_path):
6767
return managed_deps
6868

6969

70+
def get_pom_properties(pom_path):
71+
"""Extracts all properties from the <properties> section of a pom.xml."""
72+
properties = {}
73+
if not os.path.exists(pom_path):
74+
return properties
75+
76+
try:
77+
# We'll use a simple regex-based parser to avoid complex namespace issues with ET
78+
# and to handle property names that might not be valid XML tags if not careful
79+
with open(pom_path, 'r') as f:
80+
content = f.read()
81+
82+
props_match = re.search(r'<properties>(.*?)</properties>', content, re.DOTALL)
83+
if props_match:
84+
props_content = props_match.group(1)
85+
# Find all tag pairs inside properties
86+
for match in re.finditer(r'<([^/ >]+)>([^<]*)</\1>', props_content):
87+
tag = match.group(1)
88+
value = match.group(2).strip()
89+
properties[tag] = value
90+
except Exception as e:
91+
print(f"Warning: Failed to get properties from {pom_path}: {e}")
92+
93+
return properties
94+
95+
7096
def parse_pom_for_version(file_path):
7197
"""Extracts artifactId and version from a pom.xml file."""
7298
artifact_id = None
@@ -150,6 +176,10 @@ def modernize_pom(file_path, parent_version, source_repo_name=None, parent_artif
150176
lines = f.readlines()
151177

152178
new_lines = []
179+
180+
# Pre-parse properties for resolution
181+
pom_properties = get_pom_properties(file_path)
182+
153183
in_parent = False
154184
in_dep_mgmt = False
155185
in_dependencies = False
@@ -238,10 +268,17 @@ def modernize_pom(file_path, parent_version, source_repo_name=None, parent_artif
238268
current_group_id = None
239269
current_artifact_id = None
240270
has_version = False
271+
extracted_dep = None
241272
continue
242273
if '</dependency>' in line:
243274
in_dependency = False
244275

276+
if extracted_dep:
277+
# Remove version tag from current_dependency_lines if it was extracted
278+
# We do this before further checks
279+
current_dependency_lines = [l for l in current_dependency_lines if '<version>' not in l]
280+
has_version = False # It's now managed
281+
should_preserve = True # We want to keep the dependency entry
245282
# Monorepo version alignment and annotation
246283
if monorepo_versions and current_artifact_id and current_artifact_id in monorepo_versions:
247284
new_version = monorepo_versions[current_artifact_id]
@@ -317,9 +354,28 @@ def modernize_pom(file_path, parent_version, source_repo_name=None, parent_artif
317354
current_artifact_id = match.group(1).strip()
318355
if '<version>' in line:
319356
has_version = True
320-
321-
if current_artifact_id and current_artifact_id.startswith('google-api-services-'):
322-
should_preserve = True
357+
match = re.search(r'<version>(.*?)</version>', line)
358+
if match:
359+
current_version = match.group(1).strip()
360+
361+
# Resolve version if it's a property
362+
resolved_version = current_version
363+
if current_version.startswith("${") and current_version.endswith("}"):
364+
prop_name = current_version[2:-1]
365+
if prop_name in pom_properties:
366+
resolved_version = pom_properties[prop_name]
367+
368+
if current_artifact_id and current_artifact_id.startswith('google-api-services-'):
369+
if not parent_managed_deps or (current_group_id, current_artifact_id) not in parent_managed_deps:
370+
# Only extract if not already managed
371+
extracted_dep = (current_group_id, current_artifact_id, resolved_version)
372+
print(f"EXTRACT_DEP:{current_group_id}:{current_artifact_id}:{resolved_version}")
373+
else:
374+
# Even if already managed, we should remove the local version
375+
extracted_dep = (current_group_id, current_artifact_id, resolved_version)
376+
377+
# if current_artifact_id and current_artifact_id.startswith('google-api-services-'):
378+
# should_preserve = True
323379

324380
current_dependency_lines.append(line)
325381
if '{x-version-update:' in line:
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 os
18+
import re
19+
20+
def update_dependency_management(pom_path, group_id, artifact_id, version):
21+
with open(pom_path, 'r') as f:
22+
content = f.read()
23+
24+
# Find <dependencyManagement>
25+
dm_match = re.search(r'<dependencyManagement>.*?</dependencyManagement>', content, re.DOTALL)
26+
if not dm_match:
27+
print(f"Error: <dependencyManagement> section not found in {pom_path}")
28+
sys.exit(1)
29+
30+
dm_content = dm_match.group(0)
31+
32+
# Find <dependencies> inside <dependencyManagement>
33+
deps_match = re.search(r'<dependencies>(.*?)</dependencies>', dm_content, re.DOTALL)
34+
if not deps_match:
35+
print(f"Error: <dependencies> section not found inside <dependencyManagement> in {pom_path}")
36+
sys.exit(1)
37+
38+
inner_deps_content = deps_match.group(1)
39+
40+
# Check if dependency already exists
41+
dep_pattern = fr'<artifactId>{re.escape(artifact_id)}</artifactId>'
42+
if dep_pattern in inner_deps_content:
43+
# Check if version matches
44+
if fr'<version>{re.escape(version)}</version>' in inner_deps_content:
45+
print(f"Dependency {group_id}:{artifact_id}:{version} already exists in {pom_path}")
46+
return
47+
else:
48+
# Update version? Requirement says "move it", but if it exists with different version, maybe we should update it?
49+
# For now, let's just append if it's not EXACTLY same.
50+
# Actually, usually there should be only one.
51+
# Let's replace if artifactId matches but version is different.
52+
53+
new_inner_deps = re.sub(
54+
fr'(<dependency>\s*<groupId>{re.escape(group_id)}</groupId>\s*<artifactId>{re.escape(artifact_id)}</artifactId>\s*<version>).*?(</version>.*?</dependency>)',
55+
fr'\g<1>{version}\g<2>',
56+
inner_deps_content,
57+
flags=re.DOTALL
58+
)
59+
if new_inner_deps != inner_deps_content:
60+
print(f"Updated {group_id}:{artifact_id} to version {version} in {pom_path}")
61+
new_dm_content = dm_content.replace(inner_deps_content, new_inner_deps)
62+
new_content = content.replace(dm_content, new_dm_content)
63+
with open(pom_path, 'w') as f:
64+
f.write(new_content)
65+
return
66+
67+
# If not found or not updated, append it
68+
new_dep = f""" <dependency>
69+
<groupId>{group_id}</groupId>
70+
<artifactId>{artifact_id}</artifactId>
71+
<version>{version}</version>
72+
</dependency>
73+
"""
74+
# Find the last </dependency> and insert after it, or just before </dependencies>
75+
last_dep_end = inner_deps_content.rfind('</dependency>')
76+
if last_dep_end != -1:
77+
# Check if there is anything after last </dependency> that is not just whitespace
78+
insert_pos = last_dep_end + len('</dependency>')
79+
# Ensure we insert before </dependencies>
80+
new_inner_deps = inner_deps_content[:insert_pos] + "\n" + new_dep + inner_deps_content[insert_pos:]
81+
else:
82+
# No dependencies found, just insert at beginning
83+
new_inner_deps = "\n" + new_dep + inner_deps_content
84+
85+
new_dm_content = dm_content.replace(inner_deps_content, new_inner_deps)
86+
new_content = content.replace(dm_content, new_dm_content)
87+
88+
with open(pom_path, 'w') as f:
89+
f.write(new_content)
90+
print(f"Added {group_id}:{artifact_id}:{version} to {pom_path}")
91+
92+
if __name__ == "__main__":
93+
if len(sys.argv) != 5:
94+
print("Usage: update_dependency_management.py <pom_path> <groupId> <artifactId> <version>")
95+
sys.exit(1)
96+
update_dependency_management(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

0 commit comments

Comments
 (0)