ArtifactHandler configuration incorrectly adds task to TaskExecutionGraph

I found a case where gradle was executing a task it should not have been. I basically have two build execution graphs in Gradle. The primary one is using ‘build’ task with the ‘java’ plugin. The secondary is through a separate configuration I’ve created called ‘ant’. This configuration wraps all my ant build into a separate task. For some reason, running the ‘build’ task began executing some of the ant builds in my sub-projects.

I tracked the issue down to the configuration of the ArtifactHandler on one of the subprojects. The defintion below, causes gradle to attempt to execute the ‘buildAnt’ task:

configurations.create 'ant'
task buildAnt(type:GradleBuild) {
    ...
}
artifacts {
    ant file:file('build.ant/lib/output-lib.sar'), builtBy:buildAnt
}

This is not right, because ‘gradle build’ should only execute the build for the ‘main’ source set. I noticed that the above notation worked correctly for ‘jar’ files, and that was what most of the ant artifacts were creating. Changing the artifact defination caused the ‘buildAnt’ task not to be part of the TaskExecutionGraph

artifacts {
    ant file:file('build.ant/lib/output-lib.sar'), builtBy:buildAnt, type:'jar'
}

Explicitly setting the artifact type to ‘jar’ fixed the issue, but why. It should never have been part of the execution graph anyway.

‘builtBy: buildAnt’ will make tasks that use ‘configurations.ant’ depend on ‘buildAnt’ (if they are configured in the correct way). That’s likely the culprit here.

No … I can assure you that adding 'type:‘jar’ was only change made. When I did this, the task was no longer included in the execution.

That’s the symptom, but not necessarily the cause. Can you provide a reproducible example?

Please tell me if I did something wrong here: gradle.build:

apply plugin:'java'
  configurations.create 'aJarArtifact'
configurations.create 'aSarArtifact'
  task extraJar(type:DefaultTask) << {
   println ''
   println 'JAR: DID I RUN?'
   println ''
}
  task extraSar(type:DefaultTask) << {
   println ''
   println 'SAR: SHOULD I BE RUNNING?'
   println ''
}
  artifacts {
   aJarArtifact file:file('my_file.jar'), builtBy: extraJar
   aSarArtifact file:file('my_file.sar'), builtBy: extraSar
}

OUTPUT:

$ gradle build
:extraSar
  SAR: SHOULD I BE RUNNING?
  :compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
  BUILD SUCCESSFUL
  Total time: 1.387 secs

This behavior is expected, but we are working on making it more transparent. Anyway, if you want to build a particular configuration (say ‘foo’), you need to use ‘buildFoo’. Note that unlike ‘build’, the build tasks for particular configurations don’t by default depend on ‘check’.

Can you explain why extraSar is added to the execution graph, but extraJar is not? I don’t understand why gradle treats these case differently.

The current algorithm that decides what goes on the ‘archives’ configuration will pick at most one artifact of type ‘jar’. In your case, this is the artifact added by the ‘java’ plugin (i.e. ‘jar’, not ‘extraJar’).

Got it. My first mistake was that I did not realize that ‘build’ (through ‘assemble’) tries to create all artifacts. I thought it would only build artifacts with a sourceSet.

At first I was adding additional artifacts that did not get created with ‘build’, and I thought that was by design. It turns out that was a quirk/limitation. When sar got built, I thought that that was a bug, but actually it was working correctly, just not hitting the same artifact quirk.

Is there a way to prevent the java plugins ‘build’ task from building an artifact, like the SAR file in the example above?

It looks like gradle gets confused when I have a second configuration with an identically named artifact in a different dir. Is this another limitation to artifacts? I can pose a test case if you want.

My guess is that you don’t provide enough metadata along with the files, and they will thus end up with the same (file-based) defaults. If your artifacts are produced by archive tasks (‘Jar’, ‘War’, ‘Ear’, ‘Zip’, ‘Tar’), you should add the tasks themselves to the configuration. Otherwise, you need to provide the necessary metadata (see user guide).

Can you please add a warning if grade finds overlapping artifacts?

I just spent hours tracking down another issue caused by this. There must be race-condition with how gradle selects the artifact. In my case, every 3 or 4 builds Gradle would decide to recompile random parts of my project because it swapped the artifacts.

I know most users won’t hit these strange cases, but since gradle is supposed to be “extensible”, that doesn’t mean it should be so brittle as to accept user input that causes undefined results. A little error checking would go a long way in these cases. I’m sure it would also help any plugin developers too.