釋出到Maven倉庫
原文地址: ,基於Gradle Build Tool 3.4.1的,後期可能會修改。文章最後面寫了一下自己的總結。
譯文
本章描述的是通過”maven-publish”外掛來支援釋出到Maven功能。最終這種新的釋出方式會替換掉通過
Upload task
的釋出方式。
本章描述怎樣釋出構建的內容(artifacts)到Apache Maven
倉庫。一個模組釋出到Maven
倉庫以後可以供Maven
,Gradle
以及其它支援Maven
倉庫格式的工具使用。
36.1. “maven-publish” 外掛
“maven-publish” 外掛提供了釋出Maven
格式的功能。
“publishing” 外掛建立一個型別為PublishingExtension
publishing
的引數,這個引數裡面提供了publications
容器和repositories
容器。”maven-publish” 依賴的是MavenPublication
和MavenArtifactRepository
。(意思是”maven-publish”是在”publishing”上再一次的封裝)
應用”maven-publish”外掛的例子。
// build.gradle
apply plugin: 'maven-publish'
應用”Maven Plugin”需要做如下事情:
- 使用”publishing”外掛 (沒看明白,覺得意思就是需要
apply plugin: 'maven-publish'
- 建立一個規則自動為每一個
MavenPublication
建立GenerateMavenPom
任務 - 建立一個規則自動的為每一個
MavenPublication
和MavenArtifactRepository
的組合建立一個PublishToMavenRepository
任務 - 建立一個規則自動的為每一個
MavenPublication
建立PublishToMavenLocal
任務
PS:這裡說的似乎有點繞,MavenPublication
相當於是需要釋出的內容,而MavenArtifactRepository
則相當於是釋出的倉庫。”maven-pluign”主要是做三件事:GenerateMavenPom
pom
檔案;PublishToMavenRepository
可以用來發布到指定倉庫,本地某個路徑或者遠端的伺服器;PublishToMavenLocal
則是用來發布到本地的.m2
倉庫(例如我自己電腦的地址是/Users/Egos/.m2
)
36.2. Publications
Publication
物件描述的是一次釋出的結構和配置。Publications
通過任務釋出到倉庫,Publication
物件的配置則精確地確定哪些內容需要釋出。所有的釋出配置資訊定義在PublishingExtension.getPublications()
容器中,在一個專案中每一個釋出到都有一個唯一的名字。
對於”maven-publish”外掛有哪些影響,需要建立一個MavenPublication
,這個釋出決定了哪些內容需要釋出以及包含在POM檔案中的詳細資訊。釋出時可以通過增加模組、自定義構建的內容以及修改生成的POM檔案來配置。
36.2.1. 釋出一個軟體模組
最簡單的釋出一個Gradle專案到Maven倉庫的方法就是指定一個軟體模版去釋出。目前已經支援的模版有。
Name | Provided By | Artifacts | Dependencies |
---|---|---|---|
java | The Java Plugin | Generated jar file | Dependencies from ‘runtime’ configuration |
web | The War Plugin | Generated war file | No dependencies |
下面的例子,構建內容和執行的依賴都來自在Java外掛中定義的java
資訊。
// build.gradle
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
PS:什麼意思呢?上面一句from components.java
代表了使用預設的配置,從上表可以看出會生成jar檔案,同時需要執行時的一些依賴。
36.2.2. 釋出一個自定義構建內容
可以通過配置artifact
明確的指定需要生成的內容。通常會提供原始的檔案或者AbstractArchiveTask
對應的例項(例如:Jar,Zip等等)。
對於每一個自定義的構建內容,可以指定副檔名和分類資訊(classifier
)。注意只有一個釋出的構建內容可以擁有空的分類資訊(classifier
),並且所有的構建資訊必須擁有唯一的分類資訊(classifier
)和副檔名的組合。
如下配置自定義的構建內容:
// build.gradle
task sourceJar(type: Jar) {
from sourceSets.main.allJava
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourceJar {
classifier "sources"
}
}
}
}
PS:什麼意思呢? 外掛自身可以支援釋出出去生成的檔案是jar
和war
,但是這並不能滿足所有的情況,所以可以自定義構建內容,比如:aar等等。怎麼自定義呢?建立相應的任務以及在publications
中使用artifact
就可以了。
36.2.3. 在生成的POM中區別值
生成的POM檔案的值包含了如下的屬性:
- groupId Project.getGroup()
- artifactId Project.getName()
- version Project.getVersion()
覆蓋預設的標識屬性非常的簡單:只需要在MavenPublication
配置時指定groupId,artifactId,version就行。
// build.gradle
publishing {
publications {
maven(MavenPublication) {
groupId 'org.gradle.sample'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Maven
限制了groupId
和artifactId
在一個有限的字符集([A-Za-z0-9_\\-.]+
),並且Gradle
也遵循這樣的限制。對於version
(以及構建內容中的extension
和classifier
),只需要是有效的Unicode字元就行。唯一明確禁止的Unicode字元是”\”,”/”和ISO控制字元。會在publication
之前對字元進行校驗。
36.2.4. 修改生成的POM檔案
生成的POM檔案可能在釋出之前需要修改。”maven-publish”外掛提供了一個hook來允許這樣的修改。
// build.gradle
publications {
mavenCustom(MavenPublication) {
pom.withXml {
asNode().appendNode('description',
'A demonstration of maven POM customization')
}
}
}
上面例子在生成的POM檔案中增加了一個description
元素。使用hook可以修改POM中任意的元素。例如:你可以將依賴關係的版本範圍替換成生成構建的實際版本。
可以修改POM中的任意元素,這也意味著可以將POM修改成非法的POM,所以需要小心的使用這個功能。
釋出模組的唯一標識屬性(groupId
,artifactId
,version
)是一個例外,這個元素不能通過withXML
hook來修改。
36.2.5. 釋出多個模組
有時候使用Gradle不建立多個子專案釋出多個模組是非常有用的。
下面的例子是在一個專案中使用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
}
}
}
如果一個工程定義了多個釋出資訊,Gradle會將每一個釋出資訊釋出到指定的倉庫。每一個釋出需要給定一個唯一的標示。
36.3. Repositories
釋出資訊(Publications
)最終會發布到倉庫,釋出的倉庫資訊定義在PublishingExtension.getRepositories()
中。
下面是定義一個釋出的倉庫
// 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.
上面一句是對於Repositories
的描述,理解不了。自己理解的意思是使用Maven publication
只能釋出在Maven
倉庫中。
36.4. 釋出到maven
倉庫的一個例子
“maven-publish”外掛會自動的為每一個各自宣告在publishing.publications
的MavenPublication
和宣告在publishing.repositories
的MavenArtifactRepository
的組合建立一個PublishToMavenRepository
任務。
建立的任務的名字格式是publish«PUBNAME»PublicationTo«REPONAME»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
:generatePomFileForMavenJavaPublication
:compileJava
:processResources NO-SOURCE
:classes
:jar
:publishMavenJavaPublicationToMavenRepository
:publish
BUILD SUCCESSFUL
Total time: 1 secs
在這個例子中,一個型別是PublishToMavenRepository
,名稱是publishMavenJavaPublicationToMavenRepository
的任務會被建立,這個任務會被連線到釋出任務的生命週期中。執行gradle publish
會生成POM檔案以及生成要釋出的所有的構建內容,並將生成的構建內容傳輸到相應的倉庫。
36.5. 釋出到本地maven
倉庫
為了於本地maven
整合,有時候將模組釋出在本地的.m2
倉庫是非常有用的。Maven
稱之為“安裝”模組。”maven-publish”外掛會自動的為每一個宣告在publishing.publications
的內容建立一個PublishToMavenLocal
任務。每一個這樣的任務都會被連線到publishToMavenLocal
的生命週期中。不需要在publishing.repositories
中寫mavenLocal
。
建立的任務的名字格式是publish«PUBNAME»PublicationToMavenLocal
。
PS:網上很多的開源外掛有一些沒有釋出到本地的方法,對於一些需要修改程式碼進行除錯等,釋出到本地還是非常方便的。
36.6. 不釋出的情況下生成pom
檔案
有時候在不釋出的情況下修改POM檔案是非常有用的,因為POM檔案的生成是一個單獨的任務,所以非常容易實現。
生成POM檔案的任務型別是GenerateMavenPom
,名稱是基於釋出任務generatePomFileFor«PUBNAME»Publication
。因此在下面的例子中,釋出的名稱是mavenCustom
,所以生成POM檔案的名稱是generatePomFileForMavenCustomPublication
。
// 不釋出的情況下生成POM檔案
model {
tasks.generatePomFileForMavenCustomPublication {
destination = file("$buildDir/generated-pom.xml")
}
}
> gradle generatePomFileForMavenCustomPublication
:generatePomFileForMavenCustomPublication
BUILD SUCCESSFUL
Total time: 1 secs
打包android library到本地的例子
// android-artifacts.gradle
apply plugin: "maven-publish"
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
classpath += files(ext.androidJar)
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
afterEvaluate { project ->
tasks.all { Task task ->
if (task.name.equalsIgnoreCase('publishPatchLibPublicationToMavenLocal')) {
task.dependsOn tasks.getByName('assemble')
}
}
}
publishing {
publications {
PatchLib(MavenPublication) {
artifactId project.getName()
groupId group
version version
// artifact 打成aar
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
artifact androidJavadocsJar
}
}
}
// publish«PUBNAME»PublicationToMavenLocal
task pushlishLibToLocal(dependsOn: ['build', 'publish PatchLibPublicationToMavenLocal']) {
group = 'patch'
}
使用的時候只需要在需要打包到本地的lib工程的build.gradle
目錄中。
apply plugin: 'com.android.library'
...
version "1.0.0" // 需要一個version傳到android-artifacts.gradle,每一個需要打包的可能不一樣
group APP_PACKAGE_NAME // 同上
apply from: file('../gradle/android-artifacts.gradle')
打包Java library到本地的例子
Java library
就會更簡單一點了,因為有一個模版,上面文章已經有介紹了。
// java-artifacts.gradle
apply plugin: 'maven-publish'
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
afterEvaluate { project ->
tasks.all { Task task ->
if (task.name.equalsIgnoreCase('publishPatchLibPublicationToMavenLocal')) {
task.dependsOn tasks.getByName('assemble')
}
}
}
publishing {
publications {
PatchLib(MavenPublication) {
from components.java
groupId = group
artifactId = project.getName()
version = VERSION_NAME_DEV
}
}
}
// 釋出在本地倉庫
// 會自動建立'publishXXXXXPublicationToMavenLocal' 'XXXXX' 是 publishing->publications-> PatchLib
task pushlishLibToLocal(dependsOn: ['build', 'publishPatchLibPublicationToMavenLocal']) {
group = 'patch'
}
總結
將專案模組(Android Library
、Java Library
以及Groovy Plugins
等等)構建、打包發到Maven倉庫(包括本地的Maven倉庫)是一件很有意義的事情。對於公司來說,方便多個小組之間的呼叫、以及維護管理,同時也使程式碼看起來不會顯的過於臃腫,也避免了一些網路不好的情況(公司內網還是相對快一點)。這篇檔案介紹的’maven-publish’外掛是一個已經可以直接使用的外掛,個人覺得目前這個外掛的主要作用是將構建內容釋出在本地(.m2
目錄)。這樣對於修改一些開源的框架還是蠻有作用的,以及將專案中的Library
模組先發布在本地然後再依賴呼叫,也可以減少打包的時間。
對於需要打包釋出在遠端倉庫的,最好還是使用“maven”外掛和“signing”外掛,當然還有可能釋出在ivy倉庫等,需要根據實際的需求來選擇。所有的釋出都可以在官方文件中找到。想要系統的學習Gradle外掛還是得花點時間看看userguide。