Elusive "Could not resolve all dependencies" error with local file system maven repositories

I use Gradle 2.4. I have an error I do not understand with a local file system maven repository. What I try to do is to copy from a “ci” repository to a “release” repository. Here is a complete working example of the problem:

settings.gradle:

rootProject.name = "proj"

build.gradle:

apply plugin: 'distribution'

project.version = "74384"

ext {
  cwd = System.getProperty("user.dir")
  ciRepo = cwd+"/ciRepo"
  releaseRepo = cwd+"/releaseRepo"
}

buildDir = new File(ext.cwd+"/build")

def docsCopySpec = project.copySpec {
  from (cwd) {
    include 'file.txt'
  }
}

distributions {
  docs {
    baseName = rootProject.name
    contents {
      with docsCopySpec
    }
  }
}

docsDistTar {
  compression = Compression.GZIP
  classifier = "docs"
}

apply plugin: 'maven-publish'
group = "org.martin"

publishing {
  publications {
    txt(MavenPublication) {
      artifact(docsDistTar) {
        classifier "txt"
      }
    }
  }
  repositories {
    maven {
      name "ci"
      url ciRepo
    }
    maven {
      name = "release"
      url = releaseRepo
    }
  }
}

task publishTxt() {
  dependsOn "publishTxtPublicationToCiRepository"
}

repositories {
  maven {
    name = "Local file system"
    url ciRepo
  }
}

configurations {
  release
}

dependencies {
  release "${group}:${rootProject.name}:${project.version}:txt@tgz"
}

task publishRelease(type: Copy) {
  from configurations.release
  into releaseRepo
}

To run this code, first create a plain file.txt:

echo "123" > file.txt

Then run:

gradle publishTxt

The local ciRepo folder contains:

$ tree ciRepo/
ciRepo/
└── org
    └── martin
        └── proj
            ├── 74384
            │   ├── proj-74384.pom
            │   ├── proj-74384.pom.md5
            │   ├── proj-74384.pom.sha1
            │   ├── proj-74384-txt.tgz
            │   ├── proj-74384-txt.tgz.md5
            │   └── proj-74384-txt.tgz.sha1
            ├── maven-metadata.xml
            ├── maven-metadata.xml.md5
            └── maven-metadata.xml.sha1

Now run the publishRelease task:

gradle publishRelease

And:

:publishRelease

FAILURE: Build failed with an exception.

* What went wrong:
Could not resolve all dependencies for configuration ':release'.
> Could not find proj-txt.tgz (org.martin:proj:74384).
...

It looks like the version number is missing from the dependency resolution, but a few minor changes to the build.gradle file “fix” the problem:

$ diff -u build.gradle build-solved.gradle 
--- build.gradle        2015-05-21 19:20:39.918476749 -0400
+++ build-solved.gradle 2015-05-21 19:31:04.562077456 -0400
@@ -9,24 +9,24 @@
 }
 buildDir = new File(ext.cwd+"/build")
 
-def docsCopySpec = project.copySpec {
+def txtCopySpec = project.copySpec {
   from (cwd) {
     include 'file.txt'
   }
 }
 
 distributions {
-  docs {
+  txt {
     baseName = rootProject.name
     contents {
-      with docsCopySpec
+      with txtCopySpec
     }
   }
 }
 
-docsDistTar {
+txtDistTar {
   compression = Compression.GZIP
-  classifier = "docs"
+  classifier = "txt"
 }
 
 apply plugin: 'maven-publish'
@@ -35,7 +35,7 @@
 publishing {
   publications {
     txt(MavenPublication) {
-      artifact(docsDistTar) {
+      artifact(txtDistTar) {
         classifier "txt"
       }
     }

Just those few name changes are enough to “make it work”. Can someone explain to me what I am doing wrong in the first code example, and why such minor changes appear to fix the publishRelease task?

I don’t fully understand what you are trying to achieve. Can you please clarify your use case and what you’d want to happen?

I want to copy artifacts from one maven repository into another.

In that case, I’d recommend using the Artifact Query API. It allows for accessing resolved artifacts (including the metadata) in your Gradle cache to be copies somewhere else.

Does it work for non-jar, non-java family projects, and with multiple classifiers?

I think you should be able to access declare dependencies via Configuration.resolvedConfiguration.resolvedArtifacts assuming that you declare them in your build script. If you don’t declare them in your build script, you’d have to think about a different solution. Then the Artifact Query API won’t help you either.

I understand that you want to copy one repository to another. But why do you want to to that for the CI environment? Is the reason that you don’t have a central binary repository? If that’s the case, I’d highly recommend setting one up. Then your whole problem goes away.

The CI environment builds continuously. Only a few select builds deserve promotion to the release repository. Both repositories are maven file system based repositories. Yes I should use a central bin repository, that might happen after I demonstrate success with a file based approach.

I would really like to understand what is wrong in my code, because after a few cosmetic changes as shown in the diff, I am able to copy. To me the changes I have made are simply name changes, but somehow they affect functionality.

I tried to use the Artifact Query API to get the list of tests artifacts, but it is not working so far. (note: I changed the initial code to this new code below, it is easier for reproducing the scenario).

Here is the code:

repositories {
  mavenCentral()
}
configurations {
  randomName
}
dependencies {
  randomName "org.apache.commons:commons-lang3:3.4"
}

public interface TestsArtifact extends Artifact { }

task showArtifacts() << {
    def componentIds = configurations.randomName.incoming.resolutionResult.allDependencies.collect { it.selected.id }
    def result = dependencies.createArtifactResolutionQuery()
                             .forComponents(componentIds)
                             .withArtifacts(JvmLibrary, TestsArtifact)
                             .execute()
    for (component in result.resolvedComponents) {
        component.getArtifacts(TestsArtifact).each { println "Tests artifact for ${component.id}: ${it.file}" }
    }
}

I expect this code to show the tests artifact(s), but it does not. When I call .withArtifacts(JvmLibrary, JavadocArtifact) instead, I do get the javadoc artifact. I’d like to be able to list any type of artifact (and ultimately, copy them to another maven repository).

When I call .withArtifacts(JvmLibrary, JavadocArtifact) instead, I do get the javadoc artifact.

You are explicitly requesting the JavaDoc artifact.

I tried to use the Artifact Query API to get the list of tests artifacts, but it is not working so far.

As mentioned in a previous posting, the Artifact Query API won’t help here. We don’t expose arbitrary artifacts, only a set of predefined artifacts. There’s no type of TestsArtifact (at the moment).