Skip to content

Commit ff7bae8

Browse files
authoredFeb 20, 2025
Add BOM generation. (#1569)
JAVA-3808 --------- Co-authored-by: Ross Lawley <ross.lawley@gmail.com>
1 parent c95ea47 commit ff7bae8

File tree

6 files changed

+128
-6
lines changed

6 files changed

+128
-6
lines changed
 

‎.evergreen/publish.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ fi
2626
SYSTEM_PROPERTIES="-Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.internal.http.connectionTimeout=120000 -Dorg.gradle.internal.http.socketTimeout=120000"
2727

2828
./gradlew -version
29-
./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info ${TASK}
29+
./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info ${TASK} # Scala 2.13 is published as result of this gradle execution.
3030
./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info :bson-scala:${TASK} :driver-scala:${TASK} -PdefaultScalaVersions=2.12.12
3131
./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info :bson-scala:${TASK} :driver-scala:${TASK} -PdefaultScalaVersions=2.11.12

‎bom/build.gradle.kts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
group = "org.mongodb"
2+
description = "This Bill of Materials POM simplifies dependency management when referencing multiple" +
3+
" MongoDB Java Driver artifacts in projects using Gradle or Maven."
4+
5+
dependencies {
6+
constraints {
7+
api(project(":mongodb-crypt"))
8+
api(project(":driver-core"))
9+
api(project(":bson"))
10+
api(project(":bson-record-codec"))
11+
12+
api(project(":driver-sync"))
13+
api(project(":driver-reactive-streams"))
14+
15+
api(project(":bson-kotlin"))
16+
api(project(":bson-kotlinx"))
17+
api(project(":driver-kotlin-coroutine"))
18+
api(project(":driver-kotlin-sync"))
19+
20+
api(project(":bson-scala"))
21+
api(project(":driver-scala"))
22+
}
23+
}

‎build.gradle

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ ext {
6565

6666
def configDir = ext.configDir
6767
def utilProjects = project(":util").allprojects
68+
def bomProjects = project(":bom")
6869
def coreProjects = subprojects - utilProjects
69-
def scalaProjects = subprojects.findAll { it.name.contains('scala') }
70-
def javaProjects = subprojects - scalaProjects
70+
def scalaProjects = subprojects.findAll { it.name.contains('scala') } - bomProjects
71+
def javaProjects = subprojects - scalaProjects - bomProjects
7172
def javaMainProjects = javaProjects - utilProjects
7273
def javaCodeCheckedProjects = javaMainProjects.findAll { !['driver-benchmarks', 'driver-workload-executor', 'driver-lambda'].contains(it.name) }
7374
def javaAndScalaTestedProjects = javaCodeCheckedProjects + scalaProjects

‎gradle.properties

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
org.gradle.daemon=true
1818
org.gradle.jvmargs=-Duser.country=US -Duser.language=en
19+
## NOTE: This property is also used to generate scala compile versions in BOM.
1920
scalaVersions=2.11.12,2.12.20,2.13.15
2021
defaultScalaVersions=2.13.15
2122
runOnceTasks=clean,release

‎gradle/publish.gradle

+99-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ ext {
7676
def projectNamesNotToBePublished = ["driver-benchmarks", "driver-lambda", "driver-workload-executor", "graalvm-native-image-app", "util",
7777
"spock", "taglets"]
7878
def publishedProjects = subprojects.findAll { !projectNamesNotToBePublished.contains(it.name) }
79-
def scalaProjects = publishedProjects.findAll { it.name.contains('scala') }
80-
def javaProjects = publishedProjects - scalaProjects
81-
def projectsWithManifest = publishedProjects.findAll {it.name != 'driver-legacy' }
79+
def bomProjects = project(":bom")
80+
def scalaProjects = publishedProjects.findAll { it.name.contains('scala') } - bomProjects
81+
def javaProjects = publishedProjects - scalaProjects - bomProjects
82+
def projectsWithManifest = publishedProjects.findAll {it.name != 'driver-legacy' } - bomProjects
8283

8384
configure(javaProjects) { project ->
8485
apply plugin: 'maven-publish'
@@ -169,3 +170,98 @@ configure(projectsWithManifest) { project ->
169170
jar configureJarManifestAttributes(project)
170171
}
171172
}
173+
174+
configure(bomProjects) { project ->
175+
apply plugin: 'maven-publish'
176+
apply plugin: 'signing'
177+
apply plugin: 'java-platform'
178+
179+
// Get the Scala versions from the project property. Only major.minor versions.
180+
def scalaVersions = project.findProperty("scalaVersions")?.split(",")
181+
?.collect { it.split("\\.")[0] + "." + it.split("\\.")[1] }
182+
183+
assert scalaVersions != null && !scalaVersions.isEmpty() : "Scala versions must be provided as a comma-separated list" +
184+
" in the 'scalaVersions' project property"
185+
186+
publishing {
187+
publications {
188+
mavenJava(MavenPublication) {
189+
artifactId = "bom".equals(project.archivesBaseName) ? "mongodb-driver-bom" : project.archivesBaseName
190+
from components.javaPlatform
191+
192+
// Modify the generated POM to add multiple compile versions of driver-scala or bson-scala.
193+
// Scala multi-version support generates only one for BOM.
194+
pom.withXml {
195+
def pomXml = asNode()
196+
197+
def dependencyManagementNode = pomXml.get("dependencyManagement")?.getAt(0)
198+
assert dependencyManagementNode : "<dependencyManagement> node not found in the generated BOM POM"
199+
200+
def dependenciesNode = dependencyManagementNode.get("dependencies")?.getAt(0)
201+
assert dependenciesNode : "<dependencies> node not found inside <dependencyManagement>"
202+
203+
// Check if scala dependencies are present in the BOM.
204+
def existingScalaDeps = dependenciesNode.children().findAll {
205+
it.artifactId.text().contains("scala")
206+
}
207+
208+
existingScalaDeps.each { existingDep ->
209+
String groupId = existingDep.groupId.text()
210+
String originalArtifactId = existingDep.artifactId.text()
211+
String artifactVersion = existingDep.version.text()
212+
213+
// Add multiple versions with Scala suffixes for each Scala-related dependency.
214+
scalaVersions.each { scalaVersion ->
215+
// Remove existing Scala version suffix (_2.12, _2.13, etc.)
216+
String baseArtifactId = originalArtifactId.replaceAll("_\\d+\\.\\d+(\\.\\d+)?\$", "")
217+
String newArtifactId = "${baseArtifactId}_${scalaVersion}"
218+
219+
// Skip if Scala dependency with this scalaVersion already exists in BOM.
220+
if(newArtifactId != originalArtifactId) {
221+
def dependencyNode = dependenciesNode.appendNode("dependency")
222+
dependencyNode.appendNode("groupId", groupId)
223+
dependencyNode.appendNode("artifactId", newArtifactId)
224+
dependencyNode.appendNode("version", artifactVersion)
225+
}
226+
}
227+
}
228+
}
229+
}
230+
}
231+
232+
repositories configureMavenRepositories(project)
233+
}
234+
235+
afterEvaluate {
236+
publishing.publications.mavenJava.pom configurePom(project)
237+
signing {
238+
useInMemoryPgpKeys(findProperty("signingKey"), findProperty("signingPassword"))
239+
sign publishing.publications.mavenJava
240+
}
241+
}
242+
243+
tasks.withType(GenerateModuleMetadata) {
244+
enabled = false
245+
}
246+
247+
tasks.withType(GenerateMavenPom).configureEach {
248+
doLast {
249+
def xml = file(destination).text
250+
def root = new groovy.xml.XmlSlurper().parseText(xml)
251+
252+
def dependencies = root.dependencyManagement.dependencies.children()
253+
assert dependencies.children().size() > 1 : "BOM must contain more then one <dependency> element:\n$destination"
254+
255+
dependencies.each { dependency ->
256+
def groupId = dependency.groupId.text()
257+
assert groupId.startsWith('org.mongodb') : "BOM must contain only 'org.mongodb' dependencies, but found '$groupId':\n$destination"
258+
/* The <scope> and <optional> tags should be omitted in BOM dependencies.
259+
This ensures that consuming projects have the flexibility to decide whether a
260+
dependency is optional in their context. The BOM's role is to provide version information,
261+
not to dictate inclusion or exclusion of dependencies. */
262+
assert dependency.scope.size() == 0 : "BOM must not contain <scope> elements in dependency:\n$destination"
263+
assert dependency.optional.size() == 0 : "BOM must not contain <optional> elements in dependency:\n$destination"
264+
}
265+
}
266+
}
267+
}

‎settings.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ include ':driver-scala'
3333
include ':mongodb-crypt'
3434
include 'util:spock'
3535
include 'util:taglets'
36+
include ':bom'
3637

3738
if(hasProperty("includeGraalvm")) {
3839
include ':graalvm-native-image-app'

0 commit comments

Comments
 (0)
Failed to load comments.