Depending on custom publications

I am working on a non-java build and in some cases, my project will produce more than one artifacts. I’ve chosen to publish all of them as MavenPublication despite not being Java. Each publication would have unique GAV coordinates and will hold 2 artifacts with custom classifier.

Now I got to the point where I would like a build to depend on the output of another build. I don’t really need to publish artifacts, just to be able to depend on them from other projects, like this:

dependencies { 
   upstreamData project(':abc')  
   upstreamData project(':foobar:baz')  
   upstreamData project(':foobar:baz', configuration: extra_foo-bar)  // it is uncommon to have extras
   upstreamData project(':foobar:baz', configuration: extra_baz-qux)  
}

In order to achieve this, I need to add the outputs from projects :abc and :boobar:baz to the respective configurations (i.e. default and extra_*), but I am not sure how to achieve this as configurations are frozen once the build starts running.

If anybody would answer before I’ve started to read the BaseJavaPlugin it would be very appreciated.

Found a way by using an artifacts { ... } block. As it is documented in the “Legacy Publishing” I am not very clear whether I am using deprecated approach.

Can anybody confirm the status of this API and let me know if there is a better way?

p.afterEvaluate {
  p.tasks.withType(JavaExec).findAll { ext.hasProperty('report') }.each { task ->
    def configName= task.criteria=='standard'  ? 'default' : "reports-$task.reportType"
    p.configurations.maybeCreate(configName) // the `default` config is already created
    task.outputs.files.each { f ->
      p.artifacts.add(configName, [file: f, builtBy: task])
    }
  }
}

@glaforge - does this fit in the adhoc SoftwareComponents concept by any chance?

Personally I think that afterEvaluate is a hack which can usually be avoided. Imagine two or three plugins all trying to perform logic in the afterEvaluate event where each plugin wants to be last to execute

Most collections in the Gradle model extend DomainObjectCollection and you can hook into the “live” methods.

Eg: Instead of

afterEvaluate {
   tasks.withType(JavaExec).findAll {...}.each {...}
} 

You can do

tasks.withType(JavaExec).matching {...}.all{...}

That would work if all tasks were fully configured on creation. It is a good practice, but not guaranteed.

In this case, I create JavaExec tasks in a top-level subprojects {...} block and customize them in an afterEvaluated block as I need to resolve a custom configuration to create the arguments list. If the exec arguments supported it, I could have used Provider, but as it stands right now I can’t resolve the task config before all the project scripts are evaluated.

For now I have changed the build to use the live collections (step in the right direction), but I’m also keeping the afterEvaluate.

That would work if all tasks were fully configured on creation

Most file based methods in the Gradle model accept Object. You can often use a closure to delay the file resolution until after configuration phase

I need to resolve a custom configuration to create the arguments list

Ideally you will never resolve a configuration in the configuration phase. Perhaps this logic can be moved into another task which the publish task dependsOn?

If the exec arguments supported it, I could have used Provider

You can use Project.exec {...} instead of an Exec task (eg in a doFirst{…} or doLast{…} block)