Converting version ranges to specific version numbers in the generated pom

My build manages versions numbers automatically and so dependencies tend to expressed as a range. I’ve noticed the range is passed through to the POM as a range whereas I want to pass through (publish) the resolved dependency. Is there a mechanism in gradle I’m missing to achieve this? I can see there is a PomDependenciesConverter abstraction but it looks like it is not something I can override

Therefore it looks like I’ll need to use ‘pom#whenConfigured’ and then

  • walk through the dependencies on the pom - search for the corresponding project configuration

  • get the ResolvedConfiguration from that - match up the POM dependency with the resolved one - update the POM dependency version to match

Is there a better way?

IMO the default behaviour should be to realise a static set of dependencies when I do an install rather than pass through an unstable dependency. This is how ivy works in this case fwiw.

Cheers Matt

I have the same question, but on the Ivy side. I would prefer to see the resolved version number in ivy.xml.

When I use Gradle to publish to an Ivy repo, the generated ivy.xml sets ‘rev’ equal to ‘1.0.+’ instead of ‘1.0.23’ (for example). I guess your comment about Ivy describes its behavior when it is not used via Gradle?

Yes, this is what the deliver task does when using ivy ant tasks.

(apparently working) solution for maven as follows, to be called from a ‘pom.whenConfigured’

I’m sure my groovy is not especially idiomatic but it seems to work.

/**
     * Realises a Maven dependency into a specific version.
     * @param dep the dependency, expected to be of type {@link org.apache.maven.model.Dependency} otherwise there may
     * be trouble ahead!
     */
    void realiseDependency(def dep) {
        if (isDynamic(dep)) {
            project.logger.info("Realising $dep into a specific revision")
            Configuration conf = project.configurations.findByName(dep.scope)
            if (conf == null) {
                throw new BuildException("Unable to realise $dep due to missing configuration, aborting as dependency tree will be unstable")
            } else {
                def matches = conf.resolvedConfiguration.resolvedArtifacts.findAll {
                    it.moduleVersion.id.group.equals(dep.groupId) && it.moduleVersion.id.name.equals(dep.artifactId) && (it.classifier == null || (it.classifier != null && it.classifier.equals(dep.classifier)))
                }
                if (matches.size() > 1)
                    throw new BuildException("Unable to realise $dep due to multiple resolved dependencies, aborting as dependency tree will be unstable")
                else
                    matches.each { dep.version = it.moduleVersion.id.version }
            }
        }
    }
      boolean isDynamic(def dep) {
        return dep.version.any { it == '[' || it == ']' || it == '(' || it == ')' || it == '+' }
    }

FWIW I don’t see any equivalent hooks for ivy. It all seems to be baked in via the internal ivyservice & specifically the ‘org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependencyDescriptorFactory’