This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e5bd7eace build: add juneau-bom and curated dependency bundles 
(jetty/tomcat/springboot)
7e5bd7eace is described below

commit 7e5bd7eace6e66a27052ea8db8aafc387b4c1c02
Author: James Bognar <[email protected]>
AuthorDate: Thu Jun 18 15:02:26 2026 -0400

    build: add juneau-bom and curated dependency bundles 
(jetty/tomcat/springboot)
---
 juneau-bom/pom.xml                                 | 124 ++++++++++++++++
 .../juneau-microservice-jetty-bundle/pom.xml       |  59 ++++++++
 .../juneau-microservice-tomcat-bundle/pom.xml      |  59 ++++++++
 juneau-bundles/juneau-springboot-bundle/pom.xml    |  59 ++++++++
 juneau-bundles/pom.xml                             |  40 ++++++
 juneau-distrib/pom.xml                             |  25 ++++
 .../juneau-rest-server-metrics-micrometer/pom.xml  |   2 +-
 .../juneau-rest-server-tracing-otel/pom.xml        |   2 +-
 juneau-rest/juneau-rest-server/pom.xml             |   4 +-
 pom.xml                                            |   7 +
 scripts/check-bom-completeness.py                  | 160 +++++++++++++++++++++
 scripts/push.py                                    |  14 ++
 12 files changed, 551 insertions(+), 4 deletions(-)

diff --git a/juneau-bom/pom.xml b/juneau-bom/pom.xml
new file mode 100644
index 0000000000..9d374f785a
--- /dev/null
+++ b/juneau-bom/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.juneau</groupId>
+               <artifactId>juneau</artifactId>
+               <version>10.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>juneau-bom</artifactId>
+       <packaging>pom</packaging>
+
+       <name>Apache Juneau Bill of Materials</name>
+       <description>Bill-of-materials (BOM) for version-aligning Apache Juneau 
modules.  Import it (scope=import, type=pom) and drop explicit versions from 
your Juneau dependencies.  Enumerates the consumer-facing Juneau modules plus 
the small set of starter-relevant third-party versions the curated *-bundle 
POMs pin; it does NOT mirror a whole-world third-party BOM.</description>
+
+       <dependencyManagement>
+               <dependencies>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- juneau-core                                        
                                   -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-commons</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-marshall</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-marshall-rdf</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-config</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-assertions</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bct</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-junit5</artifactId><version>${project.version}</version></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- juneau-rest                                        
                                   -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-common</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-common-classic</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-rdf</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-mcp</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-auth-jwt</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-auth-saml</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-auth-oauth</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-auth-oidc-rp</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-metrics-micrometer</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-tracing-otel</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-reactive</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-reactive-reactor</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-view-jsp</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-view-thymeleaf</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-view-mustache</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-view-freemarker</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-server-springboot</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client-classic</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-mock</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client-apache-httpclient-45</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client-apache-httpclient-50</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client-okhttp</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-rest-client-jetty</artifactId><version>${project.version}</version></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- juneau-microservice                                
                                   -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-microservice</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-microservice-jetty</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-microservice-tomcat</artifactId><version>${project.version}</version></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- juneau-bean                                        
                                   -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-common</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-atom</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-html5</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-hal</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-rfc7807</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-jsonpatch</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-jsonapi</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-jsonschema</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-mcp</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-openapi-v3</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-bean-swagger-v2</artifactId><version>${project.version}</version></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- juneau-sc                                          
                                   -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-sc-client</artifactId><version>${project.version}</version></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-sc-server</artifactId><version>${project.version}</version></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- Curated dependency bundles (transitive module sets 
per deployment shape)              -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-microservice-jetty-bundle</artifactId><version>${project.version}</version><type>pom</type></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-microservice-tomcat-bundle</artifactId><version>${project.version}</version><type>pom</type></dependency>
+                       
<dependency><groupId>org.apache.juneau</groupId><artifactId>juneau-springboot-bundle</artifactId><version>${project.version}</version><type>pom</type></dependency>
+
+                       <!-- 
=====================================================================================
 -->
+                       <!-- Starter-relevant third-party versions (the small 
set the curated bundles need to be    -->
+                       <!-- coherent).  NOT a whole-world third-party BOM (see 
TODO-174c Q2).                       -->
+                       <!-- 
=====================================================================================
 -->
+                       
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-core</artifactId><version>${micrometer.version}</version></dependency>
+                       
<dependency><groupId>io.opentelemetry</groupId><artifactId>opentelemetry-api</artifactId><version>${opentelemetry.version}</version></dependency>
+                       
<dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>${jakarta.servlet-api.version}</version></dependency>
+                       
<dependency><groupId>jakarta.validation</groupId><artifactId>jakarta.validation-api</artifactId><version>${jakarta.validation-api.version}</version></dependency>
+
+               </dependencies>
+       </dependencyManagement>
+
+</project>
diff --git a/juneau-bundles/juneau-microservice-jetty-bundle/pom.xml 
b/juneau-bundles/juneau-microservice-jetty-bundle/pom.xml
new file mode 100644
index 0000000000..52af05a1a3
--- /dev/null
+++ b/juneau-bundles/juneau-microservice-jetty-bundle/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.juneau</groupId>
+               <artifactId>juneau-bundles</artifactId>
+               <version>10.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>juneau-microservice-jetty-bundle</artifactId>
+       <packaging>pom</packaging>
+
+       <name>Apache Juneau Jetty Microservice Bundle</name>
+       <description>Curated dependency bundle for a Jetty-backed Juneau 
microservice.  Depend on this single artifact to transitively pull the 
embedded-Jetty microservice stack (juneau-microservice-jetty, which itself 
brings juneau-microservice + juneau-rest-server) plus the REST client for 
typical service-to-service calls.  This is a dependency aggregator only — it 
registers no configurations and performs no classpath auto-discovery; wire your 
servers explicitly via Microservice.Builder.confi [...]
+
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>org.apache.juneau</groupId>
+                               <artifactId>juneau-bom</artifactId>
+                               <version>${project.version}</version>
+                               <type>pom</type>
+                               <scope>import</scope>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+
+       <dependencies>
+               <!-- Embedded-Jetty microservice stack (transitively brings 
juneau-microservice + juneau-rest-server). -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-microservice-jetty</artifactId>
+               </dependency>
+               <!-- REST client for typical service-to-service calls. -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-rest-client</artifactId>
+               </dependency>
+       </dependencies>
+
+</project>
diff --git a/juneau-bundles/juneau-microservice-tomcat-bundle/pom.xml 
b/juneau-bundles/juneau-microservice-tomcat-bundle/pom.xml
new file mode 100644
index 0000000000..7c56646e89
--- /dev/null
+++ b/juneau-bundles/juneau-microservice-tomcat-bundle/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.juneau</groupId>
+               <artifactId>juneau-bundles</artifactId>
+               <version>10.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>juneau-microservice-tomcat-bundle</artifactId>
+       <packaging>pom</packaging>
+
+       <name>Apache Juneau Tomcat Microservice Bundle</name>
+       <description>Curated dependency bundle for a Tomcat-backed Juneau 
microservice.  Depend on this single artifact to transitively pull the 
embedded-Tomcat microservice stack (juneau-microservice-tomcat, which itself 
brings juneau-microservice + juneau-rest-server) plus the REST client for 
typical service-to-service calls.  This is a dependency aggregator only — it 
registers no configurations and performs no classpath auto-discovery; wire your 
servers explicitly via Microservice.Builder.co [...]
+
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>org.apache.juneau</groupId>
+                               <artifactId>juneau-bom</artifactId>
+                               <version>${project.version}</version>
+                               <type>pom</type>
+                               <scope>import</scope>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+
+       <dependencies>
+               <!-- Embedded-Tomcat microservice stack (transitively brings 
juneau-microservice + juneau-rest-server). -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-microservice-tomcat</artifactId>
+               </dependency>
+               <!-- REST client for typical service-to-service calls. -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-rest-client</artifactId>
+               </dependency>
+       </dependencies>
+
+</project>
diff --git a/juneau-bundles/juneau-springboot-bundle/pom.xml 
b/juneau-bundles/juneau-springboot-bundle/pom.xml
new file mode 100644
index 0000000000..fa1dba8e5f
--- /dev/null
+++ b/juneau-bundles/juneau-springboot-bundle/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.juneau</groupId>
+               <artifactId>juneau-bundles</artifactId>
+               <version>10.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>juneau-springboot-bundle</artifactId>
+       <packaging>pom</packaging>
+
+       <name>Apache Juneau Spring Boot Bundle</name>
+       <description>Curated dependency bundle for running Juneau REST 
resources under Spring Boot.  Depend on this single artifact to transitively 
pull the Spring Boot bridge (juneau-rest-server-springboot, which brings 
juneau-rest-server + spring-boot-starter-web) plus the REST client.  This is a 
dependency aggregator only — it registers no configurations and performs no 
classpath auto-discovery; wire your resources explicitly.  Not to be confused 
with the external clone-and-go juneau-microse [...]
+
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>org.apache.juneau</groupId>
+                               <artifactId>juneau-bom</artifactId>
+                               <version>${project.version}</version>
+                               <type>pom</type>
+                               <scope>import</scope>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+
+       <dependencies>
+               <!-- Spring Boot bridge (transitively brings juneau-rest-server 
+ spring-boot-starter-web). -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-rest-server-springboot</artifactId>
+               </dependency>
+               <!-- REST client for typical service-to-service calls. -->
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-rest-client</artifactId>
+               </dependency>
+       </dependencies>
+
+</project>
diff --git a/juneau-bundles/pom.xml b/juneau-bundles/pom.xml
new file mode 100644
index 0000000000..f2c4b1eae6
--- /dev/null
+++ b/juneau-bundles/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.apache.juneau</groupId>
+               <artifactId>juneau</artifactId>
+               <version>10.0.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>juneau-bundles</artifactId>
+       <packaging>pom</packaging>
+
+       <name>Apache Juneau Dependency Bundles</name>
+       <description>Aggregator for the curated *-bundle dependency POMs.  Each 
bundle transitively pulls a coherent Juneau module set for one deployment shape 
(Jetty microservice, Tomcat microservice, Spring Boot bridge).  Bundles are 
dependency aggregators only — they do NOT register configurations or 
auto-discover anything (explicit-over-magic).</description>
+
+       <modules>
+               <module>juneau-microservice-jetty-bundle</module>
+               <module>juneau-microservice-tomcat-bundle</module>
+               <module>juneau-springboot-bundle</module>
+       </modules>
+
+</project>
diff --git a/juneau-distrib/pom.xml b/juneau-distrib/pom.xml
index 172ba9e984..fadb66c95f 100644
--- a/juneau-distrib/pom.xml
+++ b/juneau-distrib/pom.xml
@@ -833,6 +833,31 @@
                                                                        
<destFileName>org.apache.juneau.microservice.jetty_${project.version}.jar</destFileName>
                                                                </artifactItem>
 
+                                                               <!-- 
juneau-microservice-tomcat -->
+                                                               <artifactItem>
+                                                                       
<outputDirectory>${project.build.directory}/src/lib</outputDirectory>
+                                                                       
<groupId>org.apache.juneau</groupId>
+                                                                       
<artifactId>juneau-microservice-tomcat</artifactId>
+                                                                       
<version>${project.version}</version>
+                                                                       
<type>jar</type>
+                                                                       
<classifier>sources</classifier>
+                                                                       
<destFileName>apache-juneau-microservice-tomcat-${project.version}-sources.jar</destFileName>
+                                                               </artifactItem>
+                                                               <artifactItem>
+                                                                       
<outputDirectory>${project.build.directory}/bin/lib</outputDirectory>
+                                                                       
<groupId>org.apache.juneau</groupId>
+                                                                       
<artifactId>juneau-microservice-tomcat</artifactId>
+                                                                       
<version>${project.version}</version>
+                                                                       
<destFileName>apache-juneau-microservice-tomcat-${project.version}.jar</destFileName>
+                                                               </artifactItem>
+                                                               <artifactItem>
+                                                                       
<outputDirectory>${project.build.directory}/bin/osgi</outputDirectory>
+                                                                       
<groupId>org.apache.juneau</groupId>
+                                                                       
<artifactId>juneau-microservice-tomcat</artifactId>
+                                                                       
<version>${project.version}</version>
+                                                                       
<destFileName>org.apache.juneau.microservice.tomcat_${project.version}.jar</destFileName>
+                                                               </artifactItem>
+
                                                                <!-- 
juneau-sc-client -->
                                                                <artifactItem>
                                                                        
<outputDirectory>${project.build.directory}/src/lib</outputDirectory>
diff --git a/juneau-rest/juneau-rest-server-metrics-micrometer/pom.xml 
b/juneau-rest/juneau-rest-server-metrics-micrometer/pom.xml
index 32ba27b215..af6bb75ac5 100644
--- a/juneau-rest/juneau-rest-server-metrics-micrometer/pom.xml
+++ b/juneau-rest/juneau-rest-server-metrics-micrometer/pom.xml
@@ -32,7 +32,7 @@
 
        <properties>
                
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-               <micrometer.version>1.13.6</micrometer.version>
+               <!-- micrometer.version is hoisted to the root pom so the 
juneau-bom can pin it. -->
        </properties>
 
        <dependencies>
diff --git a/juneau-rest/juneau-rest-server-tracing-otel/pom.xml 
b/juneau-rest/juneau-rest-server-tracing-otel/pom.xml
index b6f900db4b..c6bb83263a 100644
--- a/juneau-rest/juneau-rest-server-tracing-otel/pom.xml
+++ b/juneau-rest/juneau-rest-server-tracing-otel/pom.xml
@@ -32,7 +32,7 @@
 
        <properties>
                
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-               <opentelemetry.version>1.62.0</opentelemetry.version>
+               <!-- opentelemetry.version is hoisted to the root pom so the 
juneau-bom can pin it. -->
        </properties>
 
        <dependencies>
diff --git a/juneau-rest/juneau-rest-server/pom.xml 
b/juneau-rest/juneau-rest-server/pom.xml
index 4eacd2f583..2a914c3801 100644
--- a/juneau-rest/juneau-rest-server/pom.xml
+++ b/juneau-rest/juneau-rest-server/pom.xml
@@ -73,7 +73,7 @@
                <dependency>
                        <groupId>jakarta.servlet</groupId>
                        <artifactId>jakarta.servlet-api</artifactId>
-                       <version>6.1.0</version>
+                       <version>${jakarta.servlet-api.version}</version>
                </dependency>
 
                <!--
@@ -85,7 +85,7 @@
                <dependency>
                        <groupId>jakarta.validation</groupId>
                        <artifactId>jakarta.validation-api</artifactId>
-                       <version>3.0.2</version>
+                       <version>${jakarta.validation-api.version}</version>
                        <scope>provided</scope>
                </dependency>
                <dependency>
diff --git a/pom.xml b/pom.xml
index 08314c8e7e..682c60dae6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,9 +69,16 @@
                
<sonar.cpd.exclusions>**/rest/server/Rest*Annotation.java,**/rest/server/RestOp.java,**/rest/server/RestGet.java,**/rest/server/RestPut.java,**/rest/server/RestPost.java,**/rest/server/RestDelete.java,**/rest/server/RestPatch.java,**/rest/server/RestOptions.java,**/rest/server/RestPreCall.java,**/rest/server/RestPostCall.java,**/rest/server/RestStartCall.java,**/rest/server/RestEndCall.java,**/rest/server/RestInit.java,**/rest/server/RestDestroy.java,**/rest/server/RestPostInit.java,**
 [...]
                
<sonar.coverage.exclusions>**/juneau-examples/**,**/juneau-petstore/**,**/*-microservice/**,**/juneau-sc-server/**,**/juneau-core/juneau-test-utils/**</sonar.coverage.exclusions>
                <jena.version>5.6.0</jena.version>
+               <!-- Hoisted from owning modules so the juneau-bom + curated 
bundles can pin one coherent version source. -->
+               <micrometer.version>1.13.6</micrometer.version>
+               <opentelemetry.version>1.62.0</opentelemetry.version>
+               <jakarta.servlet-api.version>6.1.0</jakarta.servlet-api.version>
+               
<jakarta.validation-api.version>3.0.2</jakarta.validation-api.version>
        </properties>
 
        <modules>
+               <module>juneau-bom</module>
+               <module>juneau-bundles</module>
                <module>juneau-core</module>
                <module>juneau-rest</module>
                <module>juneau-microservice</module>
diff --git a/scripts/check-bom-completeness.py 
b/scripts/check-bom-completeness.py
new file mode 100755
index 0000000000..e54990838c
--- /dev/null
+++ b/scripts/check-bom-completeness.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+# 
***************************************************************************************************************************
+# * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+# * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+# * to you 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.
+# 
***************************************************************************************************************************
+"""
+Drift guard for the published juneau-bom.
+
+Every consumer-facing reactor module must be enumerated in juneau-bom/pom.xml's
+<dependencyManagement>.  This catches the common failure mode where a new
+publishable module is added to the reactor but the maintainer forgets to add it
+to the BOM, so downstreams importing the BOM silently can't omit its version.
+
+A module is "consumer-facing publishable" when it is a leaf artifact
+(packaging jar/bundle, or a leaf packaging=pom dependency bundle with no
+<modules>) AND it is not one of the documented non-published modules:
+
+  - reactor aggregators (packaging=pom WITH <modules>) - not artifacts
+  - juneau-bom itself
+  - juneau-test-utils                    (test-only support)
+  - juneau-shaded/*                      (uber-jars, not BOM-managed)
+  - juneau-examples/*, juneau-petstore/* (sample apps, not published)
+  - juneau-integration-tests             (test-only)
+  - juneau-distrib                       (assembly only)
+
+Exit 0 when the BOM is complete (and free of stale entries); exit 1 otherwise.
+"""
+
+from __future__ import annotations
+
+import sys
+import xml.etree.ElementTree as ET
+from pathlib import Path
+
+NS = {"m": "http://maven.apache.org/POM/4.0.0"}
+
+# Path-prefix-based exclusions (relative to repo root).
+EXCLUDED_PATH_PREFIXES = (
+    "juneau-shaded/",
+    "juneau-examples/",
+    "juneau-petstore/",
+    "juneau-distrib/",
+)
+
+# Artifact-id-based exclusions (leaf artifacts that are intentionally not 
published via the BOM).
+EXCLUDED_ARTIFACTS = {
+    "juneau-bom",                # the BOM cannot manage itself
+    "juneau-test-utils",         # test-only support module
+    "juneau-integration-tests",  # cross-module test harness, not published
+    "juneau",                    # reactor root (defensive; also an aggregator)
+}
+
+
+def _text(el: ET.Element, tag: str) -> str | None:
+    child = el.find(f"m:{tag}", NS)
+    return child.text.strip() if child is not None and child.text else None
+
+
+def repo_root() -> Path:
+    # scripts/ lives directly under the reactor root.
+    return Path(__file__).resolve().parent.parent
+
+
+def own_artifact_id(root: ET.Element) -> str | None:
+    """The module's own artifactId - the direct <project><artifactId>, not the 
<parent> one."""
+    return _text(root, "artifactId")
+
+
+def is_aggregator(root: ET.Element) -> bool:
+    """A reactor aggregator: packaging=pom AND declares <modules>."""
+    packaging = _text(root, "packaging") or "jar"
+    has_modules = root.find("m:modules", NS) is not None
+    return packaging == "pom" and has_modules
+
+
+def collect_publishable(root_dir: Path) -> dict[str, Path]:
+    """Map of consumer-facing publishable artifactId -> pom path."""
+    out: dict[str, Path] = {}
+    for pom in sorted(root_dir.rglob("pom.xml")):
+        rel = pom.relative_to(root_dir).as_posix()
+        if "/target/" in f"/{rel}":
+            continue
+        if any(rel.startswith(p) for p in EXCLUDED_PATH_PREFIXES):
+            continue
+        try:
+            root = ET.parse(pom).getroot()
+        except ET.ParseError as e:
+            print(f"WARNING: could not parse {rel}: {e}", file=sys.stderr)
+            continue
+        aid = own_artifact_id(root)
+        if not aid or aid in EXCLUDED_ARTIFACTS:
+            continue
+        if is_aggregator(root):
+            continue
+        # Skip the integration-tests reactor module (artifactId 'juneau', 
already excluded) and
+        # any build-overlay helper poms living under an excluded tree (handled 
by path prefixes).
+        out[aid] = pom
+    return out
+
+
+def collect_bom_entries(bom_pom: Path) -> set[str]:
+    root = ET.parse(bom_pom).getroot()
+    dm = root.find("m:dependencyManagement", NS)
+    if dm is None:
+        return set()
+    out: set[str] = set()
+    for dep in dm.iterfind("m:dependencies/m:dependency", NS):
+        group = _text(dep, "groupId")
+        if group != "org.apache.juneau":
+            continue
+        aid = _text(dep, "artifactId")
+        if aid:
+            out.add(aid)
+    return out
+
+
+def main() -> int:
+    root_dir = repo_root()
+    bom_pom = root_dir / "juneau-bom" / "pom.xml"
+    if not bom_pom.is_file():
+        print(f"ERROR: BOM not found at {bom_pom}", file=sys.stderr)
+        return 1
+
+    publishable = collect_publishable(root_dir)
+    bom = collect_bom_entries(bom_pom)
+
+    missing = sorted(set(publishable) - bom)
+    stale = sorted(bom - set(publishable))
+
+    if not missing and not stale:
+        print(f"OK: juneau-bom enumerates all {len(publishable)} 
consumer-facing modules.")
+        return 0
+
+    if missing:
+        print("ERROR: the following published modules are MISSING from 
juneau-bom:", file=sys.stderr)
+        for aid in missing:
+            print(f"  - {aid}  
({publishable[aid].relative_to(root_dir).as_posix()})", file=sys.stderr)
+    if stale:
+        print("ERROR: juneau-bom lists artifacts that are NOT consumer-facing 
reactor modules:", file=sys.stderr)
+        for aid in stale:
+            print(f"  - {aid}", file=sys.stderr)
+    print(
+        "\nFix: add the missing <dependency> entries to juneau-bom/pom.xml (or 
remove stale ones), "
+        "or update the exclusion lists in scripts/check-bom-completeness.py if 
the module is "
+        "intentionally not published.",
+        file=sys.stderr,
+    )
+    return 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/scripts/push.py b/scripts/push.py
index 0921409b88..8385f9089b 100755
--- a/scripts/push.py
+++ b/scripts/push.py
@@ -534,6 +534,8 @@ Examples:
         if not args.skip_tests:
             print(f"  {step_num}. Verify container test tags: python3 
scripts/check-container-tags.py")
             step_num += 1
+            print(f"  {step_num}. Verify BOM completeness: python3 
scripts/check-bom-completeness.py")
+            step_num += 1
             print(f"  {step_num}. Run tests with timing capture: python3 
scripts/test.py --full --timing-log 
~/.cache/juneau-push-timings/<branch>.jsonl")
             step_num += 1
             print(f"  {step_num}. Print timing deltas: python3 
scripts/push-timings.py --log ~/.cache/juneau-push-timings/<branch>.jsonl")
@@ -575,6 +577,18 @@ Examples:
                 return 1
             step_num += 1
 
+        check_bom = script_dir / "check-bom-completeness.py"
+        if check_bom.exists():
+            if not run_command(
+                [sys.executable, str(check_bom)],
+                f"šŸ”Ž Step {step_num}: Checking BOM completeness...",
+                juneau_root
+            ):
+                print("\nāŒ Build process aborted: juneau-bom is out of sync 
with the reactor.")
+                play_sound(success=False)
+                return 1
+            step_num += 1
+
         test_script = script_dir / 'test.py'
         timing_file = timing_log_path(juneau_root)
         if test_script.exists():


Reply via email to