contents
- Usage
- Tasks
- Publications
- Repositories
- Publishing to Maven Local
- Publishing Maven relocation information
- Complete example
- Removal of deferred configuration behavior
maven publish plugin 提供了发布构建工件到maven 仓库的能力 ..
发布到maven 仓库的模块能够被maven 消费 ..
gradle(see Declaring Dependencies) 以及其他工具能够理解maven 仓库的格式..
你能够在Publishing Overview了解发布的基础知识..
Usage
为了使用Maven Publish Plugin,需要将插件引用到项目中并使用 …
尝试加入以下代码块到build.gradle
plugins {
id 'maven-publish'
}
Tasks
- generatePomFileForPubNamePublication — GenerateMavenPom
为一个已经通过PubName 命名的发布创建一个Pom,收集已知的元数据(例如,项目名称,项目版本以及依赖).
默认的POM文件的location(位置)在build/publications/$pubName/pom-default.xml.
- publishPubNamePublicationToRepoNameRepository — PublishToMavenRepository
发布PubName的发布到命名为RepoName的仓库上,如果你已经有了一个仓库定义而没有显式的名称,仓库名将默认为”Maven”.
- publishPubNamePublicationToMavenLocal — publishToMavenLocal
拷贝’PubName’ 的发布到 本地Maven 缓存中 - 例如 $USER_HOME/.m2/repository —包含发布的POM文件以及其他元数据.=
- publish
Depends on: All publishPubNamePublicationToRepoNameRepository tasks
这是一个聚合任务(将所有定义的publication 发布到 定义的仓库中).
但是它并不包括复制publication到本地Maven 缓存中.
- publishToMavenLocal
Depends on: All publishPubNamePublicationToMavenLocal
拷贝所有定义的publications 到本地Maven 缓存,包括它们的元数据(POM文件,等等)
Publications
这个插件提供了 MavenPublication 类型的 publications.
为了学习如何定义和使用publication,可以查看基础发布.
这里有四种主要需要在maven publication中配置的事情..
- 一个组件
通过MavenPublication.from(org.gradle.api.component.SoftwareComponent).
- 自定义工件
MavenPublication.artifact(java.lang.Object)方法进行配置..
查看MavenArtifact了解自定义Maven 工件的一些必要的配置选项..
- 标准的元数据
例如 artifactId,groupId以及version.
- 其他Pom文件的内容
通过MavenPublication.pom(org.gradle.api.Action)进行配置
你能够从一个完整的发布例子中学习这些东西,对于MavenPublication的Api 文档有额外的代码示例.
identity values in the generated POM
生成的POM文件的属性将包含由以下项目属性衍生的标识值.
- groupId - Project.getGroup()
- artifactId - Project.getName()
- version - Project.getVersion()
覆盖这些默认的标识值是非常容易的: 简单的在MavenPublication指定groupId,artifactId或者version属性.
publishing {
publications {
maven(MavenPublication) {
groupId = 'org.gradle.sample'
artifactId = 'library'
version = '1.1'
from components.java
}
}
}
某些仓库将不能够处理所有支持的字符. 例如‘:’ 字符串不能够被用来作为标识符(当发布到在windows上的文件系统支撑的仓库)
Maven 限制了groupId 和 artifactId 为可选的字符集合([A-Za-z0-9_\-.]+)并且Gradle 遵循这个限制. 对于version(以及extension和classifier属性),gradle 将会处理任何一个有效的Unicode 字符..
这里仅仅只有一些Unicode码是显式禁止的 ‘\’, ‘/‘ 以及任何ISO 控制字符. 早期发布时有效的,目前不支持 …
定制 生成的POM
生成的POM文件能够在发布之前进行定制.. 例如,当发布一个库到Maven 中央仓库的时候你将需要设置某些元数据..
Maven Publish 插件提供了一个DSL(领域规范语言) 来实现此目的 ..
可以查看 DSL 参考中MavenPom 部分的完整必要的属性和方法文档..
例如:
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/'
}
}
}
}
}
定制依赖版本
对于发布的依赖支持两种策略
- 声明的版本(默认)
此策略发布由构建脚本作者定义的版本以及依赖项块中的依赖项声明。任何其他类型的处理,例如通过更改已解析版本的规则,将不会被考虑用于发布。
- 已解析的版本
这个策略指定在构建的过程中解析发布的版本, 尽可能的通过解析规则和自动冲突解决.
这样做的好处是,已发布的版本与已发布的工件所针对的版本相对应。
- 对于resolved version使用情况举例
- 项目中对依赖使用动态版本,但是更喜欢暴露已经发行的已解析版本给它的使用者 …
- 结合依赖锁定,可能喜欢发布锁定的版本
- 利用了gradle 丰富的版本约束的项目,这些约束对Maven 进行了有损转换,它不依赖转换,而是发布已解决的版本..
通过versionMapping DSL方法能够去配置VersionMappingStrategy:
publishing {
publications {
mavenJava(MavenPublication) {
versionMapping {
usage('java-api') {
fromResolutionOf('runtimeClasspath')
}
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
}
这个例子中,gradle 将对声明在api 中的依赖在runtimeClasspath上解析的版本 …
这个runtimeClasspath 映射到Maven 的compile scope.
gradle 也会使用声明在implementation上的依赖使用在runtimeClasspath上的已解析版本 ,它们映射到Maven的runtime scope;
fromResolutionResult() 指定了gradle 应该使用默认的一个变种的类路径 并且 runtimeClasspath 是java-runtime的默认类路径 ….
这里可能看着很疑惑,因为api和implementation的对同一个类路径的映射却转换为不同的maven scope,其实gradle 本身也说了是一种有损转换…
仓库
插件提供了MavenArtifcatRepository类型的仓库, 为了学习如何在publishing中定义和使用仓库,可以查看basic publishing.
这里有一个定义publishing 仓库的例子:
publishing {
repositories {
maven {
url = layout.buildDirectory.dir('repo')
}
}
}
对于仓库需要配置的主要有两件事情:
- URL(required)
- Name(optional)
你能够在构建脚本中定义多个仓库只要它们有独一无二的名字即可.
你也许能够声明一个或者仅仅只有一个仓库(而没有名称),那么这个仓库具有一个隐式的名称叫做 ‘Maven’;
你也能够配置需要连接到仓库的认证详情,查看MavenArtifactRepository了解详情 …
快照以及发行仓库
它是一个常用习惯,用来发布快照和发行版本到不同的Maven 仓库..
一个简单的方式 基于项目的版本配置仓库URL
例如 根据版本使用一个URL(以SNAPSHOT’结尾)并且其他版本使用不同的URL.
publishing {
repositories {
maven {
def releasesRepoUrl = layout.buildDirectory.dir('repos/releases')
def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
}
}
}
类似的,你也能够使用一个项目或者系统属性来决定需要使用的发布仓库..
例如通过项目属性release 设置来指定发行版仓库,当用户通过
gradle -Prelease publish
同样publishing 配置如下
publishing {
repositories {
maven {
def releaseRepoUrl = layout.buildDirectory.dir('repos/releases')
def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
url = project.hasProperty('release') ? releasesRepoUrl : snapshotsRepoUrl
}
}
}
Publishing to Maven Local
如果想要集成本地Maven installation,某时这可能很有用(需要发布一些模块到Maven 本地仓库中)
包含POM文件 以及其他元数据..
在Maven的术语中,它指的是’安装’这个模块…
maven发布插件使得更容易做这个事情 - 通过自动的为在publishing.publications容器中的每一个MavenPublication创建一个PublishToMavenLocal任务 这个任务的名称遵循publishPubNamePublicationToMavenLocal,每一个这样的任务都会关联到publishToMavenLocal聚合任务 …
你不需要在publishing.repositories部分配置mavenLocal()
Publishing Maven relocation information
当一个项目改变发布工件的groupId 或者artifactId(坐标)时,这特别重要的是让用户知道哪里能够发现工件的新坐标. Maven 能够通过relocation 特性帮助你找到它 ..
这种方式的工作时项目在原来的旧坐标下发布一个由最小relocation POM组成的额外工件 …
这个POM 文件指定了新的工件能够在哪里发现… Maven 仓库浏览器 以及构建工具能够通知用户这个工件的坐标已经发生改变 …
对此,一个项目增加额外的MavenPublication (通过指定MavenPomRelocation)
publishing {
publications {
// ...artifact publications
// Specify relocation POM
relocation(MavenPublication) {
pom {
//Old artifact coordinates
groupId = "com.exmaple"
artifactId = "lib"
version = "2.0.0"
distributionManagement {
relocation {
// New artifact coordinates
groupId = "com.new-example"
artifactId = "lib"
version = "2.0.0"
message = "groupId has beean changed"
}
}
}
}
}
}
仅仅只需要在relocation 下指定已经被改变的属性 …
可以是artifactId / groupId,其他所有属性都是可选的..
指定version 是非常有用的 - 当新的工件具有不同的版本时,例如由于版本号已经再次从1.0.0 开始,一个自定义的消息允许用来解释为什么工件的坐标发生了改变)
对于旧版本的工件的下一个版本的relocation POM 应该被创建,例如当com.example:lib:1.0.0工件的坐标已经改变为新的坐标 并且它的版本号持续使用 - 发布为 com.new-example:lib:2.0.0,那么relocation POM应该指定从
com.example:lib:2.0.0 到com.new-example:lib:2.0.0
一个relocation POM 应该仅仅发布一次,如果已经发布过应该将它移除 …
注意一个relocation POM 对于所有情况来说并不可能是合适的,当一个工件已经分离出两个或者多个工件,那么一个relocation pom 可能不是足够的 …
Retroactively publishing relocation information
追溯发布搬迁信息(在过去如果一个工件的坐标发生了改变,并且当时没有相关的relocation 信息发布) .
上面的建议已经应用,为了让迁移对于用户更容易,建议在relocation POM中对version 多一点精力 ..
relocation POM 应该允许用户一步完成新工件的移动,并且允许它们通过单独步骤更新到最新版本..
并且独立的更新可以处理断崖式更新(如果有的话)
当搬迁信息追溯发布时, 它不需要等待项目的下一个常规发行版本 … 它能够在此时发布
正如上面所提到的,这个relocation 信息 应该在发布一次之后进行删除 …
构建脚本中清理这一段配置 ..
避免重复的依赖
当一个工件的坐标发生了改变,但是在这个工件的内部的类的包名仍然保持一致 … 依赖冲突必然发生..
一个项目可能(传递性)依赖旧的工件 但是同时有可能依赖新的工件(同时它们包含了相同的类),潜在不兼容的改变 ..
为了检测这样的冲突(重复依赖),capabilities 能够作为Gradle Module Metadata的一部分发布,例如使用Java Library项目的时候,查看为本地组件声明额外的能力.
执行一个尝试运行
为了验证relocation 信息能够如期工作(在发布到远程仓库之前),它能够首先发布到本地maven 仓库中测试,那么一个本地测试gradle 或者Maven 仓库能够被创建 - 这个项目依赖relocation 工件 ..
完整的例子
以下说明了如何签名并发布一个Java 库 - 包括sources ,javadoc和定制pom;
plugins {
id 'java-library'
id 'maven-pulish'
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 = layout.buildDirectory.dir('repos/releases')
def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
}
}
}
signing {
sign publishing.publications.mavenJava
}
javadoc {
if(JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption('html5',true)
}
}
这会导致以下工件将发布:
- 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
签名插件被用来生成一个签名文件(对每一个工件),除此之外所有工件和签名文件的checksum 文件也会生成 …
Removal of deferred configuration behavior
删除延迟配置行为,在Gradle 5.0之前,publishing {} 块默认是隐式处理的(就像在它内部的所有逻辑将会在项目评估/执行之后执行),这个行为导致不小的困惑并且它们在Gradle4.8已经废弃. 因为它因为它是唯一一个这样做的块。
意思是 你不应该认为这个publishing 是延迟配置的,如果你需要依赖一个延迟配置,在afterEvaluate{} block块中内嵌代码…
你也许需要在publishing 块中内嵌一些逻辑或者 一个依赖延迟配置行为的插件 … 对此,以下的逻辑假设子项目在artifactId已经设置之后进行评估 …
这是一个错误示例 …
subprojects {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifactId = jar.archiveBaseName
}
}
}
}
这种逻辑必须包装在 afterEvaluate{} 块中 ..
subprojects {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
afterEvaluate {
artifactId = jar.archiveBaseName
}
}
}
}
}