Reputation: 7351
When publishing with the use of maven-publish
(incubating, I know), compile
dependencies are added to the generate POM (in the runtime
scope), but testCompile
dependencies are ignored.
How to get the testCompile
dependencies into the generated POM as test
scope?
Upvotes: 5
Views: 2797
Reputation: 42293
I wasn't able to use any of the feature of the groovy language when I needed to modify the POM xml. And I had to rely on the API directly just like krzychu's answer.
Otherwise the xml closure wasn't applied as I expected it would, the build was failing with some warning, or the closure wasn't applied correctly resulting in invalid pom.
But recently, after reading carefully the groovy's closure documentation, I noticed one can apply a resolutionStrategy
to a closure, to help the runtime find the right context (the implicit this).
The default resolution strategy is Closure.OWNER_FIRST
, which explains why I got errors about the closure being applied to publications
in some of my trials. From their documentation I tried to set the strategy to Closure.DELEGATE_FIRST
and this proved working as expected.
Note however the closure has to apply on a Node
, hence the .children()
returns a list, .last()
returns a Node
on which you can add another node either via the .plus(...)
method or its alias +
.
publishing {
publications {
core(MavenPublication) {
pom.withXml {
def dependenciesNode =
asNode().dependencyManagement
.first()
.dependencies
.first()
dependenciesNode.children().last().plus( {
resolveStrategy = Closure.DELEGATE_FIRST
dependency {
'groupId'('org.springframework.boot')
'artifactId'('spring-boot-dependencies')
'version'(rootProject.'spring-boot.version')
'type'('pom')
'scope'('import')
}
})
}
}
}
}
Finding the right syntax was like finding a pin in haystack, here's some links (1), (2), (3) that helped me one I found the resolutionStrategy
.
Upvotes: 0
Reputation: 3687
I used several hours to find a nice way to choose what build configuration an artifact or publication should use, but with no luck. My findings were, that the only way to achieve it is by modifying resulting POM XML as below:
// build.gradle
publishing {
repositories { /* skipped for brevity */ }
publications {
core(MavenPublication) {
from components.java
artifactId project.name
artifact sourcesJar {
classifier 'sources'
}
}
generators(MavenPublication) {
from components.java
artifactId "${project.name}-generators"
artifacts = [ generatorsJar ]
artifact generatorsSourcesJar {
classifier 'sources'
}
pom.withXml { pomXml -> replaceDependenciesWith('generatorsBase', pomXml) }
}
}
}
void replaceDependenciesWith(String configurationName, XmlProvider pomXml) {
Node configurationDependencies = new Node(null, 'dependencies')
project.configurations.getByName(configurationName).allDependencies.each { dep ->
Node dependency = new Node(null, 'dependency')
dependency.appendNode('groupId', dep.group)
dependency.appendNode('artifactId', dep.name)
dependency.appendNode('version', dep.version)
dependency.appendNode('scope', 'compile')
configurationDependencies.append(dependency)
}
pomXml.asNode().dependencies*.replaceNode(configurationDependencies)
}
Above worked on Gradle 3.3
I also tried to use Groovy's XML builder-like syntax, but unfortunately wrong context was attached to closure passed to replaceNode
method and hence it did not work. When inlined it was getting the same context as publications {}
closure, while when extracted to a method, version dep.version
did not work as expected).
// Does not work!
void replaceDependenciesWith(String configurationName, Node pomXmlNode) {
pomXmlNode.dependencies*.replaceNode {
dependencies {
project.configurations.getByName(configurationName).allDependencies.each { dep ->
dependency {
groupId dep.group
artifactId dep.name
version dep.version
scope 'compile'
}
}
}
}
}
Upvotes: 3
Reputation: 2725
The POM is only used when publishing an artifact; it gets uploaded to the Maven repo along with the artifact. Therefore, the POM only needs runtime dependencies.
Gradle executes tests independent of your deployment plugin, so it does not use the POM file.
Assuming you're using the Java plugin, it adds the test
source set. This in turn creates the testCompile task.
Now, Gradle assumes that your runtime dependencies will be the same as your compile-time dependencies, if you don't configure otherwise. However, it only considers the main
source set. That's why you POM doesn't include test
dependencies.
So, in summary, configure your test dependencies similar to the below. Then, just live happy, knowing that the published artifact will not include your test code or its dependencies.
dependencies {
testCompile 'org.springframework:spring-test:4.+'
}
If you have an exceptional situation, where tests are executed on a machine that doesn't have access to the test source code, please describe in more detail what your requirements are. It should be possible to set up a separate output artifact for the test code, so it can be published, but I still don't think you should release it in the same package (or POM) as the main
source set.
Upvotes: 2