多项目构建中如何避免未变更项目的构件发布至Nexus?
这问题我在维护多模块Gradle项目时也踩过坑——默认情况下,gradle publish会触发所有子项目的发布任务,哪怕它们的代码或版本号完全没变化。结合你用versions.json管理版本号的场景,给你几个针对性的解决方案:
方案1:给发布任务添加条件判断(推荐)
通过onlyIf或publishOnlyIf给每个项目的发布任务设置触发条件,只有当项目代码有变更、或者版本号比Nexus上已发布的版本新时,才执行发布。
在每个子项目的build.gradle(或者根项目的subprojects块里统一配置)添加:
import groovy.json.JsonSlurper publishing { publications { mavenJava(MavenPublication) { // 你的现有发布配置(比如groupId、artifactId、version等) groupId project.group artifactId project.name version new JsonSlurper().parse(file("versions.json")).version // 仅当版本号未在Nexus发布过时才执行发布 publishOnlyIf { def currentVersion = version // 这里实现查询Nexus最新版本的逻辑,示例用伪代码 def nexusLatestVersion = getLatestVersionFromNexus(groupId, artifactId) // 如果Nexus上没有该版本,或者当前版本更新,则允许发布 nexusLatestVersion == null || compareVersions(currentVersion, nexusLatestVersion) > 0 } } } } // 辅助方法:对比版本号(简单实现,可根据你的版本规则调整) int compareVersions(String v1, String v2) { def parts1 = v1.split("\\.").collect { it.toInteger() } def parts2 = v2.split("\\.").collect { it.toInteger() } def minLength = Math.min(parts1.size(), parts2.size()) for (int i = 0; i < minLength; i++) { if (parts1[i] != parts2[i]) { return parts1[i] - parts2[i] } } return parts1.size() - parts2.size() } // 辅助方法:从Nexus查询最新版本(需替换为你的Nexus实际API调用) String getLatestVersionFromNexus(String group, String artifact) { def nexusUrl = "http://your-nexus-url/repository/maven-releases/${group.replace('.', '/')}/${artifact}/maven-metadata.xml" try { def metadata = new XmlSlurper().parse(new URL(nexusUrl)) return metadata.versioning.latest.text() } catch (Exception e) { // 如果元数据不存在,说明该项目从未发布过 return null } }
方案2:仅发布指定项目(手动/CI脚本控制)
如果你只是想在手动执行时避免发布所有项目,直接指定要发布的子项目即可:
gradle clean :ProjectA:publish
这个命令只会触发ProjectA的发布任务(包括它依赖的ProjectB的构建任务,但不会发布ProjectB),完全不会影响未变更的项目。如果是CI环境,可以通过脚本判断哪个项目有变更,然后动态执行对应项目的publish任务。
方案3:利用Gradle增量构建特性
把versions.json作为发布任务的输入,同时记录已发布的版本作为输出,让Gradle自动判断是否需要执行发布:
tasks.withType(PublishToMavenRepository) { // 输入:versions.json文件,文件内容变化时触发任务 inputs.file(file("versions.json")) // 输出:记录已发布版本的文件,用来对比是否需要重新发布 outputs.file(new File(buildDir, "published-version.txt")) doLast { // 发布成功后,把当前版本写入输出文件 def currentVersion = new JsonSlurper().parse(file("versions.json")).version outputs.files.singleFile.text = currentVersion } }
这样只要versions.json没修改,且published-version.txt里的版本和当前一致,Gradle就会跳过发布任务。
额外提醒:确保版本号递增逻辑只作用于变更项目
你的版本号递增脚本需要调整,只在项目有变更时才修改versions.json。比如结合Git提交记录,判断自上次发布以来项目目录下是否有文件修改,只有有修改的项目才执行版本号递增。这样未变更的ProjectB版本号不变,即使发布任务被触发,Nexus也会因为版本重复而拒绝(如果你的Nexus配置了不允许覆盖已发布版本的话),双重保险。
内容的提问来源于stack exchange,提问作者PCL

