Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bouncy-castle/bc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

plugins {
id("pulsar.java-conventions")
id("pulsar.public-java-library-conventions")
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion bouncy-castle/bcfips/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

plugins {
id("pulsar.java-conventions")
id("pulsar.public-java-library-conventions")
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ plugins {

val catalog = the<VersionCatalogsExtension>().named("libs")

group = "org.apache.pulsar"
version = catalog.findVersion("pulsar").get().requiredVersion

tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release.set(17)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@

// Convention plugin for NAR (Nifi Archive) modules.
// Configures platform module exclusions from runtimeClasspath, forces JAR artifacts
// for bundled-dependencies, and handles archive name qualification.
// for bundled-dependencies, handles archive name qualification, and publishes the
// NAR artifact with an empty POM (no dependencies — everything is bundled).

plugins {
id("io.github.merlimat.nar")
id("pulsar.publish-conventions")
}

// NAR modules should not bundle Pulsar platform dependencies — they are provided
Expand Down Expand Up @@ -91,3 +93,26 @@ if (parentProject != null && parentProject != rootProject && parentProject.paren
val narIdProp = narExt.javaClass.getMethod("getNarId").invoke(narExt) as org.gradle.api.provider.Property<String>
narIdProp.set(qualifiedName)
}

// --- NAR publishing: publish only the .nar artifact with an empty POM ---
// NAR modules bundle all dependencies, so the POM should have no <dependencies> section.
publishing {
publications {
named<MavenPublication>("maven") {
// Replace component-based artifacts with just the NAR file
artifacts.clear()
artifact(tasks.named("nar"))
pom {
packaging = "nar"
// Remove all dependencies — NAR bundles everything
withXml {
val root = asNode()
root.children().removeAll { node ->
val name = (node as groovy.util.Node).name()
name.toString().contains("dependencies")
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.
*/

// Convention plugin for public Pulsar Java libraries that are published to Maven repositories.
// Combines java-conventions (compilation, testing) with publish-conventions (Maven publishing,
// signing, POM metadata). Internal-only modules should use pulsar.java-conventions directly.

plugins {
id("pulsar.java-conventions")
id("pulsar.publish-conventions")
}

// Validate that public java-library modules only depend on other published modules
// in scopes that end up in the published POM (api, implementation, runtimeOnly).
// Test/compileOnly scoped dependencies are excluded since they don't appear in the POM.
// NAR modules are not validated here — they bundle all dependencies and have empty POMs.
run {
val publishedScopes = listOf("api", "implementation", "runtimeOnly")
val configsToCheck = publishedScopes.mapNotNull { name ->
configurations.findByName(name)?.let { name to it }
}
val currentProjectPath = project.path

val unpublishedDeps = provider {
val errors = mutableListOf<String>()
for ((configName, config) in configsToCheck) {
for (dep in config.dependencies) {
if (dep is ProjectDependency) {
val depPath = dep.path
val depProject = project.rootProject.project(depPath)
if (!depProject.plugins.hasPlugin("maven-publish")) {
errors.add(" - $configName -> $depPath (not published)")
}
}
}
}
errors
}

tasks.withType<PublishToMavenRepository>().configureEach {
val errorList = unpublishedDeps
doFirst {
val errors = errorList.get()
if (errors.isNotEmpty()) {
throw GradleException(
"Published module '$currentProjectPath' depends on unpublished projects:\n" +
errors.joinToString("\n") + "\n" +
"Either publish the dependency or move it to a test/compileOnly scope."
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* 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.
*/

// Convention plugin for publishing Pulsar modules to Maven repositories.
// Configures maven-publish, GPG signing, POM metadata, sources/javadoc JARs,
// and a local deploy repository for testing.

plugins {
`maven-publish`
signing
}

// --- java-library projects: JAR + sources + javadoc ---
pluginManager.withPlugin("java-library") {
val sourceSets = the<SourceSetContainer>()

// Match Maven's javadoc configuration: no doclint, don't fail on errors
tasks.withType<Javadoc>().configureEach {
(options as StandardJavadocDocletOptions).apply {
addStringOption("Xdoclint:none", "-quiet")
}
isFailOnError = false
}

val sourcesJar by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets["main"].allJava)
}

val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
from(tasks.named(JavaPlugin.JAVADOC_TASK_NAME))
}

// Standard java-library modules: publish from components["java"]
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
artifact(sourcesJar)
artifact(javadocJar)

versionMapping {
usage(Usage.JAVA_RUNTIME) {
fromResolutionResult()
}
usage(Usage.JAVA_API) {
fromResolutionOf("runtimeClasspath")
}
}
}
}
}

}

// --- java-platform projects (BOM, dependencies): POM-only, no JAR ---
pluginManager.withPlugin("java-platform") {
publishing {
publications {
create<MavenPublication>("maven") {
from(components["javaPlatform"])
}
}
}
}

// --- Common POM configuration for all publications ---
run {
// Capture values in a local scope so withXml closures don't capture the script object
// (which would break configuration cache serialization)
val projectName = project.name
val projectDescription = project.description
val archivesNameValue = the<BasePluginExtension>().archivesName.get()
val isPlatformProject = plugins.hasPlugin("java-platform")
val isRootProject = project == rootProject
val pulsarVersion = version.toString()
val localDeployRepoDir = rootProject.layout.buildDirectory.dir("local-deploy-repo")

publishing {
publications {
withType<MavenPublication>().configureEach {
artifactId = archivesNameValue

pom {
// Per-module name and description
if (!isRootProject) {
name.set("Apache Pulsar :: $projectName")
description.set(projectDescription ?: "Apache Pulsar :: $projectName")
}

// Clean up POM XML and inject <parent> reference
withXml {
val sb = asString()
var s = sb.toString()
// <scope>compile</scope> is the Maven default — remove for cleaner POM
s = s.replace("<scope>compile</scope>", "")
// Remove dependencyManagement from non-platform POMs
// (platform POMs need it — their dependencies ARE the management section)
if (!isPlatformProject) {
s = s.replace(
Regex(
"<dependencyManagement>.*?</dependencyManagement>",
RegexOption.DOT_MATCHES_ALL
),
""
)
}
// Inject <parent> reference for child modules (not the root/parent POM itself).
// Metadata (license, SCM, etc.) is inherited from the parent POM.
if (!isRootProject) {
s = s.replace(
"<modelVersion>4.0.0</modelVersion>",
"<modelVersion>4.0.0</modelVersion>\n <parent>\n" +
" <groupId>org.apache.pulsar</groupId>\n" +
" <artifactId>pulsar</artifactId>\n" +
" <version>$pulsarVersion</version>\n" +
" </parent>"
)
}
sb.setLength(0)
sb.append(s)
// Re-format the XML
asNode()
}
}
}
}

// Local Maven repository for testing/comparison
repositories {
maven {
name = "localDeploy"
url = uri(localDeployRepoDir)
}
}
}
}

// --- GPG signing ---
signing {
isRequired = !version.toString().endsWith("-SNAPSHOT")

val useGpgCmd = providers.gradleProperty("useGpgCmd").orNull?.toBoolean() ?: false
if (useGpgCmd) {
useGpgCmd()
}

sign(publishing.publications)
}

// Disable signing tasks when no key is configured (local dev without signing)
tasks.withType<Sign>().configureEach {
enabled = providers.gradleProperty("signing.keyId").isPresent ||
providers.gradleProperty("signing.gnupg.keyName").isPresent
}

// Suppress enforced-platform validation: all java-library modules use
// enforcedPlatform(":pulsar-dependencies") for internal version alignment,
// but this should not leak to consumers. The dependencyManagement section
// is stripped from published POMs via withXml above.
tasks.withType<GenerateModuleMetadata>().configureEach {
suppressedValidationErrors.add("enforced-platform")
}

Loading
Loading