Gradle-duplicates-plugin

From Evgeny Goldin

Jump to: navigation, search

Contents

Introduction

Similarly to Maven "duplicates-finder-plugin" this plugin locates duplicate libraries in Gradle configurations. Duplicate libraries have different coordinates (group or name) but contain an identically named classes, i.e., classes with identical fully qualified names.


For example, configurations below contain a number of legal Gradle dependencies. Yet, some of them are duplicates, can you see them right away?:


dependencies {
    compile     'org.springframework:spring-core:3.0.5.RELEASE',
                'org.springframework:spring:2.5.6',
                'commons-beanutils:commons-beanutils:1.8.3',
                'commons-collections:commons-collections:3.2.1'
    testCompile 'org.hamcrest:hamcrest-core:1.2',
                'junit:junit:4.8.2'
}


  • "spring-core" is a subset of "spring"
  • "commons-beanutils" repacks some of "commons-collections" classes
  • "junit" repacks a portion of the Hamcrest library


One source of possible duplicates are changes done to library coordinates in Maven repositories, like in Spring example above. When libraries evolve, migrate, grow up and split up they may start naming their artifacts differently. And then having an old and new version of the same library in Gradle configuration causes a duplicate problem.

While developers normally don't add duplicate libraries deliberately, this may still happen due to transitive dependencies brought by another project. Situations when outdated versions of Spring or Apache projects "leak" through transitive dependencies are not uncommon, especially when dependencies are not managed tightly. Once those duplicates found, one should normally exclude an older version from configuration.

Another possible source of duplicate classes in the same configuration are repacking portions of one library in another library, as demonstrated by JUnit and Commons BeanUtils. I believe it's a terrible thing to do and have no simple advice for how to overcome situations when eliminating duplicates is absolutely necessary but both libraries are required. One available option is to remove duplicate classes from offending library manually and deploy new artifact under a different name.


Example

Running "gradle duplicates" for this "build.gradle" script:


apply plugin: 'groovy'
apply plugin: 'duplicates'
 
buildscript {
    repositories { mavenRepo url: 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' }
    dependencies { classpath      'com.github.goldin.plugins:gradle:0.1.3' }
}
 
repositories { mavenRepo urls: 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' }
duplicates   { configurations = [ 'compile', 'testCompile' ] }
 
dependencies {
    compile     'org.springframework:spring-core:3.0.5.RELEASE',
                'org.springframework:spring:2.5.6',
                'commons-beanutils:commons-beanutils:1.8.3',
                'commons-collections:commons-collections:3.2.1'
    testCompile 'org.hamcrest:hamcrest-core:1.2',
                'junit:junit:4.8.2'
}


causes the following build error:


>gradle -q duplicates
 
FAILURE: Build failed with an exception.
 
* What went wrong:
Execution failed for task ':duplicates'.
Cause:
Configuration [compile] - duplicates found in:
-=-= [org.springframework:spring-core:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
-=-= [org.springframework:spring-asm:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
-=-= [commons-beanutils:commons-beanutils:1.8.3, commons-collections:commons-collections:3.2.1] =-=-
 
Configuration [testCompile] - duplicates found in:
-=-= [org.hamcrest:hamcrest-core:1.2, junit:junit:4.8.2] =-=-
-=-= [org.springframework:spring-core:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
-=-= [org.springframework:spring-asm:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
-=-= [commons-beanutils:commons-beanutils:1.8.3, commons-collections:commons-collections:3.2.1] =-=-


When "verbose" is turned on all duplicate classes are printed:


>gradle -q duplicates
 
FAILURE: Build failed with an exception.
 
* What went wrong:
Execution failed for task ':duplicates'.
Cause:
Configuration [compile] - duplicates found in:
-=-= [org.springframework:spring-core:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
 --- [org.springframework.core.AliasRegistry]
 --- [org.springframework.core.AttributeAccessor]
 ...
-=-= [org.springframework:spring-asm:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
 --- [org.springframework.asm.AnnotationVisitor]
 --- [org.springframework.asm.AnnotationWriter]
 ...
-=-= [commons-beanutils:commons-beanutils:1.8.3, commons-collections:commons-collections:3.2.1] =-=-
 --- [org.apache.commons.collections.ArrayStack]
 --- [org.apache.commons.collections.Buffer]
 ...
 
Configuration [testCompile] - duplicates found in:
-=-= [org.hamcrest:hamcrest-core:1.2, junit:junit:4.8.2] =-=-
 --- [org.hamcrest.BaseDescription]
 --- [org.hamcrest.BaseMatcher]
 ...
-=-= [org.springframework:spring-core:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
 --- [org.springframework.core.AliasRegistry]
 --- [org.springframework.core.AttributeAccessor]
 ...
-=-= [org.springframework:spring-asm:3.0.5.RELEASE, org.springframework:spring:2.5.6] =-=-
 --- [org.springframework.asm.AnnotationVisitor]
 --- [org.springframework.asm.AnnotationWriter]
 ...
-=-= [commons-beanutils:commons-beanutils:1.8.3, commons-collections:commons-collections:3.2.1] =-=-
 --- [org.apache.commons.collections.ArrayStack]
 --- [org.apache.commons.collections.Buffer]
 ...


Here are two more Gradle scripts using this plugin:


Details

Provided By
Source Code GitHub
Issue Tracker YouTrack
Build Server Gradle
TeamCity
Repository,
Coordinates
Artifactory
buildscript {
    repositories { mavenRepo url: 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' }
    dependencies { classpath      'com.github.goldin.plugins:gradle:0.1.3' }
}


Settings

Name Type Default value Description
configurations List<String> null List of configurations to test. All configurations are tested if list is null or empty.
verbose boolean false Whether all duplicating classes should be printed.
fail boolean true Whether build should fail when duplicate libraries are found.
Personal tools