Chapter 26Lesson 01~255 minutes

Gradle Publishing, Maven Publish, Ivy Publish, Signing, Metadata, and Repository Promotion: Concepts, Architecture, and Mental Model

Model publication as an external contract: choose a component, bind stable coordinates, generate interoperable metadata, publish immutable bytes to a repository boundary, and treat credentials and signatures as security-sensitive inputs.

Gradle 9.7.1maven-publishivy-publishGMMSigning

Learning objectives

  • Separate build outputs, software components, publications, repositories, coordinates, metadata, signatures, and promotion state.
  • Explain why POM/Ivy metadata and Gradle Module Metadata coexist and where interoperability can become lossy.
  • Distinguish a checksum from an OpenPGP signature and distinguish publishing from repository promotion.
  • Inspect publication-related model and tasks before mutating a repository.
  • Identify credential, signing-key, repository-write, and immutable-version trust boundaries.

1. Why “the JAR built” is not enough

Chapter 25 ended with a build whose performance could be measured without changing its output. A release pipeline now has a different problem: the output must cross the build boundary and become a contract that other builds can resolve later. A lone JAR file does not tell a Maven consumer its coordinates, dependencies, source/Javadoc companions, or release policy. It also does not prove who signed it or whether the same version was overwritten yesterday.

Publishing is therefore not “copy the JAR somewhere.” It is a controlled state transition from a project-local build model to a repository-visible module identity. The exact bytes matter, but so do metadata, repository layout, credentials, signatures, and promotion rules.

Trust boundary: A Gradle publishing task can send arbitrary project files and metadata to a repository while running with CI credentials and signing material. Review the build logic that selects publications and repository URLs with the same care as deployment code.

2. The publication model

Object / state Meaning Typical evidence Trust question
Software component Gradle model of consumable variants produced by plugins such as java-library. ./gradlew outgoingVariants; components["java"]. Are the variants and dependencies intended to become a public contract?
Publication A named external representation assembled from a component plus coordinates, artifacts, and metadata. MavenPublication or IvyPublication; generated POM/ivy.xml/GMM. Does the publication preserve the semantics consumers actually need?
Repository Destination/layout and transport used to store immutable published state. Disposable file tree, Maven/Ivy layout, repository URL, authentication type. Who can write, overwrite, or promote?
Coordinates Stable external identity: Maven groupId:artifactId:version; Ivy organisation/module/revision. Generated descriptor path and consumer declaration. Can the same release identity ever point to different bytes?
POM / ivy.xml Interoperability metadata understood by Maven/Ivy ecosystems. Generated descriptor and downstream Maven/Gradle resolution. Did Gradle-only semantics degrade or disappear during mapping?
Gradle Module Metadata Variant-aware metadata published alongside POM/Ivy descriptors. .module file with variants, attributes, capabilities and checksums. Will non-Gradle consumers see an equivalent enough contract?
Detached signature OpenPGP evidence over a published file; distinct from a checksum. .asc files and independent verification. Is the signing key protected and is verification policy defined?
Promotion Repository-management act that advances already-built bytes from one trust stage to another. Same SHA-256 before/after; repository audit trail. Did promotion reuse exact bytes, or silently rebuild/overwrite?

The most important separation is component → publication → repository. The Java plugin creates the java software component. The Maven/Ivy publishing plugins do not automatically mean “publish everything”; you create named publications and explicitly say what component/artifacts belong to them. Repository declarations then create destination-specific publish tasks.

3. From project model to external consumers

Publication flow: model → descriptors → repository → consumers
flowchart TD
  A[Java sources + build.gradle.kts] --> B[Java software component]
  B --> C[MavenPublication / IvyPublication]
  C --> D[POM or ivy.xml]
  C --> E[Gradle Module Metadata]
  C --> F[JAR + sources + Javadoc]
  D --> G[Disposable repository]
  E --> G
  F --> G
  G --> H[Gradle consumer]
  G --> I[Maven or Ivy consumer]
  G --> J[Promotion gate]
  J --> K[Release repository]

The first arrow is build configuration: the Java plugin knows which outgoing variants and artifacts exist. The second arrow selects which component becomes a publication. The publication generates repository-format metadata plus Gradle Module Metadata. The repository stores those files under an external coordinate. Promotion is shown separately because a repository manager should normally move or expose already-built bytes; it should not trigger another compilation.

4. Maven Publish and Ivy Publish are related but not interchangeable

maven-publish works with MavenPublication and Maven-compatible repositories. ivy-publish works with IvyPublication and Ivy repositories. Both can publish the same Java component, but they serialize identity and dependency metadata according to different repository models.

Question Maven publication Ivy publication
Primary identity groupId:artifactId:version organisation / module / revision
Native descriptor POM XML ivy.xml
Gradle-rich descriptor .module alongside POM .module alongside ivy.xml
Typical interoperability Maven, Gradle, many JVM tools Gradle/Ivy-aware consumers and custom layouts
Course rule Default compatibility target for the checkpoint Teach and inspect; do not force Maven consumers to understand Ivy

5. Why Gradle Module Metadata exists beside POM/Ivy metadata

A POM is excellent for Maven’s dependency model, but Gradle can express richer variant state: attributes, capabilities, dependency constraints, and variant-specific artifacts. Gradle Module Metadata (GMM) serializes that richer component model. Gradle publishes GMM alongside POM or Ivy metadata so Gradle consumers can recover the richer model while Maven/Ivy consumers still have their native descriptor.

This creates an interoperability obligation: if a Gradle-only concept cannot be represented faithfully in POM/Ivy metadata, Gradle can emit publication warnings. Suppressing a warning does not make the semantic mismatch disappear. The production response is to decide whether the Maven/Ivy view remains acceptable, redesign the public variant model, or consciously limit the consumer ecosystem.

6. Coordinates are an immutable public identity

For the lab, the Maven identity is dev.academy.publish:ledger-api:1.0.0. Once consumers can resolve that identity from an authoritative release repository, the safest production rule is that the coordinate is immutable: later code changes require a new version.

A file repository used in a lab may happily overwrite files. That behavior is exactly why it is not an authoritative production release policy. Repository-manager immutability, staging, retention, and promotion are separate operational controls that the Gradle build should respect rather than try to replace.

7. Checksums, signatures, and provenance are different claims

A checksum answers: “Are these bytes the same bytes I measured?” A detached OpenPGP signature additionally binds bytes to a signing key under a verification policy. A signature is not a vulnerability scan, SBOM, reproducible-build proof, or authorization to release. Those are separate evidence streams.

Gradle’s Signing Plugin signs artifacts/publications and can publish detached .asc signatures. Its OpenPGP private key is therefore a high-value secret. This chapter never embeds a real key or passphrase in a build script. The optional lab key is generated in a disposable directory, has no production trust, and is deleted with the lab.

8. Repository credentials belong outside build logic

File repositories need no credentials. Real HTTPS repositories commonly do. Gradle supports typed credentials and can derive property names from a repository name. For a repository named releases, a PasswordCredentials declaration can resolve releasesUsername and releasesPassword from Gradle property sources.

That still does not make the values safe to print. Do not log credentials, put them in Git, bake them into a Docker image, or pass them into arbitrary untrusted build logic. In CI, supply them through the platform’s secret facility and constrain which branches/jobs are allowed to publish.

9. Read-only inspection before publication

# Run in a trusted Wrapper-enabled project.
java -version
./gradlew --version
./gradlew projects
./gradlew outgoingVariants
./gradlew tasks --group publishing
./gradlew properties | grep -E '^(group|version|name):' || true

outgoingVariants lets you inspect the component contract before a publication object serializes it. tasks --group publishing shows which generation/publish tasks exist after the plugins are applied. Neither command should upload anything. Keep this evidence in CI logs before write-capable tasks are allowed to run.

10. Publish, stage, promote, and release are different verbs

Publish writes a publication to a repository. Stage writes to a location that is not yet the authoritative release channel. Promote advances already-built artifacts/metadata from staging to release according to repository policy. Release is the broader organizational decision that those immutable coordinates are supported and discoverable.

Gradle can publish directly to a Maven/Ivy repository, but a production repository manager usually owns promotion, immutability, retention, quarantine, and permission boundaries. The local checkpoint simulates promotion by copying an already-published coordinate tree only after comparing hashes; it explicitly refuses to overwrite an existing release identity.

11. DevOps operating rule

A production build-engineering team should be able to answer five questions from evidence: what component was published, under which exact coordinate, what metadata did each consumer ecosystem receive, what bytes were signed/promoted, and which principal was authorized to write them? If those answers depend on a developer’s Maven Local cache or a mutable URL, the release process is not yet auditable.

Knowledge check

Does applying maven-publish automatically publish every file in build/?

Why publish GMM next to a POM instead of replacing the POM?

If a JAR SHA-256 matches, is an OpenPGP signature redundant?

What should promotion do to the artifact bytes?

Why is Maven Local unsuitable as the authoritative release repository?

Official references and version notes

Version-sensitive behavior was rechecked against current Gradle and Apache Maven primary documentation on 2026-08-24. Mandatory publication uses only repository-owned files plus disposable file: repositories under the lab workspace. Maven Local, real credentials, real release repositories, hosted signing, Maven Central, Nexus/Artifactory administration, and CI-specific secret stores are not mandatory.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.