1
votes

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...
1
The problem is likely related to applying the java plugin. There is likely a solution, but I can't tell offhand what it is. The new maven-publish plugin gives more control (but is still incubating). You may want to give it a try first.Peter Niederwieser
@PeterNiederwieser: Thanks for the tip, I will try to figure out the new plugin and let you know whether it fixes things. (FYI, the above problem also occurs if I use the groovy plugin instead of the java plugin.)Oliver Charlesworth
Applying groovy also applies java.Peter Niederwieser

1 Answers

5
votes

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