From 0e6c1ed4f9b1850daabe161fd0c27ffa3822e215 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Wed, 27 Nov 2024 22:22:13 -0800 Subject: [PATCH 1/4] Add BOM generation for Java, Kotlin and Scala. JAVA-3808 --- .evergreen/publish.sh | 2 +- bom-kotlin/build.gradle.kts | 20 ++++++++++ bom-scala/build.gradle.kts | 20 ++++++++++ bom/build.gradle.kts | 20 ++++++++++ build.gradle | 5 ++- gradle/publish.gradle | 75 +++++++++++++++++++++++++++++++++++-- settings.gradle | 3 ++ 7 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 bom-kotlin/build.gradle.kts create mode 100644 bom-scala/build.gradle.kts create mode 100644 bom/build.gradle.kts diff --git a/.evergreen/publish.sh b/.evergreen/publish.sh index bfecc0ae865..e3f9f365d42 100755 --- a/.evergreen/publish.sh +++ b/.evergreen/publish.sh @@ -26,6 +26,6 @@ fi SYSTEM_PROPERTIES="-Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.internal.http.connectionTimeout=120000 -Dorg.gradle.internal.http.socketTimeout=120000" ./gradlew -version -./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info ${TASK} +./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info ${TASK} # Scala 2.13 is published as result of this gradle execution. ./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info :bson-scala:${TASK} :driver-scala:${TASK} -PdefaultScalaVersions=2.12.12 ./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info :bson-scala:${TASK} :driver-scala:${TASK} -PdefaultScalaVersions=2.11.12 diff --git a/bom-kotlin/build.gradle.kts b/bom-kotlin/build.gradle.kts new file mode 100644 index 00000000000..94ebed2c166 --- /dev/null +++ b/bom-kotlin/build.gradle.kts @@ -0,0 +1,20 @@ +group = "org.mongodb" +base.archivesName.set("mongodb-driver-bom") +description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + + " MongoDB Kotlin Driver artifacts in projects using Gradle or Maven." + +dependencies { + constraints { + api(project(":mongodb-crypt")) + api(project(":driver-core")) + api(project(":driver-sync")) + api(project(":driver-reactive-streams")) + api(project(":bson")) + api(project(":bson-record-codec")) + + api(project(":driver-kotlin-sync")) + api(project(":driver-kotlin-coroutine")) + api(project(":bson-kotlin")) + api(project(":bson-kotlinx")) + } +} \ No newline at end of file diff --git a/bom-scala/build.gradle.kts b/bom-scala/build.gradle.kts new file mode 100644 index 00000000000..007113b3d82 --- /dev/null +++ b/bom-scala/build.gradle.kts @@ -0,0 +1,20 @@ +group = "org.mongodb" +base.archivesName.set("mongodb-driver-bom") +description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + + " MongoDB Scala Driver artifacts in projects using Gradle or Maven." + +dependencies { + constraints { + api(project(":mongodb-crypt")) + api(project(":driver-core")) + api(project(":driver-sync")) + api(project(":driver-reactive-streams")) + api(project(":bson")) + api(project(":bson-record-codec")) + + api(project(":driver-reactive-streams")) + api(project(":bson")) + api(project(":bson-scala")) + api(project(":driver-scala")) + } +} \ No newline at end of file diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts new file mode 100644 index 00000000000..4d56540dfaf --- /dev/null +++ b/bom/build.gradle.kts @@ -0,0 +1,20 @@ +group = "org.mongodb" +base.archivesName.set("mongodb-driver-bom") +description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + + " MongoDB Java Driver artifacts in projects using Gradle or Maven." + +dependencies { + constraints { + api(project(":mongodb-crypt")) + api(project(":driver-core")) + api(project(":driver-sync")) + api(project(":driver-reactive-streams")) + api(project(":bson")) + api(project(":bson-record-codec")) + } + +} + +javaPlatform { + allowDependencies() +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index e846ea53d93..efe4b7d137b 100644 --- a/build.gradle +++ b/build.gradle @@ -64,9 +64,10 @@ ext { def configDir = ext.configDir def utilProjects = project(":util").allprojects +def bomProjects = project(":bom") def coreProjects = subprojects - utilProjects -def scalaProjects = subprojects.findAll { it.name.contains('scala') } -def javaProjects = subprojects - scalaProjects +def scalaProjects = subprojects.findAll { it.name.contains('scala') } - bomProjects +def javaProjects = subprojects - scalaProjects - bomProjects def javaMainProjects = javaProjects - utilProjects def javaCodeCheckedProjects = javaMainProjects.findAll { !['driver-benchmarks', 'driver-workload-executor', 'driver-lambda'].contains(it.name) } def javaAndScalaTestedProjects = javaCodeCheckedProjects + scalaProjects diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 9add25f9261..471c19fbea5 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -76,9 +76,10 @@ ext { def projectNamesNotToBePublished = ["driver-benchmarks", "driver-lambda", "driver-workload-executor", "graalvm-native-image-app", "util", "spock", "taglets"] def publishedProjects = subprojects.findAll { !projectNamesNotToBePublished.contains(it.name) } -def scalaProjects = publishedProjects.findAll { it.name.contains('scala') } -def javaProjects = publishedProjects - scalaProjects -def projectsWithManifest = publishedProjects.findAll {it.name != 'driver-legacy' } +def bomProjects = project(":bom") +def scalaProjects = publishedProjects.findAll { it.name.contains('scala') } - bomProjects +def javaProjects = publishedProjects - scalaProjects - bomProjects +def projectsWithManifest = publishedProjects.findAll {it.name != 'driver-legacy' } - bomProjects configure(javaProjects) { project -> apply plugin: 'maven-publish' @@ -169,3 +170,71 @@ configure(projectsWithManifest) { project -> jar configureJarManifestAttributes(project) } } + +configure(bomProjects) { project -> + apply plugin: 'maven-publish' + apply plugin: 'signing' + apply plugin: 'java-platform' + + publishing { + publications { + mavenJava(MavenPublication) { + from components.javaPlatform // Use the BOM component + artifactId = project.archivesBaseName + } + } + + repositories configureMavenRepositories(project) + } + + afterEvaluate { + publishing.publications.mavenJava.pom configurePom(project) + signing { + useInMemoryPgpKeys(findProperty("signingKey"), findProperty("signingPassword")) + sign publishing.publications.mavenJava + } + } + + //TODO do we need to generate Gradle module metadata for the BOM? + tasks.withType(GenerateModuleMetadata) { + enabled = false + } + + // Analyze dependencies to include transitive optional dependencies +// project.afterEvaluate { +// dependencies.constraints { +// configurations.compileClasspath.resolvedConfiguration.firstLevelModuleDependencies.each { dependency -> +// dependency.moduleArtifacts.each { artifact -> +// artifact.moduleDependency.artifacts.each { transitiveDep -> +// if (transitiveDep.optional) { +// api("${transitiveDep.group}:${transitiveDep.name}:${transitiveDep.version}") { +// because "Automatically added optional transitive dependency" +// } +// } +// } +// } +// } +// } +// } + + tasks.withType(GenerateMavenPom).configureEach { + doLast { + def xml = file(destination).text + assert xml.indexOf("") == xml.lastIndexOf(""): + "BOM must contain exactly one element but contained multiple:\n$destination" + assert xml.contains(""): + "BOM must contain a element:\n$destination" + + /* + The and tags should be omitted in BOM dependencies. + This ensures that consuming projects have the flexibility to decide whether a + dependency is optional in their context. The BOM's role is to provide version information, + not to dictate inclusion or exclusion of dependencies. + */ + assert !xml.contains(""): + "BOM must not contain elements:\n$destination" + assert !xml.contains(""): + "BOM must not contain elements:\n$destination" + } + } +} diff --git a/settings.gradle b/settings.gradle index 4ebbb10c4e0..1354bf0e0a3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -32,6 +32,9 @@ include ':driver-scala' include ':mongodb-crypt' include 'util:spock' include 'util:taglets' +include ':bom' +include ':bom-kotlin' +include ':bom-scala' if(hasProperty("includeGraalvm")) { include ':graalvm-native-image-app' From 5f7b73141b7243acef5ca9f7f5b134252ee5ecc2 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Thu, 28 Nov 2024 19:14:44 -0800 Subject: [PATCH 2/4] - Remove Kotlin and Scala BOM modules. - Add BOM validation. JAVA-3808 --- bom-kotlin/build.gradle.kts | 20 --------------- bom-scala/build.gradle.kts | 20 --------------- bom/build.gradle.kts | 18 ++++++++----- gradle/publish.gradle | 51 +++++++++++++------------------------ settings.gradle | 2 -- 5 files changed, 28 insertions(+), 83 deletions(-) delete mode 100644 bom-kotlin/build.gradle.kts delete mode 100644 bom-scala/build.gradle.kts diff --git a/bom-kotlin/build.gradle.kts b/bom-kotlin/build.gradle.kts deleted file mode 100644 index 94ebed2c166..00000000000 --- a/bom-kotlin/build.gradle.kts +++ /dev/null @@ -1,20 +0,0 @@ -group = "org.mongodb" -base.archivesName.set("mongodb-driver-bom") -description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + - " MongoDB Kotlin Driver artifacts in projects using Gradle or Maven." - -dependencies { - constraints { - api(project(":mongodb-crypt")) - api(project(":driver-core")) - api(project(":driver-sync")) - api(project(":driver-reactive-streams")) - api(project(":bson")) - api(project(":bson-record-codec")) - - api(project(":driver-kotlin-sync")) - api(project(":driver-kotlin-coroutine")) - api(project(":bson-kotlin")) - api(project(":bson-kotlinx")) - } -} \ No newline at end of file diff --git a/bom-scala/build.gradle.kts b/bom-scala/build.gradle.kts deleted file mode 100644 index 007113b3d82..00000000000 --- a/bom-scala/build.gradle.kts +++ /dev/null @@ -1,20 +0,0 @@ -group = "org.mongodb" -base.archivesName.set("mongodb-driver-bom") -description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + - " MongoDB Scala Driver artifacts in projects using Gradle or Maven." - -dependencies { - constraints { - api(project(":mongodb-crypt")) - api(project(":driver-core")) - api(project(":driver-sync")) - api(project(":driver-reactive-streams")) - api(project(":bson")) - api(project(":bson-record-codec")) - - api(project(":driver-reactive-streams")) - api(project(":bson")) - api(project(":bson-scala")) - api(project(":driver-scala")) - } -} \ No newline at end of file diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 4d56540dfaf..bfc7adf36b0 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -1,5 +1,4 @@ group = "org.mongodb" -base.archivesName.set("mongodb-driver-bom") description = "This Bill of Materials POM simplifies dependency management when referencing multiple" + " MongoDB Java Driver artifacts in projects using Gradle or Maven." @@ -7,14 +6,19 @@ dependencies { constraints { api(project(":mongodb-crypt")) api(project(":driver-core")) - api(project(":driver-sync")) - api(project(":driver-reactive-streams")) api(project(":bson")) api(project(":bson-record-codec")) - } -} + api(project(":driver-sync")) + api(project(":driver-reactive-streams")) + + api(project(":bson-kotlin")) + api(project(":bson-kotlinx")) + api(project(":driver-kotlin-coroutine")) + api(project(":driver-kotlin-sync")) -javaPlatform { - allowDependencies() + api(project(":bson-scala")) + api(project(":driver-scala")) + + } } \ No newline at end of file diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 471c19fbea5..8ffd5c2ed78 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -179,8 +179,8 @@ configure(bomProjects) { project -> publishing { publications { mavenJava(MavenPublication) { - from components.javaPlatform // Use the BOM component - artifactId = project.archivesBaseName + artifactId = "bom".equals(project.archivesBaseName) ? "mongodb-driver-bom" : project.archivesBaseName + from components.javaPlatform } } @@ -200,41 +200,24 @@ configure(bomProjects) { project -> enabled = false } - // Analyze dependencies to include transitive optional dependencies -// project.afterEvaluate { -// dependencies.constraints { -// configurations.compileClasspath.resolvedConfiguration.firstLevelModuleDependencies.each { dependency -> -// dependency.moduleArtifacts.each { artifact -> -// artifact.moduleDependency.artifacts.each { transitiveDep -> -// if (transitiveDep.optional) { -// api("${transitiveDep.group}:${transitiveDep.name}:${transitiveDep.version}") { -// because "Automatically added optional transitive dependency" -// } -// } -// } -// } -// } -// } -// } - tasks.withType(GenerateMavenPom).configureEach { doLast { def xml = file(destination).text - assert xml.indexOf("") == xml.lastIndexOf(""): - "BOM must contain exactly one element but contained multiple:\n$destination" - assert xml.contains(""): - "BOM must contain a element:\n$destination" - - /* - The and tags should be omitted in BOM dependencies. - This ensures that consuming projects have the flexibility to decide whether a - dependency is optional in their context. The BOM's role is to provide version information, - not to dictate inclusion or exclusion of dependencies. - */ - assert !xml.contains(""): - "BOM must not contain elements:\n$destination" - assert !xml.contains(""): - "BOM must not contain elements:\n$destination" + def root = new groovy.xml.XmlSlurper().parseText(xml) + + def dependencies = root.dependencyManagement.dependencies.children() + assert dependencies.children().size() > 1 : "BOM must contain more then one element:\n$destination" + + dependencies.each { dependency -> + def groupId = dependency.groupId.text() + assert groupId.startsWith('org.mongodb') : "BOM must contain only 'org.mongodb' dependencies, but found '$groupId':\n$destination" + /* The and tags should be omitted in BOM dependencies. + This ensures that consuming projects have the flexibility to decide whether a + dependency is optional in their context. The BOM's role is to provide version information, + not to dictate inclusion or exclusion of dependencies. */ + assert dependency.scope.size() == 0 : "BOM must not contain elements in dependency:\n$destination" + assert dependency.optional.size() == 0 : "BOM must not contain elements in dependency:\n$destination" + } } } } diff --git a/settings.gradle b/settings.gradle index 1354bf0e0a3..f613b09dcce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -33,8 +33,6 @@ include ':mongodb-crypt' include 'util:spock' include 'util:taglets' include ':bom' -include ':bom-kotlin' -include ':bom-scala' if(hasProperty("includeGraalvm")) { include ':graalvm-native-image-app' From 078cd874c075ddb6f328e5ed66b4e23bf62e055d Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Fri, 31 Jan 2025 00:06:38 -0800 Subject: [PATCH 3/4] Add custom generation of Scala compile versions in BOM. JAVA-3808 --- bom/build.gradle.kts | 1 - gradle.properties | 1 + gradle/publish.gradle | 46 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index bfc7adf36b0..4b0815fccb1 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -19,6 +19,5 @@ dependencies { api(project(":bson-scala")) api(project(":driver-scala")) - } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 12f1750c442..d3514e32f68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,6 +16,7 @@ org.gradle.daemon=true org.gradle.jvmargs=-Duser.country=US -Duser.language=en +## NOTE: This property is also used to generate scala compile versions in BOM. scalaVersions=2.11.12,2.12.20,2.13.15 defaultScalaVersions=2.13.15 runOnceTasks=clean,release diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 8ffd5c2ed78..fa56f09f138 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -176,11 +176,56 @@ configure(bomProjects) { project -> apply plugin: 'signing' apply plugin: 'java-platform' + // Get the Scala versions from the project property. Only major.minor versions. + def scalaVersions = project.findProperty("scalaVersions")?.split(",") + ?.collect { it.split("\\.")[0] + "." + it.split("\\.")[1] } + + assert scalaVersions != null && !scalaVersions.isEmpty() : "Scala versions must be provided as a comma-separated list" + + " in the 'scalaVersions' project property" + publishing { publications { mavenJava(MavenPublication) { artifactId = "bom".equals(project.archivesBaseName) ? "mongodb-driver-bom" : project.archivesBaseName from components.javaPlatform + + // Modify the generated POM to add multiple compile versions of driver-scala or bson-scala. + // Scala multi-version support generates only one for BOM. + pom.withXml { + def pomXml = asNode() + + def dependencyManagementNode = pomXml.get("dependencyManagement")?.getAt(0) + assert dependencyManagementNode : " node not found in the generated BOM POM" + + def dependenciesNode = dependencyManagementNode.get("dependencies")?.getAt(0) + assert dependenciesNode : " node not found inside " + + // Check if scala dependencies are present in the BOM. + def existingScalaDeps = dependenciesNode.children().findAll { + it.artifactId.text().contains("scala") + } + + existingScalaDeps.each { existingDep -> + String groupId = existingDep.groupId.text() + String originalArtifactId = existingDep.artifactId.text() + String artifactVersion = existingDep.version.text() + + // Add multiple versions with Scala suffixes for each Scala-related dependency. + scalaVersions.each { scalaVersion -> + // Remove existing Scala version suffix (_2.12, _2.13, etc.) + String baseArtifactId = originalArtifactId.replaceAll("_\\d+\\.\\d+(\\.\\d+)?\$", "") + String newArtifactId = "${baseArtifactId}_${scalaVersion}" + + // Skip if Scala dependency with this scalaVersion already exists in BOM. + if(newArtifactId != originalArtifactId) { + def dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", groupId) + dependencyNode.appendNode("artifactId", newArtifactId) + dependencyNode.appendNode("version", artifactVersion) + } + } + } + } } } @@ -195,7 +240,6 @@ configure(bomProjects) { project -> } } - //TODO do we need to generate Gradle module metadata for the BOM? tasks.withType(GenerateModuleMetadata) { enabled = false } From 9f67290569c69bf316e7b22ad4d3d19a729b0865 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Mon, 10 Feb 2025 18:01:21 -0800 Subject: [PATCH 4/4] Update bom/build.gradle.kts Co-authored-by: Ross Lawley --- bom/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 4b0815fccb1..5d1fb81c384 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -20,4 +20,4 @@ dependencies { api(project(":bson-scala")) api(project(":driver-scala")) } -} \ No newline at end of file +}