From 0e90a818258f9deaa33ebb843014996e53659e38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 18:40:08 +0000 Subject: [PATCH 01/10] Add Bazel dependency sync generator --- .github/workflows/bazel.yml | 9 +- CONTRIBUTING.md | 10 + MODULE.bazel | 47 +++-- pom.xml | 156 ++++++++++++++-- scripts/sync_bazel_dependencies.py | 286 +++++++++++++++++++++++++++++ 5 files changed, 471 insertions(+), 37 deletions(-) create mode 100644 scripts/sync_bazel_dependencies.py diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 907475adb0..866f684564 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,6 +18,8 @@ on: - "**/*.java" - "**/BUILD.bazel" - "MODULE.bazel" + - "pom.xml" + - "scripts/sync_bazel_dependencies.py" - ".bazelversion" - ".bazelrc" - ".github/workflows/bazel.yml" @@ -27,6 +29,8 @@ on: - "**/*.java" - "**/BUILD.bazel" - "MODULE.bazel" + - "pom.xml" + - "scripts/sync_bazel_dependencies.py" - ".bazelversion" - ".bazelrc" - ".github/workflows/bazel.yml" @@ -74,11 +78,14 @@ jobs: path: | ~/.cache/bazel-disk-cache ~/.cache/bazel/cache/repos/v1 - key: bazel-${{ runner.os }}-java${{ matrix.java }}-${{ hashFiles('MODULE.bazel', '.bazelversion', 'maven_install.json') }} + key: bazel-${{ runner.os }}-java${{ matrix.java }}-${{ hashFiles('MODULE.bazel', 'pom.xml', 'scripts/sync_bazel_dependencies.py', '.bazelversion', 'maven_install.json') }} restore-keys: | bazel-${{ runner.os }}-java${{ matrix.java }}- bazel-${{ runner.os }}- + - name: Verify Bazel dependency sync + run: python3 scripts/sync_bazel_dependencies.py --check + # Re-generate the Maven lock file so it is always consistent with # MODULE.bazel. The __INPUT_ARTIFACTS_HASH in the committed file is # intentionally set to -1 to signal that the file needs to be regenerated; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4274c74da3..73e36ef669 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,5 +20,15 @@ If you have any problem with the package or any suggestions, please file an [iss 3. Submit a pull request. 4. The bot will automatically assign someone to review your PR. Check the full list of bot commands [here](https://prow.k8s.io/command-help). +### Sync Bazel dependency versions + +The root `pom.xml` is the source of truth for Maven and Bazel dependency versions. +If you update a managed dependency version there, also regenerate the Bazel dependency +block and lock file before sending your PR: + +1. Run `python3 scripts/sync_bazel_dependencies.py` +2. Run `REPIN=1 bazel run @maven//:pin` +3. Commit the updated `MODULE.bazel` and `maven_install.json` + ### Contact You can reach the maintainers of this project at [SIG API Machinery](https://github.com/kubernetes/community/tree/master/sig-api-machinery) or on the [#kubernetes-client](https://kubernetes.slack.com/messages/kubernetes-client) channel on the Kubernetes slack. diff --git a/MODULE.bazel b/MODULE.bazel index 26f7670721..5124f4ca73 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -25,10 +25,12 @@ bazel_dep(name = "contrib_rules_jvm", version = "0.27.0") maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +# BEGIN: generated by scripts/sync_bazel_dependencies.py +# Generated from pom.xml by scripts/sync_bazel_dependencies.py. +# Do not edit this block by hand; update pom.xml and rerun the script instead. maven.install( artifacts = [ # ---- core ---- - # Versions kept in sync with the property values in the root pom.xml. "jakarta.annotation:jakarta.annotation-api:3.0.0", "io.swagger:swagger-annotations:1.6.16", "com.squareup.okhttp3:okhttp:5.3.2", @@ -37,8 +39,8 @@ maven.install( "com.squareup.okio:okio:3.16.4", "com.squareup.okio:okio-jvm:3.16.4", "com.google.code.gson:gson:2.14.0", - "com.fasterxml.jackson.core:jackson-databind:2.21.2", - "com.fasterxml.jackson.core:jackson-core:2.21.2", + "com.fasterxml.jackson.core:jackson-databind:2.21.3", + "com.fasterxml.jackson.core:jackson-core:2.21.3", "com.fasterxml.jackson.core:jackson-annotations:2.21", "io.gsonfire:gson-fire:1.9.0", "org.apache.commons:commons-lang3:3.20.0", @@ -47,18 +49,18 @@ maven.install( "commons-io:commons-io:2.22.0", "commons-codec:commons-codec:1.22.0", "org.yaml:snakeyaml:2.6", - "org.slf4j:slf4j-api:2.0.17", + "org.slf4j:slf4j-api:2.0.18", "org.bouncycastle:bcpkix-jdk18on:1.84", "org.bouncycastle:bcprov-jdk18on:1.84", "com.google.protobuf:protobuf-java:4.34.1", "org.bitbucket.b_c:jose4j:0.9.6", - "com.google.auth:google-auth-library-oauth2-http:1.46.0", - "software.amazon.awssdk:auth:2.43.0", - "software.amazon.awssdk:http-auth-aws:2.43.0", - "software.amazon.awssdk:http-auth-spi:2.43.0", - "software.amazon.awssdk:http-client-spi:2.43.0", - "software.amazon.awssdk:sts:2.43.0", - "software.amazon.awssdk:utils:2.43.0", + "com.google.auth:google-auth-library-oauth2-http:1.47.0", + "software.amazon.awssdk:auth:2.44.4", + "software.amazon.awssdk:http-auth-aws:2.44.4", + "software.amazon.awssdk:http-auth-spi:2.44.4", + "software.amazon.awssdk:http-client-spi:2.44.4", + "software.amazon.awssdk:sts:2.44.4", + "software.amazon.awssdk:utils:2.44.4", "io.prometheus:simpleclient:0.16.0", "io.prometheus:simpleclient_httpserver:0.16.0", "com.bucket4j:bucket4j-core:8.10.1", @@ -67,16 +69,12 @@ maven.install( "org.jetbrains:annotations:26.1.0", "org.reflections:reflections:0.10.2", # ---- spring (Java 17+ modules) ---- - # spring-boot 4.0.6 transitively brings in spring-framework 7.0.x, but the - # root pom.xml pins spring.version=6.2.12. Explicitly declare all - # spring-framework modules at 6.2.12 and use maven.artifact() with - # exclusions on the spring-boot artifacts so Coursier does not upgrade them. - "org.springframework:spring-aop:6.2.12", - "org.springframework:spring-beans:6.2.12", - "org.springframework:spring-context:6.2.12", - "org.springframework:spring-core:6.2.12", - "org.springframework:spring-expression:6.2.12", - "org.springframework:spring-test:6.2.12", + "org.springframework:spring-aop:6.2.8", + "org.springframework:spring-beans:6.2.8", + "org.springframework:spring-context:6.2.8", + "org.springframework:spring-core:6.2.8", + "org.springframework:spring-expression:6.2.8", + "org.springframework:spring-test:6.2.8", # ---- test ---- "org.junit.jupiter:junit-jupiter-api:5.13.4", "org.junit.jupiter:junit-jupiter-engine:5.13.4", @@ -103,9 +101,8 @@ maven.install( lock_file = "//:maven_install.json", ) -# Spring Boot 4.0.6 artifacts declared with exclusions to pin spring-framework at -# 6.2.12 (matching pom.xml spring.version) instead of the 7.0.x that spring-boot -# 4.0.x normally pulls in. +# Spring Boot 4.0.6 artifacts declared with exclusions to keep +# spring-framework pinned to 6.2.8. _SPRING_FRAMEWORK_EXCLUSIONS = [ "org.springframework:spring-aop", "org.springframework:spring-beans", @@ -143,4 +140,6 @@ maven.artifact( exclusions = _SPRING_FRAMEWORK_EXCLUSIONS, ) +# END: generated by scripts/sync_bazel_dependencies.py + use_repo(maven, "maven") diff --git a/pom.xml b/pom.xml index 8a84bd5011..9f6c270250 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ 3.0.0 4.34.1 5.13.4 - 5.13.4 + 1.13.4 ${junit-jupiter.version} 8.10.1 1.84 @@ -73,6 +73,18 @@ 6.2.8 0.16.0 0.10.2 + 2.44.4 + 1.47.0 + 0.9.6 + 26.1.0 + 1.5.32 + 5.23.0 + 3.16.4 + 3.27.7 + 4.3.0 + 2.1.8 + 3.13.2 + 0.4.16 org.apache.commons commons-lang3 @@ -161,10 +174,40 @@ bcpkix-jdk18on ${bouncycastle.version} + + org.bouncycastle + bcprov-jdk18on + ${bouncycastle.version} + software.amazon.awssdk sts - 2.44.4 + ${aws.sdk.version} + + + software.amazon.awssdk + auth + ${aws.sdk.version} + + + software.amazon.awssdk + http-auth-aws + ${aws.sdk.version} + + + software.amazon.awssdk + http-auth-spi + ${aws.sdk.version} + + + software.amazon.awssdk + http-client-spi + ${aws.sdk.version} + + + software.amazon.awssdk + utils + ${aws.sdk.version} com.google.protobuf @@ -174,7 +217,7 @@ org.bitbucket.b_c jose4j - 0.9.6 + ${jose4j.version} com.bucket4j @@ -196,11 +239,26 @@ spring-core ${spring.version} + + org.springframework + spring-aop + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + org.springframework spring-context ${spring.version} + + org.springframework + spring-expression + ${spring.version} + org.springframework.boot spring-boot-autoconfigure @@ -274,19 +332,57 @@ com.google.auth google-auth-library-oauth2-http - 1.47.0 + ${google.auth.version} org.jetbrains annotations - 26.1.0 + ${jetbrains.annotations.version} + + + org.reflections + reflections + ${reflections.version} + + + com.squareup.okhttp3 + okhttp-jvm + ${okhttp3.version} + + + com.squareup.okio + okio + ${okio.version} + + + com.squareup.okio + okio-jvm + ${okio.version} ch.qos.logback logback-classic - 1.5.32 + ${logback.version} + test + + + ch.qos.logback + logback-core + ${logback.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} test @@ -301,22 +397,58 @@ ${junit-jupiter.version} test + + org.junit.platform + junit-platform-launcher + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-commons + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-engine + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-reporting + ${junit-platform.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + org.mockito mockito-junit-jupiter - 5.23.0 + ${mockito.version} test uk.org.webcompere system-stubs-jupiter - 2.1.8 + ${system-stubs.version} + test + + + uk.org.webcompere + system-stubs-core + ${system-stubs.version} test org.wiremock wiremock - 3.13.2 + ${wiremock.version} test @@ -334,7 +466,7 @@ com.flipkart.zjsonpatch zjsonpatch - 0.4.16 + ${zjsonpatch.version} com.fasterxml.jackson.core @@ -345,13 +477,13 @@ org.assertj assertj-core - 3.27.7 + ${assertj.version} test org.awaitility awaitility - 4.3.0 + ${awaitility.version} test diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py new file mode 100644 index 0000000000..3262319f78 --- /dev/null +++ b/scripts/sync_bazel_dependencies.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import re +import sys +import xml.etree.ElementTree as ET +from pathlib import Path + + +GENERATED_START = "# BEGIN: generated by scripts/sync_bazel_dependencies.py" +GENERATED_END = "# END: generated by scripts/sync_bazel_dependencies.py" + +MAVEN_INSTALL_ARTIFACTS = { + "core": [ + "jakarta.annotation:jakarta.annotation-api", + "io.swagger:swagger-annotations", + "com.squareup.okhttp3:okhttp", + "com.squareup.okhttp3:okhttp-jvm", + "com.squareup.okhttp3:logging-interceptor", + "com.squareup.okio:okio", + "com.squareup.okio:okio-jvm", + "com.google.code.gson:gson", + "com.fasterxml.jackson.core:jackson-databind", + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-annotations", + "io.gsonfire:gson-fire", + "org.apache.commons:commons-lang3", + "org.apache.commons:commons-collections4", + "org.apache.commons:commons-compress", + "commons-io:commons-io", + "commons-codec:commons-codec", + "org.yaml:snakeyaml", + "org.slf4j:slf4j-api", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "com.google.protobuf:protobuf-java", + "org.bitbucket.b_c:jose4j", + "com.google.auth:google-auth-library-oauth2-http", + "software.amazon.awssdk:auth", + "software.amazon.awssdk:http-auth-aws", + "software.amazon.awssdk:http-auth-spi", + "software.amazon.awssdk:http-client-spi", + "software.amazon.awssdk:sts", + "software.amazon.awssdk:utils", + "io.prometheus:simpleclient", + "io.prometheus:simpleclient_httpserver", + "com.bucket4j:bucket4j-core", + "com.github.ben-manes.caffeine:caffeine", + "com.flipkart.zjsonpatch:zjsonpatch", + "org.jetbrains:annotations", + "org.reflections:reflections", + ], + "spring (Java 17+ modules)": [ + "org.springframework:spring-aop", + "org.springframework:spring-beans", + "org.springframework:spring-context", + "org.springframework:spring-core", + "org.springframework:spring-expression", + "org.springframework:spring-test", + ], + "test": [ + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-params", + "org.junit.platform:junit-platform-launcher", + "org.junit.platform:junit-platform-commons", + "org.junit.platform:junit-platform-engine", + "org.junit.platform:junit-platform-reporting", + "org.mockito:mockito-core", + "org.mockito:mockito-junit-jupiter", + "uk.org.webcompere:system-stubs-jupiter", + "uk.org.webcompere:system-stubs-core", + "org.wiremock:wiremock", + "org.awaitility:awaitility", + "org.assertj:assertj-core", + "ch.qos.logback:logback-classic", + "ch.qos.logback:logback-core", + ], +} + +SPRING_BOOT_ARTIFACTS = [ + "spring-boot", + "spring-boot-autoconfigure", + "spring-boot-actuator", + "spring-boot-test", +] + +SPRING_FRAMEWORK_EXCLUSIONS = [ + "org.springframework:spring-aop", + "org.springframework:spring-beans", + "org.springframework:spring-context", + "org.springframework:spring-core", + "org.springframework:spring-expression", + "org.springframework:spring-test", +] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Sync Bazel dependency declarations from the root pom.xml." + ) + parser.add_argument( + "--root", + type=Path, + default=Path(__file__).resolve().parents[1], + help="Repository root containing pom.xml and MODULE.bazel.", + ) + parser.add_argument( + "--check", + action="store_true", + help="Fail if MODULE.bazel is not up to date.", + ) + return parser.parse_args() + + +def local_name(tag: str) -> str: + return tag.split("}", 1)[-1] + + +def parse_managed_versions(pom_path: Path) -> dict[str, str]: + root = ET.parse(pom_path).getroot() + namespace = {} + if root.tag.startswith("{"): + namespace["m"] = root.tag[1:].split("}", 1)[0] + prefix = "m:" + else: + prefix = "" + + properties_element = root.find(f"{prefix}properties", namespace) + properties = {} + if properties_element is not None: + for child in properties_element: + properties[local_name(child.tag)] = (child.text or "").strip() + + project_version = (root.findtext(f"{prefix}version", default="", namespaces=namespace) or "").strip() + if project_version: + properties.setdefault("project.version", project_version) + properties.setdefault("pom.version", project_version) + properties.setdefault("version", project_version) + + def resolve(value: str) -> str: + resolved = value + for _ in range(20): + updated = re.sub( + r"\$\{([^}]+)\}", + lambda match: properties.get(match.group(1), match.group(0)), + resolved, + ) + if updated == resolved: + return updated + resolved = updated + raise ValueError(f"Could not fully resolve property expression: {value}") + + managed_versions = {} + dependency_path = f"{prefix}dependencyManagement/{prefix}dependencies/{prefix}dependency" + for dependency in root.findall(dependency_path, namespace): + group_id = dependency.findtext(f"{prefix}groupId", default="", namespaces=namespace).strip() + artifact_id = dependency.findtext( + f"{prefix}artifactId", default="", namespaces=namespace + ).strip() + version = dependency.findtext(f"{prefix}version", default="", namespaces=namespace).strip() + if group_id and artifact_id and version: + managed_versions[f"{group_id}:{artifact_id}"] = resolve(version) + return managed_versions + + +def render_generated_block(managed_versions: dict[str, str]) -> str: + missing = [ + coordinate + for artifacts in MAVEN_INSTALL_ARTIFACTS.values() + for coordinate in artifacts + if coordinate not in managed_versions + ] + missing.extend( + f"org.springframework.boot:{artifact}" + for artifact in SPRING_BOOT_ARTIFACTS + if f"org.springframework.boot:{artifact}" not in managed_versions + ) + if missing: + missing_list = "\n".join(f" - {coordinate}" for coordinate in sorted(missing)) + raise KeyError(f"Missing dependencyManagement entries:\n{missing_list}") + + lines = [ + GENERATED_START, + "# Generated from pom.xml by scripts/sync_bazel_dependencies.py.", + "# Do not edit this block by hand; update pom.xml and rerun the script instead.", + "maven.install(", + " artifacts = [", + ] + for section, artifacts in MAVEN_INSTALL_ARTIFACTS.items(): + lines.append(f" # ---- {section} ----") + for coordinate in artifacts: + lines.append(f' "{coordinate}:{managed_versions[coordinate]}",') + lines.extend( + [ + " ],", + " repositories = [", + ' "https://repo1.maven.org/maven2",', + ' "https://repo.spring.io/milestone",', + " ],", + " fetch_sources = False,", + ' lock_file = "//:maven_install.json",', + ")", + "", + "_SPRING_FRAMEWORK_EXCLUSIONS = [", + ] + ) + for exclusion in SPRING_FRAMEWORK_EXCLUSIONS: + lines.append(f' "{exclusion}",') + lines.extend(["]", ""]) + + spring_boot_version = managed_versions["org.springframework.boot:spring-boot"] + for artifact in SPRING_BOOT_ARTIFACTS: + lines.extend( + [ + "maven.artifact(", + f' artifact = "{artifact}",', + ' group = "org.springframework.boot",', + f' version = "{managed_versions[f"org.springframework.boot:{artifact}"]}",', + " exclusions = _SPRING_FRAMEWORK_EXCLUSIONS,", + ")", + "", + ] + ) + + if len({managed_versions[f"org.springframework.boot:{artifact}"] for artifact in SPRING_BOOT_ARTIFACTS}) != 1: + raise ValueError("Spring Boot artifact versions diverged in dependencyManagement.") + + lines.insert( + lines.index("_SPRING_FRAMEWORK_EXCLUSIONS = ["), + f"# Spring Boot {spring_boot_version} artifacts declared with exclusions to keep", + ) + lines.insert( + lines.index("_SPRING_FRAMEWORK_EXCLUSIONS = ["), + f'# spring-framework pinned to {managed_versions["org.springframework:spring-core"]}.', + ) + + lines.append(GENERATED_END) + return "\n".join(lines) + "\n" + + +def sync_module(module_path: Path, generated_block: str, check_only: bool) -> bool: + module_text = module_path.read_text() + pattern = re.compile( + rf"{re.escape(GENERATED_START)}\n.*?{re.escape(GENERATED_END)}\n?", + re.DOTALL, + ) + match = pattern.search(module_text) + if not match: + raise ValueError( + f"Could not find generated block markers in {module_path}. " + f"Expected {GENERATED_START!r} and {GENERATED_END!r}." + ) + + updated_text = module_text[: match.start()] + generated_block + module_text[match.end() :] + changed = updated_text != module_text + if changed and not check_only: + module_path.write_text(updated_text) + return changed + + +def main() -> int: + args = parse_args() + root = args.root.resolve() + pom_path = root / "pom.xml" + module_path = root / "MODULE.bazel" + + managed_versions = parse_managed_versions(pom_path) + generated_block = render_generated_block(managed_versions) + changed = sync_module(module_path, generated_block, args.check) + + if args.check and changed: + print(f"{module_path} is out of date. Run {Path(__file__).name} to regenerate it.") + return 1 + + if not args.check and changed: + print(f"Updated {module_path}") + elif not args.check: + print(f"{module_path} is already up to date") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 530756e19b702b2f26b5e9a0deb3617cd3501c61 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 May 2026 18:42:12 +0000 Subject: [PATCH 02/10] Refine Bazel dependency sync script --- scripts/sync_bazel_dependencies.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index 3262319f78..4ae7f43607 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -11,6 +11,7 @@ GENERATED_START = "# BEGIN: generated by scripts/sync_bazel_dependencies.py" GENERATED_END = "# END: generated by scripts/sync_bazel_dependencies.py" +MAX_PROPERTY_RESOLUTION_DEPTH = 20 MAVEN_INSTALL_ARTIFACTS = { "core": [ @@ -142,7 +143,7 @@ def parse_managed_versions(pom_path: Path) -> dict[str, str]: def resolve(value: str) -> str: resolved = value - for _ in range(20): + for _ in range(MAX_PROPERTY_RESOLUTION_DEPTH): updated = re.sub( r"\$\{([^}]+)\}", lambda match: properties.get(match.group(1), match.group(0)), @@ -193,6 +194,8 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: lines.append(f" # ---- {section} ----") for coordinate in artifacts: lines.append(f' "{coordinate}:{managed_versions[coordinate]}",') + spring_boot_version = managed_versions["org.springframework.boot:spring-boot"] + spring_framework_version = managed_versions["org.springframework:spring-core"] lines.extend( [ " ],", @@ -204,6 +207,8 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: ' lock_file = "//:maven_install.json",', ")", "", + f"# Spring Boot {spring_boot_version} artifacts declared with exclusions to keep", + f"# spring-framework pinned to {spring_framework_version}.", "_SPRING_FRAMEWORK_EXCLUSIONS = [", ] ) @@ -211,7 +216,6 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: lines.append(f' "{exclusion}",') lines.extend(["]", ""]) - spring_boot_version = managed_versions["org.springframework.boot:spring-boot"] for artifact in SPRING_BOOT_ARTIFACTS: lines.extend( [ @@ -228,15 +232,6 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: if len({managed_versions[f"org.springframework.boot:{artifact}"] for artifact in SPRING_BOOT_ARTIFACTS}) != 1: raise ValueError("Spring Boot artifact versions diverged in dependencyManagement.") - lines.insert( - lines.index("_SPRING_FRAMEWORK_EXCLUSIONS = ["), - f"# Spring Boot {spring_boot_version} artifacts declared with exclusions to keep", - ) - lines.insert( - lines.index("_SPRING_FRAMEWORK_EXCLUSIONS = ["), - f'# spring-framework pinned to {managed_versions["org.springframework:spring-core"]}.', - ) - lines.append(GENERATED_END) return "\n".join(lines) + "\n" From 97e5feab2d927f238eedd77f16b5aec2e5c42e82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:38:08 +0000 Subject: [PATCH 03/10] Extract Bazel dependency list from pom --- MODULE.bazel | 52 ++++---- scripts/sync_bazel_dependencies.py | 197 +++++++++++++---------------- 2 files changed, 111 insertions(+), 138 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5124f4ca73..658e698d04 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -31,51 +31,53 @@ maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( artifacts = [ # ---- core ---- - "jakarta.annotation:jakarta.annotation-api:3.0.0", - "io.swagger:swagger-annotations:1.6.16", - "com.squareup.okhttp3:okhttp:5.3.2", - "com.squareup.okhttp3:okhttp-jvm:5.3.2", - "com.squareup.okhttp3:logging-interceptor:5.3.2", - "com.squareup.okio:okio:3.16.4", - "com.squareup.okio:okio-jvm:3.16.4", - "com.google.code.gson:gson:2.14.0", - "com.fasterxml.jackson.core:jackson-databind:2.21.3", - "com.fasterxml.jackson.core:jackson-core:2.21.3", - "com.fasterxml.jackson.core:jackson-annotations:2.21", - "io.gsonfire:gson-fire:1.9.0", "org.apache.commons:commons-lang3:3.20.0", "org.apache.commons:commons-collections4:4.5.0", + "org.yaml:snakeyaml:2.6", + "commons-codec:commons-codec:1.22.0", "org.apache.commons:commons-compress:1.28.0", "commons-io:commons-io:2.22.0", - "commons-codec:commons-codec:1.22.0", - "org.yaml:snakeyaml:2.6", + "com.github.ben-manes.caffeine:caffeine:3.0.0", "org.slf4j:slf4j-api:2.0.18", "org.bouncycastle:bcpkix-jdk18on:1.84", "org.bouncycastle:bcprov-jdk18on:1.84", - "com.google.protobuf:protobuf-java:4.34.1", - "org.bitbucket.b_c:jose4j:0.9.6", - "com.google.auth:google-auth-library-oauth2-http:1.47.0", + "software.amazon.awssdk:sts:2.44.4", "software.amazon.awssdk:auth:2.44.4", "software.amazon.awssdk:http-auth-aws:2.44.4", "software.amazon.awssdk:http-auth-spi:2.44.4", "software.amazon.awssdk:http-client-spi:2.44.4", - "software.amazon.awssdk:sts:2.44.4", "software.amazon.awssdk:utils:2.44.4", + "com.google.protobuf:protobuf-java:4.34.1", + "org.bitbucket.b_c:jose4j:0.9.6", + "com.bucket4j:bucket4j-core:8.10.1", "io.prometheus:simpleclient:0.16.0", "io.prometheus:simpleclient_httpserver:0.16.0", - "com.bucket4j:bucket4j-core:8.10.1", - "com.github.ben-manes.caffeine:caffeine:3.0.0", - "com.flipkart.zjsonpatch:zjsonpatch:0.4.16", + "com.google.code.gson:gson:2.14.0", + "com.fasterxml.jackson.core:jackson-databind:2.21.3", + "com.fasterxml.jackson.core:jackson-annotations:2.21", + "com.fasterxml.jackson.core:jackson-core:2.21.3", + "io.gsonfire:gson-fire:1.9.0", + "com.squareup.okhttp3:okhttp:5.3.2", + "com.squareup.okhttp3:logging-interceptor:5.3.2", + "io.swagger:swagger-annotations:1.6.16", + "jakarta.annotation:jakarta.annotation-api:3.0.0", + "com.google.auth:google-auth-library-oauth2-http:1.47.0", "org.jetbrains:annotations:26.1.0", "org.reflections:reflections:0.10.2", + "com.squareup.okhttp3:okhttp-jvm:5.3.2", + "com.squareup.okio:okio:3.16.4", + "com.squareup.okio:okio-jvm:3.16.4", + "com.flipkart.zjsonpatch:zjsonpatch:0.4.16", # ---- spring (Java 17+ modules) ---- + "org.springframework:spring-core:6.2.8", "org.springframework:spring-aop:6.2.8", "org.springframework:spring-beans:6.2.8", "org.springframework:spring-context:6.2.8", - "org.springframework:spring-core:6.2.8", "org.springframework:spring-expression:6.2.8", "org.springframework:spring-test:6.2.8", # ---- test ---- + "ch.qos.logback:logback-classic:1.5.32", + "ch.qos.logback:logback-core:1.5.32", "org.junit.jupiter:junit-jupiter-api:5.13.4", "org.junit.jupiter:junit-jupiter-engine:5.13.4", "org.junit.jupiter:junit-jupiter-params:5.13.4", @@ -88,10 +90,8 @@ maven.install( "uk.org.webcompere:system-stubs-jupiter:2.1.8", "uk.org.webcompere:system-stubs-core:2.1.8", "org.wiremock:wiremock:3.13.2", - "org.awaitility:awaitility:4.3.0", "org.assertj:assertj-core:3.27.7", - "ch.qos.logback:logback-classic:1.5.32", - "ch.qos.logback:logback-core:1.5.32", + "org.awaitility:awaitility:4.3.0", ], repositories = [ "https://repo1.maven.org/maven2", @@ -104,10 +104,10 @@ maven.install( # Spring Boot 4.0.6 artifacts declared with exclusions to keep # spring-framework pinned to 6.2.8. _SPRING_FRAMEWORK_EXCLUSIONS = [ + "org.springframework:spring-core", "org.springframework:spring-aop", "org.springframework:spring-beans", "org.springframework:spring-context", - "org.springframework:spring-core", "org.springframework:spring-expression", "org.springframework:spring-test", ] diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index 4ae7f43607..fbc1a24b94 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse +from dataclasses import dataclass import re import sys import xml.etree.ElementTree as ET @@ -12,90 +13,32 @@ GENERATED_START = "# BEGIN: generated by scripts/sync_bazel_dependencies.py" GENERATED_END = "# END: generated by scripts/sync_bazel_dependencies.py" MAX_PROPERTY_RESOLUTION_DEPTH = 20 - -MAVEN_INSTALL_ARTIFACTS = { - "core": [ - "jakarta.annotation:jakarta.annotation-api", - "io.swagger:swagger-annotations", - "com.squareup.okhttp3:okhttp", - "com.squareup.okhttp3:okhttp-jvm", - "com.squareup.okhttp3:logging-interceptor", - "com.squareup.okio:okio", - "com.squareup.okio:okio-jvm", - "com.google.code.gson:gson", - "com.fasterxml.jackson.core:jackson-databind", - "com.fasterxml.jackson.core:jackson-core", - "com.fasterxml.jackson.core:jackson-annotations", - "io.gsonfire:gson-fire", - "org.apache.commons:commons-lang3", - "org.apache.commons:commons-collections4", - "org.apache.commons:commons-compress", - "commons-io:commons-io", - "commons-codec:commons-codec", - "org.yaml:snakeyaml", - "org.slf4j:slf4j-api", - "org.bouncycastle:bcpkix-jdk18on", - "org.bouncycastle:bcprov-jdk18on", - "com.google.protobuf:protobuf-java", - "org.bitbucket.b_c:jose4j", - "com.google.auth:google-auth-library-oauth2-http", - "software.amazon.awssdk:auth", - "software.amazon.awssdk:http-auth-aws", - "software.amazon.awssdk:http-auth-spi", - "software.amazon.awssdk:http-client-spi", - "software.amazon.awssdk:sts", - "software.amazon.awssdk:utils", - "io.prometheus:simpleclient", - "io.prometheus:simpleclient_httpserver", - "com.bucket4j:bucket4j-core", - "com.github.ben-manes.caffeine:caffeine", - "com.flipkart.zjsonpatch:zjsonpatch", - "org.jetbrains:annotations", - "org.reflections:reflections", - ], - "spring (Java 17+ modules)": [ - "org.springframework:spring-aop", - "org.springframework:spring-beans", - "org.springframework:spring-context", - "org.springframework:spring-core", - "org.springframework:spring-expression", - "org.springframework:spring-test", - ], - "test": [ - "org.junit.jupiter:junit-jupiter-api", - "org.junit.jupiter:junit-jupiter-engine", - "org.junit.jupiter:junit-jupiter-params", - "org.junit.platform:junit-platform-launcher", - "org.junit.platform:junit-platform-commons", - "org.junit.platform:junit-platform-engine", - "org.junit.platform:junit-platform-reporting", - "org.mockito:mockito-core", - "org.mockito:mockito-junit-jupiter", - "uk.org.webcompere:system-stubs-jupiter", - "uk.org.webcompere:system-stubs-core", - "org.wiremock:wiremock", - "org.awaitility:awaitility", - "org.assertj:assertj-core", - "ch.qos.logback:logback-classic", - "ch.qos.logback:logback-core", - ], +SECTION_CORE = "core" +SECTION_SPRING = "spring (Java 17+ modules)" +SECTION_TEST = "test" +SPRING_BOOT_GROUP = "org.springframework.boot" +SPRING_FRAMEWORK_GROUP = "org.springframework" +EXCLUDED_BAZEL_COORDINATES = { + "commons-cli:commons-cli", + "com.google.code.findbugs:jsr305", + "org.junit.jupiter:junit-jupiter", } -SPRING_BOOT_ARTIFACTS = [ - "spring-boot", - "spring-boot-autoconfigure", - "spring-boot-actuator", - "spring-boot-test", -] -SPRING_FRAMEWORK_EXCLUSIONS = [ - "org.springframework:spring-aop", - "org.springframework:spring-beans", - "org.springframework:spring-context", - "org.springframework:spring-core", - "org.springframework:spring-expression", - "org.springframework:spring-test", -] +@dataclass(frozen=True) +class ManagedDependency: + group_id: str + artifact_id: str + version: str + scope: str = "" + + @property + def coordinate(self) -> str: + return f"{self.group_id}:{self.artifact_id}" + + @property + def bazel_artifact(self) -> str: + return f"{self.coordinate}:{self.version}" def parse_args() -> argparse.Namespace: @@ -120,7 +63,7 @@ def local_name(tag: str) -> str: return tag.split("}", 1)[-1] -def parse_managed_versions(pom_path: Path) -> dict[str, str]: +def parse_managed_dependencies(pom_path: Path) -> list[ManagedDependency]: root = ET.parse(pom_path).getroot() namespace = {} if root.tag.startswith("{"): @@ -154,7 +97,7 @@ def resolve(value: str) -> str: resolved = updated raise ValueError(f"Could not fully resolve property expression: {value}") - managed_versions = {} + managed_dependencies = [] dependency_path = f"{prefix}dependencyManagement/{prefix}dependencies/{prefix}dependency" for dependency in root.findall(dependency_path, namespace): group_id = dependency.findtext(f"{prefix}groupId", default="", namespaces=namespace).strip() @@ -162,26 +105,56 @@ def resolve(value: str) -> str: f"{prefix}artifactId", default="", namespaces=namespace ).strip() version = dependency.findtext(f"{prefix}version", default="", namespaces=namespace).strip() + scope = dependency.findtext(f"{prefix}scope", default="", namespaces=namespace).strip() if group_id and artifact_id and version: - managed_versions[f"{group_id}:{artifact_id}"] = resolve(version) - return managed_versions + managed_dependencies.append( + ManagedDependency( + group_id=group_id, + artifact_id=artifact_id, + version=resolve(version), + scope=scope, + ) + ) + return managed_dependencies -def render_generated_block(managed_versions: dict[str, str]) -> str: - missing = [ - coordinate - for artifacts in MAVEN_INSTALL_ARTIFACTS.values() - for coordinate in artifacts - if coordinate not in managed_versions - ] - missing.extend( - f"org.springframework.boot:{artifact}" - for artifact in SPRING_BOOT_ARTIFACTS - if f"org.springframework.boot:{artifact}" not in managed_versions - ) - if missing: - missing_list = "\n".join(f" - {coordinate}" for coordinate in sorted(missing)) - raise KeyError(f"Missing dependencyManagement entries:\n{missing_list}") +def classify_dependency(dependency: ManagedDependency) -> str: + if dependency.group_id == SPRING_FRAMEWORK_GROUP: + return SECTION_SPRING + if dependency.scope == "test": + return SECTION_TEST + return SECTION_CORE + + +def partition_dependencies( + managed_dependencies: list[ManagedDependency], +) -> tuple[dict[str, list[ManagedDependency]], list[ManagedDependency]]: + install_sections = { + SECTION_CORE: [], + SECTION_SPRING: [], + SECTION_TEST: [], + } + spring_boot_dependencies = [] + + for dependency in managed_dependencies: + if dependency.group_id == SPRING_BOOT_GROUP: + spring_boot_dependencies.append(dependency) + continue + if dependency.coordinate in EXCLUDED_BAZEL_COORDINATES: + continue + install_sections[classify_dependency(dependency)].append(dependency) + + if not spring_boot_dependencies: + raise ValueError("No org.springframework.boot dependencies found in dependencyManagement.") + + return install_sections, spring_boot_dependencies + + +def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str: + install_sections, spring_boot_dependencies = partition_dependencies(managed_dependencies) + spring_framework_exclusions = [dependency.coordinate for dependency in install_sections[SECTION_SPRING]] + if not spring_framework_exclusions: + raise ValueError("No spring-framework exclusions found for spring boot artifacts.") lines = [ GENERATED_START, @@ -190,12 +163,12 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: "maven.install(", " artifacts = [", ] - for section, artifacts in MAVEN_INSTALL_ARTIFACTS.items(): + for section, dependencies in install_sections.items(): lines.append(f" # ---- {section} ----") - for coordinate in artifacts: - lines.append(f' "{coordinate}:{managed_versions[coordinate]}",') - spring_boot_version = managed_versions["org.springframework.boot:spring-boot"] - spring_framework_version = managed_versions["org.springframework:spring-core"] + for dependency in dependencies: + lines.append(f' "{dependency.bazel_artifact}",') + spring_boot_version = spring_boot_dependencies[0].version + spring_framework_version = install_sections[SECTION_SPRING][0].version lines.extend( [ " ],", @@ -212,24 +185,24 @@ def render_generated_block(managed_versions: dict[str, str]) -> str: "_SPRING_FRAMEWORK_EXCLUSIONS = [", ] ) - for exclusion in SPRING_FRAMEWORK_EXCLUSIONS: + for exclusion in spring_framework_exclusions: lines.append(f' "{exclusion}",') lines.extend(["]", ""]) - for artifact in SPRING_BOOT_ARTIFACTS: + for dependency in spring_boot_dependencies: lines.extend( [ "maven.artifact(", - f' artifact = "{artifact}",', + f' artifact = "{dependency.artifact_id}",', ' group = "org.springframework.boot",', - f' version = "{managed_versions[f"org.springframework.boot:{artifact}"]}",', + f' version = "{dependency.version}",', " exclusions = _SPRING_FRAMEWORK_EXCLUSIONS,", ")", "", ] ) - if len({managed_versions[f"org.springframework.boot:{artifact}"] for artifact in SPRING_BOOT_ARTIFACTS}) != 1: + if len({dependency.version for dependency in spring_boot_dependencies}) != 1: raise ValueError("Spring Boot artifact versions diverged in dependencyManagement.") lines.append(GENERATED_END) @@ -262,8 +235,8 @@ def main() -> int: pom_path = root / "pom.xml" module_path = root / "MODULE.bazel" - managed_versions = parse_managed_versions(pom_path) - generated_block = render_generated_block(managed_versions) + managed_dependencies = parse_managed_dependencies(pom_path) + generated_block = render_generated_block(managed_dependencies) changed = sync_module(module_path, generated_block, args.check) if args.check and changed: From 0ee9f2e536cf6b3275cec55dfad5b9f2841303ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:38:59 +0000 Subject: [PATCH 04/10] Harden pom-derived version lookup --- scripts/sync_bazel_dependencies.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index fbc1a24b94..566201630c 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -18,6 +18,8 @@ SECTION_TEST = "test" SPRING_BOOT_GROUP = "org.springframework.boot" SPRING_FRAMEWORK_GROUP = "org.springframework" +SPRING_BOOT_COORDINATE = "org.springframework.boot:spring-boot" +SPRING_CORE_COORDINATE = "org.springframework:spring-core" EXCLUDED_BAZEL_COORDINATES = { "commons-cli:commons-cli", "com.google.code.findbugs:jsr305", @@ -150,6 +152,15 @@ def partition_dependencies( return install_sections, spring_boot_dependencies +def find_dependency( + dependencies: list[ManagedDependency], coordinate: str +) -> ManagedDependency: + for dependency in dependencies: + if dependency.coordinate == coordinate: + return dependency + raise ValueError(f"Missing expected dependencyManagement entry: {coordinate}") + + def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str: install_sections, spring_boot_dependencies = partition_dependencies(managed_dependencies) spring_framework_exclusions = [dependency.coordinate for dependency in install_sections[SECTION_SPRING]] @@ -167,8 +178,12 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str lines.append(f" # ---- {section} ----") for dependency in dependencies: lines.append(f' "{dependency.bazel_artifact}",') - spring_boot_version = spring_boot_dependencies[0].version - spring_framework_version = install_sections[SECTION_SPRING][0].version + spring_boot_version = find_dependency( + spring_boot_dependencies, SPRING_BOOT_COORDINATE + ).version + spring_framework_version = find_dependency( + install_sections[SECTION_SPRING], SPRING_CORE_COORDINATE + ).version lines.extend( [ " ],", From a5b40ab7874ebf46d4049f8f34512e060072cf7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:39:44 +0000 Subject: [PATCH 05/10] Clarify spring dependency classification --- scripts/sync_bazel_dependencies.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index 566201630c..a7c43553fb 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -121,6 +121,10 @@ def resolve(value: str) -> str: def classify_dependency(dependency: ManagedDependency) -> str: + # Keep all org.springframework modules together so the generated spring + # section also doubles as the exclusion list for the spring-boot artifacts. + # This intentionally keeps spring-test in the spring section even though its + # Maven scope is test. if dependency.group_id == SPRING_FRAMEWORK_GROUP: return SECTION_SPRING if dependency.scope == "test": @@ -165,7 +169,7 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str install_sections, spring_boot_dependencies = partition_dependencies(managed_dependencies) spring_framework_exclusions = [dependency.coordinate for dependency in install_sections[SECTION_SPRING]] if not spring_framework_exclusions: - raise ValueError("No spring-framework exclusions found for spring boot artifacts.") + raise ValueError("No org.springframework dependencies found in dependencyManagement.") lines = [ GENERATED_START, From fc7c2873dc18f13cf18b5658545797b2e6e20429 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:40:22 +0000 Subject: [PATCH 06/10] Polish sync script constants --- scripts/sync_bazel_dependencies.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index a7c43553fb..bb3f852c06 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -16,6 +16,7 @@ SECTION_CORE = "core" SECTION_SPRING = "spring (Java 17+ modules)" SECTION_TEST = "test" +SCOPE_TEST = "test" SPRING_BOOT_GROUP = "org.springframework.boot" SPRING_FRAMEWORK_GROUP = "org.springframework" SPRING_BOOT_COORDINATE = "org.springframework.boot:spring-boot" @@ -32,7 +33,7 @@ class ManagedDependency: group_id: str artifact_id: str version: str - scope: str = "" + scope: str | None = None @property def coordinate(self) -> str: @@ -107,7 +108,7 @@ def resolve(value: str) -> str: f"{prefix}artifactId", default="", namespaces=namespace ).strip() version = dependency.findtext(f"{prefix}version", default="", namespaces=namespace).strip() - scope = dependency.findtext(f"{prefix}scope", default="", namespaces=namespace).strip() + scope = dependency.findtext(f"{prefix}scope", default="", namespaces=namespace).strip() or None if group_id and artifact_id and version: managed_dependencies.append( ManagedDependency( @@ -127,7 +128,7 @@ def classify_dependency(dependency: ManagedDependency) -> str: # Maven scope is test. if dependency.group_id == SPRING_FRAMEWORK_GROUP: return SECTION_SPRING - if dependency.scope == "test": + if dependency.scope == SCOPE_TEST: return SECTION_TEST return SECTION_CORE From 58ff98cc16e0831f5e933de7775e5ebe4ce92e8b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:41:02 +0000 Subject: [PATCH 07/10] Refine sync script error text --- scripts/sync_bazel_dependencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index bb3f852c06..a1009ce926 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -170,7 +170,7 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str install_sections, spring_boot_dependencies = partition_dependencies(managed_dependencies) spring_framework_exclusions = [dependency.coordinate for dependency in install_sections[SECTION_SPRING]] if not spring_framework_exclusions: - raise ValueError("No org.springframework dependencies found in dependencyManagement.") + raise ValueError("No spring-framework dependencies found in dependencyManagement.") lines = [ GENERATED_START, From 813146d2b303eb078ea9b44cba6c733a9c1fe0a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:41:42 +0000 Subject: [PATCH 08/10] Document sync script helpers --- scripts/sync_bazel_dependencies.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index a1009ce926..0c1496bd1b 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -124,8 +124,8 @@ def resolve(value: str) -> str: def classify_dependency(dependency: ManagedDependency) -> str: # Keep all org.springframework modules together so the generated spring # section also doubles as the exclusion list for the spring-boot artifacts. - # This intentionally keeps spring-test in the spring section even though its - # Maven scope is test. + # The group_id check intentionally runs before the scope check so spring-test + # stays in the spring section even though its Maven scope is test. if dependency.group_id == SPRING_FRAMEWORK_GROUP: return SECTION_SPRING if dependency.scope == SCOPE_TEST: @@ -136,6 +136,7 @@ def classify_dependency(dependency: ManagedDependency) -> str: def partition_dependencies( managed_dependencies: list[ManagedDependency], ) -> tuple[dict[str, list[ManagedDependency]], list[ManagedDependency]]: + """Split dependencyManagement entries into Bazel install sections and spring boot artifacts.""" install_sections = { SECTION_CORE: [], SECTION_SPRING: [], @@ -160,6 +161,7 @@ def partition_dependencies( def find_dependency( dependencies: list[ManagedDependency], coordinate: str ) -> ManagedDependency: + """Return the dependency matching a group/artifact coordinate or raise ValueError.""" for dependency in dependencies: if dependency.coordinate == coordinate: return dependency From c1fa31fe166b325528a7f585c99ea6ce980f692e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:42:27 +0000 Subject: [PATCH 09/10] Improve sync script validation errors --- scripts/sync_bazel_dependencies.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index 0c1496bd1b..c66133ce5f 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -170,9 +170,12 @@ def find_dependency( def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str: install_sections, spring_boot_dependencies = partition_dependencies(managed_dependencies) - spring_framework_exclusions = [dependency.coordinate for dependency in install_sections[SECTION_SPRING]] - if not spring_framework_exclusions: + spring_framework_dependencies = install_sections[SECTION_SPRING] + if not spring_framework_dependencies: raise ValueError("No spring-framework dependencies found in dependencyManagement.") + spring_framework_exclusions = [ + dependency.coordinate for dependency in spring_framework_dependencies + ] lines = [ GENERATED_START, @@ -189,7 +192,7 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str spring_boot_dependencies, SPRING_BOOT_COORDINATE ).version spring_framework_version = find_dependency( - install_sections[SECTION_SPRING], SPRING_CORE_COORDINATE + spring_framework_dependencies, SPRING_CORE_COORDINATE ).version lines.extend( [ @@ -224,8 +227,12 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str ] ) - if len({dependency.version for dependency in spring_boot_dependencies}) != 1: - raise ValueError("Spring Boot artifact versions diverged in dependencyManagement.") + spring_boot_versions = {dependency.version for dependency in spring_boot_dependencies} + if len(spring_boot_versions) != 1: + raise ValueError( + "Spring Boot artifact versions diverged in dependencyManagement: " + + ", ".join(sorted(spring_boot_versions)) + ) lines.append(GENERATED_END) return "\n".join(lines) + "\n" From 6e42086e9d6aadbe5208873867706d3ec831e044 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 01:43:18 +0000 Subject: [PATCH 10/10] Document generated dependency ordering --- MODULE.bazel | 1 + scripts/sync_bazel_dependencies.py | 1 + 2 files changed, 2 insertions(+) diff --git a/MODULE.bazel b/MODULE.bazel index 658e698d04..7580497d75 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -28,6 +28,7 @@ maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") # BEGIN: generated by scripts/sync_bazel_dependencies.py # Generated from pom.xml by scripts/sync_bazel_dependencies.py. # Do not edit this block by hand; update pom.xml and rerun the script instead. +# Artifact order follows pom.xml dependencyManagement order within each section. maven.install( artifacts = [ # ---- core ---- diff --git a/scripts/sync_bazel_dependencies.py b/scripts/sync_bazel_dependencies.py index c66133ce5f..bbef5a7281 100644 --- a/scripts/sync_bazel_dependencies.py +++ b/scripts/sync_bazel_dependencies.py @@ -181,6 +181,7 @@ def render_generated_block(managed_dependencies: list[ManagedDependency]) -> str GENERATED_START, "# Generated from pom.xml by scripts/sync_bazel_dependencies.py.", "# Do not edit this block by hand; update pom.xml and rerun the script instead.", + "# Artifact order follows pom.xml dependencyManagement order within each section.", "maven.install(", " artifacts = [", ]