如何将Jar包以新版本发布至JFrog Artifactory且不覆盖旧版本?
问题场景
首次发布1.0.0版本Jar包到JFrog Artifactory正常,将版本修改为2.0.0后再次部署时出现权限错误:
"message" : "Not enough permissions to delete/overwrite artifact 'customer-service:customer-service/com/customer/service/core/1.0.0/customer_ervice_core-1.0.0.jar' (user: 'username' needs DELETE permission)."
当前使用的build.gradle配置如下:
import org.springframework.boot.gradle.plugin.SpringBootPlugin buildscript { repositories { jcenter() } dependencies { //Check for the latest version here: http://plugins.gradle.org/plugin/com.jfrog.artifactory classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4+" } } plugins { id 'org.springframework.boot' version '2.7.5' apply false id 'io.spring.dependency-management' version '1.0.15.RELEASE' id 'java' id 'maven-publish' id 'com.jfrog.artifactory' version '4.28.1' } allprojects { apply plugin: 'com.jfrog.artifactory' apply plugin: 'maven-publish' } publishing { publications { mavenJava(MavenPublication) { artifactId = 'customer_service_core' from components.java pom { name = 'Customer service core module' description = 'Customer service core module' } } } } artifactory { contextUrl = "${artifactory_contextUrl}" jar { enabled = true } publish { repository { repoKey = 'customer-service' username = "${artifactory_user}" password = "${artifactory_password}" maven = true } defaults { // Reference to Gradle publications defined in the build script. // This is how we tell the Artifactory Plugin which artifacts should be // published to Artifactory. publications('mavenJava') publishArtifacts = true // Properties to be attached to the published artifacts. properties = ['qa.level': 'basic', 'dev.team': 'core'] // Publish generated POM files to Artifactory (true by default) publishPom = true } } } group = 'com.customer.service' version = '2.0.0' sourceCompatibility = '17' repositories { mavenCentral() } dependencyManagement { imports { mavenBom SpringBootPlugin.BOM_COORDINATES } } dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' // lombok dependencies compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' } tasks.named('test') { useJUnitPlatform() }
核心疑问
- 是否可将Jar包作为新版本部署而不覆盖旧版本?
- 是否必须在部署路径中手动加入版本号?
- 如果是,如何通过当前
build.gradle文件实现?
解决方案与解答
1. 能否部署新版本不覆盖旧版本?
完全可以,这是Artifactory和Maven生态的标准工作模式。不同版本的构件会被存储在独立路径下,不会互相覆盖。你遇到的错误是因为部署流程异常触发了覆盖旧版本构件的操作,但你的账号没有DELETE权限,导致失败。
2. 是否必须手动添加版本号到部署路径?
不需要手动添加。Maven规范下,构件部署路径由group、artifactId、version三个参数自动拼接生成,格式为:group/artifactId/version/artifactId-version.jar
Artifactory会严格遵循这个规范自动创建路径,你错误信息中显示的com/customer/service/core/1.0.0/...就是符合该规范的路径。
3. 如何通过build.gradle实现正确的版本化部署?
针对你的配置和问题,按以下步骤调整:
(1)移除冗余插件配置
你的allprojects块重复应用了com.jfrog.artifactory和maven-publish插件,可能导致配置冲突,触发错误的覆盖逻辑。直接删除该块:
// 删除以下冗余配置块 // allprojects { // apply plugin: 'com.jfrog.artifactory' // apply plugin: 'maven-publish' // }
(2)验证生效版本号
确保version = '2.0.0'已正确生效,执行以下命令检查:
./gradlew properties | grep version
若输出不是2.0.0,检查是否有其他脚本或命令行参数覆盖了版本号。
(3)清理本地缓存后重新部署
执行清理+发布命令,避免本地缓存的旧版本构件干扰:
./gradlew clean publish
(4)调整Artifactory插件配置(可选优化)
移除artifactory块中冗余的jar { enabled = true }配置,该配置不属于Artifactory插件的标准配置项,可能引发异常:
artifactory { contextUrl = "${artifactory_contextUrl}" // 删除以下冗余配置 // jar { // enabled = true // } publish { // 原有配置保留 } }
(5)检查Artifactory仓库设置
确认你的customer-service仓库是Maven类型,且未开启“强制覆盖已有版本”的配置(默认Maven仓库允许存储多版本构件)。
调整后的完整build.gradle
import org.springframework.boot.gradle.plugin.SpringBootPlugin buildscript { repositories { jcenter() } dependencies { classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4+" } } plugins { id 'org.springframework.boot' version '2.7.5' apply false id 'io.spring.dependency-management' version '1.0.15.RELEASE' id 'java' id 'maven-publish' id 'com.jfrog.artifactory' version '4.28.1' } publishing { publications { mavenJava(MavenPublication) { artifactId = 'customer_service_core' from components.java pom { name = 'Customer service core module' description = 'Customer service core module' } } } } artifactory { contextUrl = "${artifactory_contextUrl}" publish { repository { repoKey = 'customer-service' username = "${artifactory_user}" password = "${artifactory_password}" maven = true } defaults { publications('mavenJava') publishArtifacts = true properties = ['qa.level': 'basic', 'dev.team': 'core'] publishPom = true } } } group = 'com.customer.service' version = '2.0.0' sourceCompatibility = '17' repositories { mavenCentral() } dependencyManagement { imports { mavenBom SpringBootPlugin.BOM_COORDINATES } } dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' } tasks.named('test') { useJUnitPlatform() }
内容的提问来源于stack exchange,提问作者NNFdo

