简体   繁体   中英

How to prevent overwriting of released artifacts (non snapshot versions) in maven repository on hudson

Problem Description

Consider the case maven is being used on hudson.

Now someone took checkout of a project,modified some files but accidently used same artifact id and version number(non snapshot).

He/She then build this project on hudson and did maven install.The modified artifact is now in hudson .m2 . Any other project which depent on it will be build with modified artifact. No one finds this out if compilation doesn't fail. Even though correct artifact resides in central repository it is never used because modified one is picked up from .m2 when hudson starts building.

So i am looking for a way to prevent this accidental human error.

  1. Anyway to revoke permissions of maven install on non snapshot versions (released artifacts) on hudson ?
  2. Any way to compare checksums of .m2 in hudson and on in remote central repository so that checksum failures can generate warnings or fail build ?

I have already checked that there is no way to force update non-snapshots versions from central repository as they are meant to be immutable.

Purging central repository or using separate repository for each job on hudson will result in increased build times & disk space usage respectively.

Any help would be appreciated.

There was no direct way to solve this but we solved this inderctly by writing a cron-job which runs every five minutes and marks all the jars which are NON-SNAPSHOT as read only in the local repository of Hundson . In this way when some project in Hudson tries to overwrite it my mvn install or mvn deploy it fails in overwiriting the artifacts as they are readonly.

Any new artifacts to be realeased can easily be written. Once written within next five minutes script marks them as read only.

Here is code for unix script 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

Logging is also handled to see which all artifacts have been marked as released only.

I don't think you're going to find a way to stop an install from overwriting an artifact. A repository server should have a setting to prevent deploying an updated release artifact though. See, for example, "How do I disable artifact redeployment" for Nexus.

Here is how we manage versions in our project:

We work on a SNAPSHOT version. On Jenkins, we have a Fast Build job that builds and tests this application, but fails if the version is not a SNAPSHOT . This is done by a custom enforcer (this is the opposite of the require release version enforcer ).

When we want to make a release, we use a Jenkins job for that. Using theparameterized build , and Maven release plugin , the person who is in charge of doing the release will just indicate the version of the release (the stable version), the next SNAPSHOT version, as well as the name of the SCM tag. Thus, only Jenkins will define a stable version and the developers will always work on a SNAPSHOT code.

But of course, this does not prevent the developers to make what he wants on his local machine. But we always consider one trusted place: the Jenkins server. It works on my machine is never a good answer to a problem ;o)

This is solved by configuring your Maven repository (eg Nexus, Artifactory) from not allowing overwrite of the release repos. In Nexus we have a repo for SNAPSHOT and one for releases. The SNAPSHOT repo allows overwrite. But the release repo does not allow overwrite. This is just a simple checkbox feature in Nexus for that repo. Once a release version is put in the repo, it cannot be overwritten. Works out very well.

I had the same requirement. Checking for the artifact can be achieved with REST request from a gradle task.

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()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM