IvyArtifactRepository doesn't honor artifact patterns when publishing

Given this simple script:

apply plugin: 'java'
   group = 'com.example'
version = '1.0'
  jar {
 classifier = 'myClassifier'
}
  uploadArchives {
 repositories {
  ivy {
   url 'c:/temp/local'
   ivyPattern "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
   artifactPattern "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
  }
 }
}

When I run the uploadArchives task with -i, I get this output:

...
:: loading settings :: url = jar:file:/C:/dev/gradle/gradle-1.1/lib/ivy-2.2.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
Published projectA to C:\temp\local/com.example/projectA/1.0/projectA-1.0-myClassifier.jar
Published ivy to C:\temp\local/com.example/projectA/1.0/ivy-1.0.xml

You can see the published artifact does not follow the pattern I specified. The classifier should be between the artifact name and the revision number, but it’s appended at the end per the default archiveName.

I was able to work around it by accessing the API directly:

uploadArchives {
 repositories {
        add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
            addIvyPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
            addArtifactPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
        }
    }
}

That publishes the artifacts in the pattern specified:

:: loading settings :: url = jar:file:/C:/dev/gradle/gradle-1.1/lib/ivy-2.2.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
published projectA to c:/temp/local/com.example/projectA/1.0/projectA-myClassifier-1.0.jar
published ivy to c:/temp/local/com.example/projectA/1.0/ivy-1.0.xml

Should this be the case? If so, what is the point of the artifactPattern method on the IvyArtifactRepository class?

Your repositories section needs to be moved outside of your uploadArchives configuration - I am guessing your artifactPattern doesn’t know about your jar {} classifier in the current setup. Try:

apply plugin: 'java'
   group = 'com.example'
 version = '1.0'
   repositories {
   ivy {
     url 'c:/temp/local'
     ivyPattern "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
     artifactPattern "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
   }
 }
  jar {
   classifier = 'myClassifier'
 }

If a multi-project, wrap (at least) the ivy block in an allprojects block if necessary…

Andrew, I could be wrong, but per the Gradle docs I think relocating the repositories section outside the uploadArchives configuration simply configures that as a repo from which artifacts can be downloaded. I believe repos for uploading must be specified as in my example.

When I run your example, nothing gets uploaded at all.

:uploadArchives
Task ':uploadArchives' has not declared any outputs, assuming that it is out-of-date.
Publishing configuration: configuration ':archives'

The main project repositories (used for downloading) are not automatically included in the repositories used for uploading. See http://gradle.org/docs/current/userguide/userguide_single.html#N14411 for more details.

Daz, can you tell me if this problem is expected behavior, or if this ought to be a defect?

The problem is how you’re configuring your repository. There are a few things coming into play here:

  1. The first thing you need to know is that Gradle will use the first pattern specified for publishing. 2. Specifying a ‘url’ for your repository tells Gradle to apply the repository layout to the supplied URL. Since you’re not defining a ‘layout’ for your repository, Gradle is applying the default ‘gradle’ layout. 3. Specifying ‘ivyPattern’ or ‘artifactPattern’ for a repository adds an additional pattern. These patterns are not resolved relative to the ‘url’ parameter: unqualified patterns will be resolved like any other file path in Gradle, relative to the project base directory.

So the way you are configuring your repository, you are getting the following effective patterns:

// The default gradle layout applied to the URL provided
    ivyPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])"
     artifactPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])"
       // The explicit patterns resolved against project base directory
    ivyPattern "${project.projectDir}/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
     artifactPattern "${project.projectDir}/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"

There are 2 ways to achieve what you want. The simplest is probably to simply omit the repository ‘url’ parameter and supply the fully qualified ‘ivyPattern’ and ‘artifactPattern’ values you want.

ivy {
    ivyPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
    artifactPattern "c:/temp/local/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
}

Alternatively, you could define the ‘url’ of the repository and use the ‘pattern’ layout:

ivy {
    url "c:/temp/local"
    layout 'pattern' , {
        ivy "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
        artifact "[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
    }
}

This may not be overly clear in the user guide. Documentation patches very welcome!

You needed to give me a bit more time to finish crafting my answer!

Sorry. :slight_smile:

Ah, I see. It actually makes sense because we were originally passing a closure to the layout method (as in your 2nd example), and later switched to call artifactPattern directly.

Definitely some improvement in the documentation would be helpful. I think even the Javadoc doesn’t make this distinction clear enough. I’m willing to take a crack at it … I’ve never submitted a patch before, though, documentation or otherwise. Can you point me in the right direction?

Basically, you just fork the gradle project on github, make your changes and submit a pull request. You should be able to find lots of online resources to help with that part.

For Gradle-specific stuff, check out http://gradle.org/development.

Ok, I took a shot at it and submitted a pull request (I used some of your answer in this thread).

FYI, one correction to what you said: when uploading, Gradle doesn’t take the first pattern for uploading. It will use ‘url’ if it exists, and use ‘ivyPattern’ and ‘artifiactPattern’ second. So for example:

repositories {
   ivy {
  artifactPattern "c:/temp/local2/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision](.[ext])"
  url 'c:/temp/local'
   }
 }
  uploadArchives {
 repositories {
   add project.repositories.ivy
 }
}

The artifact will be published to c:/temp/local with the default pattern, even though it’s specified second.

Thanks for taking the time to create a pull request. I’ll do my best to take a look at it this week.