Converting version ranges to specific version numbers in the generated pom


(Matt Khan) #1

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


(Dan Stine) #2

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?


(Matt Khan) #3

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


(Matt Khan) #4

(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’