Skip to content

[improve][build] Add Maven publishing conventions for ASF release#25457

Merged
merlimat merged 5 commits intoapache:masterfrom
lhotari:improve/build/maven-publish-conventions
Apr 8, 2026
Merged

[improve][build] Add Maven publishing conventions for ASF release#25457
merlimat merged 5 commits intoapache:masterfrom
lhotari:improve/build/maven-publish-conventions

Conversation

@lhotari
Copy link
Copy Markdown
Member

@lhotari lhotari commented Apr 1, 2026

Motivation

The Pulsar build was migrated from Maven to Gradle, but Maven publishing (deploying artifacts to Maven repositories) was not yet implemented. This PR adds the publishing infrastructure so artifacts land at the same Maven coordinates as before (org.apache.pulsar:*), with proper POM metadata, GPG signing, sources/javadoc JARs, and Gradle module metadata.

Modifications

Parent POM (build.gradle.kts)

The root project publishes org.apache.pulsar:pulsar as a POM-only parent artifact containing all shared ASF metadata (license, SCM, organization, mailing lists, developers, issue management). Child module POMs reference this via <parent>, inheriting metadata instead of embedding it — matching the Maven build's parent POM structure.

Convention plugins (build-logic/)

pulsar.public-java-library-conventions (new) — combined plugin for published Java library modules that applies both pulsar.java-conventions and pulsar.publish-conventions. Establishes a clear convention boundary: modules using this plugin are public libraries published to Maven, while internal-only modules use just pulsar.java-conventions. Includes dependency validation ensuring public modules don't depend on unpublished projects.

pulsar.publish-conventions (new) — core publishing plugin configuring maven-publish and signing:

  • java-library modules: publishes JAR + sources JAR + javadoc JAR + POM + Gradle module metadata (.module), with version mapping that inlines resolved dependency versions into the POM
  • java-platform modules (pulsar-bom, pulsar-dependencies): publishes POM + Gradle module metadata only (no JAR), with <packaging>pom</packaging> and <dependencyManagement> entries
  • Shadow/shaded modules (pulsar-client-shaded, pulsar-client-admin-shaded, pulsar-client-all, etc.): publishes the shadow JAR as the primary artifact
  • Child POM <parent> injection: every child POM gets a <parent> reference to the root parent POM via withXml
  • POM cleanup: removes <scope>compile</scope> (Maven default) and <dependencyManagement> from non-platform POMs
  • GPG signing: configurable via Gradle properties (useGpgCmd, signing.gnupg.keyName, signing.gnupg.homeDir), disabled by default for local development
  • Local deploy repository: build/local-deploy-repo via publishAllPublicationsToLocalDeployRepository task
  • Configuration cache compatible

pulsar.nar-conventions (updated) — now applies pulsar.publish-conventions and configures NAR-specific publishing:

  • Publishes only the .nar artifact with <packaging>nar</packaging>
  • POM has no <dependencies> section — NAR bundles everything
  • No sources/javadoc JARs (NAR is self-contained)
  • Unpublished example NAR modules (java-examples-builtin, client-tools-customcommand-example) disable publishing explicitly

Module changes

  • 52 published java-library modules: use id("pulsar.public-java-library-conventions")
  • 4 published NAR modules: use id("pulsar.java-conventions") + id("pulsar.nar-conventions") — publishing comes from nar-conventions
  • 2 platform modules (pulsar-bom, pulsar-dependencies): use id("pulsar.publish-conventions") directly
  • Unpublished modules (buildtools, tests/*, microbench, jclouds-shaded, etc.): use id("pulsar.java-conventions")

Modules changed to internal (no longer published):

  • jclouds-shaded — only referenced by tiered-storage/jcloud (a NAR module that bundles it)

Project coordinates (gradle.properties)

Moved group and version from the version catalog / pulsar.java-conventions to gradle.properties — the standard Gradle pattern. Gradle auto-applies these to all projects.

Other

  • gradle.properties: added systemProp.org.gradle.internal.publish.checksums.insecure=true for ASF Nexus compatibility
  • gradle/setup-test-gpg.sh: helper script to create a temporary GPG keyring for testing signing without touching ~/.gnupg

Verifying this change

  • Ran ./gradlew publishAllPublicationsToLocalDeployRepository — all 58 modules published successfully (52 java-library + 4 NAR + 2 platform)
  • Plus the root parent POM (org.apache.pulsar:pulsar)
  • Verified parent POM contains all ASF metadata (license, SCM, organization, developers, etc.)
  • Verified child POMs have <parent> reference and no inline metadata
  • Verified pulsar-bom produces only .pom + .module files with <dependencyManagement> entries
  • Verified pulsar-client-shaded publishes 24MB shadow JAR as primary artifact
  • Verified NAR modules publish .nar with <packaging>nar</packaging> and no <dependencies> section
  • Verified jclouds-shaded is NOT published
  • Verified example NAR modules (java-examples-builtin, client-tools-customcommand-example) are NOT published
  • Verified GPG signing produces .asc files when configured with a test key
  • Verified Gradle module metadata (.module files) published alongside all POMs
  • Verified configuration cache compatibility
  • Verified unpublished dependency validation: temporarily adding implementation(project(":buildtools")) to a published module correctly fails with:
    Published module ':pulsar-client-api' depends on unpublished projects:
      - implementation -> :buildtools (not published)
    Either publish the dependency or move it to a test/compileOnly scope.
    

Does this pull request potentially affect one of the following parts:

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Documentation

  • doc-not-needed

Add `pulsar.publish-conventions` Gradle convention plugin that configures
maven-publish and GPG signing for all publishable modules, matching the
artifact coordinates previously produced by the Maven build.

The convention plugin handles:
- java-library modules: JAR + sources + javadoc + POM + Gradle metadata
- java-platform modules (BOM/dependencies): POM + Gradle metadata only
- Shadow/shaded modules: shadow JAR as primary artifact
- NAR modules: .nar as primary artifact with packaging=nar
- ASF-compliant POM metadata (license, SCM, issue management, mailing lists)
- GPG signing (configurable, disabled by default for local dev)
- Local deploy repository for testing (build/local-deploy-repo)
- Configuration cache compatible
@lhotari lhotari requested a review from merlimat April 1, 2026 18:20
@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Apr 1, 2026
Comment thread bouncy-castle/bc/build.gradle.kts Outdated
Comment thread build-logic/conventions/src/main/kotlin/pulsar.publish-conventions.gradle.kts Outdated
Comment thread build-logic/conventions/src/main/kotlin/pulsar.publish-conventions.gradle.kts Outdated
…properties

- Publish root project as parent POM (org.apache.pulsar:pulsar) with
  all shared ASF metadata (license, SCM, organization, mailing lists,
  developers, issue management)
- Child module POMs now reference the parent via <parent> element,
  inheriting metadata instead of embedding it in every POM
- Move group and version from version catalog / java-conventions to
  gradle.properties (standard Gradle pattern for project coordinates)
- Remove pulsar version from libs.versions.toml
lhotari added 2 commits April 8, 2026 18:00
… publish

Add `pulsar.public-java-library-conventions` plugin that combines
`pulsar.java-conventions` and `pulsar.publish-conventions` into a single
plugin for published Java library modules. This establishes a clear
convention boundary: modules using this plugin are public libraries
published to Maven repositories, while internal-only modules use just
`pulsar.java-conventions`.

Also fix NAR module detection to use deferred `pluginManager.withPlugin`
instead of eager `plugins.hasPlugin`, ensuring correct behavior
regardless of plugin application order.
…ed projects

Add a publish-time validation check that ensures all project dependencies
in publishable scopes (api, implementation, runtimeOnly) point to
projects that also apply maven-publish. This prevents mistakes where a
consumer downloading from Maven Central couldn't resolve a dependency
because the referenced module was never published.

Test/compileOnly scoped dependencies are excluded since they don't
appear in the published POM.
Comment thread jclouds-shaded/build.gradle.kts Outdated
- Move NAR publishing into pulsar.nar-conventions: applies
  pulsar.publish-conventions and configures NAR-specific publication
  with .nar artifact and empty POM (no dependencies)
- NAR modules use pulsar.java-conventions + pulsar.nar-conventions
  instead of pulsar.public-java-library-conventions
- Downgrade jclouds-shaded to internal (only used by tiered-storage NAR)
- Move dependency validation from pulsar.publish-conventions to
  pulsar.public-java-library-conventions (NAR modules don't need it)
- Disable publishing for example NAR modules
@merlimat merlimat merged commit 41a3932 into apache:master Apr 8, 2026
79 of 82 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-not-needed Your PR changes do not impact docs ready-to-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants