Maven Publish Plugin - Gradle User Manual

# Maven Publish Plugin

This chapter describes the new Maven publishing support provided by the Maven Publish Plugin. This new publishing support is the preferred option for publishing artifacts and will eventually replace publishing via the `Upload` task.

If you are looking for documentation on the original Maven publishing support using the `Upload` task please see the chapters on publishing artifacts and the old Maven Plugin.

The Maven Publish Plugin provides the ability to publish build artifacts to an Apache Maven repository. A module published to a Maven repository can be consumed by Maven, Gradle (see Declaring Dependencies) and other tools that understand the Maven repository format.

## Usage

The Maven Publish Plugin uses an extension on the project named `publishing` of type `PublishingExtension`. This extension provides a container of named publications and a container of named repositories. The Maven Publish Plugin works with `MavenPublication` publications and `MavenArtifactRepository` repositories.

To use the Maven Publish Plugin, include the following in your build script:

Example: Applying the Maven Publish Plugin

`build.gradle`

    apply plugin: 'maven-publish'

Applying the Maven Publish Plugin does the following:

- Automatically creates a `GenerateMavenPom` task for each `MavenPublication` added (see the section called “Publications”).

- Automatically creates a `PublishToMavenRepository` task for the combination of each `MavenPublication` added (see the section called “Publications”), with each `MavenArtifactRepository` added (see the section called “Repositories”).

- Automatically creates a `PublishToMavenLocal` task for each `MavenPublication` added (see the section called “Publications”).

## Publications

If you are not familiar with project artifacts and configurations, you should read Publishing artifacts, which introduces these concepts. That chapter also describes publishing artifacts using a different mechanism than the one described in this chapter. The publishing functionality described here will eventually supersede that functionality.

Publication objects describe the structure/configuration of a publication to be created. Publications are published to repositories via tasks, and the configuration of the publication object determines exactly what is published. All of the publications of a project are defined in the `PublishingExtension.getPublications()` container. Each publication has a unique name within the project.

For the Maven Publish Plugin to have any effect, a `MavenPublication` must be added to the set of publications. This publication determines which artifacts are actually published as well as the details included in the associated POM file. A publication can be configured by adding components, customizing artifacts, and by modifying the generated POM file directly.

### Publishing a Software Component

The simplest way to publish a Gradle project to a Maven repository is to specify a `SoftwareComponent` to publish. The components presently available for publication are:

`java` — provider: Java Plugin

  Generated JAR file, dependencies from `runtime` configuration

`web` — provider: War Plugin

  Generated WAR file, no dependencies

In the following example, artifacts and runtime dependencies are taken from the `java` component, which is added by the Java Plugin.

Example: Adding a MavenPublication for a Java component

`build.gradle`

    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
            }
        }
    }

### Publishing custom artifacts

It is also possible to explicitly configure artifacts to be included in the publication. Artifacts are commonly supplied as raw files, or as instances of `AbstractArchiveTask` (e.g. `Jar` or `Zip`).

For each custom artifact, it is possible to specify the `extension` and `classifier` values to use for publication. Note that only one of the published artifacts can have an empty classifier, and all other artifacts must have a unique classifier/extension combination.

Configure custom artifacts as follows:

Example: Adding an additional archive artifact to a MavenPublication

`build.gradle`

    task sourceJar(type: Jar) {
        from sourceSets.main.allJava
    }

    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java

                artifact sourceJar {
                    classifier "sources"
                }
            }
        }
    }

In addition, instances of `PublishArtifact` can be added to a publication. For example, let’s assume you have a custom `rpm` task that produces an RPM package of your application and writes it to `rpmFile`. The following sample demonstrates how to create a `PublishArtifact` using the `artifacts.add()` method and add it to a publication:

Example: Adding an additional custom artifact to a MavenPublication

`build.gradle`

    def rpmFile = file("$buildDir/rpms/my-package.rpm")
    def rpmArtifact = artifacts.add("archives", rpmFile) {
        type "rpm"
        builtBy "rpm"
    }
    publishing {
        publications {
            maven(MavenPublication) {
                artifact rpmArtifact
            }
        }
    }

See the `MavenPublication` class in the API documentation for more information about how artifacts can be customized.

### Identity values in the generated POM

The attributes of the generated POM file will contain identity values derived from the following project properties:

- `groupId` - `Project.getGroup()`

- `artifactId` - `Project.getName()`

- `version` - `Project.getVersion()`

Overriding the default identity values is easy: simply specify the `groupId`, `artifactId` or `version` attributes when configuring the `MavenPublication`.

Example: customizing the publication identity

`build.gradle`

    publishing {
        publications {
            maven(MavenPublication) {
                groupId 'org.gradle.sample'
                artifactId 'project1-sample'
                version '1.1'

                from components.java
            }
        }
    }

Certain repositories will not be able to handle all supported characters. For example, the `:` character cannot be used as an identifier when publishing to a filesystem-backed repository on Windows.

Maven restricts 'groupId' and 'artifactId' to a limited character set (`[A-Za-z0-9_\\-.]+`) and Gradle enforces this restriction. For 'version' (as well as artifact 'extension' and 'classifier'), Gradle will handle any valid Unicode character.

The only Unicode values that are explicitly prohibited are `\`, `/` and any ISO control character. Supplied values are validated early in publication.

### Customizing the generated POM

The generated POM file can be customized before publishing. For example, when publishing a library to Maven Central you will need to set certain metadata. The Maven Publish Plugin provides a DSL for that purpose. Please see `MavenPom` in the DSL Reference for the complete documentation of available properties and methods. The following sample shows how to use the most common ones:

Example: Customizing the POM file

`build.gradle`

    publishing {
        publications {
            mavenJava(MavenPublication) {
                pom {
                    name = 'My Library'
                    description = 'A concise description of my library'
                    url = 'http://www.example.com/library'
                    licenses {
                        license {
                            name = 'The Apache License, Version 2.0'
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    developers {
                        developer {
                            id = 'johnd'
                            name = 'John Doe'
                            email = 'john.doe@example.com'
                        }
                    }
                    scm {
                        connection = 'scm:git:git://example.com/my-library.git'
                        developerConnection = 'scm:git:ssh://example.com/my-library.git'
                        url = 'http://example.com/my-library/'
                    }
                }
            }
        }
    }

### Publishing multiple modules

Sometimes it’s useful to publish multiple modules from your Gradle build, without creating a separate Gradle subproject. An example is publishing a separate API and implementation JAR for your library. With Gradle this is simple:

Example: Publishing multiple modules from a single project

`build.gradle`

    task apiJar(type: Jar) {
        baseName "publishing-api"
        from sourceSets.main.output
        exclude '**/impl/**'
    }

    publishing {
        publications {
            impl(MavenPublication) {
                groupId 'org.gradle.sample.impl'
                artifactId 'project2-impl'
                version '2.3'

                from components.java
            }
            api(MavenPublication) {
                groupId 'org.gradle.sample'
                artifactId 'project2-api'
                version '2'

                artifact apiJar
            }
        }
    }

If a project defines multiple publications then Gradle will publish each of these to the defined repositories. Each publication must be given a unique identity as described above.

## Repositories

Publications are published to repositories. The repositories to publish to are defined by the `PublishingExtension.getRepositories()` container.

Example: Declaring repositories to publish to

`build.gradle`

    publishing {
        repositories {
            maven {
                // change to point to your repo, e.g. http://my.org/repo
                url "$buildDir/repo"
            }
        }
    }

The DSL used to declare repositories for publication is the same DSL that is used to declare repositories to consume dependencies from, `RepositoryHandler`. However, in the context of Maven publication only `MavenArtifactRepository` repositories can be used for publication.

### Snapshot and release repositories

It is a common practice to publish snapshots and releases to different Maven repositories. A simple way to accomplish this is to configure the repository URL based on the project version. The following sample uses one URL for versions that end with "SNAPSHOT" and a different URL for the rest:

Example: Configuring repository URL based on project version

`build.gradle`

    publishing {
        repositories {
            maven {
                def releasesRepoUrl = "$buildDir/repos/releases"
                def snapshotsRepoUrl = "$buildDir/repos/snapshots"
                url version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl
            }
        }
    }

Similarly, you can use a project or system property to decide which repository to publish to. The following example uses the release repository if the project property `release` is set, such as when a user runs `gradle -Prelease publish`:

Example: Configuring repository URL based on project property

`build.gradle`

    publishing {
        repositories {
            maven {
                def releasesRepoUrl = "$buildDir/repos/releases"
                def snapshotsRepoUrl = "$buildDir/repos/snapshots"
                url project.hasProperty("release") ? releasesRepoUrl : snapshotsRepoUrl
            }
        }
    }

## Performing a publish

The Maven Publish Plugin automatically creates a `PublishToMavenRepository` task for each `MavenPublication` and `MavenArtifactRepository` combination in the `publishing.publications` and `publishing.repositories` containers respectively.

The created task is named `publish«PUBNAME»PublicationTo«REPONAME»Repository`.

Example: Publishing a project to a Maven repository

`build.gradle`

    apply plugin: 'java'
    apply plugin: 'maven-publish'

    group = 'org.gradle.sample'
    version = '1.0'

    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
            }
        }
    }
    publishing {
        repositories {
            maven {
                // change to point to your repo, e.g. http://my.org/repo
                url "$buildDir/repo"
            }
        }
    }

Output of `gradle publish`

    > gradle publish
    > Task :generatePomFileForMavenJavaPublication
    > Task :compileJava
    > Task :processResources NO-SOURCE
    > Task :classes
    > Task :jar
    > Task :publishMavenJavaPublicationToMavenRepository
    > Task :publish

    BUILD SUCCESSFUL in 0s
    4 actionable tasks: 4 executed

In this example, a task named `publishMavenJavaPublicationToMavenRepository` is created, which is of type `PublishToMavenRepository`. This task is wired into the `publish` lifecycle task. Executing `gradle publish` builds the POM file and all of the artifacts to be published, and transfers them to the repository.

## Publishing to Maven Local

For integration with a local Maven installation, it is sometimes useful to publish the module into the local .m2 repository. In Maven parlance, this is referred to as 'installing' the module. The Maven Publish Plugin makes this easy to do by automatically creating a `PublishToMavenLocal` task for each `MavenPublication` in the `publishing.publications` container. Each of these tasks is wired into the `publishToMavenLocal` lifecycle task. You do not need to have `mavenLocal` in your `publishing.repositories` section.

The created task is named `publish«PUBNAME»PublicationToMavenLocal`.

Example: Publish a project to the Maven local repository

Output of `gradle publishToMavenLocal`

    > gradle publishToMavenLocal
    > Task :generatePomFileForMavenJavaPublication
    > Task :compileJava
    > Task :processResources NO-SOURCE
    > Task :classes
    > Task :jar
    > Task :publishMavenJavaPublicationToMavenLocal
    > Task :publishToMavenLocal

    BUILD SUCCESSFUL in 0s
    4 actionable tasks: 4 executed

The resulting task in this example is named `publishMavenJavaPublicationToMavenLocal`. This task is wired into the `publishToMavenLocal` lifecycle task. Executing `gradle publishToMavenLocal` builds the POM file and all of the artifacts to be published, and installs them into the local Maven repository.

## Conditional publishing

When you have defined multiple publications or repositories, you often want to control which publications are published to which repositories. For instance, consider the following sample that defines two publications and two repositories:

Example: Adding multiple publications and repositories

`build.gradle`

    publishing {
        publications {
            binary(MavenPublication) {
                from components.java
            }
            binaryAndSources(MavenPublication) {
                from components.java
                artifact sourcesJar
            }
        }
        repositories {
            // change URLs to point to your repos, e.g. http://my.org/repo
            maven {
                name "external"
                url "$buildDir/repos/external"
            }
            maven {
                name "internal"
                url "$buildDir/repos/internal"
            }
        }
    }

You may not want build users publishing both types of publications to both repositories, but the plugin automatically generates tasks for all possible combinations. So how do you stop someone from publishing the `binaryAndSources` publication to the `external` repository?

You can configure the tasks generated by the Maven Publish Plugin to be skipped based on certain criteria. The following sample demonstrates how to restrict the `binary` publication to the `external` repository and the `binaryAndSources` publication to the `internal` repository. In addition, it configures only `binaryAndSources` to be published to the local Maven repository.

Example: Configuring which artifacts should be published to which repositories

`build.gradle`

    tasks.withType(PublishToMavenRepository) {
        onlyIf {
            if (repository == publishing.repositories.external)
                return publication == publishing.publications.binary
            if (repository == publishing.repositories.internal)
                return publication == publishing.publications.binaryAndSources
            return false
        }
    }
    tasks.withType(PublishToMavenLocal) {
        onlyIf {
            publication == publishing.publications.binaryAndSources
        }
    }

Output of `gradle publish publishToMavenLocal`

    > gradle publish publishToMavenLocal
    > Task :generatePomFileForBinaryAndSourcesPublication
    > Task :compileJava
    > Task :processResources
    > Task :classes
    > Task :jar
    > Task :sourcesJar
    > Task :publishBinaryAndSourcesPublicationToExternalRepository SKIPPED
    > Task :publishBinaryAndSourcesPublicationToInternalRepository
    > Task :generatePomFileForBinaryPublication
    > Task :publishBinaryPublicationToExternalRepository
    > Task :publishBinaryPublicationToInternalRepository SKIPPED
    > Task :publish
    > Task :publishBinaryAndSourcesPublicationToMavenLocal
    > Task :publishBinaryPublicationToMavenLocal SKIPPED
    > Task :publishToMavenLocal

    BUILD SUCCESSFUL in 0s
    9 actionable tasks: 9 executed

Moreover, you may want to define your own shorthand tasks to fit your workflow. The following sample defines two tasks: `publishToExternalRepository` to publish all publications to the `external` repository and `publishForDevelopment` to publish all publications to the `internal` and the local Maven repositories:

Example: Defining your own shorthand tasks for publishing

`build.gradle`

    task publishToExternalRepository {
        group "publishing"
        description "Publishes all Maven publications to Maven repository 'external'."
        dependsOn tasks.withType(PublishToMavenRepository).matching {
            it.repository == publishing.repositories.external
        }
    }
    task publishForDevelopment {
        group "publishing"
        description "Publishes all Maven publications to Maven repository 'internal' and the local Maven repository."
        dependsOn tasks.withType(PublishToMavenRepository).matching {
            it.repository == publishing.repositories.internal
        }
        dependsOn tasks.withType(PublishToMavenLocal)
    }

## Signing artifacts

The Signing Plugin can be used to sign all artifacts, including generated ones like the POM, of a publication. In order to use it, first apply the `signing` plugin and configure the signatory credentials (please refer to the plugin’s documentation for details). Then, specify the publications you want to have signed using the `signing` DSL.

Example: Signing a publication

`build.gradle`

    signing {
        sign publishing.publications.mavenJava
    }

For each specified publication, this will create a `Sign` task and wire all `publish«PUBNAME»PublicationTo«REPONAME»Repository` tasks to depend on it. Thus, you can simply execute `gradle publish` to sign and publish.

Example: Sign and publish a project

Output of `gradle publish`

    > gradle publish
    > Task :generatePomFileForMavenJavaPublication
    > Task :compileJava
    > Task :processResources
    > Task :classes
    > Task :jar
    > Task :javadoc
    > Task :javadocJar
    > Task :sourcesJar
    > Task :signMavenJavaPublication
    > Task :publishMavenJavaPublicationToMavenRepository
    > Task :publish

    BUILD SUCCESSFUL in 0s
    9 actionable tasks: 9 executed

## Generating the POM file without publishing

At times it is useful to generate a Maven POM file for a module without actually publishing. Since POM generation is performed by a separate task, it is very easy to do so.

The task for generating the POM file is of type `GenerateMavenPom`, and it is given a name based on the name of the publication: `generatePomFileFor«PUBNAME»Publication`. So in the example below, where the publication is named `mavenCustom`, the task will be named `generatePomFileForMavenCustomPublication`.

Example: Generate a POM file without publishing

`build.gradle`

    generatePomFileForMavenCustomPublication {
        destination = file("$buildDir/generated-pom.xml")
    }

Output of `gradle generatePomFileForMavenCustomPublication`

    > gradle generatePomFileForMavenCustomPublication
    > Task :generatePomFileForMavenCustomPublication

    BUILD SUCCESSFUL in 0s
    1 actionable task: 1 executed

All details of the publishing model are still considered in POM generation, including `components`, custom `artifacts`, and any modifications made via `pom`.

## Complete example

The following example demonstrates how to sign and publish a Java library including sources, Javadoc, and a customized POM:

Example: Publishing a Java library

`build.gradle`

    apply plugin: 'java-library'
    apply plugin: 'maven-publish'
    apply plugin: 'signing'

    group = 'com.example'
    version = '1.0'

    task sourcesJar(type: Jar) {
        from sourceSets.main.allJava
        classifier 'sources'
    }

    task javadocJar(type: Jar) {
        from javadoc
        classifier 'javadoc'
    }

    publishing {
        publications {
            mavenJava(MavenPublication) {
                artifactId 'my-library'
                from components.java
                artifact sourcesJar
                artifact javadocJar
                pom {
                    name = 'My Library'
                    description = 'A concise description of my library'
                    url = 'http://www.example.com/library'
                    licenses {
                        license {
                            name = 'The Apache License, Version 2.0'
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    developers {
                        developer {
                            id = 'johnd'
                            name = 'John Doe'
                            email = 'john.doe@example.com'
                        }
                    }
                    scm {
                        connection = 'scm:git:git://example.com/my-library.git'
                        developerConnection = 'scm:git:ssh://example.com/my-library.git'
                        url = 'http://example.com/my-library/'
                    }
                }
            }
        }
        repositories {
            maven {
                // change URLs to point to your repos, e.g. http://my.org/repo
                def releasesRepoUrl = "$buildDir/repos/releases"
                def snapshotsRepoUrl = "$buildDir/repos/snapshots"
                url version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            }
        }
    }

    signing {
        sign publishing.publications.mavenJava
    }

The result is that the following artifacts will be published:

- The POM: `my-library-1.0.pom`

- The primary JAR artifact for the Java component: `my-library-1.0.jar`

- The sources JAR artifact that has been explicitly configured: `my-library-1.0-sources.jar`

- The Javadoc JAR artifact that has been explicitly configured: `my-library-1.0-javadoc.jar`

The Signing Plugin is used to generate a signature file for each artifact. In addition, checksum files will be generated for all artifacts and signature files.

## Removal of deferred configuration behavior

Gradle 5.0 will change the behavior of the publishing {} block. Read on to find out how you can make your build compatible today.

Until Gradle 4.7, the `publishing {}` block was implicitly treated as if all the logic inside it was executed after the project is evaluated. This caused quite a bit of confusion, because it was the only block that behaved that way. As part of the stabilization effort in Gradle 4.8, we are deprecating this behavior and asking all users to migrate their build.

The new, stable behavior can be switched on by adding the following to your settings file:

    enableFeaturePreview('STABLE_PUBLISHING')

We recommend doing a test run with a local repository to see whether all artifacts still have the expected coordinates. In most cases everything should work as before and you are done.

If the coordinates change unexpectedly, you may have some logic inside your publishing block or in a plugin that is depending on the deferred configuration behavior. For instance, the following logic assumes that the subprojects will be evaluated when the artifactId is set:

    subprojects {
        publishing {
            publications {
                mavenJava {
                    from components.java
                    artifactId = jar.baseName
                }
            }
        }
    }

This kind of logic must be wrapped in an `afterEvaluate {}` block to make it work going forward.

    subprojects {
        publishing {
            publications {
                mavenJava {
                    from components.java
                    afterEvaluate {
                        artifactId = jar.baseName
                    }
                }
            }
        }
    }