--- title: 'Gradle 發佈' disqus: kyleAlien --- Template === ## Overview of Content 從 Gradle 6.0 開始,Gradle 模塊元數據會將 lvy XML、Maven POM 一起發佈 [TOC] ## 發佈 - 概念 * 發佈什麼? 通常是文件(artifact)、元數據(metadata);不同的倉庫會保存不同的發佈內容,像是發佈到 Maven 倉庫的數據: 1. 1 ~ 多個 artifact,通常是項目建構 2. Gradle 模塊元數據文件將會描述發佈的變體(variants) 3. Maven POM 文件將標識主要工件及其依賴項;會產生項目的 Jar 包 * 在哪裡執行發佈? 由 Gradle 執行發佈,發佈到某個倉庫(repositories)去,該倉庫會儲存各種套件 * 如何發佈? Gradle 會自動產生發佈相關的任務,透過這個些任務就可以發佈 > e.g 發佈到 Maven 倉庫的任務為 `PublishToMavenRepository` > > 發佈到 lvy 倉庫的任務為 `PublishToIvyRepository` ### 發佈相關設置 1. 首先先使用發佈的用的二進制插件(Maven、lvy),這邊以 Maven 為例 ```groovy= // build.gradle plugins { id 'java-library' id 'maven-publish' } ``` 2. 配置發佈的數據:使用 [**PublishingExtension**](https://docs.gradle.org/current/dsl/org.gradle.api.publish.PublishingExtension.html) 來設定發佈時的相關數據 * **發佈設置** `publications`:自定義一個名為 demoLibrary 的發佈,並將其透過 [**MavenPublication**](https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html) 發佈到 Maven; 透過 `components.java` 設定這次為發佈 Jar 包 > `publications` 也稱為出版物 * **倉庫設置** `repositories`:定義一個基於文件的 Maven 儲存庫 > 一般來說是基於 Https 比較多 ```groovy= // 發佈、儲存庫必須訊息 group = 'org.example' version = '1.0' publishing { publications { // 自定義一個名為 demoLibrary 的發佈 demoLibrary(MavenPublication) { // 透過 Jar 包組件發佈 from components.java } } repositories { maven { // 倉庫的名稱,可以是任意的字串,用於識別倉庫 name = 'alienRepo' // 倉庫的 URL url = layout.buildDirectory.dir("repo") } } } ``` 在這些設置結束後,同步 Gradle 就會產生對應的任務… > 其格式如 `publish<PubName>PublicationTo<RepoName>Repository` > > 像上面設置 PubName=demoLibrary、RepoName=alienRepo,產生的任務就會是 publishDemoLibraryPublicationToAlienRepoRepository > > ![](https://hackmd.io/_uploads/ByO-cgjH3.png) * 執行發佈任務後,就會將打包好的 Jar 包,以及相關資訊上傳至設定好的 URL(目前是設定發佈到 `/build/repo` 資料夾) ```shell= # 打包上傳命令 ./gradlew publishDemoLibraryPublicationToAlienRepoRepository ``` > ![](https://hackmd.io/_uploads/r1O6oxiSn.png) ## 插件發布 我們可以把撰寫好的二進制插件,發布到私有、公有倉庫 ### 發布至 Gradle Portal * Gradle 有提供一個簡單 DSL ([Publishing Plugin](https://plugins.gradle.org/plugin/com.gradle.plugin-publish)) 將插件發布至 Gradle Plugin Portal 1. 首先要先有 [**Gradle 帳戶**](https://plugins.gradle.org/)(沒有請申請一個帳號) 2. 將 Gradle 帳戶的個人資料 **API Keys** 中的 `gradle.publish.key`、`gradle.publish.secret` 值設定到 `HOME_DIR/.gradle/gradle.properties` > 如果沒有 `gradle.properties` 創建,並將資料寫入 > > ![](https://hackmd.io/_uploads/HJOcC_QSh.png) 3. 添加發布用的插件 `com.gradle.plugin-publish` 到準備發布的模塊中的 `build.gradle` ```groovy= // build.gradle plugins { id 'com.gradle.plugin-publish' version '1.1.0' } ``` 4. 設定插件參數 ```groovy= group = 'com.test.plugin' // 版本設定 version = '1.0' // 使用 Java Gradle 插件開發插件 gradlePlugin { // 項目網址 website = 'https://github.com/ysb33r/gradleTest' // 項目倉庫 vcsUrl = 'https://github.com/ysb33r/gradleTest.git' // 上傳的插件參數 plugins { myPlugins { // 插件唯一性 id = "com.test.test-my-plugin" // 人可讀的名稱 displayName = 'Test do plugin' description = 'Test do plugin...' tags.addAll("HelloWorld") implementationClass = 'com.test.plugin.MyPluginImpl' } } } ``` :::info * 這裡有幾個坑要注意 * 上面有的 **元素都要設定**(`website`, `version`, `website`... 等等) * **`id` 設置有兩個條件** * 必須以 `com.xxx` 開頭 * `com.xxx` 中的 `xxx` 必須以插件源碼路徑為準 > 源碼包是在 `com.test.plugin`,所以 `id` 取名也需要是 `com.test` 開頭 > > ![](https://hackmd.io/_uploads/SkmwxoXSh.png) ::: 5. 點擊 gradle `publishPlugin` 任務自動上傳插件 > ![](https://hackmd.io/_uploads/SJFZ1omBn.png) ### 發布至 Maven - 插件、任務 * Gradle 也有提供一個簡單 DSL ([Maven Publish](https://plugins.gradle.org/plugin/com.gradle.plugin-publish)) 將插件發布至 Maven ```groovy= // build.gradle plugins { id 'maven-publish' } ``` * **Maven 插件也有提供幾個基礎任務** > 以下的 `PubName`、`RepoName` 兩個元素可以透過 PublishingExtension#publishing 設置 | 任務名 | 說明 | 補充 | | -------- | -------- | -------- | | generatePomFileFor<PubName\>Publication | 為 PubName 產生一個 POM 文件,內有項目的元數據(項目名稱、版本、依賴) | 產生後默認位置為 `build/publications/$pubName/pom-default.xml` | | publish<PubName\>PublicationTo<RepoName\>Repository | 將 PubName 發佈到名為 RepoName 的倉庫中 | 如果沒有定義 RepoName 那 **預設為 Maven** | | publish<PubName\>PublicationToMavenLocal | 將 PubName 發佈到本地 Maven 緩存(包含 POM 文件) | 通常路徑為 `<當前目錄>/.m2/repository` | | publish | 將所有項目發佈到倉庫 | 不包括本地 Maven | | publishToMavenLocal | 將所有項目發佈到本地 Maven | | ### 發布至 Maven - [publications](https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html) 設置 * 當項目發佈至 Maven 時有 4 著主要配置 1. [**MavenPublication**](https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html#org.gradle.api.publish.maven.MavenPublication:from(org.gradle.api.component.SoftwareComponent))#from 設置:提供相應發佈的組件 ```groovy= publishing { publications { maven(MavenPublication) { from components.java } } } ``` 2. MavenArtifact 設置(Options):當你需要自訂 Maven artifact 時需要另外配置 ```groovy= publishing { publications { maven(MavenPublication) { artifact sourceJar // Publish the output of the sourceJar task artifact 'my-file-name.jar' // Publish a file created outside of the build artifact source: sourceJar, classifier: 'src', extension: 'zip' } } } ``` 3. **基礎元數據**:如 `artifactId`、`groupId`、`version`... 等等 * POM 基礎設置可以透過 Project 物件取得(`getGroup`、`getName`、`getVersion`) ```groovy= group = 'org.example' version = '1.0' ``` * 而這些基礎 POM 標示也是 **可以透過 MavenPublication 覆蓋** ```groovy= publishing { publications { maven(MavenPublication) { // 覆蓋設置 groupId = 'org.gradle.sample' artifactId = 'library' version = '1.1' // ... 省略部分 } } } ``` :::success * 上傳到本地倉庫時,對應的資料夾結構 假設是使用以下設置 ```shell= groupId = 'org.gradle.sample' artifactId = 'library' version = '1.1' ``` 那上傳到本地 `.m2/repository` 中則會以 `.m2/repository/org/gradle/sample/1.1/library-1.1.jar` 上傳 > 也就是 `.m2/repository/<groupId>/<version>/<artifactId-version>.jar ::: 4. POM 文件的其他內容,可以透過 [**MavenPublication**](https://docs.gradle.org/current/dsl/org.gradle.api.publish.maven.MavenPublication.html#org.gradle.api.publish.maven.MavenPublication:pom(org.gradle.api.Action))#pom 設置 ```groovy= // 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/' } } } } } ``` ### 發布至 Maven - [repositories](https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.repositories.MavenArtifactRepository.html) 設置 * publishing 中的 repositories 主要內容有 **url(必填)**、name(Option,如果沒有填寫則預設為 Maven) ```groovy= // build.gradle publishing { repositories { maven { // change to point to your repo, e.g. http://my.org/repo url = layout.buildDirectory.dir('repo') } } } ``` * 發佈快照到不同 Maven 是一種常見手法 1. 使用版本設置判斷 ```groovy= publishing { repositories { maven { def releasesRepoUrl = layout.buildDirectory.dir('repos/releases') def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots') url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl } } } ``` 2. 使用項目屬性設置(透過指令控制) ```groovy= publishing { repositories { maven { def releasesRepoUrl = layout.buildDirectory.dir('repos/releases') def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots') url = project.hasProperty('release') ? releasesRepoUrl : snapshotsRepoUrl } } } ``` ## Appendix & FAQ :::info ::: ###### tags: `Gradle`