Solving version conflicts with lein-pedantic
A couple months ago I wrote do not use version ranges in project.clj. While this helps reduce confusion about what version of dependencies a project will use, it does not eliminate all sources of confusion.
Different dependency versions
This project graph has two versions of ring/ring-core
that it wants
to use. com.cemerick/friend
wants [ring/ring-core "1.0.2"]
and
noir
wants [ring/ring-core "1.1.0"]
The dependency resolution in lein/maven/aether will end up
choosing the one closest to the project root, which in this case is
[ring/ring-core "1.0.2"]
. This causes a problem because noir
wants to use ring.middleware.head
which was added in 1.1.0.
A similar problem can occur for top level dependencies.
Introducing lein-pedantic
To help solve these problems, I’ve written
lein-pedantic. It is a
plugin for leiningen that will reject
dependency graphs with common errors that would be confusing for
users. In addition, it tries to provide a helpful command to use to
fix the issue. For example, the noir
and com.cemerick.friend
issue would result in:
It is designed to use leiningen’s hook system, and only requires being
added to the :plugins
vector. No extra tasks are added, it just
runs anytime leiningen attempts to resolve dependencies.
It works by determining the dependency graph for each of the project’s dependencies on their own, and comparing them to the collective dependency graph. It will reject the graph if
- A top level dependency is overruled by another version.
- A transitive dependency is overruled by an older version.
Together, these help identify most of the problems “soft/recommended” dependencies cause. In addition, lein-pedantic does not change the dependency resolution rules, so the final dependencies put in project.clj will work the same in maven or another aether based system.