I have a potentially strange case and I think that...
# community-support
t
I have a potentially strange case and I think that a
ComponentMetadataRule
is the best way to solve it but I can't quite get it to work. I have a repo publishing a module using Bazel (and a pom file for the metadata) and that module has a dependency on something published from another repo that uses Gradle. The dependency is a test fixture (modeled in Gradle as you'd expect). I have a third module that depends on the Bazel-published module; this third module uses Gradle. Gradle is not able to resolve the transitive test-fixture dependency, failing with an `ArtifactNotFoundException`: it's looking for
name-test-fixtures.jar
when it really ought to be looking for
name-version-test-fixtures.jar
. My rule looks like this so far:
Copy code
class MyRule : ComponentMetadataRule {
  override fun execute(context: ComponentMetadataContext) {
    context.details.allVariants {
      withDependencies {
        removeAll { it.module.toString() == "com.squareup.misk:misk-vitess" }
        //add("???") // what to add?
      }
    }
}
now, if I leave it as-is, it happens that compilation succeeds because the test-fixtures module for compilation is also coming into the graph via another path. But this isn't guaranteed so I want to fix this metadata so that compilation will always succeed. But I'm not sure how to re-add the test-fixture variant. In a dependencies block, it would look like
testImplementation(testFixtures("com.squareup.misk:misk-vitess:1"))
, but I don't know how to express that (specifically the
testFixtures()
part) in the
add(...)
method.
I've tried a couple of things:
Copy code
// 1
add("com.squareup.misk:misk-vitess") {
  artifactSelectors.add(DefaultDependencyArtifact("", "", null, "test-fixtures", null))
}
but that results in a dependency on the main variant, not the test-fixtures variant.
Copy code
// 2
add("com.squareup.misk:misk-vitess") {
  attributes {
    attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
  }
}
but then I get an error:
Copy code
Cannot select module with conflict on capability 'com.squareup.misk:misk-vitess:0.0-SNAPSHOT' also provided by [com.squareup.misk:misk-v
itess:0.0-SNAPSHOT(runtimeElements), com.squareup.misk:misk-vitess:0.0-SNAPSHOT(apiElements)]
That attribute was selected by looking at the
outgoingVariants
of the module with the test-fixtures variant and just picking an attribute that was different:
Copy code
--------------------------------------------------
Variant runtimeElements
--------------------------------------------------
Runtime elements for the 'main' feature.

Capabilities
    - com.squareup.misk:misk-vitess:0.0-SNAPSHOT (default capability)
Attributes
    - org.gradle.category                = library
    - org.gradle.dependency.bundling     = external
    - org.gradle.jvm.environment         = standard-jvm
    - org.gradle.jvm.version             = 11
    - org.gradle.libraryelements         = jar
    - org.gradle.usage                   = java-runtime-jars
    - org.jetbrains.kotlin.platform.type = jvm
Artifacts
    - build/libs/misk-vitess-0.0-SNAPSHOT.jar (artifactType = jar)

--------------------------------------------------
Variant testFixturesRuntimeElements
--------------------------------------------------
Runtime elements for the 'testFixtures' feature.

Capabilities
    - com.squareup.misk:misk-vitess-test-fixtures:0.0-SNAPSHOT
Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Artifacts
    - build/libs/misk-vitess-0.0-SNAPSHOT-test-fixtures.jar (artifactType = jar, classifier = test-fixtures)
I didn't really think setting an attribute would work. What I want to do is set a capability when I'm re-adding the dependency, but the API doesn't appear to allow that
I think the question boils down to, how do you add a dependency to a test-fixture of a module with a
ComponentMetadataRule
. Is that possible?
a
What happens if you do
add("com.squareup.misk:misk-vitess-test-fixtures")
?
t
First, I wonder if your problem isn't with the metadata published by the Bazel build. That being said, it looks like a known limitation of Gradle: https://github.com/gradle/gradle/issues/30088
t
I'm not 100% positive about the metadata published by bazel. But I compared the pom metadata published by a gradle build that had a dependency on a test fixture to what the bazel pom had and they were substantially different.
I'm not sure if this is related, but I found this in the documentation:
It’s worth noting that if the external project is not publishing Gradle Module Metadata, then resolution will fail with an error indicating that such a variant cannot be found:
if it's not a problem with the bazel metadata, then it's another bug in gradle. An
ArtifactNotFoundException
is, uh, unexpected. As I said above: > it's looking for
name-test-fixtures.jar
when it really ought to be looking for
name-version-test-fixtures.jar
. I did some debugging in Gradle code and saw a map named
allResolvedArtifacts
and saw it had many instances of this artifact, but they all included the version name in the artifact file name. It was only this one case, which came from the bazel metadata, that did not.
@Adam I did try what you suggested and got this error (in part):
Copy code
Could not find com.squareup.misk:misk-vitess-test-fixtures:.
I also tried adding a version name (note that we have a bom/platform that ought to supply the version), and got this error instead:
Copy code
Could not find com.squareup.misk:misk-vitess-test-fixtures:2025.04.30-1746055579-3c9b650-cash
another wrinkle here, which is why I originally called this "strange" above, is that this test-fixture dependency actually comes from an included build in the end-consumer build that has the failure. Gradle actually correctly does dependency substitution from the external module to the internal project dependency in the included build (I can see this substitution happening in a build scan), but then fails with
ArtifactNotFoundException
for the reasons I indicated above (the artifact is missing the
version
component from the file name. I think).