How can you set an artifact name dynamically using the ivy-publish plugin?

How can I set the artifact name dynamically when using the ivy-publish plugin? I have a project which builds some custom artifacts in a JavaExec task (it’s not a Java or Web project). The JavaExec task generates several files I want to upload to Ivy, however the filenames vary with each run (as they include a generated version based on the current time).

apply plugin: 'ivy-publish'
apply plugin: 'base'
  repositories {
      mavenCentral()
}
  dependencies {
  //...
}
    task generateClientInstaller(type: JavaExec) {
        //run JavaExec, which outputs several files into build dir
    //we want to publish to Ivy
}
  publishing {
 repositories {
                          ivy {
            name = 'ivy_test_repo'
            url "../test-ivy-repo"
            layout 'pattern', {
                artifact "[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"
                ivy "[organisation]/[module]/ivys/ivy-[revision].xml"
            }
        }
 }
      publications {
  ivy(IvyPublication) {
          configurations {
    windows {}
    linux {}
    mac {}
     master {
     extend "windows,linux,mac"
    }
   }
        module 'compressed-jres'
   organisation 'jwrapper'
                        //this file name will vary each time we run the build
    //I need a way to determine the name dynamiclly otherwise I have to
    //edit this file after every run of generateClientInstaller and update the artifact names
   //before calling publish
   artifact(file('build/JWrapper-Windows32JRE-00023523138-archive.p2.l2')) {
        name 'JWrapper-Windows32JRE-00023523138-archive.p2'
    conf 'windows'
    builtBy generateClientInstaller
    revision jreVersion
   }
     //several more artifacts like this...
                     }
 }
}

I need to specify the artifact like this somehow artifact(‘build/JWrapper-Windows32JRE-*-archive.p2.l2’) {

I’ve tried this, but it fails as the path is evaluated at configuration time (I think)

File compressedJre = fileTree('build').include('**/JWrapper-Windows32JRE-*-archive.p2.l2').singleFile
artifact(file(compressedJre )) {
    name compressedJre .name
    builtBy generateClientInstaller
}

Is there any way to know the output file names at configuration time? Or do you not have the output file until after the JavaExec task has run?

In the latter case, you might be able to configure the IvyPublication during execution phase. This isn’t fully supported, but might work:

File compressedJre = fileTree('build').include('**/JWrapper-Windows32JRE-*-archive.p2.l2').singleFile
project.publishing.publications.ivy.artifact(file(compressedJre )) {
    name compressedJre .name
}

You’ll need to wire up the task dependencies yourself. You’ll need to access the publishing tasks from within a publishing block as described in http://forums.gradle.org/gradle/topics/_maven_publish_plugin_automatically_uploading_artifacts_when_jar_is_not_up_to_date.

Hi, unfortunately I don’t know the file names at configuration time, the JavaExec task I’m running generates the files and uses a different file name on each execution. I tried the code below but this doesn’t work either, I get this error (for the line with the fileTree)

Expected directory ‘build’ to contain exactly one file, however, it contains no files.

Here’s what I tried (hopefully this is what you meant by wiring the task dependencies)

File compressedJre = fileTree('build').include('**/JWrapper-Windows32JRE-*-archive.p2.l2').singleFile
project.publishing.publications.ivy.artifact(file(compressedJre)) {
    name compressedJre.name
}
  publishing {
    publishIvyPublicationToIvy_test_repoRepository.dependsOn generateClientInstaller
}

Obviously you cannot access the ‘singlefile’ generated by JavaExec until after the task has executed. So the code to create the artifact will need to run in a doLast block of ‘generateClientInstaller’ or in another task that depends on ‘generateClientInstaller’.

You’ll need to then make sure that the appropriate “GenerateIvyFile” task depends on “generateClientInstaller” (or the task the creates the artifact), so that the artifact is configured early enough.

publishing {
    generateIvyFileForIvyPublication.dependsOn generateClientInstaller
}

I’m not certain this will work, but it’s worth a try.

Ah thanks. I’ve got it working now with the following

apply plugin: 'ivy-publish'
apply plugin: 'base'
version = '1.7.0_25'
repositories {
      ivy {
        name = 'ivy_repo'
        url "$ivyRepoRemote"
        layout 'pattern', {
          artifact "[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"
          ivy "[organisation]/[module]/ivys/ivy-[revision].xml"
        }
    }
       ivy {
                name = 'ivy_test_repo'
        url "D:/tmp/test-ivy-repo"
        layout 'pattern', {
            artifact "[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"
            ivy "[organisation]/[module]/ivys/ivy-[revision].xml"
        }
    }
       }
  task generateClientInstaller(type: JavaExec) {
        //run JavaExec, which outputs several files into build dir
    //we want to publish to Ivy
}
  task createArtifactsToPublish(dependsOn: generateClientInstaller) << {
           FileTree generatedFiles = fileTree(dir: 'build/build', includes: ['**/JWrapper-*JRE-*-archive.p2.l2', '**/JWrapper-*version.txt'])
    generatedFiles.each { File file ->
        project.publishing.publications.ivy.artifact(file) {
            name file.name
            conf 'windows'
                    }
    }
}
  publishing {
 repositories {
         add project.repositories.ivy_test_repo
 }
     publications {
  ivy(IvyPublication) {
          configurations {
    windows {}
    linux {}
    mac {}
     master {
     extend "windows,linux,mac"
    }
   }
        module 'compressed-jres'
   organisation 'jwrapper'
                         }
 }
}
  publishing {
    generateDescriptorFileForIvyPublication.dependsOn createArtifactsToPublish
}

I had to use generateDescriptorFileForIvyPublication.dependsOn createArtifactsToPublish. I tried generateIvyFileForIvyPublication as you suggested but got the error

A problem occurred configuring root project ‘jwrapperJreCompressor’. > Could not find property ‘generateIvyFileForIvyPublication’ on org.gradle.api.publish.internal.DefaultPublishingExtension_Decorated@53a346a0.

Running the build I can see the following tasks being executed.

:generateClientInstaller
:createArtifactsToPublish
:generateDescriptorFileForIvyPublication
:publishIvyPublicationToIvy_test_repoRepository

I also couldn’t put a revision in the project.publishing.publications.ivy.artifact(file) as follows:

project.publishing.publications.ivy.artifact(file) {
            name file.name
            conf 'windows'
             revision "1.7"
        }

Doing this gives the following error, however that’s not really a problem as I set the project version to handle this.

Execution failed for task ‘:createArtifactsToPublish’. > Could not find method revision() for arguments [1.7.0_25] on DefaultIvyArtifact_Decorated JWrapper-JWrapper-version.txt:txt:txt:null.

I had to use publishIvyPublicationToIvytestrepoRepository.dependsOn createArtifactsToPublish. I tried generateIvyFileForIvyPublication as you suggested but got the error

Sorry I got the task name wrong, the correct dependency would be:

generateDescriptorFileForIvyPublication.dependsOn createArtifactsToPublish

Otherwise, it’s possible that you’ll generated the ivy file before the publication has been configured with the artifacts, and the ivy file won’t have the correct info. Right now I think you’re lucky that ‘createArtifactsToPublish’ is alphabetically before ‘generateDescriptorFileForIvyPublication’, the ordering is ok. If you rename ‘createArtifactsToPublish’ to ‘z_createArtifactsToPublish’ I think you’ll have a problem. Adding the correct dependency will be more robust.

I also couldn’t put a revision in the project.publishing.publications.ivy.artifact(file)

You set the revision on a publication, not on an individual aritifact:

publishing {
    publications.ivy.revision "1.7"
}