When trying to publish to a company Nexus repository the generated pom file fails to validate because dependencies that are private to our company can’t be found in central. I can’t find a way to configure the maven plugin to look elsewhere during this pom validation, and it doesn’t seem to pick up the mirror configuration from my user home settings.xml. I’m using gradle 2.0, how can I get the pom validation to look at our proxy rather than central for our dependencies?
I know the pom it generates is valid because I can run ‘mvn dependency:tree -f build/poms/pom-default.xml’ and it will properly hit our local repo and cache it in the local maven repo. If I run the gradle build after doing this it will work because the dependency is cached on my local machine.
Pleas provide the full/exact error message. Have you configured the proxy as a repository in ‘build.gradle’?
Sure thing, it is configured as a repository in a convention.gradle file that gets applied to the build.gradle file. The artifacts and the gradle build itself find the artifact in question, however the pom validation fails to use anything except central to try and find it. As a result validation fails because this artifact is not hosted on central but rather in our private repo.
Error:
:install
Downloading: com/infusionsoft/pancakes/infusionsoft-platform-bom/1.1.4.6/infusionsoft-platform-bom-1.1.4.6.pom from repository central at http://repo1.maven.org/maven2
Unable to locate resource in repository
:install FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':install'.
> Could not publish configuration 'archives'
> Unable to initialize POM pom-default.xml: POM 'com.infusionsoft.pancakes:infusionsoft-platform-bom' not found in repository: Unable to download the artifact from any repository
com.infusionsoft.pancakes:infusionsoft-platform-bom:pom:1.1.4.6
from the specified remote repositories:
central (http://repo1.maven.org/maven2)
for project com.infusionsoft.pancakes:infusionsoft-platform-bom
Configured repositories:
repositories {
maven { url "https://<ourNexusHostHere>/nexus/content/groups/infusionsoft" }
jcenter()
mavenCentral()
mavenLocal()
}
Many Gradle users are successfully publishing to their company repos, so I think the problem might be somewhere else. If I’m not mistaken, Gradle doesn’t support consuming Maven BOMs, and I’m not sure if it’s possible to publish them.
The problem isn’t really in using a bom, using the spring boot plugin you can use them in properties form which we are doing: http://docs.spring.io/autorepo/docs/spring-boot/1.2.0.BUILD-SNAPSHOT/reference/html/build-tool-plugins-gradle-plugin.html#build-tool-plugins-gradle-custom-version-management
We aren’t publishing the bom here, we have specified that it is a dependency on the build and the pom validation in the install or uploadArchives fails because it is looking in central for it instead of our proxy. Also we are publishing artifacts to our repos just fine as long as it doesn’t have a dependency that is internal only. Like I said the artifact builds fine, even with the bom properties file, but we did have a problem that it doesn’t auto generate that in the pom so we have the uploadArchives section defined as follows:
uploadArchives {
repositories {
mavenDeployer {
repository (url: repositoryUrl) {
authentication(userName: repositoryUsername, password: repositoryPassword)
}
pom.project {
dependencyManagement {
dependencies {
dependency {
groupId = 'com.infusionsoft.pancakes'
artifactId = 'infusionsoft-platform-bom'
version = pancakesVersion
scope = 'import'
type = 'pom'
}
}
}
}
}
}
}
Our bom creates a properties file based on the effective pom, just like the spring boot guys do and both are already published.
Not sure what’s going on then. Can you provide a minimal self-contained reproducible example? It would also be worthwhile to try with latest Gradle, and with the ‘maven-publish’ rather than the ‘maven’ plugin.
Tried upgrading the build to use 2.2 and I still see the same results. Interestingly enough in fiddling with getting you a minimal example I have made a discovery. It looks like all internal dependencies that are defined in the block of the pom will correctly resolve, however anything that is defined in the block always looks in central.
This doesn’t resolve the dependency correctly: https://gist.github.com/bryanstephens/a688dcc73e058752ed73
This does resolve the artifact, however the pom is now invalid because it will not import the versions (Tested by manually placing version on each dependency): https://gist.github.com/bryanstephens/22a5880e7d2a4ef9563b
I will try with the maven-publish plugin as well after posting this.
It looks like all internal dependencies that are defined in the block of the pom will correctly resolve, however anything that is defined in the block always looks in central.
I don’t understand what you are trying to say here.
My bad I wrote them as tags and they go consumed, it should read like:
It looks like all internal dependencies that are defined in the ‘dependency’ block of the pom will correctly resolve, however anything that is defined in the ‘dependencyManagement’ block always looks in central.
Interesting. I don’t think that ‘dependencyManagement’ blocks in published POMs will affect Gradle dependency resolution in any way, so you could consider not generating them.
Unfortunately if I remove it the pom become invalid because there are no versions specified. This is what including the bom in the ‘dependencyManagement’ does for us. This blocks us from publishing, not so worried about another consuming gradle project, as you are correct the dependencyManagement block wouldn’t even be considered by gradle.
Not sure where versions are missing, but perhaps you can fix that, rather than trying to compensate with ‘dependencyManagement’? Don’t think the latter will work when consuming from Gradle.
Trying with maven-publish both gradle 2.0 and 2.2:
:publishMavenJavaPublicationToMavenLocal
Downloading: com/infusionsoft/pancakes/infusionsoft-platform-bom/1.1.4.6/infusionsoft-platform-bom-1.1.4.6.pom from repository central at http://repo1.maven.org/maven2
Unable to locate resource in repository
:publishMavenJavaPublicationToMavenLocal FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':publishMavenJavaPublicationToMavenLocal'.
> Failed to publish publication 'mavenJava' to repository 'MavenLocal'
> Unable to initialize POM pom-default.xml: POM 'com.infusionsoft.pancakes:infusionsoft-platform-bom' not found in repository: Unable to download the artifact from any repository
com.infusionsoft.pancakes:infusionsoft-platform-bom:pom:1.1.4.6
from the specified remote repositories:
central (http://repo1.maven.org/maven2)
for project com.infusionsoft.pancakes:infusionsoft-platform-bom
The gist: https://gist.github.com/bryanstephens/28ed41761126cdc07231
The idea is to let developers use the recommended version from the pom when they don’t specify a version in the build. I suppose we could potentially iterate through each dependency and place them there ourselves. Is there a way to keep the publishing plugin from generating the dependency definitions for us? If there is I can try that.
Given that Gradle doesn’t consider ‘dependencyManagement’ in published POMs when resolving dependencies, how is that going to work?
Well because we are using the versionManagement from the spring boot plugin it uses the suggested versions from the properties file and iterates over every dependency and sets their version. I may be able to then iterate over the dependencies after the versions have been set and place them in the pom using the api you guys expose for modifying the generated pom. It would be simpler if I could just prevent the maven-publish plugin from generating the dependencies for me. But of course this is assuming I can hook in after the versions have been set by the spring-boot plugin.
You can customize ‘dependency’ entries any way you like using hooks such as ‘withXml’.
For anyone that is interested the following ended up being the workaround/fix to the issue, may not be the best solution but for now it works. If anyone has other suggestions I would like to hear them.
publishing {
publications {
webApp(MavenPublication) {
pom.withXml {
Node pom = asNode()
Node oldDependencies = pom.get('dependencies').getAt(0)
pom.remove(oldDependencies)
Node newDependencies = new Node(pom, 'dependencies')
Set<ResolvedDependency> compileDependencies = configurations.compile.resolvedConfiguration.firstLevelModuleDependencies
Set<ResolvedDependency> runtimeDependencies = configurations.runtime.resolvedConfiguration.firstLevelModuleDependencies
runtimeDependencies.removeAll(compileDependencies)
Set<ResolvedDependency> testRuntimeDependencies = configurations.testRuntime.resolvedConfiguration.firstLevelModuleDependencies
testRuntimeDependencies.removeAll(compileDependencies)
testRuntimeDependencies.removeAll(runtimeDependencies)
Map<String, Set<ResolvedDependency>> dependencySets = new HashMap<>()
dependencySets.put("compile", compileDependencies)
dependencySets.put('test', testRuntimeDependencies)
dependencySets.put('runtime', runtimeDependencies)
dependencySets.keySet().each { scope ->
dependencySets.get(scope).each { dependency ->
Node dependencyNode = newDependencies.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.id.id.group)
dependencyNode.appendNode('artifactId', dependency.id.id.name)
dependencyNode.appendNode('version', dependency.id.id.version)
dependencyNode.appendNode('scope', scope)
}
}
}
from components.java
}
}
repositories {
maven {
url repositoryUrl
credentials {
username repositoryUsername
password repositoryPassword
}
}
}
}