如何防止在hudson上的maven存储库中覆盖已发布的工件(非快照版本)

时间:2011-10-21 12:19:37

标签: maven hudson

问题说明

考虑在哈德森上使用maven的情况。

现在有人检查了一个项目,修改了一些文件,但意外地使用了相同的工件ID和版本号(非快照)。

然后,他/她在哈德森上构建了这个项目并做了maven安装。修改后的工件现在是hudson .m2。任何其他依赖它的项目都将使用经过修改的工件构建。如果编译没有失败,没有人发现这一点。即使正确的工件驻留在中央存储库中,它也永远不会被使用,因为当hudson开始构建时,会从.m2中选择修改过的工件。

所以我正在寻找一种方法来防止这种意外的人为错误。

  1. 无论如何要在hudson上撤销非快照版本(已发布的工件)上maven install的权限?
  2. 在hudson和远程中央存储库中比较.m2的校验和以及校验和失败会产生警告或构建失败的方法吗?
  3. 我已经检查过没有办法强制从中央存储库更新非快照版本,因为它们是不可变的。

    清除中央存储库或为hudson上的每个作业使用单独的存储库将导致构建时间增加&磁盘空间分别使用。

    任何帮助都将不胜感激。

5 个答案:

答案 0 :(得分:1)

我认为你不会找到一种方法来阻止安装覆盖工件。存储库服务器应具有防止部署更新的发布工件的设置。例如,请参阅Nexus的"How do I disable artifact redeployment"

答案 1 :(得分:1)

以下是我们如何管理项目中的版本:

我们处理SNAPSHOT版本。在Jenkins上,我们有一个构建和测试此应用程序的 Fast Build 作业,但如果版本 a SNAPSHOT则会失败。这是由custom enforcer完成的(这与require release version enforcer相反)。

当我们想要发布时,我们使用Jenkins的工作。使用parameterized buildMaven release plugin,负责执行发布的人员只会指出发布的版本(稳定版本),下一个SNAPSHOT版本作为SCM标记的名称。因此,只有Jenkins将定义一个稳定的版本,开发人员将始终使用SNAPSHOT代码。

但是,当然,这并不妨碍开发人员在他的本地机器上做出他想要的东西。但我们总是考虑一个值得信赖的地方:Jenkins服务器。 它适用于我的机器永远不是一个问题的好答案; o)

答案 2 :(得分:1)

没有直接的方法可以解决这个问题,但我们通过编写一个每5分钟运行一次的cron-job来解决这个问题,并将所有NON-SNAPSHOT的罐子标记为只读在Hundson的本地存储库中。通过这种方式,当Hudson中的某个项目试图覆盖它时,我的mvn install或mvn deploy会因为只读它们而无法覆盖工件。

可以轻松编写任何要重新发布的新工件。一旦在接下来的五分钟内写入,脚本就会将它们标记为只读。

以下是unix脚本permission-handler.sh

的代码
#!/bin/bash
cd ~/.m2
date 2>&1>> permission-handler.out
find . -name '*jar' -type f | grep -v 'SNAPSHOT' | xargs chmod -vc 444 2>&1>> permission-handler.out
chmod 777 permission-handler.out

还会处理日志记录,以查看哪些工件已标记为仅已发布。

答案 3 :(得分:0)

通过将Maven存储库(例如Nexus,Artifactory)配置为不允许覆盖发布存储库来解决此问题。在Nexus中,我们有一个SNAPSHOT的回购和一个用于发布的回购。 SNAPSHOT repo允许覆盖。但是发布回购不允许覆盖。这只是Nexus中针对该回购的简单复选框功能。一旦发布版本放入repo,它就不能被覆盖。效果很好。

答案 4 :(得分:0)

我有相同的要求。 可以通过gradle任务的REST请求来完成对工件的检查。

publish.dependsOn lookForArtifacts

task lookForArtifacts {
    group "upload"
    doLast {

        def pomFileName = "${ARTIFACT_ID}-${ARTIFACT_VERSION}.pom"
        def artifactPath = "${ARTIFACT_GROUP.replace(".", "/")}/${ARTIFACT_ID}/${ARTIFACT_VERSION}/${pomFileName}"
        def repositoryUrl = "$MAVEN_SERVER/${artifactPath}"

        println("# searching for existing artifact wit id ${ARTIFACT_VERSION}")
        println("")

        if (urlExists(repositoryUrl)) {
            println("# Existing artifact found")
            println("")
            throw new RuntimeException("Artifact with version $ARTIFACT_VERSION already exist - increase the verion to publish")
        } else {
            println("# No existing artifact found. Preceding to publish")
            println("")
        }
    }
}

def urlExists(String repositoryUrl) {

    try {
        def connection = (HttpURLConnection) new URL(repositoryUrl).openConnection()

        connection.setRequestProperty("Authorization", "Basic " + getBase64EncodedCredentials())
        connection.setConnectTimeout(10000)
        connection.setReadTimeout(10000)
        connection.setRequestMethod("HEAD")

        def responseCode = connection.getResponseCode()

        if (responseCode == 401) {
            throw new RuntimeException("Unauthorized MavenUser user. Please provide valid username and password.")
        }

        return (200 == responseCode)

    } catch (IOException ignored) {
        println(ignored)
        return false
    }
}

def getBase64EncodedCredentials() {
    def s = "$MAVEN_USERNAME" + ":" + "$MAVEN_PASSWORD"
    return s.bytes.encodeBase64().toString()
}