Gradle publish attemps to upload RPM to Artifactor

2019-05-23 23:39发布

问题:

I'm trying to publish an RPM artifact to a local YUM repo on Artifactory using gradle and the ivy-publish plugin. The issue I'm having is that the publish tasks appears to attempt to upload the artifact twice, and the second attempt fails (correctly) with a HTTP status code of 403. The artifactory user I authenticate with has deploy/cache privileges but not delete.

My question is why is the publish task attempting to upload the artifact twice?

I include my gradle configuration and an extract from the artifactory log file below. Note that the RPM is build using the netflix os-package

Gradle Config Publishing Configuration:

apply plugin: "ivy-publish"

publishing {
    publications {
        rpm(IvyPublication) {
            artifact  buildRpm.outputs.getFiles().getSingleFile()
            /* Ivy plugin forces an organisation to be set. Set it to anything
               as the pattern layout later supresses it from appearing in the filename */
            organisation 'dummy'
        }
    }
    repositories {
        ivy {
            credentials {
                username 'username'
                password 'password'
            }
            url 'http://my.artifactory.com/artifactory/yum-dev-local/'
            layout "pattern", {
                artifact "${buildRpm.outputs.getFiles().getSingleFile().getName()}"
            }
        }
    }
}

To build and publish the artifact I execute the following (with an empty yum-local repo on artifactory)

./gradlew clean buildRpm publish

which produces the following:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':my-artifact-service:publishRpmPublicationToIvyRepository'.
> Failed to publish publication 'rpm' to repository 'ivy'
> java.io.IOException: Could not PUT   'http://my.artifactory.com/artifactory/yum-dev-local/my-artifact-service-0.0.1-1.el7.x86_64.rpm'. Received status code 403 from server: Forbidden

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

The Artifactory log shows:

2016-10-12 15:41:41,828 [http-nio-8081-exec-92] [INFO ] (o.a.e.UploadServiceImpl:453) - Deploy to 'yum-dev-local:my-artifact-service-0.0.1-1.el7.x86_64.rpm' Content-Length: 4420
2016-10-12 15:41:41,842 [http-nio-8081-exec-64] [INFO ] (o.a.e.UploadServiceImpl:299) - Deploy to 'yum-dev-local:my-artifact-service-0.0.1-1.el7.x86_64.rpm.sha1' Content-Length: 40
2016-10-12 15:41:41,850 [http-nio-8081-exec-90] [WARN ] (o.a.r.ArtifactoryResponseBase:105) - Sending HTTP error code 403: Not enough permissions to overwrite artifact 'yum-dev-local:my-artifact-service-0.0.1-1.el7.x86_64.rpm' (user 'username' needs DELETE permission).

The last log line indicates that a request was made to PUT the artifact again. When I check the repo, the artifact has indeed been successfully uploaded, however the publish task is failing. Can someone point out what is going on here?

Versions:

------------------------------------------------------------
Gradle 2.14.1
------------------------------------------------------------

Build time:   2016-07-18 06:38:37 UTC
Revision:     d9e2113d9fb05a5caabba61798bdb8dfdca83719

Groovy:       2.4.4
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_73 (Oracle Corporation 25.73-b02)
OS:           Linux 4.3.5-300.fc23.x86_64 amd64

回答1:

This is happening because the Gradle Ivy publishing plugin will push, apart from your artifact, 3 extra files, which are:

  • A .sha1 file which contains a checksum of your artifact
  • A .xml Ivy package file, which contains information about the artifact
  • a .sha1 file for the previous xml

The problem is with the first .sha1 file. When uploading this, Artifactory / JFrog will think that you want to overwrite the previously uploaded artifact, which has the same name, hence the error.

You would think that just giving DELETE permissions would fix the issue, but that is not the case. Doing that will just replace your previously uploaded package with a checksum .sha1 file, and since that kind of file is not a valid .deb file (in my case, .rpm in yours), when unpacking and generating the Debian repository structure, it will just wipe out your original artifact, so you would not be able to download properly.

Unfortunately, there is not fix for this problem since there is no way of telling Ivy / Gradle to not generate these additional files, that I know of (https://github.com/gradle/gradle/blob/master/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolver.java#L266)

Finally, the solution I went with is to just PUT to Artifactory / JFrog directly using curl, which results in actually less code, but an additional OS dependency (curl). If you are worried about that, you can just use an Gradle HTTP library to do the same thing:

task uploadArtifactory(type: Exec) {

    def artifact = buildDeb.outputs.getFiles().filter {
        it.getAbsolutePath().endsWith ".deb"
    }.getSingleFile()

    commandLine "curl",
        "-X",
        "PUT",
        "https://$artifactoryUser:$artifactoryPassword@$artifactoryAccount.jfrog.io/$artifactoryAccount/$artifactoryRepo/pool/${project.name}_${version}_all.deb;deb.distribution={...};deb.component=main;deb.architecture=all",
        "--upload-file",
        artifact
}


回答2:

I have the similar issue.

Resolving by using Gradle Artifactory Plugin.

Sample config provided in other answer:

https://stackoverflow.com/a/41238443/575350