Oliver Charlesworth
Oliver Charlesworth

Reputation: 272577

Gradle Maven plugin generates incorrect POM dependencies for custom configuration

I have a Gradle project which does a couple of orthogonal things:

  1. Compile and run some Java.
  2. Generate and publish an artifact.

This artifact is nothing to do with the Java; it's generated by a custom JavaExec task. However, the auto-generated POM (from the Maven plugin) seems to include the wrong dependencies. Question: How can I prevent this?

My build.gradle looks something like this:

apply plugin: "java"
apply plugin: "maven"

configurations {
    foo  // Custom configuration for the artifact I want to build and publish
}

// Dependencies for Java configurations (nothing to do with foo)
dependencies {
    compile "foo:foo:1.1"
    testCompile "bar:bar:2.2"
}

// Custom task
task generateFoo(type: JavaExec) {
    ext.outputFile = new File(buildDir, "foo.bar")
    ...
}

artifacts {
    foo    file: generateFoo.outputFile, builtBy: generateFoo
}

uploadFoo {
    repositories {
        mavenDeployer { ... }
    }
}

I invoke Gradle like this:

./gradlew uploadFoo

AFAICS, the foo configuration is unrelated to the Java configurations. So I expect the published POM to list no dependencies. However, I observe all the unrelated dependencies listed.

The Gradle docs for the Maven plugin hint at dependency mapping with conf2ScopeMappings, but I'm entirely unclear what (if anything) I should be doing with this.


Note: I'm using Gradle wrapper 1.6; I'll be trying the latest to see if that makes a difference...

Upvotes: 2

Views: 2170

Answers (1)

Michal Moravcik
Michal Moravcik

Reputation: 2329

I managed to setup similar configuration with both maven and maven-publish gradle plugins.

In my case I was using custom Jar task with custom configuration, but it should work because the artifacts { ... } are used in both cases.

With maven plugin, your build.gradle would look like:

apply plugin: "java"
apply plugin: "maven"

configurations {
    foo  // Custom configuration for the artifact I want to build and publish
}

// Dependencies for Java configurations (nothing to do with foo)
dependencies {
    compile "foo:foo:1.1"
    testCompile "bar:bar:2.2"
}

// Custom task
task generateFoo(type: JavaExec) {
    ext.outputFile = new File(buildDir, "foo.bar")
    ...
}

artifacts {
    foo    file: generateFoo.outputFile, builtBy: generateFoo
}

uploadFoo {
    repositories {
        mavenDeployer { 
            pom.scopeMappings.with {
                mappings.clear()
                addMapping(300, configurations.foo, 'runtime')
            }
            pom.artifactId = 'other artifact id than main jar'
            ... 
        }
    }
}

This solution was inspired by following thread:
http://gradle.1045684.n5.nabble.com/pom-generation-and-inherited-dependencies-td1436197.html

Note the line:

addMapping(300, configurations.foo, 'runtime')

You can add other configurations as well, or use other maven scope than the 'runtime' scope.
300 stands for priority, which is not significant in this case.

Advantage of this solution is that we have quite fine control over dependencies and their mappings. Disadvantage would be that this will not work for the install task. We would need to setup different poms for the install task, which might be possible, but it is beyond my knowledge.

Alternative with usage of maven-publish plugin:

apply plugin: "java"
apply plugin: "maven-publish"

configurations {
    foo  // Custom configuration for the artifact I want to build and publish
}

// Dependencies for Java configurations (nothing to do with foo)
dependencies {
    compile "foo:foo:1.1"
    testCompile "bar:bar:2.2"
}

// Custom task
task generateFoo(type: JavaExec) {
    ext.outputFile = new File(buildDir, "foo.bar")
    ...
}

artifacts {
    foo    file: generateFoo.outputFile, builtBy: generateFoo
}

publishing {
    publications {
        foo(MavenPublication) {
            from new org.gradle.api.internal.java.JavaLibrary(\
                configurations.api.artifacts.toArray()[0], \
                configurations.api.allDependencies)
            artifactId 'other artifact id than main jar'
        }
    }
    repositories {
        maven { ... }
    }
}

gradle tasks will give you possible publish commands:

publish - Publishes all publications produced by this project.
publishFooPublicationToMavenLocal - Publishes Maven publication 'foo' to the local Maven repository.
publishFooPublicationToMavenRepository - Publishes Maven publication 'foo' to Maven repository 'maven'.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.
...

The advantege of maven-publish alternative is that it will work for both local and remote maven repositories. Disadvantage may be a fact that we are using the internal API which may change in future and that all dependencies are mapped to the 'runtime' maven scope. Also the MavenPublication snippet would be much more verbose and more internal API would be used if we would like to use some other maven scope or apply some scope mapping.

I am using Gradle 1.10

Upvotes: 5

Related Questions