Maven发布插件提供了将构建工件发布到Apache Maven存储库的功能. 发布到Maven存储库的模块可由Maven,Gradle(请参阅声明依赖项 )和其他了解Maven存储库格式的工具使用. 您可以在发布概述中了解发布的基础知识.

Usage

要使用Maven发布插件,请在构建脚本中包括以下内容:

示例1.应用Maven发布插件
build.gradle
plugins {
    id 'maven-publish'
}
build.gradle.kts
plugins {
    `maven-publish`
}

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.

Tasks

generatePomFileForPubNamePublicationGenerateMavenPom

为名为PubName的发布创建一个POM文件,填充已知的元数据,例如项目名称,项目版本和依赖项. POM文件的默认位置是build / publications / $ pubName / pom-default.xml .

publishPubNamePublicationToRepoNameRepositoryPublishToMavenRepository

PubName发布发布到名为RepoName的存储库. 如果您的存储库定义没有明确的名称,则RepoName将为" Maven".

publishPubNamePublicationToMavenLocalPublishToMavenLocal

PubName发布以及本地发布的POM文件和其他元数据复制到本地Maven缓存中(通常为$ USER_HOME / .m2 / repository) .

publish

取决于 :全部publish PubName PublicationTo RepoName Repository任务

将所有定义的发布发布到所有定义的存储库的聚合任务. 它包括复制出版物本地Maven缓存.

publishToMavenLocal

取决于 :全部publish PubName PublicationToMavenLocal任务

将所有定义的发布(包括它们的元数据(POM文件等))复制到本地Maven缓存.

Publications

此插件提供出版物类型的MavenPublication . 要了解如何定义和使用发布,请参见基本发布部分.

您可以在Maven发布中配置以下四项主要内容:

您可以在完整的发布示例中看到所有这些内容. MavenPublication的API文档包含其他代码示例.

Identity values in the generated POM

生成的POM文件的属性将包含从以下项目属性派生的标识值:

覆盖默认标识值很容易:在配置MavenPublication时只需指定groupIdartifactIdversion属性.

示例2.定制发布标识
build.gradle
    publishing {
        publications {
            maven(MavenPublication) {
                groupId = 'org.gradle.sample'
                artifactId = 'project1-sample'
                version = '1.1'

                from components.java
            }
        }
    }
build.gradle.kts
    publishing {
        publications {
            create<MavenPublication>("maven") {
                groupId = "org.gradle.sample"
                artifactId = "project1-sample"
                version = "1.1"

                from(components["java"])
            }
        }
    }
💡

某些存储库将无法处理所有受支持的字符. 例如,在发布到Windows上由文件系统支持的存储库时, :字符不能用作标识符.

Maven将groupIdartifactId限制为一个有限的字符集( [A-Za-z0-9_\\-.]+ ),并且Gradle强制执行此限制. 对于version (以及工件extensionclassifier属性),Gradle将处理任何有效的Unicode字符.

明确禁止的唯一Unicode值是\/和任何ISO控制字符. 提供的值在发布早期就得到了验证.

Customizing the generated POM

可以在发布之前自定义生成的POM文件. 例如,将库发布到Maven Central时,您需要设置某些元数据. Maven发布插件为此提供了DSL. 请参阅DSL参考中的MavenPom ,以获取可用属性和方法的完整文档. 下面的示例演示如何使用最常见的方法:

例子3.定制POM文件
build.gradle
publishing {
    publications {
        mavenJava(MavenPublication) {
            pom {
                name = 'My Library'
                description = 'A concise description of my library'
                url = 'http://www.example.com/library'
                properties = [
                    myProp: "value",
                    "prop.with.dots": "anotherValue"
                ]
                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/'
                }
            }
        }
    }
}
build.gradle.kts
publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            pom {
                name.set("My Library")
                description.set("A concise description of my library")
                url.set("http://www.example.com/library")
                properties.set(mapOf(
                    "myProp" to "value",
                    "prop.with.dots" to "anotherValue"
                ))
                licenses {
                    license {
                        name.set("The Apache License, Version 2.0")
                        url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
                    }
                }
                developers {
                    developer {
                        id.set("johnd")
                        name.set("John Doe")
                        email.set("john.doe@example.com")
                    }
                }
                scm {
                    connection.set("scm:git:git://example.com/my-library.git")
                    developerConnection.set("scm:git:ssh://example.com/my-library.git")
                    url.set("http://example.com/my-library/")
                }
            }
        }
    }
}

Customizing dependencies versions

支持两种策略来发布依赖项:

Declared versions (default)

此策略使用dependencies块中的依赖项声明发布由构建脚本作者定义的版本. 发布不会考虑任何其他类型的处理,例如通过更改已解决版本的规则进行的处理.

Resolved versions

此策略可能会通过应用解决方案规则和自动冲突解决方案来发布在构建期间已解决的版本. 这样做的好处是,发布的版本对应于测试发布的工件的版本.

解析版本的示例用例:

  • 项目将动态版本用于依赖项,但更喜欢将给定版本的已解析版本公开给其使用者.

  • 依赖项锁定结合使用,您要发布锁定的版本.

  • 一个项目利用了Gradle的丰富版本约束,这些约束对Maven的转换是有损的. 它不依赖转换,而是发布已解决的版本.

这是通过使用versionMapping DSL方法完成的,该方法允许配置VersionMappingStrategy

例子4.使用解析版本
build.gradle
publishing {
    publications {
        mavenJava(MavenPublication) {
            versionMapping {
                usage('java-api') {
                    fromResolutionOf('runtimeClasspath')
                }
                usage('java-runtime') {
                    fromResolutionResult()
                }
            }
        }
    }
}
build.gradle.kts
publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            versionMapping {
                usage("java-api") {
                    fromResolutionOf("runtimeClasspath")
                }
                usage("java-runtime") {
                    fromResolutionResult()
                }
            }
        }
    }
}

在上面的示例中,Gradle将在runtimeClasspath上解析的版本用于api声明的依赖项,这些依赖项映射到Maven的compile范围. Gradle还将在runtimeClasspath上解析的版本用于在implementation声明的依赖项,这些依赖项映射到Maven的runtime范围. fromResolutionResult()表示Gradle应该使用变量的默认类路径, runtimeClasspathjava-runtime的默认类路径.

Repositories

该插件提供了MavenArtifactRepository类型的存储库 . 要了解如何定义和使用存储库进行发布,请参见" 基本发布 "部分.

这是定义发布存储库的简单示例:

示例5.声明要发布到的存储库
build.gradle
publishing {
    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = "$buildDir/repo"
        }
    }
}
build.gradle.kts
publishing {
    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = uri("$buildDir/repo")
        }
    }
}

您将要配置的两件事是存储库:

  • 网址(必填)

  • 名称(可选)

您可以定义多个存储库,只要它们在构建脚本中具有唯一的名称即可. 您也可以声明一个(只有一个)没有名称的存储库. 该存储库将采用隐式名称" Maven".

您还可以配置连接到存储库所需的任何身份验证详细信息. 有关更多详细信息,请参见MavenArtifactRepository .

Snapshot and release repositories

将快照和发行版发布到不同的Maven存储库是一种常见的做法. 一种简单的方法是根据项目版本配置存储库URL. 下面的示例对以" SNAPSHOT"结尾的版本使用一个URL,对其余版本使用不同的URL:

例子6.根据项目版本配置存储库URL
build.gradle
publishing {
    repositories {
        maven {
            def releasesRepoUrl = "$buildDir/repos/releases"
            def snapshotsRepoUrl = "$buildDir/repos/snapshots"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
        }
    }
}
build.gradle.kts
publishing {
    repositories {
        maven {
            val releasesRepoUrl = "$buildDir/repos/releases"
            val snapshotsRepoUrl = "$buildDir/repos/snapshots"
            url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
        }
    }
}

同样,您可以使用项目或系统属性来决定发布到哪个存储库. 如果设置了项目属性release ,例如在用户运行gradle -Prelease publish时,以下示例将使用release存储库:

示例7.根据项目属性配置存储库URL
build.gradle
publishing {
    repositories {
        maven {
            def releasesRepoUrl = "$buildDir/repos/releases"
            def snapshotsRepoUrl = "$buildDir/repos/snapshots"
            url = project.hasProperty('release') ? releasesRepoUrl : snapshotsRepoUrl
        }
    }
}
build.gradle.kts
publishing {
    repositories {
        maven {
            val releasesRepoUrl = "$buildDir/repos/releases"
            val snapshotsRepoUrl = "$buildDir/repos/snapshots"
            url = uri(if (project.hasProperty("release")) releasesRepoUrl else snapshotsRepoUrl)
        }
    }
}

Publishing to Maven Local

为了与本地Maven安装集成,有时将模块及其POM文件和其他元数据发布到Maven本地存储库(通常位于$ USER_HOME / .m2 / repository中很有用. 用Maven的话来说,这被称为"安装"模块.

The Maven Publish Plugin makes this easy to do by automatically creating a PublishToMavenLocal task for each MavenPublication in the publishing.publications container. The task name follows the pattern of publishPubNamePublicationToMavenLocal. Each of these tasks is wired into the publishToMavenLocal aggregate task. You do not need to have mavenLocal() in your publishing.repositories section.

Complete example

以下示例演示如何签名和发布Java库,包括源,Javadoc和自定义的POM:

例子8.发布一个Java库
build.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'signing'
}

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

java {
    withJavadocJar()
    withSourcesJar()
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifactId = 'my-library'
            from components.java
            versionMapping {
                usage('java-api') {
                    fromResolutionOf('runtimeClasspath')
                }
                usage('java-runtime') {
                    fromResolutionResult()
                }
            }
            pom {
                name = 'My Library'
                description = 'A concise description of my library'
                url = 'http://www.example.com/library'
                properties = [
                    myProp: "value",
                    "prop.with.dots": "anotherValue"
                ]
                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
}


javadoc {
    if(JavaVersion.current().isJava9Compatible()) {
        options.addBooleanOption('html5', true)
    }
}
build.gradle.kts
plugins {
    `java-library`
    `maven-publish`
    signing
}

group = "com.example"
version = "1.0"

java {
    withJavadocJar()
    withSourcesJar()
}

publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            artifactId = "my-library"
            from(components["java"])
            versionMapping {
                usage("java-api") {
                    fromResolutionOf("runtimeClasspath")
                }
                usage("java-runtime") {
                    fromResolutionResult()
                }
            }
            pom {
                name.set("My Library")
                description.set("A concise description of my library")
                url.set("http://www.example.com/library")
                properties.set(mapOf(
                    "myProp" to "value",
                    "prop.with.dots" to "anotherValue"
                ))
                licenses {
                    license {
                        name.set("The Apache License, Version 2.0")
                        url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
                    }
                }
                developers {
                    developer {
                        id.set("johnd")
                        name.set("John Doe")
                        email.set("john.doe@example.com")
                    }
                }
                scm {
                    connection.set("scm:git:git://example.com/my-library.git")
                    developerConnection.set("scm:git:ssh://example.com/my-library.git")
                    url.set("http://example.com/my-library/")
                }
            }
        }
    }
    repositories {
        maven {
            // change URLs to point to your repos, e.g. http://my.org/repo
            val releasesRepoUrl = uri("$buildDir/repos/releases")
            val snapshotsRepoUrl = uri("$buildDir/repos/snapshots")
            url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
        }
    }
}

signing {
    sign(publishing.publications["mavenJava"])
}

tasks.javadoc {
    if (JavaVersion.current().isJava9Compatible) {
        (options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
    }
}

结果是将发布以下工件:

  • POM: my-library-1.0.pom

  • Java组件的主要JAR工件: my-library-1.0.jar

  • 已明确配置的源JAR工件: my-library-1.0-sources.jar

  • 已明确配置的Javadoc JAR工件: my-library-1.0-javadoc.jar

签名插件用于为每个工件生成签名文件. 此外,还将为所有工件和签名文件生成校验和文件.

Removal of deferred configuration behavior

在Gradle 5.0之前, publishing {}块(默认情况下)被隐式地视为在评估项目后执行了其中的所有逻辑. 此行为引起了很多混乱,在Gradle 4.8中已弃用,因为它是唯一以这种方式运行的块.

您的发布块中或插件中可能有一些逻辑,具体取决于延迟的配置行为. 例如,以下逻辑假定在设置artifactId时将评估子项目:

build.gradle
subprojects {
    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
                artifactId = jar.archiveBaseName
            }
        }
    }
}
build.gradle.kts
subprojects {
    publishing {
        publications {
            create<MavenPublication>("mavenJava") {
                from(components["java"])
                artifactId = tasks.jar.get().archiveBaseName.get()
            }
        }
    }
}

现在必须将这种逻辑包装在afterEvaluate {}块中.

build.gradle
subprojects {
    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
                afterEvaluate {
                    artifactId = jar.archiveBaseName
                }
            }
        }
    }
}
build.gradle.kts
subprojects {
    publishing {
        publications {
            create<MavenPublication>("mavenJava") {
                from(components["java"])
                afterEvaluate {
                    artifactId = tasks.jar.get().archiveBaseName.get()
                }
            }
        }
    }
}