You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Gradle向GitHub Packages发布Java库SNAPSHOT版本无法覆盖更新的问题求助

解决GitHub Packages无法更新/覆盖SNAPSHOT版本的问题

你遇到的问题其实是GitHub Packages Maven仓库的特殊设计导致的——和标准Maven仓库不同,GitHub把SNAPSHOT版本当成了"正式版本"对待:一旦某个SNAPSHOT版本(比如0.0.1-SNAPSHOT)被上传,就不允许再修改、覆盖或更新它,哪怕你本地执行了clean重新构建,GitHub也只会返回"发布成功"但实际上不会替换已有的版本。

为什么标准Maven仓库可以?

标准Maven仓库的SNAPSHOT机制是每次发布都会生成带时间戳的子版本(比如0.0.1-20240520123456-SNAPSHOT),仓库会保留多个快照版本,客户端拉取时自动获取最新的那个。但GitHub Packages不支持这个时间戳快照的自动生成和管理,它只认你指定的版本号——只要版本号存在,就拒绝覆盖。

解决方案:

1. 使用动态生成的SNAPSHOT版本号(推荐)

既然固定版本号无法覆盖,我们可以给SNAPSHOT版本加上动态后缀,比如时间戳、CI构建号,这样每次发布的版本号都是唯一的,既实现了快照的"更新"效果,又符合GitHub Packages的规则。

比如在Gradle里动态生成版本:

plugins {
    id 'java'
    id 'maven-publish'
}

// 生成带时间戳的SNAPSHOT版本
def timestamp = new Date().format('yyyyMMddHHmmss')
version = "0.0.1-${timestamp}-SNAPSHOT"

// 如果是CI环境(比如GitHub Actions),可以用构建号代替时间戳
// version = "0.0.1-${System.getenv('GITHUB_RUN_NUMBER')}-SNAPSHOT"

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
    repositories {
        maven {
            url = "https://maven.pkg.github.com/myOrg/myRepo"
            credentials {
                username = "myUsername"
                password = "myPassword"
            }
        }
    }
}

这样每次发布的版本号都是唯一的,GitHub会正常接收,客户端也能通过依赖声明0.0.1-SNAPSHOT拉取最新的版本(需要开启Maven的SNAPSHOT更新策略)。

2. 自动删除旧SNAPSHOT版本(适合必须用固定版本号的场景)

如果你坚持要用固定的0.0.1-SNAPSHOT版本,可以在发布前通过GitHub API自动删除已存在的版本,然后再执行publish

比如在GitHub Actions里添加一个步骤:

steps:
  - name: Delete old SNAPSHOT version
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      PACKAGE_NAME: myRepo
      VERSION_NAME: 0.0.1-SNAPSHOT
    run: |
      # 获取旧版本的ID
      VERSION_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
        "https://api.github.com/orgs/myOrg/packages/maven/$PACKAGE_NAME/versions" \
        | jq -r ".[] | select(.name == \"$VERSION_NAME\") | .id")
      
      # 如果版本存在,删除它
      if [ -n "$VERSION_ID" ]; then
        curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" \
          "https://api.github.com/orgs/myOrg/packages/maven/$PACKAGE_NAME/versions/$VERSION_ID"
      fi
      
  - name: Publish to GitHub Packages
    run: ./gradlew publish

注意:

  • 需要给GITHUB_TOKEN授予delete:packages权限(在仓库Settings -> Actions -> General里配置)
  • 环境里的myOrg要替换成你的组织名,PACKAGE_NAME替换成你的包名
  • 需要在CI环境中安装jq工具来解析JSON

3. 检查本地发布缓存(辅助排查)

虽然你已经执行了clean,但Gradle的发布缓存可能还保留着旧的快照信息,可以尝试清理发布缓存:

./gradlew clean publish --no-build-cache --no-config-cache

不过这个方法通常只能解决本地缓存问题,无法解决GitHub Packages的版本覆盖限制。

总结

GitHub Packages的Maven仓库不支持标准的SNAPSHOT版本覆盖机制,所以要么用动态版本号生成唯一快照,要么自动删除旧版本后重新发布。这是GitHub的设计决定,目的是避免意外覆盖已发布的包版本。

内容的提问来源于stack exchange,提问作者Nick Melis

火山引擎 最新活动